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 }