View Javadoc

1   package org.apache.turbine.services.mimetype.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  
24  /***
25   * This class is used to represent parsed MIME types.
26   * The representation is parsed from a string based
27   * representation of the MIME type, as defined in the RFC1345.
28   *
29   * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
30   * @version $Id: MimeType.java 534527 2007-05-02 16:10:59Z tv $
31   */
32  public class MimeType
33          implements Cloneable
34  {
35      /***
36       * A list of well known MIME types.
37       */
38      public static MimeType TEXT_HTML;
39      public static MimeType TEXT_WML;
40      public static MimeType TEXT_HDML;
41      public static MimeType TEXT_CHTML;
42      public static MimeType TEXT_PLAIN;
43      public static MimeType MULTIPART;
44      public static MimeType MULTIPART_FORM_DATA;
45      public static MimeType APPLICATION_POSTSCRIPT;
46      public static MimeType APPLICATION_OCTET_STREAM;
47      public static MimeType APPLICATION_X_JAVA_AGENT;
48      public static MimeType APPLICATION_X_WWW_FORM_URLENCODED;
49      public static MimeType MESSAGE_HTTP;
50      public static MimeType TEXT_CSS;
51      public static MimeType TEXT;
52      public static MimeType IMAGE_GIF;
53      public static MimeType IMAGE_JPEG;
54      public static MimeType IMAGE_WBMP;
55  
56      static
57      {
58          TEXT_HTML =
59                  new MimeType("text/html");
60          TEXT_WML =
61                  new MimeType("text/vnd.wap.wml");
62          TEXT_HDML =
63                  new MimeType("text/x-hdml");
64          TEXT_CHTML =
65                  new MimeType("text/x-chtml");
66          TEXT_PLAIN =
67                  new MimeType("text/plain");
68          MULTIPART =
69                  new MimeType("multipart/*");
70          MULTIPART_FORM_DATA =
71                  new MimeType("multipart/form-data");
72          APPLICATION_POSTSCRIPT =
73                  new MimeType("application/postscript");
74          APPLICATION_OCTET_STREAM =
75                  new MimeType("application/octet-stream");
76          APPLICATION_X_JAVA_AGENT =
77                  new MimeType("application/x-java-agent");
78          APPLICATION_X_WWW_FORM_URLENCODED =
79                  new MimeType("application/x-www-form-urlencoded");
80          MESSAGE_HTTP =
81                  new MimeType("message/http");
82          TEXT_CSS =
83                  new MimeType("text/css");
84          TEXT =
85                  new MimeType("text/*");
86          IMAGE_GIF =
87                  new MimeType("image/gif");
88          IMAGE_JPEG =
89                  new MimeType("image/jpeg");
90          IMAGE_WBMP =
91                  new MimeType("image/vnd.wap.wbmp");
92      }
93  
94      /***
95       * MIME type matching constants.
96       */
97      public static final int NO_MATCH = 0;
98      public static final int MATCH_TYPE = 1;
99      public static final int MATCH_SUBTYPE = 2;
100     public static final int MATCH_SPECIFIC_SUBTYPE = 3;
101 
102     /***
103      * A string representation of the main type.
104      */
105     private String mimeType;
106 
107     /***
108      * A string representation of the subtype.
109      */
110     private String mimeSubtype;
111 
112     /***
113      * Parameter names.
114      */
115     private String parameterNames[];
116 
117     /***
118      * Parameter values.
119      */
120     private String parameterValues[];
121 
122     /***
123      * A string representation of the MIME type.
124      */
125     private String mimeTypeString;
126 
127     /***
128      * Constructs a new MIME type by parsing a specification string.
129      *
130      * @param spec a string representing a MIME type.
131      */
132     public MimeType(String spec)
133     {
134         this(spec, true);
135     }
136 
137     /***
138      * Constructs a new MIME type by parsing a specification string.
139      *
140      * @param spec a string representing a MIME type.
141      * @param parsep a flag for parsing parameters also.
142      * @throws IllegalArgumentException for parsing errors.
143      */
144     public MimeType(String spec,
145                     boolean parsep)
146     {
147         int start = 0;
148         char look = '\0';
149         int length = spec.length();
150 
151         // Skip leading/trailing blanks.
152         while ((start < length) &&
153                 Character.isWhitespace(spec.charAt(start)))
154         {
155             start++;
156         }
157         while ((length > start) &&
158                 Character.isWhitespace(spec.charAt(length - 1)))
159         {
160             length--;
161         }
162 
163         // Get the type.
164         StringBuffer sb = new StringBuffer();
165         while ((start < length) &&
166                 ((look = spec.charAt(start)) != '/'))
167         {
168             sb.append((char) look);
169             start++;
170         }
171         if (look != '/')
172         {
173             throw new IllegalArgumentException(
174                     "Syntax error in MIME type " + spec);
175         }
176         mimeType = sb.toString();
177 
178         // Get the subtype.
179         start++;
180         sb.setLength(0);
181         while ((start < length) &&
182                 ((look = spec.charAt(start)) != ';') &&
183                 !Character.isWhitespace(look))
184         {
185             sb.append((char) look);
186             start++;
187         }
188         mimeSubtype = sb.toString();
189 
190         if (parsep)
191         {
192             // Get parameters, if any.
193             while ((start < length) &&
194                     Character.isWhitespace(spec.charAt(start)))
195             {
196                 start++;
197             }
198             if (start < length)
199             {
200                 if (spec.charAt(start) != ';')
201                 {
202                     throw new IllegalArgumentException(
203                             "Syntax error in MIME type parameters " + spec);
204                 }
205                 start++;
206                 ArrayList na = new ArrayList(4);
207                 ArrayList va = new ArrayList(4);
208                 while (start < length)
209                 {
210                     // Get the name.
211                     while ((start < length) &&
212                             Character.isWhitespace(spec.charAt(start)))
213                     {
214                         start++;
215                     }
216                     sb.setLength(0);
217                     while ((start < length) &&
218                             ((look = spec.charAt(start)) != '=') &&
219                             !Character.isWhitespace(look))
220                     {
221                         sb.append(Character.toLowerCase((char) look));
222                         start++;
223                     }
224                     String name = sb.toString();
225 
226                     // Get the value.
227                     while ((start < length) &&
228                             Character.isWhitespace(spec.charAt(start)))
229                     {
230                         start++;
231                     }
232                     if (spec.charAt(start) != '=')
233                     {
234                         throw new IllegalArgumentException(
235                                 "Syntax error in MIME type parameters " + spec);
236                     }
237                     start++;
238                     while ((start < length) &&
239                             Character.isWhitespace(spec.charAt(start)))
240                     {
241                         start++;
242                     }
243                     sb.setLength(0);
244                     char delim = ';';
245                     if (spec.charAt(start) == '"')
246                     {
247                         start++;
248                         delim = '"';
249                     }
250                     while ((start < length) &&
251                             ((look = spec.charAt(start)) != delim) &&
252                             ((delim == '"') ||
253                             !Character.isWhitespace(look)))
254                     {
255                         sb.append((char) look);
256                         start++;
257                     }
258                     while ((start < length) &&
259                             (spec.charAt(start) != ';'))
260                     {
261                         start++;
262                     }
263                     start++;
264                     String value = sb.toString();
265 
266                     na.add(name);
267                     va.add(value);
268                 }
269                 parameterNames = (String[]) na.toArray(new String[na.size()]);
270                 parameterValues = (String[]) va.toArray(new String[va.size()]);
271             }
272         }
273     }
274 
275     /***
276      * Contructs a new MIME type from specified types.
277      *
278      * @param type a type.
279      * @param subtype a subtype.
280      * @throws NullPointerException if type or subtype are nulls.
281      */
282     public MimeType(String type,
283                     String subtype)
284     {
285         this(type, subtype, null, null);
286     }
287 
288     /***
289      * Contructs a new MIME type from specified parameters.
290      *
291      * @param type a type.
292      * @param subtype a subtype.
293      * @param names parameters names.
294      * @param values parameter values.
295      * @throws NullPointerException if type or subtype are nulls.
296      */
297     public MimeType(String type,
298                     String subtype,
299                     String names[],
300                     String values[])
301     {
302         if ((type == null) ||
303                 (subtype == null))
304         {
305             throw new NullPointerException("MIME type or subtype missing");
306         }
307         mimeType = type.trim();
308         mimeSubtype = subtype.trim();
309         parameterNames = names;
310         parameterValues = values;
311     }
312 
313     /***
314      * Compares the specified MIME type to this one
315      * and returns a matching level:
316      * NO_MATCH=types do not match,
317      * MATCH_TYPE=types match,
318      * MATCH_SPECIFIC_TYPE=types match exactly,
319      * MATCH_SUBTYPE=types match, subtypes match too,
320      * MATCH_SPECIFIC_SUBTYPE=types match, subtypes match exactly.
321      *
322      * @param other the MimeType to compare.
323      * @return the matching level.
324      */
325     public int match(MimeType other)
326     {
327         if (mimeType.equals("*") ||
328                 other.mimeType.equals("*"))
329         {
330             return MATCH_TYPE;
331         }
332         else if (!mimeType.equalsIgnoreCase(other.mimeType))
333         {
334             return NO_MATCH;
335         }
336         else if (mimeSubtype.equals("*") ||
337                 other.mimeSubtype.equals("*"))
338         {
339             return MATCH_SUBTYPE;
340         }
341         else if (!mimeSubtype.equalsIgnoreCase(other.mimeSubtype))
342         {
343             return NO_MATCH;
344         }
345         else
346         {
347             return MATCH_SPECIFIC_SUBTYPE;
348         }
349     }
350 
351     /***
352      * Gets the main type of the MIME type.
353      *
354      * @return the main type as a string.
355      */
356     public String getType()
357     {
358         return mimeType;
359     }
360 
361     /***
362      * Gets the subtype of the MIME type.
363      *
364      * @return the subtype as a string.
365      */
366     public String getSubtype()
367     {
368         return mimeSubtype;
369     }
370 
371     /***
372      * Gets the type and the subtype of the MIME type.
373      *
374      * @return the types as a string.
375      */
376     public String getTypes()
377     {
378         return mimeType + '/' + mimeSubtype;
379     }
380 
381     /***
382      * Checks whether the MIME type contains the specified parameter.
383      *
384      * @param param the name opf the parameter.
385      * @return true if the parameter found, otherwise false.
386      */
387     public boolean hasParameter(String param)
388     {
389         String[] na = parameterNames;
390         if (na != null)
391         {
392             for (int i = 0; i < na.length; i++)
393             {
394                 if (na[i].equalsIgnoreCase(param))
395                 {
396                     return true;
397                 }
398             }
399         }
400         return false;
401     }
402 
403     /***
404      * Gets the value of a MIME type parameter.
405      * The first parameter with the specifed name will be returned.
406      *
407      * @param param the name of the parameter.
408      * @return the value of the parameter, or null.
409      */
410     public String getParameter(String param)
411     {
412         String[] na = parameterNames;
413         if (na != null)
414         {
415             String[] va = parameterValues;
416             for (int i = 0; i < na.length; i++)
417             {
418                 if (na[i].equalsIgnoreCase(param))
419                 {
420                     return va[i];
421                 }
422             }
423         }
424         return null;
425     }
426 
427     /***
428      * Sets the value of a MIME type parameter replacing the old one.
429      *
430      * @param param the name of the parameter.
431      * @param value the value of the parameter.
432      */
433     public synchronized void setParameter(String param,
434                                           String value)
435     {
436         if (parameterNames != null)
437         {
438             for (int i = 0; i < parameterNames.length; i++)
439             {
440                 if (parameterNames[i].equalsIgnoreCase(param))
441                 {
442                     parameterValues[i] = value;
443                     mimeTypeString = null;
444                     return;
445                 }
446             }
447         }
448         addParameter(param, value);
449     }
450 
451     /***
452      * Adds a parameter to the MIME type.
453      *
454      * @param param the name of the parameter.
455      * @param value the value of the parameter.
456      */
457     public void addParameter(String param,
458                              String value)
459     {
460         addParameters(new String[]{param}, new String[]{value});
461     }
462 
463     /***
464      * Adds parameters to the MIME type.
465      *
466      * @param params an array of parameter names.
467      * @param values an array of parameter values.
468      * @throw IllegalArgumentException for incorrect parameters.
469      */
470     public synchronized void addParameters(String[] params,
471                                            String[] values)
472     {
473         if ((params == null) ||
474                 (values == null) ||
475                 (params.length != values.length))
476             throw new IllegalArgumentException("Incorrect MIME type parameters");
477 
478         if (parameterNames != null)
479         {
480             String[] na = new String[parameterNames.length + params.length];
481             String[] va = new String[parameterValues.length + values.length];
482             System.arraycopy(parameterNames, 0, na, 0, parameterNames.length);
483             System.arraycopy(params, 0, na, parameterNames.length, params.length);
484             System.arraycopy(parameterValues, 0, va, 0, parameterValues.length);
485             System.arraycopy(values, 0, va, parameterValues.length, values.length);
486             parameterNames = na;
487             parameterValues = va;
488         }
489         else
490         {
491             parameterNames = params;
492             parameterValues = values;
493         }
494         mimeTypeString = null;
495     }
496 
497     /***
498      * Converts the MIME type into a string.
499      *
500      * @return the string representation of the MIME type.
501      */
502     public String toString()
503     {
504         if (mimeTypeString == null)
505         {
506             StringBuffer sb = new StringBuffer(mimeType);
507             sb.append('/');
508             sb.append(mimeSubtype);
509             String[] na = parameterNames;
510             if (na != null)
511             {
512                 String[] va = parameterValues;
513                 for (int i = 0; i < va.length; i++)
514                 {
515                     sb.append(';');
516                     sb.append(na[i]);
517                     if (va[i] != null)
518                     {
519                         sb.append('=');
520                         sb.append(va[i]);
521                     }
522                 }
523             }
524             mimeTypeString = sb.toString();
525         }
526         return mimeTypeString;
527     }
528 }