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 }