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.Arrays;
024 import java.util.HashSet;
025 import java.util.Set;
026
027 /**
028 * Implementation meta-data.
029 * <p>An implementation consists of the properties {@code identifier},
030 * {@code name}, {@code vendor} and {@code version}. Property
031 * {@code identifier} holds an identifier uniquely identifying the
032 * implementation in a collection of implementations. Property {@code name}
033 * holds a name of the implementation uniquely identifying the implementation
034 * for a specification. Property {@code vendor} holds vendor information for the
035 * vendor providing the implementation. Property {@code version} holds a textual
036 * version of the implementation. Properties, dependencies and implemented
037 * specifications may be inherited from a {@code parent} up the hierarchy.</p>
038 *
039 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
040 * @version $Id: Implementation.java 2230 2007-03-26 01:37:48Z schulte2005 $
041 */
042 public class Implementation implements Cloneable, Serializable
043 {
044
045 //--Implementation----------------------------------------------------------
046
047 /**
048 * The parent to inherit from.
049 * @serial
050 */
051 private Implementation parent;
052
053 /**
054 * The name of the module holding the implementation.
055 * @serial
056 */
057 private String moduleName;
058
059 /**
060 * The specifications the implementation implements.
061 * @serial
062 */
063 private Specifications implementedSpecifications;
064 private transient Specifications cachedSpecifications;
065
066 /**
067 * The dependencies of the implementation.
068 * @serial
069 */
070 private Dependencies dependencies;
071 private transient Dependencies cachedDependencies;
072
073 /**
074 * The properties of the implementation.
075 * @serial
076 */
077 private Properties properties;
078 private transient Properties cachedProperties;
079
080 /**
081 * The identifier of the implementation.
082 * @serial
083 */
084 private String identifier;
085
086 /**
087 * The name of the implementation.
088 * @serial
089 */
090 private String name;
091
092 /**
093 * The vendor of the implementation.
094 * @serial
095 */
096 private String vendor;
097
098 /**
099 * The version of the implementation.
100 * @serial
101 */
102 private String version;
103
104 /**
105 * Gets the name of the module holding the implementation.
106 *
107 * @return the name of the module holding the implementation.
108 */
109 public String getModuleName()
110 {
111 if(this.moduleName == null)
112 {
113 this.moduleName = "";
114 }
115
116 return this.moduleName;
117 }
118
119 /**
120 * Setter for property {@code moduleName}.
121 *
122 * @param value the new name of the module holding the implementation.
123 */
124 public void setModuleName(final String value)
125 {
126 this.moduleName = value;
127 }
128
129 /**
130 * Gets the specifications the implementation implements.
131 *
132 * @return the specifications the implementation implements.
133 */
134 public Specifications getImplementedSpecifications()
135 {
136 if(this.cachedSpecifications == null)
137 {
138 if(this.implementedSpecifications == null)
139 {
140 this.implementedSpecifications = new Specifications();
141 }
142
143 this.cachedSpecifications = this.implementedSpecifications;
144
145 if(this.getParent() != null)
146 {
147 Specification pSpec;
148 final Specifications pSpecs = this.getParent().
149 getImplementedSpecifications();
150
151 final Set specs = new HashSet();
152
153 for(int i = pSpecs.size() - 1; i >= 0; i--)
154 {
155 pSpec = pSpecs.getSpecification(i);
156
157 try
158 {
159 this.implementedSpecifications.
160 getSpecification(pSpec.getIdentifier());
161
162 }
163 catch(MissingSpecificationException e)
164 {
165 specs.add(pSpec);
166 }
167 }
168
169 specs.addAll(Arrays.asList(
170 this.implementedSpecifications.getSpecifications()));
171
172 this.cachedSpecifications = new Specifications();
173 this.cachedSpecifications.setSpecifications((Specification[])
174 specs.toArray(new Specification[specs.size()]));
175
176 }
177 }
178
179 return this.cachedSpecifications;
180 }
181
182 /**
183 * Setter for property {@code implementedSpecifications}.
184 *
185 * @param value the new specifications the implementation implements.
186 */
187 public void setImplementedSpecifications(final Specifications value)
188 {
189 this.implementedSpecifications = value;
190 this.cachedSpecifications = null;
191 }
192
193 /**
194 * Gets the dependencies of the implementation.
195 *
196 * @return the dependencies the implementation depends on.
197 */
198 public Dependencies getDependencies()
199 {
200 if(this.cachedDependencies == null)
201 {
202 if(this.dependencies == null)
203 {
204 this.dependencies = new Dependencies();
205 }
206
207 this.cachedDependencies = this.dependencies;
208
209 if(this.getParent() != null)
210 {
211 Dependency pDep;
212 final Dependencies pDeps = this.getParent().getDependencies();
213 final Set deps = new HashSet();
214
215 for(int i = pDeps.size() - 1; i >= 0; i--)
216 {
217 pDep = pDeps.getDependency(i);
218
219 try
220 {
221 this.dependencies.getDependency(pDep.getName());
222 }
223 catch(MissingDependencyException e)
224 {
225 deps.add(pDep);
226 }
227 }
228
229 deps.addAll(Arrays.asList(
230 this.dependencies.getDependencies()));
231
232 this.cachedDependencies = new Dependencies();
233 this.cachedDependencies.setDependencies((Dependency[]) deps.
234 toArray(new Dependency[deps.size()]));
235
236 }
237 }
238
239 return this.cachedDependencies;
240 }
241
242 /**
243 * Setter for property {@code dependencies}.
244 *
245 * @param value the new dependencies of the implementation.
246 */
247 public void setDependencies(final Dependencies value)
248 {
249 this.dependencies = value;
250 this.cachedDependencies = null;
251 }
252
253 /**
254 * Gets the properties of the implementation.
255 *
256 * @return the properties of the implementation.
257 */
258 public Properties getProperties()
259 {
260 if(this.cachedProperties == null)
261 {
262 if(this.properties == null)
263 {
264 this.properties = new Properties();
265 }
266
267 this.cachedProperties = this.properties;
268
269 if(this.getParent() != null)
270 {
271 Property pProp;
272 final Properties pProps = this.getParent().getProperties();
273 final Set props = new HashSet();
274 for(int i = pProps.size() - 1; i >= 0; i--)
275 {
276 pProp = pProps.getProperty(i);
277
278 try
279 {
280 this.properties.getProperty(pProp.getName());
281 }
282 catch(MissingPropertyException e)
283 {
284 props.add(pProp);
285 }
286 }
287
288 props.addAll(Arrays.asList(
289 this.properties.getProperties()));
290
291 this.cachedProperties = new Properties();
292 this.cachedProperties.setProperties((Property[]) props.
293 toArray(new Property[props.size()]));
294
295 }
296 }
297
298 return this.cachedProperties;
299 }
300
301 /**
302 * Setter for property {@code properties}.
303 *
304 * @param value new properties of the implementation.
305 */
306 public void setProperties(final Properties value)
307 {
308 this.properties = value;
309 this.cachedProperties = null;
310 }
311
312 /**
313 * Gets the identifier of the implementation.
314 *
315 * @return the unique identifier of the implementation.
316 */
317 public String getIdentifier()
318 {
319 if(this.identifier == null)
320 {
321 this.identifier = "";
322 }
323
324 return this.identifier;
325 }
326
327 /**
328 * Setter for property {@code identifier}.
329 *
330 * @param value the new identifier of the implementation.
331 */
332 public void setIdentifier(final String value)
333 {
334 this.identifier = value;
335 }
336
337 /**
338 * Gets the name of the implementation.
339 *
340 * @return the name of the implementation.
341 */
342 public String getName()
343 {
344 if(this.name == null)
345 {
346 this.name = "";
347 }
348
349 return name;
350 }
351
352 /**
353 * Setter for property {@code name}.
354 *
355 * @param value the new name of the implementation.
356 */
357 public void setName(final String value)
358 {
359 this.name = value;
360 }
361
362 /**
363 * Gets the parent implementation the implementation inherits from.
364 *
365 * @return the parent implementation the implementation inherits from or
366 * {@code null} if the implementation has no parent.
367 */
368 public Implementation getParent()
369 {
370 return parent;
371 }
372
373 /**
374 * Setter for property {@code parent}.
375 *
376 * @param value the new parent implementation of the implementation.
377 */
378 public void setParent(final Implementation value)
379 {
380 this.parent = value;
381 this.cachedDependencies = null;
382 this.cachedProperties = null;
383 this.cachedSpecifications = null;
384 }
385
386 /**
387 * Gets the vendor of the implementation.
388 *
389 * @return the vendor of the implementation.
390 */
391 public String getVendor()
392 {
393 if(this.vendor == null)
394 {
395 this.vendor = "";
396 }
397
398 return this.vendor;
399 }
400
401 /**
402 * Setter for property {@code name}.
403 *
404 * @param value the new vendor of the implementation.
405 */
406 public void setVendor(final String value)
407 {
408 this.vendor = value;
409 }
410
411 /**
412 * Gets the version of the implementation.
413 *
414 * @return the version of the implementation.
415 */
416 public String getVersion()
417 {
418 if(this.version == null)
419 {
420 this.version = "";
421 }
422
423 return this.version;
424 }
425
426 /**
427 * Setter for property {@code version}.
428 *
429 * @param value the new version of the implementation.
430 */
431 public void setVersion(final String value)
432 {
433 this.version = value;
434 }
435
436 /**
437 * Creates a string representing the properties of the instance.
438 *
439 * @return a string representing the properties of the instance.
440 */
441 private String internalString()
442 {
443 return new StringBuffer(500).
444 append("\n\tdependencies=").append(this.dependencies).
445 append("\n\tidentifier=").append(this.identifier).
446 append("\n\timplementedSpecifications=").
447 append(this.implementedSpecifications).
448 append("\n\tmoduleName=").append(this.moduleName).
449 append("\n\tname=").append(this.name).
450 append("\n\tparent=").append(this.parent).
451 append("\n\tproperties=").append(this.properties).
452 append("\n\tvendor=").append(this.vendor).
453 append("\n\tversion=").append(this.version).
454 toString();
455
456 }
457
458 //----------------------------------------------------------Implementation--
459 //--Object------------------------------------------------------------------
460
461 /**
462 * Returns a string representation of the object.
463 *
464 * @return a string representation of the object.
465 */
466 public String toString()
467 {
468 return super.toString() + this.internalString();
469 }
470
471 /**
472 * Creates and returns a deep copy of this object.
473 *
474 * @return a clone of this instance.
475 */
476 public Object clone()
477 {
478 try
479 {
480 final Implementation ret = (Implementation) super.clone();
481 if(this.parent != null)
482 {
483 ret.parent = (Implementation) this.parent.clone();
484 }
485 if(this.implementedSpecifications != null)
486 {
487 ret.implementedSpecifications =
488 (Specifications) this.implementedSpecifications.clone();
489
490 }
491 if(this.properties != null)
492 {
493 ret.properties = (Properties) this.properties.clone();
494 }
495 if(this.dependencies != null)
496 {
497 ret.dependencies = (Dependencies) this.dependencies.clone();
498 }
499
500 return ret;
501 }
502 catch(CloneNotSupportedException e)
503 {
504 throw new AssertionError(e);
505 }
506 }
507
508 /**
509 * Indicates whether some other object is equal to this one by comparing
510 * property {@code identifier}.
511 *
512 * @param o the reference object with which to compare.
513 *
514 * @return {@code true} if this object is the same as {@code o};
515 * {@code false} otherwise.
516 */
517 public final boolean equals(final Object o)
518 {
519 return o == this || (o != null && o instanceof Implementation &&
520 ((Implementation)o).getIdentifier().equals(this.getIdentifier()));
521
522 }
523
524 /**
525 * Returns a hash code value for this object.
526 *
527 * @return a hash code value for this object.
528 */
529 public final int hashCode()
530 {
531 return this.getIdentifier().hashCode();
532 }
533
534 //------------------------------------------------------------------Object--
535
536 }