001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2013 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.ProjectLink;
029    import org.sonar.api.resources.Resource;
030    
031    import javax.persistence.CascadeType;
032    import javax.persistence.Column;
033    import javax.persistence.Entity;
034    import javax.persistence.FetchType;
035    import javax.persistence.OneToMany;
036    import javax.persistence.Table;
037    import javax.persistence.Temporal;
038    import javax.persistence.TemporalType;
039    
040    import java.util.ArrayList;
041    import java.util.Date;
042    import java.util.List;
043    
044    /**
045     * Class to map resource with hibernate model
046     */
047    @Entity
048    @Table(name = "projects")
049    public class ResourceModel extends BaseIdentifiable implements Cloneable {
050    
051      public static final String SCOPE_PROJECT = "PRJ";
052      public static final String QUALIFIER_PROJECT_TRUNK = "TRK";
053    
054      public static final int DESCRIPTION_COLUMN_SIZE = 2000;
055      public static final int NAME_COLUMN_SIZE = 256;
056      public static final int KEY_SIZE = 400;
057    
058      @Column(name = "name", updatable = true, nullable = true, length = NAME_COLUMN_SIZE)
059      private String name;
060    
061      @Column(name = "long_name", updatable = true, nullable = true, length = NAME_COLUMN_SIZE)
062      private String longName;
063    
064      @Column(name = "description", updatable = true, nullable = true, length = DESCRIPTION_COLUMN_SIZE)
065      private String description;
066    
067      @Column(name = "enabled", updatable = true, nullable = false)
068      private Boolean enabled = Boolean.TRUE;
069    
070      @Column(name = "scope", updatable = true, nullable = false, length = 3)
071      private String scope;
072    
073      @Column(name = "qualifier", updatable = true, nullable = false, length = 10)
074      private String qualifier;
075    
076      @Column(name = "kee", updatable = false, nullable = false, length = KEY_SIZE)
077      private String key;
078    
079      @Column(name = "language", updatable = true, nullable = true, length = 20)
080      private String languageKey;
081    
082      @Column(name = "root_id", updatable = true, nullable = true)
083      private Integer rootId;
084    
085      @Column(name = "copy_resource_id", updatable = true, nullable = true)
086      private Integer copyResourceId;
087    
088      @Column(name = "person_id", updatable = true, nullable = true)
089      private Integer personId;
090    
091      @Temporal(TemporalType.TIMESTAMP)
092      @Column(name = "created_at", updatable = true, nullable = true)
093      private Date createdAt;
094    
095      @OneToMany(mappedBy = "resource", fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE})
096      @BatchSize(size = 8)
097      private List<ProjectLink> projectLinks = new ArrayList<ProjectLink>();
098    
099      /**
100       * Default constructor
101       */
102      public ResourceModel() {
103        this.createdAt = new Date();
104      }
105    
106      /**
107       * <p>Creates a resource model</p>
108       *
109       * @param scope     the scope the rule will apply on
110       * @param key       the rule key. This is the name of the resource, including the path
111       * @param qualifier the resource qualifier
112       * @param rootId    the rootId for the resource
113       * @param name      the short name of the resource
114       */
115      public ResourceModel(String scope, String key, String qualifier, Integer rootId, String name) {
116        // call this to have the "createdAt" field initialized
117        this();
118        this.scope = scope;
119        this.key = key;
120        this.rootId = rootId;
121        this.name = name;
122        this.qualifier = qualifier;
123      }
124    
125      /**
126       * Only available at project level.
127       */
128      public List<ProjectLink> getProjectLinks() {
129        return projectLinks;
130      }
131    
132      public void setProjectLinks(List<ProjectLink> projectLinks) {
133        this.projectLinks = projectLinks;
134      }
135    
136      /**
137       * @return a project link given its key if exists, null otherwise
138       */
139      public ProjectLink getProjectLink(String key) {
140        for (ProjectLink projectLink : projectLinks) {
141          if (key.equals(projectLink.getKey())) {
142            return projectLink;
143          }
144        }
145        return null;
146      }
147    
148      /**
149       * Only available at project level.
150       */
151      public String getDescription() {
152        return description;
153      }
154    
155      /**
156       * Sets the resource description, truncated to DESCRIPTION_COLUMN_SIZE
157       */
158      public void setDescription(String description) {
159        this.description = StringUtils.abbreviate(description, DESCRIPTION_COLUMN_SIZE);
160      }
161    
162      public String getName() {
163        return name;
164      }
165    
166      /**
167       * Sets the resource name, truncated to NAME_COLUMN_SIZE
168       */
169      public void setName(String name) {
170        this.name = StringUtils.abbreviate(name, NAME_COLUMN_SIZE);
171        if (this.longName == null) {
172          this.longName = this.name;
173        }
174      }
175    
176      public String getLongName() {
177        return longName;
178      }
179    
180      /**
181       * Sets the long name of the resource, truncated to NAME_COLUMN_SIZE
182       */
183      public void setLongName(String s) {
184        if (StringUtils.isBlank(s)) {
185          this.longName = name;
186        } else {
187          this.longName = StringUtils.abbreviate(s, NAME_COLUMN_SIZE);
188        }
189      }
190    
191      public Boolean getEnabled() {
192        return enabled;
193      }
194    
195      public void setEnabled(Boolean enabled) {
196        this.enabled = enabled;
197      }
198    
199      public String getScope() {
200        return scope;
201      }
202    
203      public void setScope(String scope) {
204        this.scope = scope;
205      }
206    
207      public String getKey() {
208        return key;
209      }
210    
211      public String getLanguageKey() {
212        return languageKey;
213      }
214    
215      public void setLanguageKey(String lang) {
216        this.languageKey = lang;
217      }
218    
219      public Integer getCopyResourceId() {
220        return copyResourceId;
221      }
222    
223      public void setCopyResourceId(Integer i) {
224        this.copyResourceId = i;
225      }
226    
227      /**
228       * @since 2.14
229       */
230      public Integer getPersonId() {
231        return personId;
232      }
233    
234      /**
235       * @since 2.14
236       */
237      public ResourceModel setPersonId(Integer i) {
238        this.personId = i;
239        return this;
240      }
241    
242      /**
243       * @throws IllegalArgumentException if the key is longer than KEY_SIZE
244       */
245      public void setKey(String key) {
246        if (key.length() > KEY_SIZE) {
247          throw new IllegalArgumentException("Resource key is too long, max is " + KEY_SIZE + " characters. Got : " + key);
248        }
249        this.key = key;
250      }
251    
252      public Integer getRootId() {
253        return rootId;
254      }
255    
256      public void setRootId(Integer rootId) {
257        this.rootId = rootId;
258      }
259    
260      public String getQualifier() {
261        return qualifier;
262      }
263    
264      public void setQualifier(String qualifier) {
265        this.qualifier = qualifier;
266      }
267    
268      public Date getCreatedAt() {
269        return createdAt; // NOSONAR May expose internal representation by returning reference to mutable object
270      }
271    
272      public void setCreatedAt(Date createdAt) {
273        this.createdAt = createdAt; // NOSONAR May expose internal representation by returning reference to mutable object
274      }
275    
276      @Override
277      public boolean equals(Object obj) {
278        if (!(obj instanceof ResourceModel)) {
279          return false;
280        }
281        if (this == obj) {
282          return true;
283        }
284        ResourceModel other = (ResourceModel) obj;
285        return new EqualsBuilder()
286            .append(key, other.key)
287            .append(enabled, other.enabled)
288            .append(rootId, other.rootId)
289            .isEquals();
290      }
291    
292      @Override
293      public int hashCode() {
294        return new HashCodeBuilder(17, 37)
295            .append(key)
296            .append(enabled)
297            .append(rootId)
298            .toHashCode();
299      }
300    
301      @Override
302      public String toString() {
303        return new ToStringBuilder(this)
304            .append("id", getId())
305            .append("key", key)
306            .append("scope", scope)
307            .append("qualifier", qualifier)
308            .append("name", name)
309            .append("longName", longName)
310            .append("lang", languageKey)
311            .append("enabled", enabled)
312            .append("rootId", rootId)
313            .append("copyResourceId", copyResourceId)
314            .append("personId", personId)
315            .append("createdAt", createdAt)
316            .toString();
317      }
318    
319      @Override
320      public Object clone() {
321        ResourceModel clone = new ResourceModel(getScope(), getKey(), getQualifier(), getRootId(), getName());
322        clone.setDescription(getDescription());
323        clone.setEnabled(getEnabled());
324        clone.setProjectLinks(getProjectLinks());
325        clone.setLanguageKey(getLanguageKey());
326        clone.setCopyResourceId(getCopyResourceId());
327        clone.setLongName(getLongName());
328        clone.setPersonId(getPersonId());
329        clone.setCreatedAt(getCreatedAt());
330        return clone;
331      }
332    
333      /**
334       * Maps a resource to a resource model and returns the resource
335       */
336      public static ResourceModel build(Resource resource) {
337        ResourceModel model = new ResourceModel();
338        model.setEnabled(Boolean.TRUE);
339        model.setDescription(resource.getDescription());
340        model.setKey(resource.getKey());
341        if (resource.getLanguage() != null) {
342          model.setLanguageKey(resource.getLanguage().getKey());
343        }
344        if (StringUtils.isNotBlank(resource.getName())) {
345          model.setName(resource.getName());
346        } else {
347          model.setName(resource.getKey());
348        }
349        model.setLongName(resource.getLongName());
350        model.setQualifier(resource.getQualifier());
351        model.setScope(resource.getScope());
352        return model;
353      }
354    
355    }