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 implementations.
31 *
32 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
33 * @version $JDTAUS: Implementations.java 8743 2012-10-07 03:06:20Z schulte $
34 */
35 public class Implementations 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 = 5611937453792676565L;
42
43 //---------------------------------------------------------------Constants--
44 //--Implementations---------------------------------------------------------
45
46 /**
47 * The implementations held by the instance.
48 * @serial
49 */
50 private Implementation[] implementations;
51
52 /**
53 * Maps implementation identifiers to implementations.
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 Implementations} instance. */
65 public Implementations()
66 {
67 super();
68 }
69
70 /**
71 * Gets all implementations of the collection.
72 *
73 * @return all implementations of the collection.
74 */
75 public Implementation[] getImplementations()
76 {
77 if ( this.implementations == null )
78 {
79 this.implementations = new Implementation[ 0 ];
80 this.hashCode = 0;
81 }
82
83 return this.implementations;
84 }
85
86 /**
87 * Setter for property {@code implementations}.
88 *
89 * @param value the new implementations for the instance.
90 *
91 * @throws DuplicateImplementationException if {@code value} contains
92 * duplicate implementations.
93 */
94 public void setImplementations( final Implementation[] value )
95 {
96 this.identifiers.clear();
97 this.hashCode = 0;
98 this.implementations = 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
106 if ( this.identifiers.put( value[i].getIdentifier(),
107 value[i] ) != null )
108 {
109 this.identifiers.clear();
110 this.hashCode = 0;
111
112 throw new DuplicateImplementationException(
113 value[i].getIdentifier() );
114
115 }
116 }
117
118 this.implementations = value;
119 }
120 }
121
122 /**
123 * Gets an implementation for an identifier.
124 *
125 * @param identifier the identifier of the implementation to return.
126 *
127 * @return a reference to the implementation identified by
128 * {@code identifier}.
129 *
130 * @throws NullPointerException if {@code identifier} is {@code null}.
131 * @throws MissingImplementationException if no implementation matching
132 * {@code identifier} exists in the collection.
133 */
134 public Implementation getImplementation( final String identifier )
135 {
136 if ( identifier == null )
137 {
138 throw new NullPointerException( "identifier" );
139 }
140
141 final Implementation ret =
142 (Implementation) this.identifiers.get( identifier );
143
144 if ( ret == null )
145 {
146 throw new MissingImplementationException( identifier );
147 }
148
149 return ret;
150 }
151
152 /**
153 * Gets an implementation for an index.
154 *
155 * @param index the index of the implementation to return.
156 *
157 * @return a reference to the implementation at {@code index}.
158 *
159 * @throws IndexOutOfBoundsException if {@code index} is negativ,
160 * greater than or equal to {@code size()}.
161 */
162 public final Implementation getImplementation( final int index )
163 {
164 if ( index < 0 || index >= this.size() )
165 {
166 throw new ArrayIndexOutOfBoundsException( index );
167 }
168
169 return this.getImplementations()[index];
170 }
171
172 /**
173 * Gets the number of implementations held by the instance.
174 *
175 * @return the number of implementations held by the instance.
176 */
177 public final int size()
178 {
179 return this.getImplementations().length;
180 }
181
182 /**
183 * Creates a string representing the properties of the instance.
184 *
185 * @return a string representing the properties of the instance.
186 */
187 private String internalString()
188 {
189 final StringBuffer buf = new StringBuffer( 200 ).append( '{' );
190 buf.append( this.internalString( this ) );
191
192 final Implementation[] impls = this.getImplementations();
193 for ( int i = impls.length - 1; i >= 0; i-- )
194 {
195 buf.append( ", [" ).append( i ).append( "]=" ).
196 append( impls[i] );
197
198 }
199
200 buf.append( '}' );
201 return buf.toString();
202 }
203
204 //---------------------------------------------------------Implementations--
205 //--Object------------------------------------------------------------------
206
207 /**
208 * Indicates whether some other object is equal to this one by comparing
209 * the values of all properties.
210 *
211 * @param o the reference object with which to compare.
212 *
213 * @return {@code true} if this object is the same as {@code o};
214 * {@code false} otherwise.
215 */
216 public boolean equals( final Object o )
217 {
218 boolean equal = this == o;
219
220 if ( !equal && o instanceof Implementations )
221 {
222 final Implementations that = (Implementations) o;
223 final Collection these = Arrays.asList( this.getImplementations() );
224 final Collection those = Arrays.asList( that.getImplementations() );
225
226 equal = this.size() == that.size() && these.containsAll( those );
227 }
228
229 return equal;
230 }
231
232 /**
233 * Returns a hash code value for this object.
234 *
235 * @return a hash code value for this object.
236 */
237 public int hashCode()
238 {
239 return this.hashCode;
240 }
241
242 /**
243 * Returns a string representation of the object.
244 *
245 * @return a string representation of the object.
246 */
247 public String toString()
248 {
249 return super.toString() + this.internalString();
250 }
251
252 /**
253 * Creates and returns a deep copy of this object.
254 *
255 * @return a clone of this instance.
256 */
257 public Object clone()
258 {
259 try
260 {
261 final Implementations ret = (Implementations) super.clone();
262 final Implementation[] impls = this.getImplementations();
263 final Implementation[] cloned = new Implementation[ impls.length ];
264
265 for ( int i = impls.length - 1; i >= 0; i-- )
266 {
267 cloned[i] = (Implementation) impls[i].clone();
268 }
269
270 ret.setImplementations( cloned );
271 return ret;
272 }
273 catch ( final CloneNotSupportedException e )
274 {
275 throw new AssertionError( e );
276 }
277 }
278
279 //------------------------------------------------------------------Object--
280 }