001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package com.noelios.restlet.util;
020:
021: import java.io.IOException;
022: import java.text.DecimalFormat;
023: import java.text.NumberFormat;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Locale;
027:
028: import org.restlet.data.CharacterSet;
029: import org.restlet.data.ClientInfo;
030: import org.restlet.data.Encoding;
031: import org.restlet.data.Language;
032: import org.restlet.data.MediaType;
033: import org.restlet.data.Parameter;
034: import org.restlet.data.Preference;
035:
036: /**
037: * Preference manipulation utilities.<br/>
038: *
039: * @author Jerome Louvel (contact@noelios.com)
040: */
041: public class PreferenceUtils {
042: /**
043: * Formats a list of preferences with a comma separator.
044: *
045: * @param prefs
046: * The list of preferences.
047: * @return The formatted list of preferences.
048: * @throws IOException
049: */
050: public static String format(List<? extends Preference<?>> prefs)
051: throws IOException {
052: StringBuilder sb = new StringBuilder();
053:
054: Preference<?> pref;
055: for (int i = 0; i < prefs.size(); i++) {
056: if (i > 0)
057: sb.append(", ");
058: pref = prefs.get(i);
059: format(pref, sb);
060: }
061:
062: return sb.toString();
063: }
064:
065: /**
066: * Formats a preference.
067: *
068: * @param pref
069: * The preference to format.
070: * @param destination
071: * The appendable destination.
072: * @throws IOException
073: */
074: @SuppressWarnings("unchecked")
075: public static void format(Preference pref, Appendable destination)
076: throws IOException {
077: destination.append(pref.getMetadata().getName());
078:
079: if (pref.getMetadata() instanceof MediaType) {
080: MediaType mediaType = (MediaType) pref.getMetadata();
081:
082: if (mediaType.getParameters() != null) {
083: Parameter param;
084: for (Iterator<Parameter> iter = mediaType
085: .getParameters().iterator(); iter.hasNext();) {
086: param = iter.next();
087:
088: if (param.getName() != null) {
089: destination.append(';').append(param.getName());
090:
091: if ((param.getValue() != null)
092: && (param.getValue().length() > 0)) {
093: destination.append('=').append(
094: param.getValue());
095: }
096: }
097: }
098: }
099: }
100:
101: if (pref.getQuality() < 1F) {
102: destination.append(";q=");
103: formatQuality(pref.getQuality(), destination);
104: }
105:
106: if (pref.getParameters() != null) {
107: Parameter param;
108: for (Iterator<Parameter> iter = pref.getParameters()
109: .iterator(); iter.hasNext();) {
110: param = iter.next();
111:
112: if (param.getName() != null) {
113: destination.append(';').append(param.getName());
114:
115: if ((param.getValue() != null)
116: && (param.getValue().length() > 0)) {
117: destination.append('=')
118: .append(param.getValue());
119: }
120: }
121: }
122: }
123: }
124:
125: /**
126: * Formats a quality value.<br/> If the quality is invalid, an
127: * IllegalArgumentException is thrown.
128: *
129: * @param quality
130: * The quality value as a float.
131: * @param destination
132: * The appendable destination;
133: * @throws IOException
134: */
135: public static void formatQuality(float quality,
136: Appendable destination) throws IOException {
137: if (!isQuality(quality)) {
138: throw new IllegalArgumentException(
139: "Invalid quality value detected. Value must be between 0 and 1.");
140: } else {
141: NumberFormat formatter = DecimalFormat
142: .getNumberInstance(Locale.US);
143: formatter.setMaximumFractionDigits(2);
144: destination.append(formatter.format(quality));
145: }
146: }
147:
148: /**
149: * Parses a quality value.<br/> If the quality is invalid, an
150: * IllegalArgumentException is thrown.
151: *
152: * @param quality
153: * The quality value as a string.
154: * @return The parsed quality value as a float.
155: */
156: public static float parseQuality(String quality) {
157: try {
158: float result = Float.valueOf(quality);
159:
160: if (isQuality(result)) {
161: return result;
162: } else {
163: throw new IllegalArgumentException(
164: "Invalid quality value detected. Value must be between 0 and 1.");
165: }
166: } catch (NumberFormatException nfe) {
167: throw new IllegalArgumentException(
168: "Invalid quality value detected. Value must be between 0 and 1.");
169: }
170: }
171:
172: /**
173: * Indicates if the quality value is valid.
174: *
175: * @param quality
176: * The quality value.
177: * @return True if the quality value is valid.
178: */
179: public static boolean isQuality(float quality) {
180: return (quality >= 0F) && (quality <= 1F);
181: }
182:
183: /**
184: * Parses character set preferences from a header.
185: *
186: * @param acceptCharsetHeader
187: * The header to parse.
188: * @param client
189: * The client preferences to update.
190: */
191: @SuppressWarnings("unchecked")
192: public static void parseCharacterSets(String acceptCharsetHeader,
193: ClientInfo client) {
194: if (acceptCharsetHeader != null) {
195: // Implementation according to
196: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2
197: if (acceptCharsetHeader.length() == 0) {
198: client.getAcceptedCharacterSets().add(
199: new Preference<CharacterSet>(
200: CharacterSet.ISO_8859_1));
201: } else {
202: try {
203: PreferenceReader pr = new PreferenceReader(
204: PreferenceReader.TYPE_CHARACTER_SET,
205: acceptCharsetHeader);
206: Preference currentPref = pr.readPreference();
207: while (currentPref != null) {
208: client.getAcceptedCharacterSets().add(
209: currentPref);
210: currentPref = pr.readPreference();
211: }
212: } catch (IOException ioe) {
213: throw new IllegalArgumentException(
214: "An exception occurred during character set preferences parsing. Header: "
215: + acceptCharsetHeader
216: + ". Ignoring header.");
217: }
218: }
219: } else {
220: client.getAcceptedCharacterSets().add(
221: new Preference(CharacterSet.ALL));
222: }
223: }
224:
225: /**
226: * Parses encoding preferences from a header.
227: *
228: * @param acceptEncodingHeader
229: * The header to parse.
230: * @param preference
231: * The client preferences to update.
232: */
233: @SuppressWarnings("unchecked")
234: public static void parseEncodings(String acceptEncodingHeader,
235: ClientInfo preference) {
236: if (acceptEncodingHeader != null) {
237: try {
238: PreferenceReader pr = new PreferenceReader(
239: PreferenceReader.TYPE_ENCODING,
240: acceptEncodingHeader);
241: Preference currentPref = pr.readPreference();
242: while (currentPref != null) {
243: preference.getAcceptedEncodings().add(currentPref);
244: currentPref = pr.readPreference();
245: }
246: } catch (IOException ioe) {
247: throw new IllegalArgumentException(
248: "An exception occurred during encoding preferences parsing. Header: "
249: + acceptEncodingHeader
250: + ". Ignoring header.");
251: }
252: } else {
253: preference.getAcceptedEncodings().add(
254: new Preference(Encoding.IDENTITY));
255: }
256: }
257:
258: /**
259: * Parses language preferences from a header.
260: *
261: * @param acceptLanguageHeader
262: * The header to parse.
263: * @param preference
264: * The client preferences to update.
265: */
266: @SuppressWarnings("unchecked")
267: public static void parseLanguages(String acceptLanguageHeader,
268: ClientInfo preference) {
269: if (acceptLanguageHeader != null) {
270: try {
271: PreferenceReader pr = new PreferenceReader(
272: PreferenceReader.TYPE_LANGUAGE,
273: acceptLanguageHeader);
274: Preference currentPref = pr.readPreference();
275: while (currentPref != null) {
276: preference.getAcceptedLanguages().add(currentPref);
277: currentPref = pr.readPreference();
278: }
279: } catch (IOException ioe) {
280: throw new IllegalArgumentException(
281: "An exception occurred during language preferences parsing. Header: "
282: + acceptLanguageHeader
283: + ". Ignoring header.");
284: }
285: } else {
286: preference.getAcceptedLanguages().add(
287: new Preference(Language.ALL));
288: }
289: }
290:
291: /**
292: * Parses media type preferences from a header.
293: *
294: * @param acceptMediaTypeHeader
295: * The header to parse.
296: * @param preference
297: * The client preferences to update.
298: */
299: @SuppressWarnings("unchecked")
300: public static void parseMediaTypes(String acceptMediaTypeHeader,
301: ClientInfo preference) {
302: if (acceptMediaTypeHeader != null) {
303: try {
304: PreferenceReader pr = new PreferenceReader(
305: PreferenceReader.TYPE_MEDIA_TYPE,
306: acceptMediaTypeHeader);
307: Preference currentPref = pr.readPreference();
308: while (currentPref != null) {
309: preference.getAcceptedMediaTypes().add(currentPref);
310: currentPref = pr.readPreference();
311: }
312: } catch (IOException ioe) {
313: throw new IllegalArgumentException(
314: "An exception occurred during media type preferences parsing. Header: "
315: + acceptMediaTypeHeader
316: + ". Ignoring header.");
317: }
318: } else {
319: preference.getAcceptedMediaTypes().add(
320: new Preference(MediaType.ALL));
321: }
322: }
323:
324: }
|