1 /*
2 * jDTAUS Core API
3 * Copyright (C) 2005 Christian Schulte
4 * <cs@schulte.it>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21 package org.jdtaus.core.container;
22
23 import java.io.Serializable;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 /**
30 * Collection of specifications.
31 *
32 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
33 * @version $JDTAUS: Specifications.java 8743 2012-10-07 03:06:20Z schulte $
34 */
35 public class Specifications extends ModelObject
36 implements Cloneable, Serializable
37 {
38 //--Constants---------------------------------------------------------------
39
40 /** Serial version UID for backwards compatibility with 1.0.x classes. */
41 private static final long serialVersionUID = 9166476268404849994L;
42
43 //---------------------------------------------------------------Constants--
44 //--Specifications----------------------------------------------------------
45
46 /**
47 * The specifications of the collection.
48 * @serial
49 */
50 private Specification[] specifications;
51
52 /**
53 * Maps specification identifiers to specifications.
54 * @serial
55 */
56 private final Map identifiers = new HashMap();
57
58 /**
59 * Hash code.
60 * @serial
61 */
62 private int hashCode;
63
64 /** Creates a new {@code Specifications} instance. */
65 public Specifications()
66 {
67 super();
68 }
69
70 /**
71 * Gets the specifications of the collection.
72 *
73 * @return the specifications of the collection.
74 */
75 public Specification[] getSpecifications()
76 {
77 if ( this.specifications == null )
78 {
79 this.specifications = new Specification[ 0 ];
80 this.hashCode = 0;
81 }
82
83 return this.specifications;
84 }
85
86 /**
87 * Setter for property {@code specifications}.
88 *
89 * @param value the new specifications for the instance.
90 *
91 * @throws DuplicateSpecificationException if {@code value} contains
92 * duplicate specifications.
93 */
94 public void setSpecifications( final Specification[] value )
95 {
96 this.identifiers.clear();
97 this.hashCode = 0;
98 this.specifications = null;
99
100 if ( value != null )
101 {
102 for ( int i = value.length - 1; i >= 0; i-- )
103 {
104 this.hashCode += value[i].hashCode();
105 if ( this.identifiers.put( value[i].getIdentifier(),
106 value[i] ) != null )
107 {
108 this.identifiers.clear();
109 this.hashCode = 0;
110
111 throw new DuplicateSpecificationException(
112 value[i].getIdentifier() );
113
114 }
115 }
116
117 this.specifications = value;
118 }
119 }
120
121 /**
122 * Gets a specification for an identifier.
123 *
124 * @param identifier the identifier of the specification to return.
125 *
126 * @return a reference to the specification identified by
127 * {@code identifier}.
128 *
129 * @throws NullPointerException if {@code identifier} is {@code null}.
130 * @throws MissingSpecificationException if no specification matching
131 * {@code identifier} exists in the collection.
132 */
133 public Specification getSpecification( final String identifier )
134 {
135 if ( identifier == null )
136 {
137 throw new NullPointerException( "identifier" );
138 }
139
140 final Specification ret =
141 (Specification) this.identifiers.get( identifier );
142
143 if ( ret == null )
144 {
145 throw new MissingSpecificationException( identifier );
146 }
147
148 return ret;
149 }
150
151 /**
152 * Gets a specification for an index.
153 *
154 * @param index the index of the specification to return.
155 *
156 * @return a reference to the specification at {@code index}.
157 *
158 * @throws IndexOutOfBoundsException if {@code index} is negativ,
159 * greater than or equal to {@code size()}.
160 */
161 public final Specification getSpecification( final int index )
162 {
163 if ( index < 0 || index >= this.size() )
164 {
165 throw new ArrayIndexOutOfBoundsException( index );
166 }
167
168 return this.getSpecifications()[index];
169 }
170
171 /**
172 * Gets the number of specifications held by the instance.
173 *
174 * @return the number of specifications held by the instance.
175 */
176 public final int size()
177 {
178 return this.getSpecifications().length;
179 }
180
181 /**
182 * Creates a string representing the properties of the instance.
183 *
184 * @return a string representing the properties of the instance.
185 */
186 private String internalString()
187 {
188 final StringBuffer buf = new StringBuffer( 200 ).append( '{' );
189 buf.append( this.internalString( this ) );
190
191 final Specification[] specs = this.getSpecifications();
192 for ( int i = specs.length - 1; i >= 0; i-- )
193 {
194 buf.append( ", [" ).append( i ).append( "]=" ).append( specs[i] );
195 }
196
197 buf.append( '}' );
198 return buf.toString();
199 }
200
201 //----------------------------------------------------------Specifications--
202 //--Object------------------------------------------------------------------
203
204 /**
205 * Indicates whether some other object is equal to this one by comparing
206 * the values of all properties.
207 *
208 * @param o the reference object with which to compare.
209 *
210 * @return {@code true} if this object is the same as {@code o};
211 * {@code false} otherwise.
212 */
213 public boolean equals( final Object o )
214 {
215 boolean equal = this == o;
216
217 if ( !equal && o instanceof Specifications )
218 {
219 final Specifications that = (Specifications) o;
220 final Collection these = Arrays.asList( this.getSpecifications() );
221 final Collection those = Arrays.asList( that.getSpecifications() );
222
223 equal = this.size() == that.size() && these.containsAll( those );
224 }
225
226 return equal;
227 }
228
229 /**
230 * Returns a hash code value for this object.
231 *
232 * @return a hash code value for this object.
233 */
234 public int hashCode()
235 {
236 return this.hashCode;
237 }
238
239 /**
240 * Returns a string representation of the object.
241 *
242 * @return a string representation of the object.
243 */
244 public String toString()
245 {
246 return super.toString() + this.internalString();
247 }
248
249 /**
250 * Creates and returns a deep copy of this object.
251 *
252 * @return a clone of this instance.
253 */
254 public Object clone()
255 {
256 try
257 {
258 final Specifications ret = (Specifications) super.clone();
259 final Specification[] specs = this.getSpecifications();
260 final Specification[] cloned = new Specification[ specs.length ];
261
262 for ( int i = specs.length - 1; i >= 0; i-- )
263 {
264 cloned[i] = (Specification) specs[i].clone();
265 }
266
267 ret.setSpecifications( cloned );
268 return ret;
269 }
270 catch ( final CloneNotSupportedException e )
271 {
272 throw new AssertionError( e );
273 }
274 }
275
276 //------------------------------------------------------------------Object--
277 }