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 java.io.Serializable;
20  import java.util.Comparator;
21  
22  import org.apache.commons.lang.builder.CompareToBuilder;
23  import org.apache.commons.lang.builder.ToStringBuilder;
24  
25  /**
26   * A Project version.
27   * 
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  	 * 
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
94  	 *            project to which this version belongs
95  	 * @param number
96  	 *            unique within the project
97  	 */
98  	public Version(Project project, String number) {
99  		setProject(project);
100 		setVersionInfo(number);
101 
102 		// A new version is active by default.
103 		this.status = Status.ACTIVE;
104 	}
105 
106 	public int getMajor() {
107 		return major;
108 	}
109 
110 	public void setMajor(int getMajor) {
111 		this.major = getMajor;
112 	}
113 
114 	public int getMinor() {
115 		return minor;
116 	}
117 
118 	public void setMinor(int getMinor) {
119 		this.minor = getMinor;
120 	}
121 
122 	public String getNumber() {
123 		return number;
124 	}
125 
126 	public void setNumber(String getNumber) {
127 		this.number = getNumber;
128 	}
129 
130 	public String getDescription() {
131 		return description;
132 	}
133 
134 	public void setDescription(String getDescription) {
135 		this.description = getDescription;
136 	}
137 
138 	public Project getProject() {
139 		return project;
140 	}
141 
142 	public void setProject(Project project) {
143 		if (project == null) {
144 			throw new IllegalArgumentException("null project");
145 		}
146 		this.project = project;
147 	}
148 
149 	/**
150 	 * Returns this version's status.
151 	 * 
152 	 * @return enum constant
153 	 */
154 	public Status getStatus() {
155 		return status;
156 	}
157 
158 	/**
159 	 * Sets this version's status.
160 	 * 
161 	 * @param status
162 	 *            enum constant
163 	 * @throws IllegalArgumentException
164 	 *             <code>status</code> is <tt>null</tt>
165 	 */
166 	public void setStatus(Status status) {
167 		if (status == null) {
168 			throw new IllegalArgumentException("null status");
169 		}
170 		this.status = status;
171 	}
172 
173 	/**
174 	 * Convience method to set the number, major and minor fields with a single
175 	 * call. It will first set the number to the provided data, and then attempt
176 	 * to parse the info if in the form major.minor into parts to set the other
177 	 * information.
178 	 * 
179 	 * @param versionInfo
180 	 *            the version number string to use
181 	 */
182 	public void setVersionInfo(String versionInfo) {
183 		setNumber(versionInfo);
184 
185 		if (null == versionInfo) {
186 			throw new IllegalArgumentException("version info must not be null.");
187 		}
188 		String versionNumber = this.number.trim();
189 		int firstDot = versionNumber.indexOf('.');
190 		String major = "0";
191 		major = (firstDot > 0 ? versionNumber.substring(0, firstDot).trim()
192 				: versionNumber.trim());
193 
194 		try {
195 			setMajor(Integer.parseInt(major));
196 		} catch (NumberFormatException ex) {
197 			setMajor(0);
198 		}
199 
200 		int secondDot = (firstDot > -1 ? versionNumber.indexOf('.',
201 				firstDot + 1) : -1);
202 		String minor = (secondDot > -1 ? versionNumber.substring(firstDot + 1,
203 				secondDot).trim() : versionNumber.substring(firstDot + 1)
204 				.trim());
205 		try {
206 			setMinor(Integer.parseInt(minor));
207 		} catch (NumberFormatException ex) {
208 			setMinor(0);
209 		}
210 	}
211 
212 	/**
213 	 * @return <tt>Version [id=<id>, project=<project>, number=<number>]</tt>
214 	 */
215 	@Override
216 	public String toString() {
217 		return new ToStringBuilder(this).append("id", getId()).append("number",
218 				getNumber()).append("project", getProject()).append(getMajor()).append(getMinor())
219 				.append("status", getStatus()).toString();
220 	}
221 
222 	/**
223 	 * Compares 2 Versions by major and minor number.
224 	 */
225 	public static final class VersionComparator implements Comparator<Version>, Serializable {
226 		/**
227 		 * 
228 		 */
229 		private static final long serialVersionUID = 1L;
230 
231 		private boolean ascending = true;
232 
233 		public VersionComparator() {
234 		}
235 
236 		public VersionComparator(boolean ascending) {
237 			setAscending(ascending);
238 		}
239 
240 		private boolean isAscending() {
241 			return ascending;
242 		}
243 
244 		private void setAscending(boolean ascending) {
245 			this.ascending = ascending;
246 		}
247 
248 		public int compare(Version a, Version b) {
249 			int result = new CompareToBuilder().append(a.getNumber(), b.getNumber())
250 					.append(a.getMajor(), b.getMajor()).append(a.getMinor(), b.getMinor()).toComparison();
251 
252 			return (isAscending() ? result : -result);
253 		}
254 
255 	}
256 
257 }