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    }