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 }