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