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