001    /*
002     * The contents of this file are subject to the terms
003     * of the Common Development and Distribution License
004     * (the "License").  You may not use this file except
005     * in compliance with the License.
006     * 
007     * You can obtain a copy of the license at
008     * http://www.opensource.org/licenses/cddl1.php
009     * See the License for the specific language governing
010     * permissions and limitations under the License.
011     */
012    
013    /*
014     * Variant.java
015     *
016     * Created on September 27, 2007, 3:12 PM
017     *
018     */
019    
020    package javax.ws.rs.core;
021    
022    import java.io.StringWriter;
023    import java.util.List;
024    import java.util.Locale;
025    import javax.ws.rs.ext.RuntimeDelegate;
026    
027    /**
028     * Abstraction for a resource representation variant. 
029     */
030    public class Variant {
031        
032        private Locale language;
033        private MediaType mediaType;
034        private String encoding;
035        
036        /**
037         * Create a new instance of Variant
038         * @param mediaType the media type of the variant - may be null
039         * @param language the language of the variant - may be null
040         * @param encoding the content encoding of the variant - may be null
041         * @throws java.lang.IllegalArgumentException if all three parameters are
042         * null
043         */
044        public Variant(MediaType mediaType, Locale language, String encoding) {
045            if (mediaType==null && language==null && encoding==null)
046                throw new IllegalArgumentException("mediaType, language, encoding all null");
047            this.encoding = encoding;
048            this.language = language;
049            this.mediaType = mediaType;
050        }
051        
052        /**
053         * Get the language of the variant
054         * @return the language or null if none set
055         */
056        public Locale getLanguage() {
057            return language;
058        }
059    
060        /**
061         * Get the media type of the variant
062         * @return the media type or null if none set
063         */
064        public MediaType getMediaType() {
065            return mediaType;
066        }
067    
068        /**
069         * Get the encoding of the variant
070         * @return the encoding or null if none set
071         */
072        public String getEncoding() {
073            return encoding;
074        }
075        
076        /**
077         * Create a {@link VariantListBuilder} initialized with a set of supported
078         * media types.
079         * @param mediaTypes the available mediaTypes. If specific charsets
080         * are supported they should be included as parameters of the respective
081         * media type.
082         * @return the initailized builder
083         * @throws java.lang.IllegalArgumentException if mediaTypes is null or
084         * contains no elements.
085         */
086        public static VariantListBuilder mediaTypes(MediaType... mediaTypes) {
087            VariantListBuilder b = VariantListBuilder.newInstance();
088            b.mediaTypes(mediaTypes);
089            return b;
090        }
091        
092        /**
093         * Create a {@link VariantListBuilder} initialized with a set of supported
094         * languages.
095         * @param languages the available languages.
096         * @return the initailized builder
097         * @throws java.lang.IllegalArgumentException if languages is null or
098         * contains no elements.
099         */
100        public static VariantListBuilder languages(Locale... languages) {
101            VariantListBuilder b = VariantListBuilder.newInstance();
102            b.languages(languages);
103            return b;
104        }
105        
106        /**
107         * Create a {@link VariantListBuilder} initialized with a set of supported
108         * encodings.
109         * @param encodings the available encodings.
110         * @return the initailized builder
111         * @throws java.lang.IllegalArgumentException if encodings is null or
112         * contains no elements.
113         */
114        public static VariantListBuilder encodings(String... encodings) {
115            VariantListBuilder b = VariantListBuilder.newInstance();
116            b.encodings(encodings);
117            return b;
118        }
119    
120        /**
121         * Generate hash code from variant properties.
122         * @return the hash code
123         */
124        @Override
125        public int hashCode() {
126            int hash = 7;
127            hash = 29 * hash + (this.language != null ? this.language.hashCode() : 0);
128            hash = 29 * hash + (this.mediaType != null ? this.mediaType.hashCode() : 0);
129            hash = 29 * hash + (this.encoding != null ? this.encoding.hashCode() : 0);
130            return hash;
131        }
132    
133        /**
134         * Compares obj to this variant to see if they are the same 
135         * considering all property values.
136         * @param obj the object to compare to
137         * @return true if the two variants are the same, false otherwise.
138         */
139        @Override
140        public boolean equals(Object obj) {
141            if (obj == null) {
142                return false;
143            }
144            if (getClass() != obj.getClass()) {
145                return false;
146            }
147            final Variant other = (Variant) obj;
148            if (this.language != other.language && (this.language == null || !this.language.equals(other.language))) {
149                return false;
150            }
151            if (this.mediaType != other.mediaType && (this.mediaType == null || !this.mediaType.equals(other.mediaType))) {
152                return false;
153            }
154            if (this.encoding != other.encoding && (this.encoding == null || !this.encoding.equals(other.encoding))) {
155                return false;
156            }
157            return true;
158        }
159    
160        @Override
161        public String toString() {
162            StringWriter w = new StringWriter();
163            w.append("Variant[mediaType=");
164            w.append(mediaType==null ? "null" : mediaType.toString());
165            w.append(", language=");
166            w.append(language==null ? "null" : language.toString());
167            w.append(", encoding=");
168            w.append(encoding==null ? "null" : encoding);
169            w.append("]");
170            return w.toString();
171        }
172        
173        /**
174         * A builder for a list of representation variants. 
175         */
176        public static abstract class VariantListBuilder {
177            
178            /**
179             * Protected constructor, use the static <code>newInstance</code>
180             * method to obtain an instance.
181             */
182            protected VariantListBuilder() {}
183            
184            /**
185             * Create a new builder instance.
186             * @return a new Builder
187             */
188            public static VariantListBuilder newInstance() {
189                VariantListBuilder b = RuntimeDelegate.getInstance().createVariantListBuilder();
190                return b;
191            }
192                    
193            /**
194             * Build a list of representation variants from the current state of
195             * the builder. After this method is called the builder is reset to
196             * an empty state.
197             * @return a list of representation variants
198             */
199            public abstract List<Variant> build();
200            
201            /**
202             * Add the current combination of metadata to the list of supported variants,
203             * after this method is called the current combination of metadata is emptied.
204             * If more than one value is supplied for one or more of the variant properties
205             * then a variant will be generated for each possible combination. E.g.
206             * in the following <code>list</code> would have four members:
207             * <p><pre>List<Variant> list = VariantListBuilder.newInstance().languages("en","fr")
208             *   .encodings("zip", "identity").add().build()</pre>
209             * 
210             * @return the updated builder
211             * @throws java.lang.IllegalStateException if there is not at least one
212             * mediaType, language or encoding set for the current variant.
213             */
214            public abstract VariantListBuilder add();
215            
216            /**
217             * Set the language[s] for this variant.
218             * @param languages the available languages
219             * @return the updated builder
220             */
221            public abstract VariantListBuilder languages(Locale... languages);
222            
223            /**
224             * Set the encoding[s] for this variant.
225             * @param encodings the available encodings
226             * @return the updated builder
227             */
228            public abstract VariantListBuilder encodings(String... encodings);
229            
230            /**
231             * Set the media type[s] for this variant.
232             * @param mediaTypes the available mediaTypes. If specific charsets
233             * are supported they should be included as parameters of the respective
234             * media type.
235             * @return the updated builder
236             */
237            public abstract VariantListBuilder mediaTypes(MediaType... mediaTypes);
238        }
239    }