Source for javax.activation.MimetypesFileTypeMap

   1: /* MimeTypesFileTypeMap.java -- A file type map using mime.types.
   2:    Copyright (C) 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.activation;
  39: 
  40: import gnu.java.lang.CPStringBuilder;
  41: 
  42: import java.io.BufferedReader;
  43: import java.io.File;
  44: import java.io.FileReader;
  45: import java.io.InputStream;
  46: import java.io.InputStreamReader;
  47: import java.io.IOException;
  48: import java.io.Reader;
  49: import java.io.StringReader;
  50: import java.net.URL;
  51: import java.util.ArrayList;
  52: import java.util.Enumeration;
  53: import java.util.HashMap;
  54: import java.util.Iterator;
  55: import java.util.List;
  56: import java.util.Map;
  57: 
  58: /**
  59:  * Implementation of FileTypeMap that uses the <tt>mime.types</tt> format.
  60:  * File entries are searched for in the following locations and order:
  61:  * <ol>
  62:  * <li>Programmatically added entries to this instance</li>
  63:  * <li>The file <tt>.mime.types</tt> in the user's home directory</li>
  64:  * <li>The file <i>&lt;java.home&gt;</i><tt>/lib/mime.types</tt></li>
  65:  * <li>The resource <tt>META-INF/mime.types</tt></li>
  66:  * <li>The resource <tt>META-INF/mimetypes.default</tt> in the JAF
  67:  * distribution</li>
  68:  * </ol>
  69:  *
  70:  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  71:  * @version 1.1
  72:  */
  73: public class MimetypesFileTypeMap
  74:   extends FileTypeMap
  75: {
  76: 
  77:   private static final int PROG = 0;
  78:   private static final int HOME = 1;
  79:   private static final int SYS = 2;
  80:   private static final int JAR = 3;
  81:   private static final int DEF = 4;
  82:   private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
  83:   private static boolean debug = false;
  84:   static
  85:   {
  86:     try
  87:       {
  88:         String d = System.getProperty("javax.activation.debug");
  89:         debug = Boolean.valueOf(d).booleanValue();
  90:       }
  91:     catch (SecurityException e)
  92:       {
  93:       }
  94:   }
  95: 
  96:   private Map<String,String>[] mimetypes;
  97: 
  98:   /**
  99:    * Default constructor.
 100:    */
 101:   public MimetypesFileTypeMap()
 102:   {
 103:     init(null);
 104:   }
 105: 
 106:   /**
 107:    * Constructor specifying a filename.
 108:    * @param mimeTypeFileName the name of the file to read mime.types
 109:    * entries from
 110:    */
 111:   public MimetypesFileTypeMap(String mimeTypeFileName)
 112:     throws IOException
 113:   {
 114:     Reader in = null;
 115:     try
 116:       {
 117:         in = new FileReader(mimeTypeFileName);
 118:         init(in);
 119:       }
 120:     finally
 121:       {
 122:         if (in != null)
 123:           {
 124:             in.close();
 125:           }
 126:       }
 127:   }
 128: 
 129:   /**
 130:    * Constructor specifying an input stream.
 131:    * @param is the input stream to read mime.types entries from
 132:    */
 133:   public MimetypesFileTypeMap(InputStream is)
 134:   {
 135:     init(new InputStreamReader(is));
 136:   }
 137: 
 138:   private void init(Reader in)
 139:   {
 140:     mimetypes = new Map[5];
 141:     for (int i = 0; i < mimetypes.length; i++)
 142:       {
 143:         mimetypes[i] = new HashMap<String,String>();
 144:       }
 145:     if (in != null)
 146:       {
 147:         if (debug)
 148:           {
 149:             System.out.println("MimetypesFileTypeMap: load PROG");
 150:           }
 151:         try
 152:           {
 153:             parse(mimetypes[PROG], in);
 154:           }
 155:         catch (IOException e)
 156:           {
 157:           }
 158:       }
 159: 
 160:     if (debug)
 161:       {
 162:         System.out.println("MimetypesFileTypeMap: load HOME");
 163:       }
 164:     try
 165:       {
 166:         String home = System.getProperty("user.home");
 167:         if (home != null)
 168:           {
 169:             parseFile(mimetypes[HOME], new CPStringBuilder(home)
 170:                       .append(File.separatorChar)
 171:                       .append(".mime.types")
 172:                       .toString());
 173:           }
 174:       }
 175:     catch (SecurityException e)
 176:       {
 177:       }
 178: 
 179:     if (debug)
 180:       {
 181:         System.out.println("MimetypesFileTypeMap: load SYS");
 182:       }
 183:     try
 184:       {
 185:         parseFile(mimetypes[SYS],
 186:                   new CPStringBuilder(System.getProperty("java.home"))
 187:                   .append(File.separatorChar)
 188:                   .append("lib")
 189:                   .append(File.separatorChar)
 190:                   .append("mime.types")
 191:                   .toString());
 192:       }
 193:     catch (SecurityException e)
 194:       {
 195:       }
 196:     if (debug)
 197:       {
 198:         System.out.println("MimetypesFileTypeMap: load JAR");
 199:       }
 200:     List<URL> systemResources = getSystemResources("META-INF/mime.types");
 201:     int len = systemResources.size();
 202:     if (len > 0)
 203:       {
 204:         for (int i = 0; i < len ; i++)
 205:           {
 206:             Reader urlIn = null;
 207:             URL url = (URL)systemResources.get(i);
 208:             try
 209:               {
 210:                 urlIn = new InputStreamReader(url.openStream());
 211:                 parse(mimetypes[JAR], urlIn);
 212:               }
 213:             catch (IOException e)
 214:               {
 215:               }
 216:             finally
 217:               {
 218:                 if (urlIn != null)
 219:                   {
 220:                     try
 221:                       {
 222:                         urlIn.close();
 223:                       }
 224:                     catch (IOException e)
 225:                       {
 226:                       }
 227:                   }
 228:               }
 229:           }
 230:       }
 231:     else
 232:       {
 233:         parseResource(mimetypes[JAR], "/META-INF/mime.types");
 234:       }
 235: 
 236:     if (debug)
 237:       {
 238:         System.out.println("MimetypesFileTypeMap: load DEF");
 239:       }
 240:     parseResource(mimetypes[DEF], "/META-INF/mimetypes.default");
 241:   }
 242: 
 243:   /**
 244:    * Adds entries prorammatically to the registry.
 245:    * @param mime_types a mime.types formatted entries string
 246:    */
 247:   public synchronized void addMimeTypes(String mime_types)
 248:   {
 249:     if (debug)
 250:       {
 251:         System.out.println("MimetypesFileTypeMap: add to PROG");
 252:       }
 253:     try
 254:       {
 255:         parse(mimetypes[PROG], new StringReader(mime_types));
 256:       }
 257:     catch (IOException e)
 258:       {
 259:       }
 260:   }
 261: 
 262:   /**
 263:    * Returns the MIME content type of the file.
 264:    * This calls <code>getContentType(f.getName())</code>.
 265:    * @param f the file
 266:    */
 267:   public String getContentType(File f)
 268:   {
 269:     return getContentType(f.getName());
 270:   }
 271: 
 272:   /**
 273:    * Returns the MIME type based on the given filename.
 274:    * If no entry is found, returns "application/octet-stream".
 275:    * @param filename the filename
 276:    */
 277:   public synchronized String getContentType(String filename)
 278:   {
 279:     int di = filename.lastIndexOf('.');
 280:     if (di < 0)
 281:       {
 282:         return DEFAULT_MIME_TYPE;
 283:       }
 284:     String tail = filename.substring(di + 1);
 285:     if (tail.length() < 1)
 286:       {
 287:         return DEFAULT_MIME_TYPE;
 288:       }
 289:     for (int i = 0; i < mimetypes.length; i++)
 290:       {
 291:         String mimeType = (String)mimetypes[i].get(tail);
 292:         if (mimeType != null)
 293:           {
 294:             return mimeType;
 295:           }
 296:       }
 297:     return DEFAULT_MIME_TYPE;
 298:   }
 299: 
 300:   private void parseFile(Map<String,String> mimetypes, String filename)
 301:   {
 302:     Reader in = null;
 303:     try
 304:       {
 305:         in = new FileReader(filename);
 306:         parse(mimetypes, in);
 307:       }
 308:     catch (IOException e)
 309:       {
 310:       }
 311:     finally
 312:       {
 313:         if (in != null)
 314:           {
 315:             try
 316:               {
 317:                 in.close();
 318:               }
 319:             catch (IOException e)
 320:               {
 321:               }
 322:           }
 323:       }
 324:   }
 325: 
 326:   private void parseResource(Map<String,String> mimetypes, String name)
 327:   {
 328:     Reader in = null;
 329:     try
 330:       {
 331:         InputStream is = getClass().getResourceAsStream(name);
 332:         if (is != null)
 333:           {
 334:             in = new InputStreamReader(is);
 335:             parse(mimetypes, in);
 336:           }
 337:       }
 338:     catch (IOException e)
 339:       {
 340:       }
 341:     finally
 342:       {
 343:         if (in != null)
 344:           {
 345:             try
 346:               {
 347:                 in.close();
 348:               }
 349:             catch (IOException e)
 350:               {
 351:               }
 352:           }
 353:       }
 354:   }
 355: 
 356:   private void parse(Map<String,String> mimetypes, Reader in)
 357:     throws IOException
 358:   {
 359:     BufferedReader br = new BufferedReader(in);
 360:     CPStringBuilder buf = null;
 361:     for (String line = br.readLine(); line != null; line = br.readLine())
 362:       {
 363:         line = line.trim();
 364:         int len = line.length();
 365:         if (len == 0 || line.charAt(0) == '#')
 366:           {
 367:             continue; // Empty line / comment
 368:           }
 369:         if (line.charAt(len - 1) == '\\')
 370:           {
 371:             if (buf == null)
 372:               {
 373:                 buf = new CPStringBuilder();
 374:               }
 375:             buf.append(line.substring(0, len - 1));
 376:           }
 377:         else if (buf != null)
 378:           {
 379:             buf.append(line);
 380:             parseEntry(mimetypes, buf.toString());
 381:             buf = null;
 382:           }
 383:         else
 384:           {
 385:             parseEntry(mimetypes, line);
 386:           }
 387:       }
 388:   }
 389: 
 390:   private void parseEntry(Map<String,String> mimetypes,
 391:                           String line)
 392:   {
 393:     // Tokenize
 394:     String mimeType = null;
 395:     char[] chars = line.toCharArray();
 396:     int len = chars.length;
 397:     CPStringBuilder buffer = new CPStringBuilder();
 398:     for (int i = 0; i < len; i++)
 399:       {
 400:         char c = chars[i];
 401:         if (Character.isWhitespace(c))
 402:           {
 403:             if (mimeType == null)
 404:               {
 405:                 mimeType = buffer.toString();
 406:               }
 407:             else if (buffer.length() > 0)
 408:               {
 409:                 mimetypes.put(buffer.toString(), mimeType);
 410:               }
 411:             buffer.setLength(0);
 412:           }
 413:         else
 414:           buffer.append(c);
 415:       }
 416:     if (buffer.length() > 0)
 417:       {
 418:         mimetypes.put(buffer.toString(), mimeType);
 419:       }
 420:   }
 421: 
 422:   // -- Utility methods --
 423: 
 424:   private List<URL> getSystemResources(String name)
 425:   {
 426:     List<URL> acc = new ArrayList<URL>();
 427:     try
 428:       {
 429:         for (Enumeration<URL> i = ClassLoader.getSystemResources(name);
 430:              i.hasMoreElements(); )
 431:           acc.add(i.nextElement());
 432:       }
 433:     catch (IOException e)
 434:       {
 435:       }
 436:     return acc;
 437:   }
 438: 
 439: }