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

ohair@286: * ohair@286: * MIME types file search order:

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

ohair@286: *

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

ohair@286: * MIME types file format:

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