1 /*
2 * This software was designed and created by Jason Carroll.
3 * Copyright (c) 2002, 2003, 2004 Jason Carroll.
4 * The author can be reached at jcarroll@cowsultants.com
5 * ITracker website: http://www.cowsultants.com
6 * ITracker forums: http://www.cowsultants.com/phpBB/index.php
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it only under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19 package org.itracker.model;
20
21 import java.io.Serializable;
22 import java.util.Comparator;
23
24 import org.apache.commons.lang.builder.CompareToBuilder;
25 import org.apache.commons.lang.builder.ToStringBuilder;
26
27 /**
28 * Models a project component.
29 *
30 * <p>
31 * A Component is a project subdivision, like a sub-project or functional area,
32 * ... <br>
33 * It is identified by a unique name within the project to which it belongs
34 * (composition). <br>
35 * e.g.: core, web-ui, swing-ui, help, ...
36 * </p>
37 *
38 * <p>
39 * A component cannot have sub-components, unlike categories and sub-categories
40 * that exist in some issue tracking systems.
41 * </p>
42 *
43 * @author Jason
44 * @author Johnny
45 */
46 public class Component extends AbstractEntity implements Comparable<Entity> {
47
48 /**
49 *
50 */
51 private static final long serialVersionUID = 1L;
52
53 public static final Comparator<Component> NAME_COMPARATOR = new NameComparator();
54 public static final Comparator<Component> PROJECTNAME_COMPARATOR = new ProjectNameComparator();
55
56 /**
57 * Project to which this component belongs. Invariant: never <tt>null</tt>.
58 */
59
60 private Project project;
61
62 /**
63 * Unique name identifying this component within its project. Invariant:
64 * never <tt>null</tt>.
65 */
66 private String name;
67
68 /** Component description. */
69 private String description;
70
71 /**
72 * Component status.
73 * <p>
74 * Invariant: never <tt>null</tt>.
75 * </p>
76 */
77 private Status status;
78
79 /*
80 * This class used to have a <code>issues</code> attribute, which was a
81 * Collection<Issue>. This has been removed because the association
82 * Component - Issue doesn't need to be navigatable in this direction.
83 */
84
85 /**
86 * Default constructor (required by Hibernate).
87 *
88 * <p>
89 * PENDING: should be <code>private</code> so that it can only be used by
90 * Hibernate, to ensure that <code>project</code> and <code>name</code>,
91 * which form an instance's identity, are never <tt>null</tt>.
92 * </p>
93 */
94 public Component() {
95 }
96
97 /**
98 * Creates a new active Component of the given name for the given Project.
99 *
100 * @param project
101 * owning this component
102 * @param name
103 * unique component name within the project
104 */
105 public Component(Project project, String name) {
106 setProject(project);
107 setName(name);
108
109 // A new component is active by default.
110 this.status = Status.ACTIVE;
111 }
112
113 /**
114 * Returns the project owning this component.
115 *
116 * @return parent project
117 */
118 public Project getProject() {
119 return project;
120 }
121
122 /**
123 * Sets the project owning this component.
124 *
125 * <p>
126 * PENDING: The project shouldn't be modified because it is part of a
127 * component's natural key and is used in the equals method!
128 * </p>
129 *
130 * @param project
131 * parent project
132 * @throws IllegalArgumentException
133 * null project
134 */
135 public void setProject(Project project) {
136 if (project == null) {
137 throw new IllegalArgumentException("null project");
138 }
139 this.project = project;
140 }
141
142 /**
143 * Returns this component's name.
144 *
145 * @return unique name within the parent project
146 */
147 public String getName() {
148 return name;
149 }
150
151 /**
152 * Sets this component's name.
153 *
154 * <p>
155 * PENDING: The name shouldn't be modified because it is part of a
156 * component's natural key and is used in the equals method!
157 * </p>
158 *
159 * @param name
160 * unique name within the parent project
161 * @throws IllegalArgumentException
162 * null name
163 */
164 public void setName(String name) {
165 if (name == null) {
166 throw new IllegalArgumentException("null name");
167 }
168 this.name = name;
169 }
170
171 /**
172 * Returns this component's description.
173 *
174 * @return description
175 */
176 public String getDescription() {
177 return description;
178 }
179
180 /**
181 * Sets this component's description.
182 *
183 * @param description
184 * description
185 */
186 public void setDescription(String description) {
187 this.description = description;
188 }
189
190 /**
191 * Returns this component's status.
192 *
193 * @return enum value
194 */
195 public Status getStatus() {
196 return status;
197 }
198
199 /**
200 * Sets this component's status.
201 *
202 * @param status
203 * enum value
204 * @throws IllegalArgumentException
205 * <code>status</code> is <tt>null</tt>
206 */
207 public void setStatus(Status status) {
208 if (status == null) {
209 throw new IllegalArgumentException("null status");
210 }
211 this.status = status;
212 }
213
214 // /**
215 // * Two component instances are equal if they belong to the same project
216 // * and have the same name.
217 // */
218 // @Override
219 // public boolean equals(Object obj) {
220 // if (this == obj) {
221 // return true;
222 // }
223 //
224 // if (obj instanceof Component) {
225 // final Component other = (Component)obj;
226 //
227 // return this.project.equals(other.project)
228 // && this.name.equals(other.name);
229 // }
230 // return false;
231 // }
232
233 // /**
234 // * Overridden to match implementation of method {@link #equals(Object)}.
235 // */
236 // @Override
237 // public int hashCode() {
238 // return this.project.hashCode() + this.name.hashCode();
239 // }
240
241 /**
242 * Returns contatanation of system ID and object natural key.
243 *
244 * @return <tt>Component [id=this.id, project=this.project, name=this.name]</tt>
245 */
246 @Override
247 public String toString() {
248 return new ToStringBuilder(this).append("id", getId()).append("project",
249 getProject()).append("name", getName()).toString();
250 }
251
252 // /**
253 // * Compares 2 Components by project and name (natural key).
254 // */
255 // public int compareTo(Component other) {
256 //
257 // final int projectComparison = this.project.compareTo(other.project);
258 //
259 // if (projectComparison == 0) {
260 // return this.name.compareTo(other.name);
261 // }
262 // return projectComparison;
263 // }
264 //
265
266 /**
267 * Compares 2 Components by name.
268 *
269 * <p>
270 * It should only be used to compare components of the same project, because
271 * it doesn't take the project into account.
272 * </p>
273 */
274 private static class NameComparator implements Comparator<Component>, Serializable {
275
276 /**
277 *
278 */
279 private static final long serialVersionUID = 1L;
280
281 public int compare(Component a, Component b) {
282 return new CompareToBuilder().append(a.getName(), b.getName()).append(a.getId(), b.getId()).toComparison();
283
284 }
285
286 }
287
288 public static final class ProjectNameComparator implements
289 Comparator<Component>, Serializable {
290 /**
291 *
292 */
293 private static final long serialVersionUID = 1L;
294
295 public int compare(Component o1, Component o2) {
296 if (null != o1.getProject() && null != o2.getProject()) {
297 return new CompareToBuilder().append(o1.getProject().getName(), o2.getProject().getName())
298 .append(o1.getName(), o2.getName()).toComparison();
299 }
300 return NAME_COMPARATOR.compare(o1, o2);
301 }
302 }
303
304 }