View Javadoc

1   /*
2    *  jDTAUS Core API
3    *  Copyright (C) 2005 Christian Schulte
4    *  <cs@schulte.it>
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19   *
20   */
21  package org.jdtaus.core.container;
22  
23  import java.io.Serializable;
24  import java.util.Iterator;
25  import java.util.Map;
26  import java.util.TreeMap;
27  
28  /**
29   * Dependency meta-data.
30   * <p>A dependency consists of a name uniquely identifying the dependency in a
31   * set of dependencies and pairs a specification with corresponding
32   * implementations from a set of available implementations. Properties set with
33   * a dependency overwrite properties of the dependency's specification. The
34   * {@code bound} flag indicates if the instance of the dependency is bound to
35   * the declaring implementation.</p>
36   *
37   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
38   * @version $JDTAUS: Dependency.java 8743 2012-10-07 03:06:20Z schulte $
39   */
40  public class Dependency extends ModelObject implements Cloneable, Serializable
41  {
42      //--Constants---------------------------------------------------------------
43  
44      /** Serial version UID for backwards compatibility with 1.0.x classes. */
45      private static final long serialVersionUID = -8556956703006143247L;
46  
47      //---------------------------------------------------------------Constants--
48      //--Dependency--------------------------------------------------------------
49  
50      /**
51       * The name of the dependency.
52       * @serial
53       */
54      private String name;
55  
56      /**
57       * The specification of the dependency.
58       * @serial
59       */
60      private Specification specification;
61  
62      /**
63       * The implementation of the dependency.
64       * @serial
65       */
66      private Implementation implementation;
67  
68      /**
69       * The properties of the dependency.
70       * @serial
71       */
72      private Properties properties;
73  
74      /**
75       * Flag indicating if the dependency is bound to the requesting
76       * implementation.
77       * @serial
78       */
79      private boolean bound;
80  
81      /** Creates a new {@code Dependency} instance. */
82      public Dependency()
83      {
84          super();
85      }
86  
87      /**
88       * Gets the name of the dependency.
89       *
90       * @return the name of the dependency.
91       */
92      public String getName()
93      {
94          if ( this.name == null )
95          {
96              this.name = "";
97          }
98  
99          return this.name;
100     }
101 
102     /**
103      * Setter for property {@code name}.
104      *
105      * @param value the new name of the dependency.
106      */
107     public void setName( final String value )
108     {
109         this.name = value;
110     }
111 
112     /**
113      * Gets the specification of the dependency.
114      *
115      * @return the specification of the dependency.
116      */
117     public Specification getSpecification()
118     {
119         return this.specification;
120     }
121 
122     /**
123      * Setter for property {@code specification}.
124      *
125      * @param value the new specification of the dependency.
126      */
127     public void setSpecification( final Specification value )
128     {
129         this.specification = value;
130     }
131 
132     /**
133      * Gets the implementation of the dependency.
134      *
135      * @return the implementation of the dependency or {@code null}.
136      */
137     public Implementation getImplementation()
138     {
139         return this.implementation;
140     }
141 
142     /**
143      * Setter for property {@code implementation}.
144      *
145      * @param value the new implementation of the dependency.
146      */
147     public void setImplementation( final Implementation value )
148     {
149         this.implementation = value;
150     }
151 
152     /**
153      * Gets the properties of the dependency.
154      * <p>The properties of a dependency are a merged set of the properties
155      * declared for the dependency's implementation overwritten by any
156      * properties declared for the dependency.</p>
157      *
158      * @return the properties of the dependency.
159      *
160      * @throws IllegalPropertyTypeException for any property type collisions
161      * during merging.
162      *
163      * @see PropertyOverwriteConstraintException
164      */
165     public Properties getProperties()
166     {
167         final Map declaredProperties = new TreeMap();
168         final Map implementationProperties = new TreeMap();
169         final Map dependencyProperties = new TreeMap();
170 
171         for ( int i = this.getDeclaredProperties().size() - 1; i >= 0; i-- )
172         {
173             final Property declaredProperty =
174                 this.getDeclaredProperties().getProperty( i );
175 
176             declaredProperties.put( declaredProperty.getName(),
177                                     declaredProperty );
178 
179         }
180 
181         if ( this.getImplementation() != null )
182         {
183             for ( int i = this.getImplementation().getProperties().
184                 size() - 1; i >= 0; i-- )
185             {
186                 final Property implementationProperty =
187                     this.getImplementation().getProperties().
188                     getProperty( i );
189 
190                 implementationProperties.put(
191                     implementationProperty.getName(),
192                     implementationProperty );
193 
194             }
195         }
196 
197         dependencyProperties.putAll( implementationProperties );
198 
199         for ( final Iterator it = declaredProperties.entrySet().iterator();
200               it.hasNext(); )
201         {
202             final Map.Entry entry = (Map.Entry) it.next();
203             final String propertyName = (String) entry.getKey();
204             final Property property = (Property) entry.getValue();
205 
206             final Property dependencyProperty =
207                 (Property) dependencyProperties.get( propertyName );
208 
209             if ( dependencyProperty != null )
210             {
211                 if ( !dependencyProperty.getType().equals(
212                     property.getType() ) )
213                 {
214                     throw new IllegalPropertyTypeException(
215                         propertyName, property.getType(),
216                         dependencyProperty.getType() );
217 
218                 }
219                 if ( property.getDocumentation().getValue() == null
220                      && dependencyProperty.getDocumentation().
221                     getValue() != null )
222                 {
223                     property.setDocumentation(
224                         dependencyProperty.getDocumentation() );
225 
226                 }
227 
228                 dependencyProperties.put( propertyName, property );
229             }
230         }
231 
232         final Properties p = new Properties();
233         p.setProperties( (Property[]) dependencyProperties.values().toArray(
234             new Property[ dependencyProperties.size() ] ) );
235 
236         return p;
237     }
238 
239     /**
240      * Setter for property {@code properties}.
241      *
242      * @param value the new properties of the dependency.
243      *
244      * @see PropertyOverwriteConstraintException
245      */
246     public void setProperties( final Properties value )
247     {
248         this.properties = value;
249     }
250 
251     /**
252      * Gets the declared properties of the dependency.
253      *
254      * @return the declared properties of the dependency.
255      */
256     public Properties getDeclaredProperties()
257     {
258         if ( this.properties == null )
259         {
260             this.properties = new Properties();
261         }
262 
263         return this.properties;
264     }
265 
266     /**
267      * Gets the flag indicating if the dependency is bound to a requesting
268      * implementation.
269      *
270      * @return {@code true} if the dependency object is bound to the declaring
271      * implementation; {@code false} if not.
272      */
273     public boolean isBound()
274     {
275         return this.bound;
276     }
277 
278     /**
279      * Setter for property {@code bound}.
280      *
281      * @param value {@code true} if the dependency object should be bound to the
282      * declaring implementation; {@code false} if not.
283      */
284     public void setBound( final boolean value )
285     {
286         this.bound = value;
287     }
288 
289     /**
290      * Creates a string representing the properties of the instance.
291      *
292      * @return a string representing the properties of the instance.
293      */
294     private String internalString()
295     {
296         return new StringBuffer( 500 ).append( '{' ).
297             append( this.internalString( this ) ).
298             append( ", name=" ).append( this.name ).
299             append( ", bound=" ).append( this.bound ).
300             append( ", implementation=" ).
301             append( this.implementation == null
302                     ? "null"
303                     : this.implementation.getIdentifier() + "@"
304                       + this.implementation.getVersion() ).
305             append( ", specification=" ).
306             append( this.specification == null
307                     ? "null"
308                     : this.specification.getIdentifier() + "@"
309                       + this.specification.getVersion() ).
310             append( ", properties=" ).append( this.properties ).
311             append( '}' ).toString();
312 
313     }
314 
315     //--------------------------------------------------------------Dependency--
316     //--Object------------------------------------------------------------------
317 
318     /**
319      * Returns a string representation of the object.
320      *
321      * @return a string representation of the object.
322      */
323     public String toString()
324     {
325         return super.toString() + this.internalString();
326     }
327 
328     /**
329      * Indicates whether some other object is equal to this one by comparing
330      * the values of all properties.
331      *
332      * @param o the reference object with which to compare.
333      *
334      * @return {@code true} if this object is the same as {@code o};
335      * {@code false} otherwise.
336      */
337     public boolean equals( final Object o )
338     {
339         boolean equal = this == o;
340 
341         if ( !equal && o instanceof Dependency )
342         {
343             final Dependency that = (Dependency) o;
344             equal = this.getName().equals( that.getName() )
345                     && ( this.implementation == null
346                          ? that.implementation == null
347                          : this.implementation.equals( that.implementation ) )
348                     && ( this.specification == null
349                          ? that.specification == null
350                          : this.specification.equals( that.specification ) );
351 
352         }
353 
354         return equal;
355     }
356 
357     /**
358      * Returns a hash code value for this object.
359      *
360      * @return a hash code value for this object.
361      */
362     public int hashCode()
363     {
364         return this.getName().hashCode()
365                + ( this.implementation == null
366                    ? 0 : this.implementation.hashCode() )
367                + ( this.specification == null
368                    ? 0 : this.specification.hashCode() );
369 
370     }
371 
372     /**
373      * Creates and returns a copy of this object. This method  performs a
374      * "shallow copy" of this object, not a "deep copy" operation.
375      *
376      * @return a clone of this instance.
377      */
378     public Object clone()
379     {
380         try
381         {
382             return super.clone();
383         }
384         catch ( final CloneNotSupportedException e )
385         {
386             throw new AssertionError( e );
387         }
388     }
389 
390     //------------------------------------------------------------------Object--
391 }