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 }