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        this.qualifier = resource.getQualifier();
092        this.scope = resource.getScope();
093        
094        if (parent == null) {
095          path = "";
096          depth = 0;
097          this.createdAt = new Date();
098    
099        } else {
100          this.parentId = parent.getId();
101          this.rootId = (parent.getRootId() == null ? parent.getId() : parent.getRootId());
102          this.createdAt = parent.getCreatedAt();
103          this.depth = parent.getDepth() + 1;
104          this.path = new StringBuilder()
105              .append(parent.getPath())
106              .append(parent.getId())
107              .append(".")
108              .toString();
109        }
110        this.rootProjectId = guessRootProjectId(resource, parent);
111      }
112    
113      private static Integer guessRootProjectId(ResourceModel resource, Snapshot parent) {
114        Integer result;
115    
116        // design problem : constants are defined in the Resource class, that should not be used by this class...
117        if ("TRK".equals(resource.getQualifier()) || "VW".equals(resource.getQualifier()) || "SVW".equals(resource.getQualifier())) {
118          result = resource.getCopyResourceId() != null ? resource.getCopyResourceId() : resource.getId();
119    
120        } else if (parent == null) {
121          result = resource.getCopyResourceId() != null ? resource.getCopyResourceId() : resource.getId();
122    
123        } else {
124          result = (parent.getRootProjectId() == null ? parent.getResourceId() : parent.getRootProjectId());
125        }
126        return result;
127      }
128    
129      public Snapshot save(DatabaseSession session) {
130        return session.save(this);
131      }
132    
133      public Snapshot(ResourceModel resource, boolean last, String status, Date date) {
134        this();
135        setResource(resource);
136        this.status = status;
137        this.last = last;
138        this.createdAt = date;
139      }
140    
141      public Date getCreatedAt() {
142        return createdAt;
143      }
144    
145      public void setCreatedAt(Date createdAt) {
146        this.createdAt = createdAt;
147      }
148    
149      public Integer getResourceId() {
150        return resourceId;
151      }
152    
153      public void setResourceId(Integer resourceId) {
154        this.resourceId = resourceId;
155      }
156    
157      public final void setResource(ResourceModel resource) {
158        this.resourceId = resource.getId();
159        this.scope = resource.getScope();
160        this.qualifier = resource.getQualifier();
161      }
162    
163      public String getVersion() {
164        return version;
165      }
166    
167      public void setVersion(String version) {
168        this.version = version;
169      }
170    
171      public Integer getParentId() {
172        return parentId;
173      }
174    
175      public void setParentId(Integer i) {
176        this.parentId = i;
177      }
178    
179      public Boolean getLast() {
180        return last;
181      }
182    
183      public void setLast(Boolean last) {
184        this.last = last;
185      }
186    
187      public String getStatus() {
188        return status;
189      }
190    
191      public void setStatus(String status) {
192        this.status = status;
193      }
194    
195      public String getScope() {
196        return scope;
197      }
198    
199      public void setScope(String scope) {
200        this.scope = scope;
201      }
202    
203      public String getQualifier() {
204        return qualifier;
205      }
206    
207      public void setQualifier(String qualifier) {
208        this.qualifier = qualifier;
209      }
210    
211      public Integer getRootId() {
212        return rootId;
213      }
214    
215      public void setRootId(Integer i) {
216        this.rootId = i;
217      }
218    
219      public String getPath() {
220        return path;
221      }
222    
223      public void setPath(String path) {
224        this.path = path;
225      }
226    
227      public Integer getDepth() {
228        return depth;
229      }
230    
231      public Integer getRootProjectId() {
232        return rootProjectId;
233      }
234    
235      public void setRootProjectId(Integer rootProjectId) {
236        this.rootProjectId = rootProjectId;
237      }
238    
239      /**
240       * Sets the depth of the snapshot
241       *
242       * @throws IllegalArgumentException when depth is negative
243       */
244      public void setDepth(Integer depth) {
245        if (depth != null && depth < 0) {
246          throw new IllegalArgumentException("depth can not be negative : " + depth);
247        }
248        this.depth = depth;
249      }
250    
251    
252      @Override
253      public boolean equals(Object obj) {
254        if (!(obj instanceof Snapshot)) {
255          return false;
256        }
257        if (this == obj) {
258          return true;
259        }
260        Snapshot other = (Snapshot) obj;
261        return new EqualsBuilder()
262            .append(resourceId, other.getResourceId())
263            .append(createdAt, other.getCreatedAt())
264            .isEquals();
265      }
266    
267      @Override
268      public int hashCode() {
269        return new HashCodeBuilder(17, 37)
270            .append(resourceId)
271            .append(createdAt)
272            .toHashCode();
273      }
274    
275      @Override
276      public String toString() {
277        return new ToStringBuilder(this)
278            .append("id", getId())
279            .append("resourceId", resourceId)
280            .append("scope", scope)
281            .append("qualifier", qualifier)
282            .append("version", version)
283            .append("last", last)
284            .append("createdAt", createdAt)
285            .append("status", status)
286            .append("path", path)
287            .append("rootId", rootId)
288            .append("rootProjectId", rootProjectId)
289            .append("parentId", parentId)
290            .toString();
291      }
292    }