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