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.HashMap;
024    import java.util.Map;
025    
026    /**
027     * Specification meta-data.
028     * <p>A specification consists of the properties {@code identifier},
029     * {@code vendor}, {@code description} and {@code version}. Property
030     * {@code identifier} holds an identifier uniquely identifying the specification
031     * in a collection of specifications. Property {@code vendor} holds vendor
032     * information for the vendor providing the specification. Property
033     * {@code description} holds a textual description and property {@code version}
034     * holds a textual version of the specification. The {@code singleton} flag
035     * indicates whether implementations of the specification should be instantiated
036     * once or whenever requested through the container.</p>
037     *
038     * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
039     * @version $Id: Specification.java 2230 2007-03-26 01:37:48Z schulte2005 $
040     */
041    public class Specification implements Cloneable, Serializable
042    {
043    
044        //--Specification-----------------------------------------------------------
045    
046        /**
047         * The name of the module holding the specification.
048         * @serial
049         */
050        private String moduleName;
051    
052        /**
053         * The description of the specification.
054         * @serial
055         */
056        private String description;
057    
058        /**
059         * The identifier of the specification.
060         * @serial
061         */
062        private String identifier;
063    
064        /**
065         * The flag indicating that instance of the specification should be
066         * created using a singleton strategy.
067         * @serial
068         */
069        private boolean singleton;
070    
071        /**
072         * The vendor of the specification.
073         * @serial
074         */
075        private String vendor;
076    
077        /**
078         * The version of the specification.
079         * @serial
080         */
081        private String version;
082    
083        /**
084         * The implementations available for the specification.
085         * @serial
086         */
087        private Implementations implementations;
088    
089        /**
090         * Maps implementation names to implementations.
091         * @serial
092         */
093        private final Map implementationNames = new HashMap();
094    
095        /**
096         * Gets the name of the module holding the specification.
097         *
098         * @return the name of the module holding the specification.
099         */
100        public String getModuleName()
101        {
102            if(this.moduleName == null)
103            {
104                this.moduleName = "";
105            }
106    
107            return this.moduleName;
108        }
109    
110        /**
111         * Setter for property {@code moduleName}.
112         *
113         * @param value the new name of the module holding the specification.
114         */
115        public void setModuleName(final String value)
116        {
117            this.moduleName = value;
118        }
119    
120        /**
121         * Gets the description of the specification.
122         *
123         * @return the description of the specification.
124         */
125        public String getDescription()
126        {
127            if(this.description == null)
128            {
129                this.description = "";
130            }
131    
132            return this.description;
133        }
134    
135        /**
136         * Setter for property {@code description}.
137         *
138         * @param value the new description of the specification.
139         */
140        public void setDescription(final String value)
141        {
142            this.description = value;
143        }
144    
145        /**
146         * Gets the identifier of the specification.
147         *
148         * @return the unique identifier of the specification.
149         */
150        public String getIdentifier()
151        {
152            if(this.identifier == null)
153            {
154                this.identifier = "";
155            }
156    
157            return this.identifier;
158        }
159    
160        /**
161         * Setter for property {@code identifier}.
162         *
163         * @param value the new identifier of the specification.
164         */
165        public void setIdentifier(final String value)
166        {
167            this.identifier = value;
168        }
169    
170        /**
171         * Gets the flag indicating the instantiation strategy of the specification.
172         *
173         * @return {@code true} if the specification is specifying a singleton;
174         * {@code false} if not.
175         */
176        public boolean isSingleton()
177        {
178            return this.singleton;
179        }
180    
181        /**
182         * Setter for property {@code singleton}.
183         *
184         * @param value {@code true} to flag the specification as a singleton;
185         * {@code false} to not flag the specification as a singleton.
186         */
187        public void setSingleton(boolean value)
188        {
189            this.singleton = value;
190        }
191    
192        /**
193         * Gets the vendor of the specification.
194         *
195         * @return the vendor of the specification.
196         */
197        public String getVendor()
198        {
199            if(this.vendor == null)
200            {
201                this.vendor = "";
202            }
203    
204            return this.vendor;
205        }
206    
207        /**
208         * Setter for property {@code vendor}.
209         *
210         * @param value the new vendor of the specification.
211         */
212        public void setVendor(final String value)
213        {
214            this.vendor = value;
215        }
216    
217        /**
218         * Gets the version of the specification.
219         *
220         * @return the version of the specification.
221         */
222        public String getVersion()
223        {
224            if(this.version == null)
225            {
226                this.version = "";
227            }
228    
229            return this.version;
230        }
231    
232        /**
233         * Setter for property {@code version}.
234         *
235         * @param value the new version of the specification.
236         */
237        public void setVersion(final String value)
238        {
239            this.version = value;
240        }
241    
242        /**
243         * Gets an implementation for a name.
244         *
245         * @param name the name of the implementation to return.
246         *
247         * @return a reference to the implementation named {@code name}.
248         *
249         * @throws NullPointerException if {@code name} is {@code null}.
250         * @throws MissingImplementationException if no implementation matching
251         * {@code name} exists.
252         */
253        public Implementation getImplementation(final String name)
254        {
255            if(name == null)
256            {
257                throw new NullPointerException("name");
258            }
259    
260            final Implementation ret =
261                (Implementation) this.implementationNames.get(name);
262    
263            if(ret == null)
264            {
265                throw new MissingImplementationException(name);
266            }
267    
268            return ret;
269        }
270    
271        /**
272         * Gets all available implementations of the specification.
273         *
274         * @return all available implementations of the specification.
275         */
276        public Implementations getImplementations()
277        {
278            if(this.implementations == null)
279            {
280                this.implementations = new Implementations();
281            }
282    
283            return this.implementations;
284        }
285    
286        /**
287         * Setter for property {@code implementations}.
288         *
289         * @param value the new implementations of the specification.
290         *
291         * @throws DuplicateImplementationException if {@code value} contains
292         * duplicate implementations.
293         */
294        public void setImplementations(final Implementations value)
295        {
296            if(value != null)
297            {
298                this.implementationNames.clear();
299                for(int i = value.size() - 1; i >= 0; i--)
300                {
301                    if(this.implementationNames.put(
302                        value.getImplementation(i).getName(),
303                        value.getImplementation(i)) != null)
304                    {
305    
306                        throw new DuplicateImplementationException(
307                            value.getImplementation(i).getName());
308    
309                    }
310                }
311            }
312            this.implementations = value;
313        }
314    
315        /**
316         * Creates a string representing the properties of the instance.
317         *
318         * @return a string representing the properties of the instance.
319         */
320        private String internalString()
321        {
322            return new StringBuffer(500).
323                append("\n\tdescription=").append(this.description).
324                append("\n\tidentifier=").append(this.identifier).
325                append("\n\timplementations=").append(this.implementations).
326                append("\n\tmoduleName=").append(this.moduleName).
327                append("\n\tsingleton=").append(this.singleton).
328                append("\n\tvendor=").append(this.vendor).
329                append("\n\tversion=").append(this.version).
330                toString();
331    
332        }
333    
334        //-----------------------------------------------------------Specification--
335        //--Object------------------------------------------------------------------
336    
337        /**
338         * Returns a string representation of the object.
339         *
340         * @return a string representation of the object.
341         */
342        public String toString()
343        {
344            return super.toString() + this.internalString();
345        }
346    
347        /**
348         * Creates and returns a deep copy of this object.
349         *
350         * @return a clone of this instance.
351         */
352        public Object clone()
353        {
354            try
355            {
356                final Specification ret = (Specification) super.clone();
357                ret.setImplementations(
358                    (Implementations) this.getImplementations().clone());
359    
360                return ret;
361            }
362            catch(CloneNotSupportedException e)
363            {
364                throw new AssertionError(e);
365            }
366        }
367    
368        /**
369         * Indicates whether some other object is equal to this one by comparing
370         * property {@code identifier}.
371         *
372         * @param o the reference object with which to compare.
373         *
374         * @return {@code true} if this object is the same as {@code o};
375         * {@code false} otherwise.
376         */
377        public final boolean equals(final Object o)
378        {
379            return o == this || (o != null && o instanceof Specification &&
380                ((Specification)o).getIdentifier().equals(this.getIdentifier()));
381    
382        }
383    
384        /**
385         * Returns a hash code value for this object.
386         *
387         * @return a hash code value for this object.
388         */
389        public final int hashCode()
390        {
391            return this.getIdentifier().hashCode();
392        }
393    
394        //------------------------------------------------------------------Object--
395    
396    }