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 implementations.
033 *
034 * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
035 * @version $Id: Implementations.java 8044 2009-07-02 01:29:05Z schulte2005 $
036 */
037 public class Implementations 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 = 5611937453792676565L;
044
045 //---------------------------------------------------------------Constants--
046 //--Implementations---------------------------------------------------------
047
048 /**
049 * The implementations held by the instance.
050 * @serial
051 */
052 private Implementation[] implementations;
053
054 /**
055 * Maps implementation identifiers to implementations.
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 all implementations of the collection.
068 *
069 * @return all implementations of the collection.
070 */
071 public Implementation[] getImplementations()
072 {
073 if ( this.implementations == null )
074 {
075 this.implementations = new Implementation[ 0 ];
076 this.hashCode = 0;
077 }
078
079 return this.implementations;
080 }
081
082 /**
083 * Setter for property {@code implementations}.
084 *
085 * @param value the new implementations for the instance.
086 *
087 * @throws DuplicateImplementationException if {@code value} contains
088 * duplicate implementations.
089 */
090 public void setImplementations( final Implementation[] value )
091 {
092 this.identifiers.clear();
093 this.hashCode = 0;
094 this.implementations = 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
102 if ( this.identifiers.put( value[i].getIdentifier(),
103 value[i] ) != null )
104 {
105 this.identifiers.clear();
106 this.hashCode = 0;
107
108 throw new DuplicateImplementationException(
109 value[i].getIdentifier() );
110
111 }
112 }
113
114 this.implementations = value;
115 }
116 }
117
118 /**
119 * Gets an implementation for an identifier.
120 *
121 * @param identifier the identifier of the implementation to return.
122 *
123 * @return a reference to the implementation identified by
124 * {@code identifier}.
125 *
126 * @throws NullPointerException if {@code identifier} is {@code null}.
127 * @throws MissingImplementationException if no implementation matching
128 * {@code identifier} exists in the collection.
129 */
130 public Implementation getImplementation( final String identifier )
131 {
132 if ( identifier == null )
133 {
134 throw new NullPointerException( "identifier" );
135 }
136
137 final Implementation ret =
138 (Implementation) this.identifiers.get( identifier );
139
140 if ( ret == null )
141 {
142 throw new MissingImplementationException( identifier );
143 }
144
145 return ret;
146 }
147
148 /**
149 * Gets an implementation for an index.
150 *
151 * @param index the index of the implementation to return.
152 *
153 * @return a reference to the implementation at {@code index}.
154 *
155 * @throws IndexOutOfBoundsException if {@code index} is negativ,
156 * greater than or equal to {@code size()}.
157 */
158 public final Implementation getImplementation( final int index )
159 {
160 if ( index < 0 || index >= this.size() )
161 {
162 throw new ArrayIndexOutOfBoundsException( index );
163 }
164
165 return this.getImplementations()[index];
166 }
167
168 /**
169 * Gets the number of implementations held by the instance.
170 *
171 * @return the number of implementations held by the instance.
172 */
173 public final int size()
174 {
175 return this.getImplementations().length;
176 }
177
178 /**
179 * Creates a string representing the properties of the instance.
180 *
181 * @return a string representing the properties of the instance.
182 */
183 private String internalString()
184 {
185 final StringBuffer buf = new StringBuffer( 200 ).append( '{' );
186 buf.append( this.internalString( this ) );
187
188 final Implementation[] impls = this.getImplementations();
189 for ( int i = impls.length - 1; i >= 0; i-- )
190 {
191 buf.append( ", [" ).append( i ).append( "]=" ).
192 append( impls[i] );
193
194 }
195
196 buf.append( '}' );
197 return buf.toString();
198 }
199
200 //---------------------------------------------------------Implementations--
201 //--Object------------------------------------------------------------------
202
203 /**
204 * Indicates whether some other object is equal to this one by comparing
205 * the values of all properties.
206 *
207 * @param o the reference object with which to compare.
208 *
209 * @return {@code true} if this object is the same as {@code o};
210 * {@code false} otherwise.
211 */
212 public boolean equals( final Object o )
213 {
214 boolean equal = this == o;
215
216 if ( !equal && o instanceof Implementations )
217 {
218 final Implementations that = (Implementations) o;
219 final Collection these = Arrays.asList( this.getImplementations() );
220 final Collection those = Arrays.asList( that.getImplementations() );
221
222 equal = this.size() == that.size() && these.containsAll( those );
223 }
224
225 return equal;
226 }
227
228 /**
229 * Returns a hash code value for this object.
230 *
231 * @return a hash code value for this object.
232 */
233 public int hashCode()
234 {
235 return this.hashCode;
236 }
237
238 /**
239 * Returns a string representation of the object.
240 *
241 * @return a string representation of the object.
242 */
243 public String toString()
244 {
245 return super.toString() + this.internalString();
246 }
247
248 /**
249 * Creates and returns a deep copy of this object.
250 *
251 * @return a clone of this instance.
252 */
253 public Object clone()
254 {
255 try
256 {
257 final Implementations ret = (Implementations) super.clone();
258 final Implementation[] impls = this.getImplementations();
259 final Implementation[] cloned = new Implementation[ impls.length ];
260
261 for ( int i = impls.length - 1; i >= 0; i-- )
262 {
263 cloned[i] = (Implementation) impls[i].clone();
264 }
265
266 ret.setImplementations( cloned );
267 return ret;
268 }
269 catch ( CloneNotSupportedException e )
270 {
271 throw new AssertionError( e );
272 }
273 }
274
275 //------------------------------------------------------------------Object--
276 }