View Javadoc
1   /* This software was designed and created by Jason Carroll.
2    * Copyright (c) 2002, 2003, 2004 Jason Carroll.
3    * The author can be reached at jcarroll@cowsultants.com
4    * ITracker website: http://www.cowsultants.com
5    * ITracker forums: http://www.cowsultants.com/phpBB/index.php
6    *
7    * This program is free software; you can redistribute it and/or modify
8    * it only under the terms of the GNU General Public License as published by
9    * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   */
17  package org.itracker.model;
18  
19  import org.apache.commons.lang.builder.CompareToBuilder;
20  import org.apache.commons.lang.builder.ToStringBuilder;
21  
22  import java.io.Serializable;
23  import java.util.Comparator;
24  
25  /**
26   * A Project version.
27   * <p/>
28   * <p>
29   * A Version can only belong to 1 Project (composition).
30   * </p>
31   *
32   * @author ready
33   */
34  public class Version extends AbstractEntity implements Comparable<Entity> {
35  
36      /**
37       *
38       */
39      private static final long serialVersionUID = 1L;
40  
41      /**
42       * Invariant: never <tt>null</tt>.
43       */
44      private Project project;
45  
46      /**
47       * Invariant: never <tt>null</tt>.
48       */
49      private String number;
50  
51      /*
52        * major and minor are only used to compare Versions. They can be computed
53        * from the <code>number</code> attribute, PENDING: We should also allow
54        * to specify them separately in order not to impose any constraint on the
55        * format of the version number.
56        */
57      private int major;
58      private int minor;
59  
60      private String description;
61  
62      /**
63       * Version status.
64       * <p>
65       * Invariant: never <tt>null</tt>.
66       * </p>
67       */
68      private Status status;
69  
70      /*
71        * This class used to have a <code>issues</code> attribute, which was a
72        * Collection<Issue>. This has been removed because the association Version -
73        * Issue doesn't need to be navigatable in this direction.
74        */
75  
76      public static final Comparator<Version> VERSION_COMPARATOR = new VersionComparator();
77  
78      /**
79       * Default constructor (required by Hibernate).
80       * <p/>
81       * <p>
82       * PENDING: should be <code>private</code> so that it can only be used by
83       * Hibernate, to ensure that <code>project</code> and <code>number</code>,
84       * which form an instance's identity, are never <tt>null</tt>.
85       * </p>
86       */
87      public Version() {
88      }
89  
90      /**
91       * Creates a new active Version for the given Project.
92       *
93       * @param project project to which this version belongs
94       * @param number  unique within the project
95       */
96      public Version(Project project, String number) {
97          setProject(project);
98          setVersionInfo(number);
99  
100         // A new version is active by default.
101         this.status = Status.ACTIVE;
102     }
103 
104     public int getMajor() {
105         return major;
106     }
107 
108     public void setMajor(int getMajor) {
109         this.major = getMajor;
110     }
111 
112     public int getMinor() {
113         return minor;
114     }
115 
116     public void setMinor(int getMinor) {
117         this.minor = getMinor;
118     }
119 
120     public String getNumber() {
121         return number;
122     }
123 
124     public void setNumber(String getNumber) {
125         this.number = getNumber;
126     }
127 
128     public String getDescription() {
129         return description;
130     }
131 
132     public void setDescription(String getDescription) {
133         this.description = getDescription;
134     }
135 
136     public Project getProject() {
137         return project;
138     }
139 
140     public void setProject(Project project) {
141         if (project == null) {
142             throw new IllegalArgumentException("null project");
143         }
144         this.project = project;
145     }
146 
147     /**
148      * Returns this version's status.
149      *
150      * @return enum constant
151      */
152     public Status getStatus() {
153         return status;
154     }
155 
156     /**
157      * Sets this version's status.
158      *
159      * @param status enum constant
160      * @throws IllegalArgumentException <code>status</code> is <tt>null</tt>
161      */
162     public void setStatus(Status status) {
163         if (status == null) {
164             throw new IllegalArgumentException("null status");
165         }
166         this.status = status;
167     }
168 
169     /**
170      * Convience method to set the number, major and minor fields with a single
171      * call. It will first set the number to the provided data, and then attempt
172      * to parse the info if in the form major.minor into parts to set the other
173      * information.
174      *
175      * @param versionInfo the version number string to use
176      */
177     public void setVersionInfo(String versionInfo) {
178         setNumber(versionInfo);
179 
180         if (null == versionInfo) {
181             throw new IllegalArgumentException("version info must not be null.");
182         }
183         String versionNumber = this.number.trim();
184         int firstDot = versionNumber.indexOf('.');
185         String major = "0";
186         major = (firstDot > 0 ? versionNumber.substring(0, firstDot).trim()
187                 : versionNumber.trim());
188 
189         try {
190             setMajor(Integer.parseInt(major));
191         } catch (NumberFormatException ex) {
192             setMajor(0);
193         }
194 
195         int secondDot = (firstDot > -1 ? versionNumber.indexOf('.',
196                 firstDot + 1) : -1);
197         String minor = (secondDot > -1 ? versionNumber.substring(firstDot + 1,
198                 secondDot).trim() : versionNumber.substring(firstDot + 1)
199                 .trim());
200         try {
201             setMinor(Integer.parseInt(minor));
202         } catch (NumberFormatException ex) {
203             setMinor(0);
204         }
205     }
206 
207     /**
208      * @return <tt>Version [id=<id>, project=<project>, number=<number>]</tt>
209      */
210     @Override
211     public String toString() {
212         return new ToStringBuilder(this).append("id", getId()).append("number",
213                 getNumber()).append("project", getProject()).append(getMajor()).append(getMinor())
214                 .append("status", getStatus()).toString();
215     }
216 
217     /**
218      * Compares 2 Versions by major and minor number.
219      */
220     public static final class VersionComparator implements Comparator<Version>, Serializable {
221         /**
222          *
223          */
224         private static final long serialVersionUID = 1L;
225 
226         private boolean ascending = true;
227 
228         public VersionComparator() {
229         }
230 
231         public VersionComparator(boolean ascending) {
232             setAscending(ascending);
233         }
234 
235         private boolean isAscending() {
236             return ascending;
237         }
238 
239         private void setAscending(boolean ascending) {
240             this.ascending = ascending;
241         }
242 
243         public int compare(Versionhref="../../../org/itracker/model/Version.html#Version">Version a, Version b) {
244             int result = new CompareToBuilder().append(a.getNumber(), b.getNumber())
245                     .append(a.getMajor(), b.getMajor()).append(a.getMinor(), b.getMinor()).toComparison();
246 
247             return (isAscending() ? result : -result);
248         }
249 
250     }
251 
252 }