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.Arrays; 025import java.util.Collection; 026import java.util.HashMap; 027import java.util.Map; 028 029/** 030 * Collection of implementations. 031 * 032 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 033 * @version $JDTAUS: Implementations.java 8743 2012-10-07 03:06:20Z schulte $ 034 */ 035public class Implementations extends ModelObject 036 implements Cloneable, Serializable 037{ 038 //--Constants--------------------------------------------------------------- 039 040 /** Serial version UID for backwards compatibility with 1.0.x classes. */ 041 private static final long serialVersionUID = 5611937453792676565L; 042 043 //---------------------------------------------------------------Constants-- 044 //--Implementations--------------------------------------------------------- 045 046 /** 047 * The implementations held by the instance. 048 * @serial 049 */ 050 private Implementation[] implementations; 051 052 /** 053 * Maps implementation identifiers to implementations. 054 * @serial 055 */ 056 private final Map identifiers = new HashMap(); 057 058 /** 059 * Hash code. 060 * @serial 061 */ 062 private int hashCode; 063 064 /** Creates a new {@code Implementations} instance. */ 065 public Implementations() 066 { 067 super(); 068 } 069 070 /** 071 * Gets all implementations of the collection. 072 * 073 * @return all implementations of the collection. 074 */ 075 public Implementation[] getImplementations() 076 { 077 if ( this.implementations == null ) 078 { 079 this.implementations = new Implementation[ 0 ]; 080 this.hashCode = 0; 081 } 082 083 return this.implementations; 084 } 085 086 /** 087 * Setter for property {@code implementations}. 088 * 089 * @param value the new implementations for the instance. 090 * 091 * @throws DuplicateImplementationException if {@code value} contains 092 * duplicate implementations. 093 */ 094 public void setImplementations( final Implementation[] value ) 095 { 096 this.identifiers.clear(); 097 this.hashCode = 0; 098 this.implementations = null; 099 100 if ( value != null ) 101 { 102 for ( int i = value.length - 1; i >= 0; i-- ) 103 { 104 this.hashCode += value[i].hashCode(); 105 106 if ( this.identifiers.put( value[i].getIdentifier(), 107 value[i] ) != null ) 108 { 109 this.identifiers.clear(); 110 this.hashCode = 0; 111 112 throw new DuplicateImplementationException( 113 value[i].getIdentifier() ); 114 115 } 116 } 117 118 this.implementations = value; 119 } 120 } 121 122 /** 123 * Gets an implementation for an identifier. 124 * 125 * @param identifier the identifier of the implementation to return. 126 * 127 * @return a reference to the implementation identified by 128 * {@code identifier}. 129 * 130 * @throws NullPointerException if {@code identifier} is {@code null}. 131 * @throws MissingImplementationException if no implementation matching 132 * {@code identifier} exists in the collection. 133 */ 134 public Implementation getImplementation( final String identifier ) 135 { 136 if ( identifier == null ) 137 { 138 throw new NullPointerException( "identifier" ); 139 } 140 141 final Implementation ret = 142 (Implementation) this.identifiers.get( identifier ); 143 144 if ( ret == null ) 145 { 146 throw new MissingImplementationException( identifier ); 147 } 148 149 return ret; 150 } 151 152 /** 153 * Gets an implementation for an index. 154 * 155 * @param index the index of the implementation to return. 156 * 157 * @return a reference to the implementation at {@code index}. 158 * 159 * @throws IndexOutOfBoundsException if {@code index} is negativ, 160 * greater than or equal to {@code size()}. 161 */ 162 public final Implementation getImplementation( final int index ) 163 { 164 if ( index < 0 || index >= this.size() ) 165 { 166 throw new ArrayIndexOutOfBoundsException( index ); 167 } 168 169 return this.getImplementations()[index]; 170 } 171 172 /** 173 * Gets the number of implementations held by the instance. 174 * 175 * @return the number of implementations held by the instance. 176 */ 177 public final int size() 178 { 179 return this.getImplementations().length; 180 } 181 182 /** 183 * Creates a string representing the properties of the instance. 184 * 185 * @return a string representing the properties of the instance. 186 */ 187 private String internalString() 188 { 189 final StringBuffer buf = new StringBuffer( 200 ).append( '{' ); 190 buf.append( this.internalString( this ) ); 191 192 final Implementation[] impls = this.getImplementations(); 193 for ( int i = impls.length - 1; i >= 0; i-- ) 194 { 195 buf.append( ", [" ).append( i ).append( "]=" ). 196 append( impls[i] ); 197 198 } 199 200 buf.append( '}' ); 201 return buf.toString(); 202 } 203 204 //---------------------------------------------------------Implementations-- 205 //--Object------------------------------------------------------------------ 206 207 /** 208 * Indicates whether some other object is equal to this one by comparing 209 * the values of all properties. 210 * 211 * @param o the reference object with which to compare. 212 * 213 * @return {@code true} if this object is the same as {@code o}; 214 * {@code false} otherwise. 215 */ 216 public boolean equals( final Object o ) 217 { 218 boolean equal = this == o; 219 220 if ( !equal && o instanceof Implementations ) 221 { 222 final Implementations that = (Implementations) o; 223 final Collection these = Arrays.asList( this.getImplementations() ); 224 final Collection those = Arrays.asList( that.getImplementations() ); 225 226 equal = this.size() == that.size() && these.containsAll( those ); 227 } 228 229 return equal; 230 } 231 232 /** 233 * Returns a hash code value for this object. 234 * 235 * @return a hash code value for this object. 236 */ 237 public int hashCode() 238 { 239 return this.hashCode; 240 } 241 242 /** 243 * Returns a string representation of the object. 244 * 245 * @return a string representation of the object. 246 */ 247 public String toString() 248 { 249 return super.toString() + this.internalString(); 250 } 251 252 /** 253 * Creates and returns a deep copy of this object. 254 * 255 * @return a clone of this instance. 256 */ 257 public Object clone() 258 { 259 try 260 { 261 final Implementations ret = (Implementations) super.clone(); 262 final Implementation[] impls = this.getImplementations(); 263 final Implementation[] cloned = new Implementation[ impls.length ]; 264 265 for ( int i = impls.length - 1; i >= 0; i-- ) 266 { 267 cloned[i] = (Implementation) impls[i].clone(); 268 } 269 270 ret.setImplementations( cloned ); 271 return ret; 272 } 273 catch ( final CloneNotSupportedException e ) 274 { 275 throw new AssertionError( e ); 276 } 277 } 278 279 //------------------------------------------------------------------Object-- 280}