001 /*
002 * jDTAUS - DTAUS fileformat.
003 * Copyright (c) 2005 Christian Schulte <cs@schulte.it>
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either
008 * version 2.1 of the License, or any later version.
009 *
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013 * Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public
016 * License along with this library; if not, write to the Free Software
017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
018 *
019 */
020 package org.jdtaus.core.container;
021
022 import java.io.Serializable;
023 import java.util.Arrays;
024 import java.util.Collection;
025 import java.util.HashMap;
026 import java.util.Map;
027
028 /**
029 * Collection of specifications.
030 *
031 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
032 * @version $Id: Specifications.java 2230 2007-03-26 01:37:48Z schulte2005 $
033 */
034 public class Specifications implements Cloneable, Serializable
035 {
036
037 //--Specifications----------------------------------------------------------
038
039 /**
040 * The specifications of the collection.
041 * @serial
042 */
043 private Specification[] specifications;
044
045 /**
046 * Maps specification identifiers to specifications.
047 * @serial
048 */
049 private final Map identifiers = new HashMap();
050
051 /**
052 * Hash code.
053 * @serial
054 */
055 private int hashCode;
056
057 /**
058 * Gets the specifications of the collection.
059 *
060 * @return the specifications of the collection.
061 */
062 public Specification[] getSpecifications()
063 {
064 if(this.specifications == null)
065 {
066 this.specifications = new Specification[0];
067 this.hashCode = 0;
068 }
069
070 return this.specifications;
071 }
072
073 /**
074 * Setter for property {@code specifications}.
075 *
076 * @param value the new specifications for the instance.
077 *
078 * @throws DuplicateSpecificationException if {@code value} contains
079 * duplicate specifications.
080 */
081 public void setSpecifications(final Specification[] value)
082 {
083 this.identifiers.clear();
084 this.hashCode = 0;
085 this.specifications = value;
086
087 if(value != null)
088 {
089 for(int i = value.length - 1; i >= 0; i--)
090 {
091 this.hashCode += value[i].hashCode();
092 if(this.identifiers.put(value[i].getIdentifier(),
093 value[i]) != null)
094 {
095 throw new DuplicateSpecificationException(
096 value[i].getIdentifier());
097
098 }
099 }
100 }
101 }
102
103 /**
104 * Gets a specification for an identifier.
105 *
106 * @param identifier the identifier of the specification to return.
107 *
108 * @return a reference to the specification identified by
109 * {@code identifier}.
110 *
111 * @throws NullPointerException if {@code identifier} is {@code null}.
112 * @throws MissingSpecificationException if no specification matching
113 * {@code identifier} exists in the collection.
114 */
115 public Specification getSpecification(final String identifier)
116 {
117
118 if(identifier == null)
119 {
120 throw new NullPointerException("identifier");
121 }
122
123 final Specification ret =
124 (Specification) this.identifiers.get(identifier);
125
126 if(ret == null)
127 {
128 throw new MissingSpecificationException(identifier);
129 }
130
131 return ret;
132 }
133
134 /**
135 * Gets a specification for an index.
136 *
137 * @param index the index of the specification to return.
138 *
139 * @return a reference to the specification at {@code index}.
140 *
141 * @throws IndexOutOfBoundsException if {@code index} is negativ,
142 * greater than or equal to {@code size()}.
143 */
144 public final Specification getSpecification(final int index)
145 {
146 if(index < 0 || index >= this.size())
147 {
148 throw new ArrayIndexOutOfBoundsException(index);
149 }
150
151 return this.getSpecifications()[index];
152 }
153
154 /**
155 * Gets the number of specifications held by the instance.
156 *
157 * @return the number of specifications held by the instance.
158 */
159 public final int size()
160 {
161 return this.getSpecifications().length;
162 }
163
164 /**
165 * Creates a string representing the properties of the instance.
166 *
167 * @return a string representing the properties of the instance.
168 */
169 private String internalString()
170 {
171 final StringBuffer buf = new StringBuffer(200);
172 final Specification[] specifications = this.getSpecifications();
173 for(int i = specifications.length - 1; i >= 0; i--)
174 {
175 buf.append("\n\tspecification[").append(i).append("]=").
176 append(specifications[i]);
177
178 }
179
180 return buf.toString();
181 }
182
183 //----------------------------------------------------------Specifications--
184 //--Object------------------------------------------------------------------
185
186 /**
187 * Indicates whether some other object is equal to this one by comparing
188 * the values of all properties.
189 *
190 * @param o the reference object with which to compare.
191 *
192 * @return {@code true} if this object is the same as {@code o};
193 * {@code false} otherwise.
194 */
195 public boolean equals(final Object o)
196 {
197 boolean equal = this == o;
198
199 if(!equal && o instanceof Specifications)
200 {
201 final Specifications that = (Specifications) o;
202 final Collection these = Arrays.asList(this.getSpecifications());
203 final Collection those = Arrays.asList(that.getSpecifications());
204
205 equal = these.size() == that.size() && these.containsAll(those);
206 }
207
208 return equal;
209 }
210
211 /**
212 * Returns a hash code value for this object.
213 *
214 * @return a hash code value for this object.
215 */
216 public int hashCode()
217 {
218 return this.hashCode;
219 }
220
221 /**
222 * Returns a string representation of the object.
223 *
224 * @return a string representation of the object.
225 */
226 public String toString()
227 {
228 return super.toString() + this.internalString();
229 }
230
231 /**
232 * Creates and returns a deep copy of this object.
233 *
234 * @return a clone of this instance.
235 */
236 public Object clone()
237 {
238 try
239 {
240 final Specifications ret = (Specifications) super.clone();
241 final Specification[] specs = this.getSpecifications();
242 ret.specifications = new Specification[specs.length];
243
244 for(int i = specs.length - 1; i >= 0; i--)
245 {
246 ret.specifications[i] = (Specification) specs[i].clone();
247 }
248
249 return ret;
250 }
251 catch(CloneNotSupportedException e)
252 {
253 throw new AssertionError(e);
254 }
255 }
256
257 //------------------------------------------------------------------Object--
258 }