001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2009 SonarSource SA 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar 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 * Sonar 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 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 package org.sonar.api.database.model; 021 022 import org.apache.commons.lang.builder.EqualsBuilder; 023 import org.apache.commons.lang.builder.HashCodeBuilder; 024 import org.apache.commons.lang.builder.ToStringBuilder; 025 import org.hibernate.annotations.Cache; 026 import org.hibernate.annotations.CacheConcurrencyStrategy; 027 import org.sonar.api.database.BaseIdentifiable; 028 import org.sonar.api.database.DatabaseSession; 029 030 import java.util.Date; 031 import javax.persistence.*; 032 033 /** 034 * A class to map a snapshot with its hibernate model 035 */ 036 @Entity 037 @Table(name = "snapshots") 038 public class Snapshot extends BaseIdentifiable { 039 040 /** 041 * This status is set on the snapshot at the beginning of the batch 042 */ 043 public final static String STATUS_UNPROCESSED = "U"; 044 045 /** 046 * This status is set on the snapshot at the end of the batch 047 */ 048 public final static String STATUS_PROCESSED = "P"; 049 050 @ManyToOne(fetch = FetchType.LAZY) 051 @JoinColumn(name = "project_id", updatable = true, nullable = true) 052 @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 053 private ResourceModel resource; 054 055 @Temporal(TemporalType.TIMESTAMP) 056 @Column(name = "created_at", updatable = true, nullable = true) 057 private Date createdAt; 058 059 @Column(name = "version", updatable = true, nullable = true, length = 32) 060 private String version; 061 062 @Column(name = "islast") 063 private Boolean last = Boolean.FALSE; 064 065 @Column(name = "status") 066 private String status = STATUS_UNPROCESSED; 067 068 @Column(name = "scope", updatable = true, nullable = true, length = 3) 069 private String scope; 070 071 @Column(name = "path", updatable = true, nullable = true, length = 96) 072 private String path; 073 074 @Column(name = "depth", updatable = true, nullable = true) 075 private Integer depth; 076 077 @Column(name = "qualifier", updatable = true, nullable = true, length = 3) 078 private String qualifier; 079 080 @Column(name = "root_snapshot_id", updatable = true, nullable = true) 081 private Integer rootId; 082 083 @Column(name = "parent_snapshot_id", updatable = true, nullable = true) 084 private Integer parentId; 085 086 @Column(name = "root_project_id", updatable = true, nullable = true) 087 private Integer rootProjectId; 088 089 public Snapshot() { 090 091 } 092 093 public Snapshot(ResourceModel resource, Snapshot parent) { 094 this.resource = resource; 095 096 if (resource != null) { 097 this.qualifier = resource.getQualifier(); 098 this.scope = resource.getScope(); 099 } 100 101 if (parent == null) { 102 path = ""; 103 depth = 0; 104 105 } else { 106 this.parentId = parent.getId(); 107 this.rootId = (parent.getRootId()==null ? parent.getId() : parent.getRootId()); 108 this.createdAt = parent.getCreatedAt(); 109 this.depth = parent.getDepth() + 1; 110 this.path = new StringBuilder() 111 .append(parent.getPath()) 112 .append(parent.getId()) 113 .append(".") 114 .toString(); 115 } 116 this.rootProjectId = guessRootProjectId(resource, parent); 117 } 118 119 private static Integer guessRootProjectId(ResourceModel resource, Snapshot parent) { 120 Integer result; 121 122 // design problem : constants are defined in the Resource class, that should not be used by this class... 123 if ("TRK".equals(resource.getQualifier()) || "VW".equals(resource.getQualifier()) || "SVW".equals(resource.getQualifier())) { 124 result = resource.getCopyResourceId() != null ? resource.getCopyResourceId() : resource.getId(); 125 126 } else if (parent==null) { 127 result = resource.getCopyResourceId() != null ? resource.getCopyResourceId() : resource.getId(); 128 129 } else { 130 result= (parent.getRootProjectId()==null ? parent.getResourceId() : parent.getRootProjectId()); 131 } 132 return result; 133 } 134 135 public Snapshot save(DatabaseSession session) { 136 if (resource != null && resource.getId() != null) { 137 resource = session.reattach(ResourceModel.class, resource.getId()); 138 } 139 return session.save(this); 140 } 141 142 public Snapshot(ResourceModel resource, boolean last, String status, Date date) { 143 this(); 144 setResource(resource); 145 this.status = status; 146 this.last = last; 147 this.createdAt = date; 148 } 149 150 public Date getCreatedAt() { 151 return createdAt; 152 } 153 154 public void setCreatedAt(Date createdAt) { 155 this.createdAt = createdAt; 156 } 157 158 public ResourceModel getResource() { 159 return resource; 160 } 161 162 public Integer getResourceId() { 163 if (resource != null) { 164 return resource.getId(); 165 } 166 return null; 167 } 168 169 public final void setResource(ResourceModel resource) { 170 this.resource = resource; 171 this.scope = resource.getScope(); 172 this.qualifier = resource.getQualifier(); 173 } 174 175 public String getVersion() { 176 return version; 177 } 178 179 public void setVersion(String version) { 180 this.version = version; 181 } 182 183 public Integer getParentId() { 184 return parentId; 185 } 186 187 public void setParentId(Integer i) { 188 this.parentId = i; 189 } 190 191 public Boolean getLast() { 192 return last; 193 } 194 195 public void setLast(Boolean last) { 196 this.last = last; 197 } 198 199 public String getStatus() { 200 return status; 201 } 202 203 public void setStatus(String status) { 204 this.status = status; 205 } 206 207 public String getScope() { 208 return scope; 209 } 210 211 public void setScope(String scope) { 212 this.scope = scope; 213 } 214 215 public String getQualifier() { 216 return qualifier; 217 } 218 219 public void setQualifier(String qualifier) { 220 this.qualifier = qualifier; 221 } 222 223 public Integer getRootId() { 224 return rootId; 225 } 226 227 public void setRootId(Integer i) { 228 this.rootId = i; 229 } 230 231 public String getPath() { 232 return path; 233 } 234 235 public void setPath(String path) { 236 this.path = path; 237 } 238 239 public Integer getDepth() { 240 return depth; 241 } 242 243 public Integer getRootProjectId() { 244 return rootProjectId; 245 } 246 247 public void setRootProjectId(Integer rootProjectId) { 248 this.rootProjectId = rootProjectId; 249 } 250 251 /** 252 * Sets the depth of the snapshot 253 * 254 * @throws IllegalArgumentException when depth is negative 255 */ 256 public void setDepth(Integer depth) { 257 if (depth != null && depth < 0) { 258 throw new IllegalArgumentException("depth can not be negative : " + depth); 259 } 260 this.depth = depth; 261 } 262 263 264 @Override 265 public boolean equals(Object obj) { 266 if (!(obj instanceof Snapshot)) { 267 return false; 268 } 269 if (this == obj) { 270 return true; 271 } 272 Snapshot other = (Snapshot) obj; 273 return new EqualsBuilder() 274 .append(resource, other.getResource()) 275 .append(createdAt, other.getCreatedAt()) 276 .isEquals(); 277 } 278 279 @Override 280 public int hashCode() { 281 return new HashCodeBuilder(17, 37) 282 .append(resource) 283 .append(createdAt) 284 .toHashCode(); 285 } 286 287 @Override 288 public String toString() { 289 return new ToStringBuilder(this) 290 .append("id", getId()) 291 .append("scope", scope) 292 .append("qualifier", qualifier) 293 .append("version", version) 294 .append("last", last) 295 .append("createdAt", createdAt) 296 .append("status", status) 297 .append("path", path) 298 .append("rootId", rootId) 299 .append("rootProjectId", rootProjectId) 300 .append("parentId", parentId) 301 .toString(); 302 } 303 }