001/* 002 * jDTAUS Core API 003 * Copyright (C) 2005 Christian Schulte 004 * <cs@schulte.it> 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License, or any later version. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 019 * 020 */ 021package org.jdtaus.core.container; 022 023import java.io.Serializable; 024import java.util.Iterator; 025import java.util.Map; 026import java.util.TreeMap; 027 028/** 029 * Dependency meta-data. 030 * <p>A dependency consists of a name uniquely identifying the dependency in a 031 * set of dependencies and pairs a specification with corresponding 032 * implementations from a set of available implementations. Properties set with 033 * a dependency overwrite properties of the dependency's specification. The 034 * {@code bound} flag indicates if the instance of the dependency is bound to 035 * the declaring implementation.</p> 036 * 037 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 038 * @version $JDTAUS: Dependency.java 8743 2012-10-07 03:06:20Z schulte $ 039 */ 040public class Dependency extends ModelObject implements Cloneable, Serializable 041{ 042 //--Constants--------------------------------------------------------------- 043 044 /** Serial version UID for backwards compatibility with 1.0.x classes. */ 045 private static final long serialVersionUID = -8556956703006143247L; 046 047 //---------------------------------------------------------------Constants-- 048 //--Dependency-------------------------------------------------------------- 049 050 /** 051 * The name of the dependency. 052 * @serial 053 */ 054 private String name; 055 056 /** 057 * The specification of the dependency. 058 * @serial 059 */ 060 private Specification specification; 061 062 /** 063 * The implementation of the dependency. 064 * @serial 065 */ 066 private Implementation implementation; 067 068 /** 069 * The properties of the dependency. 070 * @serial 071 */ 072 private Properties properties; 073 074 /** 075 * Flag indicating if the dependency is bound to the requesting 076 * implementation. 077 * @serial 078 */ 079 private boolean bound; 080 081 /** Creates a new {@code Dependency} instance. */ 082 public Dependency() 083 { 084 super(); 085 } 086 087 /** 088 * Gets the name of the dependency. 089 * 090 * @return the name of the dependency. 091 */ 092 public String getName() 093 { 094 if ( this.name == null ) 095 { 096 this.name = ""; 097 } 098 099 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}