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: *
.mime.types
in the user's home directory.
aoqi@0: * /lib/mime.types
.
aoqi@0: * META-INF/mime.types
.
aoqi@0: * META-INF/mimetypes.default
aoqi@0: * (usually found only in the activation.jar
file).
aoqi@0: * aoqi@0: * MIME types file format:
aoqi@0: *
aoqi@0: *
aoqi@0: * # comments begin with a '#'
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: *
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: * 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: }