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     * Dependency meta-data.
029     * <p>A dependency consists of a name uniquely identifying the dependency in a
030     * collection of dependencies. A dependency pairs a specification with a
031     * corresponding implementation from a set of available implementations.
032     * Properties set with a dependency overwrite the properties defined by the
033     * implementation. The {@code bound} flag indicates if an instance of the
034     * dependency is bound to the requesting implementation.</p>
035     *
036     * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
037     * @version $Id: Dependency.java 2230 2007-03-26 01:37:48Z schulte2005 $
038     */
039    public class Dependency implements Cloneable, Serializable
040    {
041    
042        //--Dependency--------------------------------------------------------------
043    
044        /**
045         * The name of the dependency.
046         * @serial
047         */
048        private String name;
049    
050        /**
051         * The specification of the dependency.
052         * @serial
053         */
054        private Specification specification;
055    
056        /**
057         * The implementation of the dependency.
058         * @serial
059         */
060        private Implementation implementation;
061    
062        /**
063         * The properties of the dependency.
064         * @serial
065         */
066        private Properties properties;
067        private transient Properties cachedProperties;
068    
069        /**
070         * Flag indicating if the dependency is bound to the requesting
071         * implementation.
072         * @serial
073         */
074        private boolean bound;
075    
076        /**
077         * Gets the name of the dependency.
078         *
079         * @return the name of the dependency.
080         */
081        public String getName()
082        {
083            if(this.name == null)
084            {
085                this.name = "";
086            }
087    
088            return name;
089        }
090    
091        /**
092         * Setter for property {@code name}.
093         *
094         * @param value the new name of the dependency.
095         */
096        public void setName(final String value)
097        {
098            this.name = value;
099        }
100    
101        /**
102         * Gets the specification of the dependency.
103         *
104         * @return the specification of the dependency.
105         */
106        public Specification getSpecification()
107        {
108            return this.specification;
109        }
110    
111        /**
112         * Setter for property {@code specification}.
113         *
114         * @param value the new specification of the dependency.
115         */
116        public void setSpecification(final Specification value)
117        {
118            this.specification = value;
119        }
120    
121        /**
122         * Gets the implementation of the dependency.
123         *
124         * @return the implementation of the dependency.
125         */
126        public Implementation getImplementation()
127        {
128            return this.implementation;
129        }
130    
131        /**
132         * Setter for property {@code implementation}.
133         *
134         * @param value the new implementation of the dependency.
135         */
136        public void setImplementation(final Implementation value)
137        {
138            this.implementation = value;
139            this.cachedProperties = null;
140        }
141    
142        /**
143         * Gets the properties of the dependency.
144         *
145         * @return the properties of the dependency.
146         */
147        public Properties getProperties()
148        {
149            if(this.cachedProperties == null)
150            {
151                if(this.properties == null)
152                {
153                    this.properties = new Properties();
154                }
155    
156                Property iProp;
157                Properties iProps = this.getImplementation().getProperties();
158                final Set props = new HashSet();
159                this.cachedProperties = new Properties();
160    
161                for(int i = iProps.size() - 1; i >= 0; i--)
162                {
163                    iProp = iProps.getProperty(i);
164    
165                    try
166                    {
167                        this.properties.getProperty(iProp.getName());
168                    }
169                    catch(MissingPropertyException e)
170                    {
171                        props.add(iProp);
172                    }
173                }
174    
175                props.addAll(Arrays.asList(this.properties.getProperties()));
176                this.cachedProperties.setProperties((Property[]) props.
177                    toArray(new Property[props.size()]));
178    
179            }
180    
181            return this.cachedProperties;
182        }
183    
184        /**
185         * Setter for property {@code properties}.
186         *
187         * @param value the new properties of the dependency.
188         */
189        public void setProperties(final Properties value)
190        {
191            this.properties = value;
192            this.cachedProperties = null;
193        }
194    
195        /**
196         * Gets the flag indicating if the dependency is bound to a requesting
197         * implementation.
198         *
199         * @return {@code true} if an instance of the dependency is bound to the
200         * requesting implementation; {@code false} if not.
201         */
202        public boolean isBound()
203        {
204            return this.bound;
205        }
206    
207        /**
208         * Setter for property {@code bound}.
209         *
210         * @param value {@code true} if an instance of the dependency should be
211         * bound to the requesting implementation; {@code false} if not.
212         */
213        public void setBound(boolean value)
214        {
215            this.bound = value;
216        }
217    
218        /**
219         * Creates a string representing the properties of the instance.
220         *
221         * @return a string representing the properties of the instance.
222         */
223        private String internalString()
224        {
225            return new StringBuffer(500).
226                append("\n\tbound=").append(this.bound).
227                append("\n\timplementation=").append(this.implementation).
228                append("\n\tname=").append(this.name).
229                append("\n\tproperties=").append(this.properties).
230                append("\n\tspecification=").append(this.specification).
231                toString();
232    
233        }
234    
235        //--------------------------------------------------------------Dependency--
236        //--Object------------------------------------------------------------------
237    
238        /**
239         * Returns a string representation of the object.
240         *
241         * @return a string representation of the object.
242         */
243        public String toString()
244        {
245            return super.toString() + this.internalString();
246        }
247    
248        /**
249         * Indicates whether some other object is equal to this one by comparing
250         * the values of all properties.
251         *
252         * @param o the reference object with which to compare.
253         *
254         * @return {@code true} if this object is the same as {@code o};
255         * {@code false} otherwise.
256         */
257        public boolean equals(final Object o)
258        {
259            boolean equal = this == o;
260    
261            if(!equal && o instanceof Dependency)
262            {
263                final Dependency that = (Dependency) o;
264                equal = this.getName().equals(that.getName()) &&
265                    (this.implementation == null ? that.implementation == null :
266                        this.implementation.equals(that.implementation)) &&
267                    (this.specification == null ? that.specification == null :
268                        this.specification.equals(that.specification));
269    
270            }
271    
272            return equal;
273        }
274    
275        /**
276         * Returns a hash code value for this object.
277         *
278         * @return a hash code value for this object.
279         */
280        public int hashCode()
281        {
282            return this.getName().hashCode() +
283                (this.getImplementation() == null ?
284                    0 : this.getImplementation().hashCode()) +
285                (this.getSpecification() == null ?
286                    0 : this.getSpecification().hashCode());
287    
288        }
289    
290        /**
291         * Creates and returns a deep copy of this object.
292         *
293         * @return a clone of this instance.
294         */
295        public Object clone()
296        {
297            try
298            {
299                final Dependency ret = (Dependency) super.clone();
300                if(this.implementation != null)
301                {
302                    ret.implementation =
303                        (Implementation) this.implementation.clone();
304    
305                }
306                if(this.properties != null)
307                {
308                    ret.properties = (Properties) this.properties.clone();
309                }
310                if(this.specification != null)
311                {
312                    ret.specification = (Specification) this.specification.clone();
313                }
314    
315                return ret;
316            }
317            catch(CloneNotSupportedException e)
318            {
319                throw new AssertionError(e);
320            }
321        }
322    
323        //------------------------------------------------------------------Object--
324    }