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.ArrayList;
024 import java.util.Arrays;
025 import java.util.Collection;
026 import java.util.HashMap;
027 import java.util.Iterator;
028 import java.util.Map;
029
030 /**
031 * Collection of modules.
032 *
033 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
034 * @version $Id: Modules.java 2230 2007-03-26 01:37:48Z schulte2005 $
035 */
036 public class Modules implements Cloneable, Serializable
037 {
038
039 //--Modules-----------------------------------------------------------------
040
041 /**
042 * The modules held by the instance.
043 * @serial
044 */
045 private Module[] modules;
046
047 /**
048 * The specifications of all modules.
049 * @serial
050 */
051 private Specifications specifications;
052
053 /**
054 * The implementations of all modules.
055 * @serial
056 */
057 private Implementations implementations;
058
059 /**
060 * Maps module names to modules.
061 * @serial
062 */
063 private Map names = new HashMap(1000);
064
065 /**
066 * Maps specification identifiers to specifications.
067 * @serial
068 */
069 private Map specificationMap = new HashMap(1000);
070
071 /**
072 * Maps implementation identifiers to implementations.
073 * @serial
074 */
075 private Map implementationMap = new HashMap(1000);
076
077 /**
078 * Hash code.
079 * @serial
080 */
081 private int hashCode;
082
083 /**
084 * Gets the modules of the collection.
085 *
086 * @return the modules of the collection.
087 */
088 public Module[] getModules()
089 {
090 if(this.modules == null)
091 {
092 this.modules = new Module[0];
093 this.hashCode = 0;
094 }
095
096 return this.modules;
097 }
098
099 /**
100 * Setter for property {@code modules}.
101 *
102 * @param value the new collection of modules.
103 *
104 * @throws DuplicateModuleException if {@code value} contains duplicate
105 * modules.
106 * @throws DuplicateSpecificationException if {@code value} contains
107 * duplicate specifications.
108 * @throws DuplicateImplementationException if {@code value} contains
109 * duplicate implementations.
110 */
111 public void setModules(final Module[] value)
112 {
113 Specification spec;
114 Specifications specs;
115 Implementation impl;
116 Implementations impls;
117
118 this.implementations = null;
119 this.specifications = null;
120 this.names.clear();
121 this.specificationMap.clear();
122 this.implementationMap.clear();
123 this.hashCode = 0;
124 this.modules = value;
125
126 if(value != null)
127 {
128 for(int i = value.length - 1; i >= 0; i--)
129 {
130 this.hashCode += value[i].hashCode();
131
132 // Check module name uniqueness.
133 if(this.names.put(value[i].getName(), value[i]) != null)
134 {
135 throw new DuplicateModuleException(value[i].getName());
136 }
137
138 // Check specification identifier uniqueness.
139 specs = value[i].getSpecifications();
140 for(int j = specs.size() - 1; j >= 0; j--)
141 {
142 spec = specs.getSpecification(j);
143 if(this.specificationMap.
144 put(spec.getIdentifier(), spec) != null)
145 {
146
147 throw new DuplicateSpecificationException(
148 spec.getIdentifier());
149
150 }
151 }
152
153 // Check implementation identifier uniqueness.
154 impls = value[i].getImplementations();
155 for(int j = impls.size() - 1; j >= 0; j--)
156 {
157 impl = impls.getImplementation(j);
158 if(this.implementationMap.
159 put(impl.getIdentifier(), impl) != null)
160 {
161
162 throw new DuplicateImplementationException(
163 impl.getIdentifier());
164
165 }
166 }
167 }
168 }
169 }
170
171 /**
172 * Gets a module for a name.
173 *
174 * @param name the name of the module to return.
175 *
176 * @return a reference to the module named {@code name}.
177 *
178 * @throws NullPointerException if {@code name} is {@code null}.
179 * @throws MissingModuleException if no module matching {@code name} exists
180 * in the collection.
181 */
182 public Module getModule(final String name)
183 {
184
185 if(name == null)
186 {
187 throw new NullPointerException("name");
188 }
189
190 final Module ret = (Module) this.names.get(name);
191
192 if(ret == null)
193 {
194 throw new MissingModuleException(name);
195 }
196
197 return ret;
198 }
199
200 /**
201 * Gets a module for an index.
202 *
203 * @param index the index of the module to return.
204 *
205 * @return a reference to the module at {@code index}.
206 *
207 * @throws IndexOutOfBoundsException if {@code index} is negativ,
208 * greater than or equal to {@code size()}.
209 */
210 public final Module getModule(final int index)
211 {
212 if(index < 0 || index >= this.size())
213 {
214 throw new ArrayIndexOutOfBoundsException(index);
215 }
216
217 return this.getModules()[index];
218 }
219
220 /**
221 * Gets a specification for an identifier.
222 *
223 * @param identifier the identifier of the specification to return.
224 *
225 * @return a reference to the specification identified by
226 * {@code identifier}.
227 *
228 * @throws NullPointerException if {@code identifier} is {@code null}.
229 * @throws MissingSpecificationException if no specification matching
230 * {@code identifier} exists.
231 */
232 public Specification getSpecification(final String identifier)
233 {
234
235 if(identifier == null)
236 {
237 throw new NullPointerException("identifier");
238 }
239
240 final Specification ret =
241 (Specification) this.specificationMap.get(identifier);
242
243 if(ret == null)
244 {
245 throw new MissingSpecificationException(identifier);
246 }
247
248 return ret;
249 }
250
251 /**
252 * Gets a collection of all specifications of all modules.
253 *
254 * @return a reference to all specifications of all modules held by the
255 * instance.
256 */
257 public Specifications getSpecifications()
258 {
259 if(this.specifications == null)
260 {
261 final Iterator it;
262 final Collection specs =
263 new ArrayList(this.specificationMap.size());
264
265 this.specifications = new Specifications();
266 for(it = this.specificationMap.keySet().iterator(); it.hasNext();)
267 {
268 specs.add(this.specificationMap.get(it.next()));
269 }
270 this.specifications.setSpecifications((Specification[]) specs.
271 toArray(new Specification[specs.size()]));
272
273 }
274
275 return this.specifications;
276 }
277
278 /**
279 * Gets an implementation for an identifier.
280 *
281 * @param identifier the identifier of the implementation to return.
282 *
283 * @return a reference to the implementation identified by
284 * {@code identifier}.
285 *
286 * @throws NullPointerException if {@code identifier} is {@code null}.
287 * @throws MissingImplementationException if no implementation matching
288 * {@code identifier} exists.
289 */
290 public Implementation getImplementation(final String identifier)
291 {
292
293 if(identifier == null)
294 {
295 throw new NullPointerException("identifier");
296 }
297
298 final Implementation ret =
299 (Implementation) this.implementationMap.get(identifier);
300
301 if(ret == null)
302 {
303 throw new MissingImplementationException(identifier);
304 }
305
306 return ret;
307 }
308
309 /**
310 * Gets a collection of all implementations of all modules held by the
311 * instance.
312 *
313 * @return a reference to all implementations of all modules held by the
314 * instance.
315 */
316 public Implementations getImplementations()
317 {
318 if(this.implementations == null)
319 {
320 final Iterator it;
321 final Collection impls =
322 new ArrayList(this.implementationMap.size());
323
324 this.implementations = new Implementations();
325 for(it = this.implementationMap.keySet().
326 iterator(); it.hasNext();)
327 {
328
329 impls.add(this.implementationMap.get(it.next()));
330 }
331
332 this.implementations.setImplementations((Implementation[]) impls.
333 toArray(new Implementation[impls.size()]));
334
335 }
336
337 return this.implementations;
338 }
339
340 /**
341 * Gets the number of modules held by the instance.
342 *
343 * @return the number of modules held by the instance.
344 */
345 public final int size()
346 {
347 return this.getModules().length;
348 }
349
350 /**
351 * Creates a string representing the properties of the instance.
352 *
353 * @return a string representing the properties of the instance.
354 */
355 private String internalString()
356 {
357 final StringBuffer buf = new StringBuffer(200);
358 final Module[] modules = this.getModules();
359 for(int i = modules.length - 1; i >= 0; i--)
360 {
361 buf.append("\n\tmodule[").append(i).append("]=").
362 append(modules[i]);
363
364 }
365
366 return buf.toString();
367 }
368
369 //-----------------------------------------------------------------Modules--
370 //--Object------------------------------------------------------------------
371
372 /**
373 * Indicates whether some other object is equal to this one by comparing
374 * the values of all properties.
375 *
376 * @param o the reference object with which to compare.
377 *
378 * @return {@code true} if this object is the same as {@code o};
379 * {@code false} otherwise.
380 */
381 public boolean equals(final Object o)
382 {
383 boolean equal = this == o;
384
385 if(!equal && o instanceof Modules)
386 {
387 final Modules that = (Modules) o;
388 final Collection these = Arrays.asList(this.getModules());
389 final Collection those = Arrays.asList(that.getModules());
390
391 equal = these.size() == that.size() && these.containsAll(those);
392 }
393
394 return equal;
395 }
396
397 /**
398 * Returns a hash code value for this object.
399 *
400 * @return a hash code value for this object.
401 */
402 public int hashCode()
403 {
404 return this.hashCode;
405 }
406
407 /**
408 * Returns a string representation of the object.
409 *
410 * @return a string representation of the object.
411 */
412 public String toString()
413 {
414 return super.toString() + this.internalString();
415 }
416
417 /**
418 * Creates and returns a deep copy of this object.
419 *
420 * @return a clone of this instance.
421 */
422 public Object clone()
423 {
424 try
425 {
426 final Modules ret = (Modules) super.clone();
427 final Module[] mods = this.getModules();
428 final Module[] cloned = new Module[mods.length];
429
430 for(int i = mods.length - 1; i >= 0; i--)
431 {
432 cloned[i] = (Module) mods[i].clone();
433 }
434
435 ret.setModules(cloned);
436 return ret;
437 }
438 catch(CloneNotSupportedException e)
439 {
440 throw new AssertionError(e);
441 }
442 }
443
444 //------------------------------------------------------------------Object--
445
446 }