001    /*
002     * file PropertyNameList.java
003     *
004     * Licensed Materials - Property of IBM
005     * Restricted Materials of IBM
006     *
007     * (c) Copyright IBM Corporation 2004, 2008.  All Rights Reserved. 
008     * Note to U.S. Government Users Restricted Rights:  Use, duplication or  
009     * disclosure restricted by GSA ADP  Schedule Contract with IBM Corp. 
010     */
011    package javax.wvcm;
012    
013    import java.util.Arrays;
014    import java.util.Collections;
015    import java.util.HashSet;
016    import java.util.Set;
017    
018    /**
019     * A list of resource property names.
020     * 
021     * @since 1.0
022     */
023    public final class PropertyNameList implements PropertyRequestItem {
024    
025        /**
026         * The name of a property of a persistent resource. The PropertyName
027         * type parameter specifies the type of the value of the PropertyName
028         */
029        public static class PropertyName<T> implements PropertyRequestItem {
030    
031            private final String _namespace;
032            private final String _name;
033    
034            /**
035             * Create a PropertyName with a null namespace and the given name.
036             * 
037             * @param name the name for this property.  May not be null.
038             */
039            PropertyName(String name) {
040                this(null, name);
041            }
042    
043            /**
044             * Create a PropertyName with the given namespace and name.
045             * 
046             * @param namespace the namespace for this PropertyName.
047             * May be null to indicate a system property, or non-null
048             * to indicate a property in the specified name space.
049             * @param name the name for this property.  May not be null.
050             */
051            public PropertyName(String namespace, String name) {
052                _namespace = namespace;
053                _name = name;
054            }
055    
056            /**
057             * Get the namespace of the property name.
058             * 
059             * @return the namespace.  May be null to indicate a system property,
060             * or non-null to indicate a property in the specified name space.
061             */
062            public String getNamespace() {
063                return _namespace;
064            }
065    
066            /**
067             * Get the property name.
068             * 
069             * @return the name part of the property name */
070            public String getName() {
071                return _name;
072            }
073    
074            /**
075             * Calculate a hash code value for the object.
076             * 
077             * @return the hash code for the object.
078             */
079            @Override
080            public int hashCode() {
081                int result = 17;
082                result = 37*result + ((_namespace == null) ? 0 : _namespace.hashCode());
083                result = 37*result + _name.hashCode();
084                return result;
085            }
086    
087            /**
088             * Indicates whether some other object is "equal to" this one.
089             * 
090             * @param o the object to compare with.
091             * @return true if and only if the specified object is a PropertyName whose
092             * type, namespace value, and name value equals those of this object.
093             */
094            @Override
095            public boolean equals(Object o) {
096                if (o == null || this.getClass() != o.getClass()) {
097                    return false;
098                }
099                PropertyName<?> pn = (PropertyName<?>) o;
100                if (_namespace == null) {
101                    return pn._namespace == null && _name.equals(pn._name);
102                }
103                return _namespace.equals(pn._namespace) && _name.equals(pn._name);
104            }
105    
106            /**
107             * Returns a string representation of the PropertyName for diagnostic 
108             * purposes.  
109             * @see java.lang.Object#toString
110             * 
111             * @return The string representation of this PropertyName in the format
112             * [namespace:]name.
113             */
114            @Override
115            public String toString() {
116                if (_namespace != null)
117                    return _namespace + ":" + _name; //$NON-NLS-1$
118                else
119                    return _name;
120            }
121            
122            /**
123             * Constructs a NestedPropertyName whose root property is this
124             * PropertyName with the property request items supplied as arguments as
125             * its nested property request. This method allows a more succinct
126             * syntax for the declaration of PropertyRequest objects at compile
127             * time. For example,
128             * 
129             * <pre>
130             * final static PropertyRequest WORKSPACE_PROPERTIES = 
131             *     new PropertyRequest(
132             *         Workspace.DISPLAY_NAME,
133             *         Workspace.COMMENT,
134             *         Workspace.ACTIVITY_LIST.nest( 
135             *             Activity.DISPLAY_NAME,
136             *             Activity.ACTIVITY_VERSION_LIST.nest( 
137             *                 Version.DISPLAY_NAME, 
138             *                 Version.COMMENT, 
139             *                 Version.CREATION_DATE)));
140             * </pre>
141             * 
142             * @param pnl An array of PropertyRequestItem objects that specify the
143             *            properties to be requested from the value of the property
144             *            identified by this PropertyName.
145             * @return A NestedPropertyName whose root is this PropertyName and
146             *         whose nested properties are the property request items given
147             *         as arguments.
148             */
149            public NestedPropertyName<T> nest(PropertyRequestItem... pnl)
150            {
151                return new NestedPropertyName<T>(this, pnl);
152            }
153    
154            /**
155             * A convenience method for constructing nested property names from a
156             * NestedPropertyName[] without requiring an explicit cast to
157             * PropertyRequestItem[]
158             * 
159             * @param pnl A NestedPropertyName[] that specifies the nested
160             *            properties of the NestedPropertyName to be constructed
161             * @return A NestedPropertyName whose root is this PropertyName and
162             *         whose nested properties are the elements of the
163             *         NestedPropertyNames[] argument.
164             */
165            public NestedPropertyName<T> nest(NestedPropertyName<?>[] pnl)
166            {
167                return new NestedPropertyName<T>(this, (PropertyRequestItem[])pnl);
168            }
169    
170            /**
171             * A convenience method for constructing nested property names from a
172             * PropertyName[] without requiring an explicit cast to
173             * PropertyRequestItem[]
174             * 
175             * @param pnl A PropertyName[] that specifies the nested properties of
176             *            the NestedPropertyName to be constructed
177             * @return A NestedPropertyName whose root is this PropertyName and
178             *         whose nested properties are the elements of the
179             *         PropertyNames[] argument.
180             */
181            public NestedPropertyName<T> nest(PropertyName<?>[] pnl)
182            {
183                return new NestedPropertyName<T>(this, (PropertyRequestItem[])pnl);
184            }
185        }
186    
187        // An empty immutable PropertyName[]
188        private static final PropertyName<?>[] EMPTY_PNA = new PropertyName[0];
189    
190        // The immutable array of property names for this PropertyNameList.
191        private final PropertyName<?>[] _propertyNames;
192    
193        // The lazy initialized Set for this immutable object.
194        private volatile Set<PropertyName<?>> _asSet = null;
195    
196        /**
197         * Construct a PropertyNameList from an array of property names.
198         * 
199         * @param propertyNames an array of property names, or null.
200         * Passing null is equivalent to passing an empty array.
201         */
202        public PropertyNameList(PropertyName<?>... propertyNames) {
203            _propertyNames = (propertyNames == null || propertyNames.length == 0)
204            ? EMPTY_PNA : propertyNames;
205        }
206    
207        /**
208         * Get an array of property names from a property name list.
209         * 
210         * @return the array of property names maintained by this 
211         * PropertyNameList. Will never be <code>null</code>.
212         */
213        public PropertyName<?>[] getPropertyNames() {
214            return _propertyNames;
215        }
216    
217        /**
218         * Indicates whether some other object is "equal to" this one.
219         * 
220         * @param o the object to compare with.
221         * @return true if and only if the specified object is a PropertyNameList
222         *         whose property names array is equal to the property names array
223         *         of this ignoring order.
224         */
225        @Override
226        public boolean equals(Object o) {
227            if (o == null || this.getClass() != o.getClass()) {
228                return false;
229            }
230            PropertyNameList pnl = (PropertyNameList) o;
231            return getPropertyNamesAsSet().equals(pnl.getPropertyNamesAsSet());
232        }
233    
234    
235        /**
236         * Calculate a hash code for a PropertyNameList.
237         * 
238         * @return a hash code for the list.
239         */
240        @Override
241        public int hashCode() {
242            return getPropertyNamesAsSet().hashCode();
243        }
244    
245        /**
246         * Returns a string representation of this PropertyNameList suitable for
247         * diagnostics.
248         * 
249         * @return The string representation of this PropertyNameList formatted as
250         * "[&LT;first property name&GT;, &LT;second property name&GT;]"
251         */
252        @Override
253        public String toString() {
254    
255            StringBuffer builder = new StringBuffer();
256            builder.append('[');
257    
258            for(PropertyName<?> name: getPropertyNames()) {
259                if (builder.length() > 1)
260                    builder.append(", "); //$NON-NLS-1$
261                
262                builder.append(name.toString());
263            }
264                
265            builder.append(']');
266    
267            return builder.toString();
268        }
269    
270        // the property names maintained by this PropertyNameList as a Set.
271        private Set<PropertyName<?>> getPropertyNamesAsSet() {
272            if (_asSet == null) {
273                if (_propertyNames == EMPTY_PNA)
274                    _asSet = Collections.emptySet();
275                else
276                    _asSet = new HashSet<PropertyName<?>>(Arrays.asList(_propertyNames));
277            }
278            return _asSet;
279        }
280    }