aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package javax.activation; aoqi@0: aoqi@0: import java.io.*; aoqi@0: import java.net.*; aoqi@0: import java.util.*; aoqi@0: import com.sun.activation.registries.MimeTypeFile; aoqi@0: import com.sun.activation.registries.LogSupport; aoqi@0: aoqi@0: /** aoqi@0: * This class extends FileTypeMap and provides data typing of files aoqi@0: * via their file extension. It uses the .mime.types format.

aoqi@0: * aoqi@0: * MIME types file search order:

aoqi@0: * The MimetypesFileTypeMap looks in various places in the user's aoqi@0: * system for MIME types file entries. When requests are made aoqi@0: * to search for MIME types in the MimetypesFileTypeMap, it searches aoqi@0: * MIME types files in the following order: aoqi@0: *

aoqi@0: *

    aoqi@0: *
  1. Programmatically added entries to the MimetypesFileTypeMap instance. aoqi@0: *
  2. The file .mime.types in the user's home directory. aoqi@0: *
  3. The file <java.home>/lib/mime.types. aoqi@0: *
  4. The file or resources named META-INF/mime.types. aoqi@0: *
  5. The file or resource named META-INF/mimetypes.default aoqi@0: * (usually found only in the activation.jar file). aoqi@0: *
aoqi@0: *

aoqi@0: * MIME types file format:

aoqi@0: * aoqi@0: * aoqi@0: * # comments begin with a '#'
aoqi@0: * # the format is <mime type> <space separated file extensions>
aoqi@0: * # for example:
aoqi@0: * text/plain txt text TXT
aoqi@0: * # this would map file.txt, file.text, and file.TXT to
aoqi@0: * # the mime type "text/plain"
aoqi@0: *
aoqi@0: * aoqi@0: * @author Bart Calder aoqi@0: * @author Bill Shannon aoqi@0: * aoqi@0: * @since 1.6 aoqi@0: */ aoqi@0: public class MimetypesFileTypeMap extends FileTypeMap { aoqi@0: /* aoqi@0: * We manage a collection of databases, searched in order. aoqi@0: */ aoqi@0: private MimeTypeFile[] DB; aoqi@0: private static final int PROG = 0; // programmatically added entries aoqi@0: aoqi@0: private static String defaultType = "application/octet-stream"; aoqi@0: aoqi@0: /** aoqi@0: * The default constructor. aoqi@0: */ aoqi@0: public MimetypesFileTypeMap() { aoqi@0: Vector dbv = new Vector(5); // usually 5 or less databases aoqi@0: MimeTypeFile mf = null; aoqi@0: dbv.addElement(null); // place holder for PROG entry aoqi@0: aoqi@0: LogSupport.log("MimetypesFileTypeMap: load HOME"); aoqi@0: try { aoqi@0: String user_home = System.getProperty("user.home"); aoqi@0: aoqi@0: if (user_home != null) { aoqi@0: String path = user_home + File.separator + ".mime.types"; aoqi@0: mf = loadFile(path); aoqi@0: if (mf != null) aoqi@0: dbv.addElement(mf); aoqi@0: } aoqi@0: } catch (SecurityException ex) {} aoqi@0: aoqi@0: LogSupport.log("MimetypesFileTypeMap: load SYS"); aoqi@0: try { aoqi@0: // check system's home aoqi@0: String system_mimetypes = System.getProperty("java.home") + aoqi@0: File.separator + "lib" + File.separator + "mime.types"; aoqi@0: mf = loadFile(system_mimetypes); aoqi@0: if (mf != null) aoqi@0: dbv.addElement(mf); aoqi@0: } catch (SecurityException ex) {} aoqi@0: aoqi@0: LogSupport.log("MimetypesFileTypeMap: load JAR"); aoqi@0: // load from the app's jar file aoqi@0: loadAllResources(dbv, "META-INF/mime.types"); aoqi@0: aoqi@0: LogSupport.log("MimetypesFileTypeMap: load DEF"); aoqi@0: mf = loadResource("/META-INF/mimetypes.default"); aoqi@0: aoqi@0: if (mf != null) aoqi@0: dbv.addElement(mf); aoqi@0: aoqi@0: DB = new MimeTypeFile[dbv.size()]; aoqi@0: dbv.copyInto(DB); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Load from the named resource. aoqi@0: */ aoqi@0: private MimeTypeFile loadResource(String name) { aoqi@0: InputStream clis = null; aoqi@0: try { aoqi@0: clis = SecuritySupport.getResourceAsStream(this.getClass(), name); aoqi@0: if (clis != null) { aoqi@0: MimeTypeFile mf = new MimeTypeFile(clis); aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: successfully " + aoqi@0: "loaded mime types file: " + name); aoqi@0: return mf; aoqi@0: } else { aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: not loading " + aoqi@0: "mime types file: " + name); aoqi@0: } aoqi@0: } catch (IOException e) { aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: can't load " + name, e); aoqi@0: } catch (SecurityException sex) { aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: can't load " + name, sex); aoqi@0: } finally { aoqi@0: try { aoqi@0: if (clis != null) aoqi@0: clis.close(); aoqi@0: } catch (IOException ex) { } // ignore it aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Load all of the named resource. aoqi@0: */ aoqi@0: private void loadAllResources(Vector v, String name) { aoqi@0: boolean anyLoaded = false; aoqi@0: try { aoqi@0: URL[] urls; aoqi@0: ClassLoader cld = null; aoqi@0: // First try the "application's" class loader. aoqi@0: cld = SecuritySupport.getContextClassLoader(); aoqi@0: if (cld == null) aoqi@0: cld = this.getClass().getClassLoader(); aoqi@0: if (cld != null) aoqi@0: urls = SecuritySupport.getResources(cld, name); aoqi@0: else aoqi@0: urls = SecuritySupport.getSystemResources(name); aoqi@0: if (urls != null) { aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: getResources"); aoqi@0: for (int i = 0; i < urls.length; i++) { aoqi@0: URL url = urls[i]; aoqi@0: InputStream clis = null; aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: URL " + url); aoqi@0: try { aoqi@0: clis = SecuritySupport.openStream(url); aoqi@0: if (clis != null) { aoqi@0: v.addElement(new MimeTypeFile(clis)); aoqi@0: anyLoaded = true; aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: " + aoqi@0: "successfully loaded " + aoqi@0: "mime types from URL: " + url); aoqi@0: } else { aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: " + aoqi@0: "not loading " + aoqi@0: "mime types from URL: " + url); aoqi@0: } aoqi@0: } catch (IOException ioex) { aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: can't load " + aoqi@0: url, ioex); aoqi@0: } catch (SecurityException sex) { aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: can't load " + aoqi@0: url, sex); aoqi@0: } finally { aoqi@0: try { aoqi@0: if (clis != null) aoqi@0: clis.close(); aoqi@0: } catch (IOException cex) { } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } catch (Exception ex) { aoqi@0: if (LogSupport.isLoggable()) aoqi@0: LogSupport.log("MimetypesFileTypeMap: can't load " + name, ex); aoqi@0: } aoqi@0: aoqi@0: // if failed to load anything, fall back to old technique, just in case aoqi@0: if (!anyLoaded) { aoqi@0: LogSupport.log("MimetypesFileTypeMap: !anyLoaded"); aoqi@0: MimeTypeFile mf = loadResource("/" + name); aoqi@0: if (mf != null) aoqi@0: v.addElement(mf); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Load the named file. aoqi@0: */ aoqi@0: private MimeTypeFile loadFile(String name) { aoqi@0: MimeTypeFile mtf = null; aoqi@0: aoqi@0: try { aoqi@0: mtf = new MimeTypeFile(name); aoqi@0: } catch (IOException e) { aoqi@0: // e.printStackTrace(); aoqi@0: } aoqi@0: return mtf; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Construct a MimetypesFileTypeMap with programmatic entries aoqi@0: * added from the named file. aoqi@0: * aoqi@0: * @param mimeTypeFileName the file name aoqi@0: */ aoqi@0: public MimetypesFileTypeMap(String mimeTypeFileName) throws IOException { aoqi@0: this(); aoqi@0: DB[PROG] = new MimeTypeFile(mimeTypeFileName); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Construct a MimetypesFileTypeMap with programmatic entries aoqi@0: * added from the InputStream. aoqi@0: * aoqi@0: * @param is the input stream to read from aoqi@0: */ aoqi@0: public MimetypesFileTypeMap(InputStream is) { aoqi@0: this(); aoqi@0: try { aoqi@0: DB[PROG] = new MimeTypeFile(is); aoqi@0: } catch (IOException ex) { aoqi@0: // XXX - really should throw it aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Prepend the MIME type values to the registry. aoqi@0: * aoqi@0: * @param mime_types A .mime.types formatted string of entries. aoqi@0: */ aoqi@0: public synchronized void addMimeTypes(String mime_types) { aoqi@0: // check to see if we have created the registry aoqi@0: if (DB[PROG] == null) aoqi@0: DB[PROG] = new MimeTypeFile(); // make one aoqi@0: aoqi@0: DB[PROG].appendToRegistry(mime_types); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Return the MIME type of the file object. aoqi@0: * The implementation in this class calls aoqi@0: * getContentType(f.getName()). aoqi@0: * aoqi@0: * @param f the file aoqi@0: * @return the file's MIME type aoqi@0: */ aoqi@0: public String getContentType(File f) { aoqi@0: return this.getContentType(f.getName()); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Return the MIME type based on the specified file name. aoqi@0: * The MIME type entries are searched as described above under aoqi@0: * MIME types file search order. aoqi@0: * If no entry is found, the type "application/octet-stream" is returned. aoqi@0: * aoqi@0: * @param filename the file name aoqi@0: * @return the file's MIME type aoqi@0: */ aoqi@0: public synchronized String getContentType(String filename) { aoqi@0: int dot_pos = filename.lastIndexOf("."); // period index aoqi@0: aoqi@0: if (dot_pos < 0) aoqi@0: return defaultType; aoqi@0: aoqi@0: String file_ext = filename.substring(dot_pos + 1); aoqi@0: if (file_ext.length() == 0) aoqi@0: return defaultType; aoqi@0: aoqi@0: for (int i = 0; i < DB.length; i++) { aoqi@0: if (DB[i] == null) aoqi@0: continue; aoqi@0: String result = DB[i].getMIMETypeString(file_ext); aoqi@0: if (result != null) aoqi@0: return result; aoqi@0: } aoqi@0: return defaultType; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * for debugging... aoqi@0: * aoqi@0: public static void main(String[] argv) throws Exception { aoqi@0: MimetypesFileTypeMap map = new MimetypesFileTypeMap(); aoqi@0: System.out.println("File " + argv[0] + " has MIME type " + aoqi@0: map.getContentType(argv[0])); aoqi@0: System.exit(0); aoqi@0: } aoqi@0: */ aoqi@0: }