View Javadoc
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 }