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 org.apache.commons.lang.builder.CompareToBuilder;
22 import org.apache.commons.lang.builder.ToStringBuilder;
23
24 import java.io.Serializable;
25 import java.util.Comparator;
26
27 /**
28 * Models a project component.
29 * <p/>
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 * <p/>
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 /**
69 * Component description.
70 */
71 private String description;
72
73 /**
74 * Component status.
75 * <p>
76 * Invariant: never <tt>null</tt>.
77 * </p>
78 */
79 private Status status;
80
81 /*
82 * This class used to have a <code>issues</code> attribute, which was a
83 * Collection<Issue>. This has been removed because the association
84 * Component - Issue doesn't need to be navigatable in this direction.
85 */
86
87 /**
88 * Default constructor (required by Hibernate).
89 * <p/>
90 * <p>
91 * PENDING: should be <code>private</code> so that it can only be used by
92 * Hibernate, to ensure that <code>project</code> and <code>name</code>,
93 * which form an instance's identity, are never <tt>null</tt>.
94 * </p>
95 */
96 public Component() {
97 }
98
99 /**
100 * Creates a new active Component of the given name for the given Project.
101 *
102 * @param project owning this component
103 * @param name 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 * <p/>
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 parent project
131 * @throws IllegalArgumentException null project
132 */
133 public void setProject(Project project) {
134 if (project == null) {
135 throw new IllegalArgumentException("null project");
136 }
137 this.project = project;
138 }
139
140 /**
141 * Returns this component's name.
142 *
143 * @return unique name within the parent project
144 */
145 public String getName() {
146 return name;
147 }
148
149 /**
150 * Sets this component's name.
151 * <p/>
152 * <p>
153 * PENDING: The name shouldn't be modified because it is part of a
154 * component's natural key and is used in the equals method!
155 * </p>
156 *
157 * @param name unique name within the parent project
158 * @throws IllegalArgumentException null name
159 */
160 public void setName(String name) {
161 if (name == null) {
162 throw new IllegalArgumentException("null name");
163 }
164 this.name = name;
165 }
166
167 /**
168 * Returns this component's description.
169 *
170 * @return description
171 */
172 public String getDescription() {
173 return description;
174 }
175
176 /**
177 * Sets this component's description.
178 *
179 * @param description description
180 */
181 public void setDescription(String description) {
182 this.description = description;
183 }
184
185 /**
186 * Returns this component's status.
187 *
188 * @return enum value
189 */
190 public Status getStatus() {
191 return status;
192 }
193
194 /**
195 * Sets this component's status.
196 *
197 * @param status enum value
198 * @throws IllegalArgumentException <code>status</code> is <tt>null</tt>
199 */
200 public void setStatus(Status status) {
201 if (status == null) {
202 throw new IllegalArgumentException("null status");
203 }
204 this.status = status;
205 }
206
207 // /**
208 // * Two component instances are equal if they belong to the same project
209 // * and have the same name.
210 // */
211 // @Override
212 // public boolean equals(Object obj) {
213 // if (this == obj) {
214 // return true;
215 // }
216 //
217 // if (obj instanceof Component) {
218 // final Component other = (Component)obj;
219 //
220 // return this.project.equals(other.project)
221 // && this.name.equals(other.name);
222 // }
223 // return false;
224 // }
225
226 // /**
227 // * Overridden to match implementation of method {@link #equals(Object)}.
228 // */
229 // @Override
230 // public int hashCode() {
231 // return this.project.hashCode() + this.name.hashCode();
232 // }
233
234 /**
235 * Returns contatanation of system ID and object natural key.
236 *
237 * @return <tt>Component [id=this.id, project=this.project, name=this.name]</tt>
238 */
239 @Override
240 public String toString() {
241 return new ToStringBuilder(this).append("id", getId()).append("project",
242 getProject()).append("name", getName()).toString();
243 }
244
245 // /**
246 // * Compares 2 Components by project and name (natural key).
247 // */
248 // public int compareTo(Component other) {
249 //
250 // final int projectComparison = this.project.compareTo(other.project);
251 //
252 // if (projectComparison == 0) {
253 // return this.name.compareTo(other.name);
254 // }
255 // return projectComparison;
256 // }
257 //
258
259 /**
260 * Compares 2 Components by name.
261 * <p/>
262 * <p>
263 * It should only be used to compare components of the same project, because
264 * it doesn't take the project into account.
265 * </p>
266 */
267 private static class NameComparator implements Comparator<Component>, Serializable {
268
269 /**
270 *
271 */
272 private static final long serialVersionUID = 1L;
273
274 public int compare(Componentef="../../../org/itracker/model/Component.html#Component">Component a, Component b) {
275 return new CompareToBuilder().append(a.getName(), b.getName()).append(a.getId(), b.getId()).toComparison();
276
277 }
278
279 }
280
281 public static final class ProjectNameComparator implements
282 Comparator<Component>, Serializable {
283 /**
284 *
285 */
286 private static final long serialVersionUID = 1L;
287
288 public int compare(Componentf="../../../org/itracker/model/Component.html#Component">Component o1, Component o2) {
289 if (null != o1.getProject() && null != o2.getProject()) {
290 return new CompareToBuilder().append(o1.getProject().getName(), o2.getProject().getName())
291 .append(o1.getName(), o2.getName()).toComparison();
292 }
293 return NAME_COMPARATOR.compare(o1, o2);
294 }
295 }
296
297 }