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 */ 020package org.sonar.api.database.model; 021 022import org.apache.commons.lang.StringUtils; 023import org.apache.commons.lang.builder.EqualsBuilder; 024import org.apache.commons.lang.builder.HashCodeBuilder; 025import org.apache.commons.lang.builder.ToStringBuilder; 026import org.hibernate.annotations.BatchSize; 027import org.sonar.api.database.BaseIdentifiable; 028import org.sonar.api.resources.Language; 029import org.sonar.api.resources.ProjectLink; 030import org.sonar.api.resources.Resource; 031 032import javax.annotation.Nullable; 033import javax.persistence.CascadeType; 034import javax.persistence.Column; 035import javax.persistence.Entity; 036import javax.persistence.FetchType; 037import javax.persistence.OneToMany; 038import javax.persistence.Table; 039import javax.persistence.Temporal; 040import javax.persistence.TemporalType; 041 042import java.util.ArrayList; 043import java.util.Date; 044import java.util.List; 045 046/** 047 * Class to map resource with hibernate model 048 */ 049@Entity 050@Table(name = "projects") 051public 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}