View Javadoc

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.Arrays;
25  import java.util.Collection;
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  /**
30   * Collection of specifications.
31   *
32   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
33   * @version $JDTAUS: Specifications.java 8743 2012-10-07 03:06:20Z schulte $
34   */
35  public class Specifications extends ModelObject
36      implements Cloneable, Serializable
37  {
38      //--Constants---------------------------------------------------------------
39  
40      /** Serial version UID for backwards compatibility with 1.0.x classes. */
41      private static final long serialVersionUID = 9166476268404849994L;
42  
43      //---------------------------------------------------------------Constants--
44      //--Specifications----------------------------------------------------------
45  
46      /**
47       * The specifications of the collection.
48       * @serial
49       */
50      private Specification[] specifications;
51  
52      /**
53       * Maps specification identifiers to specifications.
54       * @serial
55       */
56      private final Map identifiers = new HashMap();
57  
58      /**
59       * Hash code.
60       * @serial
61       */
62      private int hashCode;
63  
64      /** Creates a new {@code Specifications} instance. */
65      public Specifications()
66      {
67          super();
68      }
69  
70      /**
71       * Gets the specifications of the collection.
72       *
73       * @return the specifications of the collection.
74       */
75      public Specification[] getSpecifications()
76      {
77          if ( this.specifications == null )
78          {
79              this.specifications = new Specification[ 0 ];
80              this.hashCode = 0;
81          }
82  
83          return this.specifications;
84      }
85  
86      /**
87       * Setter for property {@code specifications}.
88       *
89       * @param value the new specifications for the instance.
90       *
91       * @throws DuplicateSpecificationException if {@code value} contains
92       * duplicate specifications.
93       */
94      public void setSpecifications( final Specification[] value )
95      {
96          this.identifiers.clear();
97          this.hashCode = 0;
98          this.specifications = null;
99  
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 }