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 }