001    /*
002     * Copyright 2004 Stephen J. McConnell.
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.metro.info;
020    
021    import java.io.Serializable;
022    
023    import java.util.Properties;
024    
025    /**
026     * This is the Abstract class for all feature feature descriptors.
027     *
028     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
029     * @version 1.0.4
030     */
031    public abstract class Descriptor
032        implements Serializable
033    {
034       /**
035        * Serial version identifier.
036        */
037        static final long serialVersionUID = 1L;
038    
039        private static final String[] EMPTY_SET = new String[0];
040    
041        /**
042         * The arbitrary set of attributes associated with Component.
043         */
044        private final Properties m_attributes;
045    
046        /**
047         * Creation of an abstract descriptor.
048         * @param attributes the set of attributes to assign to the descriptor
049         */
050        protected Descriptor( final Properties attributes )
051        {
052            m_attributes = attributes;
053        }
054    
055        /**
056         * Return the attribute for specified key.
057         *
058         * @param key the attribute key to resolve
059         * @return the attribute for specified key.
060         */
061        public String getAttribute( final String key )
062        {
063            if ( null == m_attributes )
064            {
065                return null;
066            }
067            else
068            {
069                return m_attributes.getProperty( key );
070            }
071        }
072    
073        /**
074         * Return the attribute for specified key.
075         *
076         * @param key the attribute key to resolve
077         * @param defaultValue the default value to use if the value is not defined
078         * @return the attribute for specified key.
079         */
080        public String getAttribute( final String key, final String defaultValue )
081        {
082            if ( null == m_attributes )
083            {
084                return defaultValue;
085            }
086            else
087            {
088                return m_attributes.getProperty( key, defaultValue );
089            }
090        }
091    
092        /**
093         * Returns the set of attribute names available under this descriptor.
094         *
095         * @return an array of the properties names held by the descriptor.
096         */
097        public String[] getAttributeNames()
098        {
099            if ( null == m_attributes )
100            {
101                return EMPTY_SET;
102            }
103            else
104            {
105                return (String[]) m_attributes.keySet().toArray( EMPTY_SET );
106            }
107        }
108    
109        /**
110         * Compare this object with another for equality.
111         * @param other the object to compare this object with
112         * @return TRUE if the supplied object equivalent
113         */
114        public boolean equals( Object other )
115        {
116            if ( other instanceof Descriptor )
117            {
118                Descriptor descriptor = (Descriptor) other;
119                return equals( m_attributes, descriptor.m_attributes );
120            }
121            else
122            {
123                return false;
124            }
125        }
126    
127       /**
128        * Return the hashcode for the object.
129        * @return the hashcode value
130        */
131        public int hashCode()
132        {
133            if( m_attributes != null )
134            {
135                return m_attributes.hashCode();
136            }
137            else
138            {
139                return 132482349;
140            }
141        }
142    
143        /**
144         * Returns the property set.
145         *
146         * @return the property set.
147         */
148        public Properties getProperties()
149        {
150            return m_attributes;
151        }
152        
153       /**
154        * Utility to hash an array.
155        * @param array the array
156        * @return the hash value
157        */
158        int hashArray( Object[] array )
159        {
160            if( null == array )
161            {
162                return 0;
163            }
164            int hash = 0;
165            for( int i=0; i<array.length; i++ )
166            {
167                Object object = array[i];
168                hash ^= hashValue( object );
169            }
170            return hash;
171        }
172        
173       /**
174        * Utility to hash an object.
175        * @param value the object
176        * @return the hash value
177        */
178        int hashValue( Object value )
179        {
180            if( null == value )
181            {
182                return 0;
183            }
184            else if( value instanceof Object[] )
185            {
186                return hashArray( (Object[]) value );
187            }
188            else
189            {
190                return value.hashCode();
191            }
192        }
193        
194       /**
195        * Utility to compare two object for equality.
196        * @param a the first object
197        * @param b the second object
198        * @return true if the objects are equal
199        */
200        boolean equals( Object a, Object b )
201        {
202            if( null == a )
203            {
204                return ( null == b );
205            }
206            else
207            {
208                return a.equals( b );
209            }
210        }    
211    }