001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2014 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * SonarQube is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public License
017     * along with this program; if not, write to the Free Software Foundation,
018     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019     */
020    package org.sonar.api.database.model;
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.apache.commons.lang.builder.EqualsBuilder;
024    import org.apache.commons.lang.builder.HashCodeBuilder;
025    import org.apache.commons.lang.builder.ToStringBuilder;
026    import org.hibernate.annotations.BatchSize;
027    import org.sonar.api.database.BaseIdentifiable;
028    import org.sonar.api.resources.Language;
029    import org.sonar.api.resources.ProjectLink;
030    import org.sonar.api.resources.Resource;
031    
032    import javax.annotation.Nullable;
033    import javax.persistence.CascadeType;
034    import javax.persistence.Column;
035    import javax.persistence.Entity;
036    import javax.persistence.FetchType;
037    import javax.persistence.OneToMany;
038    import javax.persistence.Table;
039    import javax.persistence.Temporal;
040    import javax.persistence.TemporalType;
041    
042    import java.util.ArrayList;
043    import java.util.Date;
044    import java.util.List;
045    
046    /**
047     * Class to map resource with hibernate model
048     */
049    @Entity
050    @Table(name = "projects")
051    public class ResourceModel extends BaseIdentifiable implements Cloneable {
052    
053      public static final String SCOPE_PROJECT = "PRJ";
054      public static final String QUALIFIER_PROJECT_TRUNK = "TRK";
055    
056      public static final int DESCRIPTION_COLUMN_SIZE = 2000;
057      public static final int NAME_COLUMN_SIZE = 256;
058      public static final int KEY_SIZE = 400;
059      public static final int PATH_SIZE = 2000;
060    
061      @Column(name = "name", updatable = true, nullable = true, length = NAME_COLUMN_SIZE)
062      private String name;
063    
064      @Column(name = "long_name", updatable = true, nullable = true, length = NAME_COLUMN_SIZE)
065      private String longName;
066    
067      @Column(name = "description", updatable = true, nullable = true, length = DESCRIPTION_COLUMN_SIZE)
068      private String description;
069    
070      @Column(name = "enabled", updatable = true, nullable = false)
071      private Boolean enabled = Boolean.TRUE;
072    
073      @Column(name = "scope", updatable = true, nullable = false, length = 3)
074      private String scope;
075    
076      @Column(name = "qualifier", updatable = true, nullable = false, length = 10)
077      private String qualifier;
078    
079      @Column(name = "kee", updatable = true, nullable = false, length = KEY_SIZE)
080      private String key;
081    
082      @Column(name = "deprecated_kee", updatable = true, nullable = true, length = KEY_SIZE)
083      private String deprecatedKey;
084    
085      @Column(name = "language", updatable = true, nullable = true, length = 20)
086      private String languageKey;
087    
088      @Column(name = "root_id", updatable = true, nullable = true)
089      private Integer rootId;
090    
091      @Column(name = "path", updatable = true, nullable = true, length = PATH_SIZE)
092      private String path;
093    
094      @Column(name = "copy_resource_id", updatable = true, nullable = true)
095      private Integer copyResourceId;
096    
097      @Column(name = "person_id", updatable = true, nullable = true)
098      private Integer personId;
099    
100      @Temporal(TemporalType.TIMESTAMP)
101      @Column(name = "created_at", updatable = true, nullable = true)
102      private Date createdAt;
103    
104      @OneToMany(mappedBy = "resource", fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE})
105      @BatchSize(size = 8)
106      private List<ProjectLink> projectLinks = new ArrayList<ProjectLink>();
107    
108      @Column(name = "uuid", updatable = false, nullable = true, length = 50)
109      private String uuid;
110    
111      @Column(name = "project_uuid", updatable = true, nullable = true, length = 50)
112      private String projectUuid;
113    
114      @Column(name = "module_uuid", updatable = true, nullable = true, length = 50)
115      private String moduleUuid;
116    
117      @Column(name = "module_uuid_path", updatable = true, nullable = true, length = 4000)
118      private String moduleUuidPath;
119    
120      /**
121       * Default constructor
122       */
123      public ResourceModel() {
124        this.createdAt = new Date();
125      }
126    
127      public ResourceModel(String scope, String key, String qualifier, Integer rootId, String name) {
128        this(scope, key, qualifier, rootId, null, name);
129      }
130    
131      /**
132       * <p>Creates a resource model</p>
133       *
134       * @param scope     the scope the rule will apply on
135       * @param key       the rule key. This is the name of the resource, including the path
136       * @param qualifier the resource qualifier
137       * @param rootId    the rootId for the resource
138       * @param path      the path of the resource
139       * @param name      the short name of the resource
140       */
141      public ResourceModel(String scope, String key, String qualifier, Integer rootId, @Nullable String path, String name) {
142        // call this to have the "createdAt" field initialized
143        this();
144        this.scope = scope;
145        this.key = key;
146        this.rootId = rootId;
147        this.path = path;
148        this.name = name;
149        this.qualifier = qualifier;
150      }
151    
152      /**
153       * Only available at project level.
154       */
155      public List<ProjectLink> getProjectLinks() {
156        return projectLinks;
157      }
158    
159      public void setProjectLinks(List<ProjectLink> projectLinks) {
160        this.projectLinks = projectLinks;
161      }
162    
163      /**
164       * @return a project link given its key if exists, null otherwise
165       */
166      public ProjectLink getProjectLink(String key) {
167        for (ProjectLink projectLink : projectLinks) {
168          if (key.equals(projectLink.getKey())) {
169            return projectLink;
170          }
171        }
172        return null;
173      }
174    
175      /**
176       * Only available at project level.
177       */
178      public String getDescription() {
179        return description;
180      }
181    
182      /**
183       * Sets the resource description, truncated to DESCRIPTION_COLUMN_SIZE
184       */
185      public void setDescription(String description) {
186        this.description = StringUtils.abbreviate(description, DESCRIPTION_COLUMN_SIZE);
187      }
188    
189      public String getName() {
190        return name;
191      }
192    
193      /**
194       * Sets the resource name, truncated to NAME_COLUMN_SIZE
195       */
196      public void setName(String name) {
197        this.name = StringUtils.abbreviate(name, NAME_COLUMN_SIZE);
198        if (this.longName == null) {
199          this.longName = this.name;
200        }
201      }
202    
203      public String getLongName() {
204        return longName;
205      }
206    
207      /**
208       * Sets the long name of the resource, truncated to NAME_COLUMN_SIZE
209       */
210      public void setLongName(String s) {
211        if (StringUtils.isBlank(s)) {
212          this.longName = name;
213        } else {
214          this.longName = StringUtils.abbreviate(s, NAME_COLUMN_SIZE);
215        }
216      }
217    
218      public Boolean getEnabled() {
219        return enabled;
220      }
221    
222      public void setEnabled(Boolean enabled) {
223        this.enabled = enabled;
224      }
225    
226      public String getScope() {
227        return scope;
228      }
229    
230      public void setScope(String scope) {
231        this.scope = scope;
232      }
233    
234      public String getKey() {
235        return key;
236      }
237    
238      public String getDeprecatedKey() {
239        return deprecatedKey;
240      }
241    
242      public String getLanguageKey() {
243        return languageKey;
244      }
245    
246      public void setLanguageKey(String lang) {
247        this.languageKey = lang;
248      }
249    
250      public Integer getCopyResourceId() {
251        return copyResourceId;
252      }
253    
254      public void setCopyResourceId(Integer i) {
255        this.copyResourceId = i;
256      }
257    
258      /**
259       * @since 2.14
260       */
261      public Integer getPersonId() {
262        return personId;
263      }
264    
265      /**
266       * @since 2.14
267       */
268      public ResourceModel setPersonId(Integer i) {
269        this.personId = i;
270        return this;
271      }
272    
273      /**
274       * @throws IllegalArgumentException if the key is longer than KEY_SIZE
275       */
276      public void setKey(String key) {
277        checkSize(key);
278        this.key = key;
279      }
280    
281      private void checkSize(String key) {
282        if (key.length() > KEY_SIZE) {
283          throw new IllegalArgumentException("Resource key is too long, max is " + KEY_SIZE + " characters. Got : " + key);
284        }
285      }
286    
287      /**
288       * @throws IllegalArgumentException if the key is longer than KEY_SIZE
289       */
290      public void setDeprecatedKey(String deprecatedKey) {
291        checkSize(deprecatedKey);
292        this.deprecatedKey = deprecatedKey;
293      }
294    
295      public Integer getRootId() {
296        return rootId;
297      }
298    
299      public void setRootId(Integer rootId) {
300        this.rootId = rootId;
301      }
302    
303      public String getPath() {
304        return path;
305      }
306    
307      public ResourceModel setPath(@Nullable String path) {
308        if (path != null && path.length() > PATH_SIZE) {
309          throw new IllegalArgumentException("Resource path is too long, max is " + PATH_SIZE + " characters. Got : " + path);
310        }
311        this.path = path;
312        return this;
313      }
314    
315      public String getQualifier() {
316        return qualifier;
317      }
318    
319      public void setQualifier(String qualifier) {
320        this.qualifier = qualifier;
321      }
322    
323      public Date getCreatedAt() {
324        return createdAt; // NOSONAR May expose internal representation by returning reference to mutable object
325      }
326    
327      public void setCreatedAt(Date createdAt) {
328        this.createdAt = createdAt; // NOSONAR May expose internal representation by returning reference to mutable object
329      }
330    
331      public String getUuid() {
332        return uuid;
333      }
334    
335      public void setUuid(String uuid) {
336        this.uuid = uuid;
337      }
338    
339      public String getProjectUuid() {
340        return projectUuid;
341      }
342    
343      public void setProjectUuid(String projectUuid) {
344        this.projectUuid = projectUuid;
345      }
346    
347      public String getModuleUuid() {
348        return moduleUuid;
349      }
350    
351      public void setModuleUuid(String moduleUuid) {
352        this.moduleUuid = moduleUuid;
353      }
354    
355      public String getModuleUuidPath() {
356        return moduleUuidPath;
357      }
358    
359      public void setModuleUuidPath(String moduleUuidPath) {
360        this.moduleUuidPath = moduleUuidPath;
361      }
362    
363      @Override
364      public boolean equals(Object obj) {
365        if (!(obj instanceof ResourceModel)) {
366          return false;
367        }
368        if (this == obj) {
369          return true;
370        }
371        ResourceModel other = (ResourceModel) obj;
372        return new EqualsBuilder()
373          .append(key, other.key)
374          .append(enabled, other.enabled)
375          .append(rootId, other.rootId)
376          .isEquals();
377      }
378    
379      @Override
380      public int hashCode() {
381        return new HashCodeBuilder(17, 37)
382          .append(key)
383          .append(enabled)
384          .append(rootId)
385          .toHashCode();
386      }
387    
388      @Override
389      public String toString() {
390        return new ToStringBuilder(this)
391          .append("id", getId())
392          .append("key", key)
393          .append("deprecatedKey", deprecatedKey)
394          .append("scope", scope)
395          .append("qualifier", qualifier)
396          .append("name", name)
397          .append("longName", longName)
398          .append("lang", languageKey)
399          .append("enabled", enabled)
400          .append("rootId", rootId)
401          .append("path", path)
402          .append("copyResourceId", copyResourceId)
403          .append("personId", personId)
404          .append("createdAt", createdAt)
405          .toString();
406      }
407    
408      @Override
409      public Object clone() {
410        ResourceModel clone = new ResourceModel(getScope(), getKey(), getQualifier(), getRootId(), getPath(), getName());
411        clone.setDescription(getDescription());
412        clone.setDeprecatedKey(getDeprecatedKey());
413        clone.setEnabled(getEnabled());
414        clone.setProjectLinks(getProjectLinks());
415        clone.setLanguageKey(getLanguageKey());
416        clone.setCopyResourceId(getCopyResourceId());
417        clone.setLongName(getLongName());
418        clone.setPersonId(getPersonId());
419        clone.setCreatedAt(getCreatedAt());
420        return clone;
421      }
422    
423      /**
424       * Maps a resource to a resource model and returns the resource
425       */
426      public static ResourceModel build(Resource resource) {
427        ResourceModel model = new ResourceModel();
428        model.setEnabled(Boolean.TRUE);
429        model.setDescription(resource.getDescription());
430        model.setKey(resource.getEffectiveKey());
431        model.setPath(resource.getPath());
432        Language lang = resource.getLanguage();
433        if (lang != null) {
434          model.setLanguageKey(lang.getKey());
435        }
436        if (StringUtils.isNotBlank(resource.getName())) {
437          model.setName(resource.getName());
438        } else {
439          model.setName(resource.getKey());
440        }
441        model.setLongName(resource.getLongName());
442        model.setQualifier(resource.getQualifier());
443        model.setScope(resource.getScope());
444        return model;
445      }
446    
447    }