001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.internal.xjc.util;
027:
028: import java.text.ParseException;
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.HashMap;
032: import java.util.List;
033: import java.util.Map;
034:
035: import javax.activation.MimeType;
036: import javax.activation.MimeTypeParseException;
037:
038: /**
039: * @author Kohsuke Kawaguchi
040: */
041: public class MimeTypeRange {
042: public final String majorType;
043: public final String subType;
044:
045: public final Map<String, String> parameters = new HashMap<String, String>();
046:
047: /**
048: * Each media-range MAY be followed by one or more accept-params,
049: * beginning with the "q" parameter for indicating a relative quality
050: * factor. The first "q" parameter (if any) separates the media-range
051: * parameter(s) from the accept-params. Quality factors allow the user
052: * or user agent to indicate the relative degree of preference for that
053: * media-range, using the qvalue scale from 0 to 1 (section 3.9). The
054: * default value is q=1.
055: */
056: public final float q;
057:
058: // accept-extension is not implemented
059:
060: public static List<MimeTypeRange> parseRanges(String s)
061: throws ParseException {
062: StringCutter cutter = new StringCutter(s, true);
063: List<MimeTypeRange> r = new ArrayList<MimeTypeRange>();
064: while (cutter.length() > 0) {
065: r.add(new MimeTypeRange(cutter));
066: }
067: return r;
068: }
069:
070: public MimeTypeRange(String s) throws ParseException {
071: this (new StringCutter(s, true));
072: }
073:
074: /**
075: * Used only to produce the static constants within this class.
076: */
077: private static MimeTypeRange create(String s) {
078: try {
079: return new MimeTypeRange(s);
080: } catch (ParseException e) {
081: // we only use this method for known inputs
082: throw new Error(e);
083: }
084: }
085:
086: /**
087: * @param cutter
088: * A string like "text/html; charset=utf-8;
089: */
090: private MimeTypeRange(StringCutter cutter) throws ParseException {
091: majorType = cutter.until("/");
092: cutter.next("/");
093: subType = cutter.until("[;,]");
094:
095: float q = 1.0f;
096:
097: while (cutter.length() > 0) {
098: String sep = cutter.next("[;,]");
099: if (sep.equals(","))
100: break;
101:
102: String key = cutter.until("=");
103: cutter.next("=");
104: String value;
105: char ch = cutter.peek();
106: if (ch == '"') {
107: // quoted
108: cutter.next("\"");
109: value = cutter.until("\"");
110: cutter.next("\"");
111: } else {
112: value = cutter.until("[;,]");
113: }
114:
115: if (key.equals("q")) {
116: q = Float.parseFloat(value);
117: } else {
118: parameters.put(key, value);
119: }
120: }
121:
122: this .q = q;
123: }
124:
125: public MimeType toMimeType() throws MimeTypeParseException {
126: // due to the additional error check done in the MimeType class,
127: // an error at this point is possible
128: return new MimeType(toString());
129: }
130:
131: public String toString() {
132: StringBuilder sb = new StringBuilder(majorType + '/' + subType);
133: if (q != 1)
134: sb.append("; q=").append(q);
135:
136: for (Map.Entry<String, String> p : parameters.entrySet()) {
137: // I'm too lazy to quote the value
138: sb.append("; ").append(p.getKey()).append('=').append(
139: p.getValue());
140: }
141: return sb.toString();
142: }
143:
144: public static final MimeTypeRange ALL = create("*/*");
145:
146: /**
147: * Creates a range by merging all the given types.
148: */
149: public static MimeTypeRange merge(Collection<MimeTypeRange> types) {
150: if (types.size() == 0)
151: throw new IllegalArgumentException();
152: if (types.size() == 1)
153: return types.iterator().next();
154:
155: String majorType = null;
156: for (MimeTypeRange mt : types) {
157: if (majorType == null)
158: majorType = mt.majorType;
159: if (!majorType.equals(mt.majorType))
160: return ALL;
161: }
162:
163: return create(majorType + "/*");
164: }
165:
166: public static void main(String[] args) throws ParseException {
167: for (MimeTypeRange m : parseRanges(args[0]))
168: System.out.println(m.toString());
169: }
170: }
|