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