001    /*
002     *  jDTAUS Core API
003     *  Copyright (c) 2005 Christian Schulte
004     *
005     *  Christian Schulte, Haldener Strasse 72, 58095 Hagen, Germany
006     *  <schulte2005@users.sourceforge.net> (+49 2331 3543887)
007     *
008     *  This library is free software; you can redistribute it and/or
009     *  modify it under the terms of the GNU Lesser General Public
010     *  License as published by the Free Software Foundation; either
011     *  version 2.1 of the License, or any later version.
012     *
013     *  This library is distributed in the hope that it will be useful,
014     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
015     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
016     *  Lesser General Public License for more details.
017     *
018     *  You should have received a copy of the GNU Lesser General Public
019     *  License along with this library; if not, write to the Free Software
020     *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
021     *
022     */
023    package org.jdtaus.core.container;
024    
025    import java.io.Serializable;
026    import java.util.Arrays;
027    import java.util.Collection;
028    import java.util.HashMap;
029    import java.util.Map;
030    
031    /**
032     * Collection of dependencies.
033     *
034     * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
035     * @version $Id: Dependencies.java 8044 2009-07-02 01:29:05Z schulte2005 $
036     */
037    public class Dependencies extends ModelObject implements Cloneable, Serializable
038    {
039        //--Constants---------------------------------------------------------------
040    
041        /** Serial version UID for backwards compatibility with 1.0.x classes. */
042        private static final long serialVersionUID = 4207539567564921413L;
043    
044        //---------------------------------------------------------------Constants--
045        //--Dependencies------------------------------------------------------------
046    
047        /**
048         * The dependencies held by the instance.
049         * @serial
050         */
051        private Dependency[] dependencies;
052    
053        /**
054         * Maps dependency names to dependencies.
055         * @serial
056         */
057        private final Map names = new HashMap();
058    
059        /**
060         * Hash code.
061         * @serial
062         */
063        private int hashCode;
064    
065        /**
066         * Gets all dependencies of the collection.
067         *
068         * @return all dependencies of the collection.
069         */
070        public Dependency[] getDependencies()
071        {
072            if ( this.dependencies == null )
073            {
074                this.dependencies = new Dependency[ 0 ];
075                this.hashCode = 0;
076            }
077    
078            return this.dependencies;
079        }
080    
081        /**
082         * Setter for property {@code dependencies}.
083         *
084         * @param value the new dependencies for the collection.
085         *
086         * @throws DuplicateDependencyException if {@code value} contains duplicate
087         * dependencies.
088         */
089        public void setDependencies( final Dependency[] value )
090        {
091            this.names.clear();
092            this.hashCode = 0;
093            this.dependencies = null;
094    
095            if ( value != null )
096            {
097                for ( int i = value.length - 1; i >= 0; i-- )
098                {
099                    this.hashCode += value[i].hashCode();
100                    if ( this.names.put( value[i].getName(), value[i] ) != null )
101                    {
102                        this.names.clear();
103                        this.hashCode = 0;
104    
105                        throw new DuplicateDependencyException( value[i].getName() );
106                    }
107    
108                }
109    
110                this.dependencies = value;
111            }
112        }
113    
114        /**
115         * Gets a dependency for a name.
116         *
117         * @param name the name of the dependency to return.
118         *
119         * @return a reference to the dependency named {@code name}.
120         *
121         * @throws NullPointerException if {@code name} is {@code null}.
122         * @throws MissingDependencyException if no dependency matching {@code name}
123         * exists in the collection.
124         */
125        public Dependency getDependency( final String name )
126        {
127            if ( name == null )
128            {
129                throw new NullPointerException( "name" );
130            }
131    
132            final Dependency ret = (Dependency) this.names.get( name );
133    
134            if ( ret == null )
135            {
136                throw new MissingDependencyException( name );
137            }
138    
139            return ret;
140        }
141    
142        /**
143         * Gets a dependency for an index.
144         *
145         * @param index the index of the dependency to return.
146         *
147         * @return a reference to the dependency at {@code index}.
148         *
149         * @throws IndexOutOfBoundsException if {@code index} is negativ,
150         * greater than or equal to {@code size()}.
151         */
152        public final Dependency getDependency( final int index )
153        {
154            if ( index < 0 || index >= this.size() )
155            {
156                throw new ArrayIndexOutOfBoundsException( index );
157            }
158    
159            return this.getDependencies()[index];
160        }
161    
162        /**
163         * Gets the number of dependencies held by the instance.
164         *
165         * @return the number of dependencies held by the instance.
166         */
167        public final int size()
168        {
169            return this.getDependencies().length;
170        }
171    
172        /**
173         * Creates a string representing the properties of the instance.
174         *
175         * @return a string representing the properties of the instance.
176         */
177        private String internalString()
178        {
179            final StringBuffer buf = new StringBuffer( 200 ).append( '{' );
180            buf.append( this.internalString( this ) );
181    
182            final Dependency[] deps = this.getDependencies();
183            for ( int i = deps.length - 1; i >= 0; i-- )
184            {
185                buf.append( ", [" ).append( i ).append( "]=" ).
186                    append( deps[i] );
187    
188            }
189            buf.append( '}' );
190            return buf.toString();
191        }
192    
193        //------------------------------------------------------------Dependencies--
194        //--Object------------------------------------------------------------------
195    
196        /**
197         * Indicates whether some other object is equal to this one by comparing
198         * the values of all properties.
199         *
200         * @param o the reference object with which to compare.
201         *
202         * @return {@code true} if this object is the same as {@code o};
203         * {@code false} otherwise.
204         */
205        public boolean equals( final Object o )
206        {
207            boolean equal = this == o;
208    
209            if ( !equal && o instanceof Dependencies )
210            {
211                final Dependencies that = (Dependencies) o;
212                final Collection these = Arrays.asList( this.getDependencies() );
213                final Collection those = Arrays.asList( that.getDependencies() );
214    
215                equal = this.size() == that.size() && these.containsAll( those );
216            }
217    
218            return equal;
219        }
220    
221        /**
222         * Returns a hash code value for this object.
223         *
224         * @return a hash code value for this object.
225         */
226        public int hashCode()
227        {
228            return this.hashCode;
229        }
230    
231        /**
232         * Returns a string representation of the object.
233         *
234         * @return a string representation of the object.
235         */
236        public String toString()
237        {
238            return super.toString() + this.internalString();
239        }
240    
241        /**
242         * Creates and returns a deep copy of this object.
243         *
244         * @return a clone of this instance.
245         */
246        public Object clone()
247        {
248            try
249            {
250                final Dependencies ret = (Dependencies) super.clone();
251                final Dependency[] deps = this.getDependencies();
252                final Dependency[] cloned = new Dependency[ deps.length ];
253                for ( int i = deps.length - 1; i >= 0; i-- )
254                {
255                    cloned[i] = (Dependency) deps[i].clone();
256                }
257    
258                ret.setDependencies( cloned );
259                return ret;
260            }
261            catch ( CloneNotSupportedException e )
262            {
263                throw new AssertionError( e );
264            }
265        }
266    
267        //------------------------------------------------------------------Object--
268    }