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 }