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