001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006     * See the AUTHORS.txt file in the distribution for a full listing of 
007     * individual contributors. 
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.graph.property;
025    
026    import java.util.Iterator;
027    import net.jcip.annotations.Immutable;
028    import org.jboss.dna.common.text.TextEncoder;
029    
030    /**
031     * Representation of a property consisting of a name and value(s). Note that this property is immutable, meaning that the property
032     * values may not be changed through this interface.
033     * <p>
034     * This class is designed to be used with the {@link ValueFactories} interface and the particular {@link ValueFactory} that
035     * corresponds to the type of value you'd like to use. The <code>ValueFactory</code> will then return the values (if no type
036     * conversion is required) or will convert the values using the appropriate conversion algorithm.
037     * </p>
038     * <p>
039     * The following example shows how to obtain the {@link String} representations of the {@link #getValues() property values}:
040     * 
041     * <pre>
042     *   ValueFactories valueFactories = ...
043     *   Property property = ...
044     *   Iterator&lt;String&gt; iter = valueFactories.getStringFactory().create(property.getValues());
045     *   while ( iter.hasNext() ) {
046     *       System.out.println(iter.next());
047     *   }
048     * </pre>
049     * 
050     * Meanwhile, the {@link ValueFactories#getLongFactory() long value factory} converts the values to <code>long</code>, the
051     * {@link ValueFactories#getDateFactory() date value factory} converts the values to {@link DateTime} instances, and so on.
052     * </p>
053     * <p>
054     * This technique is much better and far safer than casting the values. It is possible that some Property instances contain
055     * heterogeneous values, so casting may not always work. Also, this technique guarantees that the values are properly converted if
056     * the type is not what you expected.
057     * </p>
058     * 
059     * @author Randall Hauch
060     */
061    @Immutable
062    public interface Property extends Iterable<Object>, Comparable<Property> {
063    
064        /**
065         * Get the name of the property.
066         * 
067         * @return the property name; never null
068         */
069        Name getName();
070    
071        /**
072         * Get the number of actual values in this property. If the property allows {@link #isMultiple() multiple values}, then this
073         * method may return a value greater than 1. If the property only allows a {@link #isSingle() single value}, then this method
074         * will return either 0 or 1. This method may return 0 regardless of whether the property allows a {@link #isSingle() single
075         * value}, or {@link #isMultiple() multiple values}.
076         * 
077         * @return the number of actual values in this property; always non-negative
078         */
079        int size();
080    
081        /**
082         * Determine whether the property currently has multiple values.
083         * 
084         * @return true if the property has multiple values, or false otherwise.
085         * @see #isSingle()
086         * @see #isEmpty()
087         */
088        boolean isMultiple();
089    
090        /**
091         * Determine whether the property currently has a single value.
092         * 
093         * @return true if the property has a single value, or false otherwise.
094         * @see #isMultiple()
095         * @see #isEmpty()
096         */
097        boolean isSingle();
098    
099        /**
100         * Determine whether this property has no actual values. This method may return <code>true</code> regardless of whether the
101         * property allows a {@link #isSingle() single value}, or {@link #isMultiple() multiple values}.
102         * <p>
103         * This method is a convenience method that is equivalent to <code>size() == 0</code>.
104         * </p>
105         * 
106         * @return true if this property has no values, or false otherwise
107         * @see #isMultiple()
108         * @see #isSingle()
109         */
110        boolean isEmpty();
111    
112        /**
113         * Obtain the property's first value in its natural form. This is equivalent to calling
114         * <code>isEmpty() ? null : iterator().next()</code>
115         * 
116         * @return the first value, or null if the property is {@link #isEmpty() empty}
117         * @see Iterable#iterator()
118         * @see #getValues()
119         * @see #getValuesAsArray()
120         * @see #isEmpty()
121         */
122        Object getFirstValue();
123    
124        /**
125         * Obtain the property's values in their natural form. This is equivalent to calling {@link Iterable#iterator() iterator()}.
126         * <p>
127         * A valid iterator is returned if the property has {@link #isSingle() single valued} or {@link #isMultiple() multi-valued}.
128         * </p>
129         * <p>
130         * The resulting iterator is immutable, and all property values are immutable.
131         * </p>
132         * 
133         * @return an iterator over the values; never null
134         * @see #getFirstValue()
135         * @see Iterable#iterator()
136         * @see #getValuesAsArray()
137         * @see ValueFactory#create(Iterator)
138         */
139        Iterator<?> getValues();
140    
141        /**
142         * Obtain the property's values as an array of objects in their natural form.
143         * <p>
144         * A valid array is return if the property has {@link #isSingle() single valued} or {@link #isMultiple() multi-valued}, or a
145         * null value is returned if the property is {@link #isEmpty() empty}.
146         * </p>
147         * <p>
148         * The resulting array is a copy, guaranteeing immutability for the property.
149         * </p>
150         * 
151         * @return the array of values
152         * @see #getFirstValue()
153         * @see Iterable#iterator()
154         * @see #getValues()
155         * @see ValueFactory#create(Object[])
156         */
157        Object[] getValuesAsArray();
158    
159        /**
160         * Get the string form of the property, using the default encoder.
161         * 
162         * @return the encoded string
163         * @see #getString(TextEncoder)
164         */
165        public String getString();
166    
167        /**
168         * Get the encoded string form of the property, using the supplied encoder to encode characters in the property's name and
169         * values.
170         * 
171         * @param encoder the encoder to use, or null if the default encoder should be used
172         * @return the encoded string
173         * @see #getString()
174         */
175        public String getString( TextEncoder encoder );
176    
177        /**
178         * Get the string form of the property, using the supplied namespace registry to convert the property's name and values.
179         * 
180         * @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
181         *        {@link Name#getNamespaceUri() namespace URIs} in the property {@link #getName() name}
182         * @return the string
183         * @throws IllegalArgumentException if the namespace registry is null
184         * @see #getString(NamespaceRegistry,TextEncoder)
185         * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
186         */
187        public String getString( NamespaceRegistry namespaceRegistry );
188    
189        /**
190         * Get the encoded string form of the property, using the supplied namespace registry to convert the property's namespace URIs
191         * to prefixes and the supplied encoder to encode characters in the property's name and values.
192         * 
193         * @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
194         *        {@link Name#getNamespaceUri() namespace URIs} in the property {@link #getName() name}, or null if the namespace
195         *        registry should not be used
196         * @param encoder the encoder to use for encoding the name and values, or null if the default encoder should be used
197         * @return the encoded string
198         * @see #getString(NamespaceRegistry)
199         * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
200         */
201        public String getString( NamespaceRegistry namespaceRegistry,
202                                 TextEncoder encoder );
203    
204        /**
205         * Get the encoded string form of the property, using the supplied namespace registry to convert the property's namespace URIs
206         * to prefixes and the supplied encoder to encode characters in the property's name and values.
207         * 
208         * @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
209         *        {@link Name#getNamespaceUri() namespace URIs} in the property {@link #getName() name}, or null if the namespace
210         *        registry should not be used
211         * @param encoder the encoder to use for encoding the name and values, or null if the default encoder should be used
212         * @param delimiterEncoder the encoder to use for encoding delimiters used in paths and names, or null if the standard
213         *        delimiters should be used
214         * @return the encoded string
215         * @see #getString(NamespaceRegistry)
216         * @see #getString(NamespaceRegistry, TextEncoder)
217         */
218        public String getString( NamespaceRegistry namespaceRegistry,
219                                 TextEncoder encoder,
220                                 TextEncoder delimiterEncoder );
221    }