001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: /*
038: * @(#)MimetypesFileTypeMap.java 1.18 07/05/14
039: */
040:
041: package javax.activation;
042:
043: import java.io.*;
044: import java.net.*;
045: import java.util.*;
046: import com.sun.activation.registries.MimeTypeFile;
047: import com.sun.activation.registries.LogSupport;
048:
049: /**
050: * This class extends FileTypeMap and provides data typing of files
051: * via their file extension. It uses the <code>.mime.types</code> format. <p>
052: *
053: * <b>MIME types file search order:</b><p>
054: * The MimetypesFileTypeMap looks in various places in the user's
055: * system for MIME types file entries. When requests are made
056: * to search for MIME types in the MimetypesFileTypeMap, it searches
057: * MIME types files in the following order:
058: * <p>
059: * <ol>
060: * <li> Programmatically added entries to the MimetypesFileTypeMap instance.
061: * <li> The file <code>.mime.types</code> in the user's home directory.
062: * <li> The file <<i>java.home</i>><code>/lib/mime.types</code>.
063: * <li> The file or resources named <code>META-INF/mime.types</code>.
064: * <li> The file or resource named <code>META-INF/mimetypes.default</code>
065: * (usually found only in the <code>activation.jar</code> file).
066: * </ol>
067: * <p>
068: * <b>MIME types file format:</b><p>
069: *
070: * <code>
071: * # comments begin with a '#'<br>
072: * # the format is <mime type> <space separated file extensions><br>
073: * # for example:<br>
074: * text/plain txt text TXT<br>
075: * # this would map file.txt, file.text, and file.TXT to<br>
076: * # the mime type "text/plain"<br>
077: * </code>
078: *
079: * @author Bart Calder
080: * @author Bill Shannon
081: */
082: public class MimetypesFileTypeMap extends FileTypeMap {
083: /*
084: * We manage a collection of databases, searched in order.
085: * The default database is shared between all instances
086: * of this class.
087: * XXX - Can we safely share more databases between instances?
088: */
089: private static MimeTypeFile defDB = null;
090: private MimeTypeFile[] DB;
091: private static final int PROG = 0; // programmatically added entries
092:
093: private static String defaultType = "application/octet-stream";
094:
095: /**
096: * The default constructor.
097: */
098: public MimetypesFileTypeMap() {
099: Vector dbv = new Vector(5); // usually 5 or less databases
100: MimeTypeFile mf = null;
101: dbv.addElement(null); // place holder for PROG entry
102:
103: LogSupport.log("MimetypesFileTypeMap: load HOME");
104: try {
105: String user_home = System.getProperty("user.home");
106:
107: if (user_home != null) {
108: String path = user_home + File.separator
109: + ".mime.types";
110: mf = loadFile(path);
111: if (mf != null)
112: dbv.addElement(mf);
113: }
114: } catch (SecurityException ex) {
115: }
116:
117: LogSupport.log("MimetypesFileTypeMap: load SYS");
118: try {
119: // check system's home
120: String system_mimetypes = System.getProperty("java.home")
121: + File.separator + "lib" + File.separator
122: + "mime.types";
123: mf = loadFile(system_mimetypes);
124: if (mf != null)
125: dbv.addElement(mf);
126: } catch (SecurityException ex) {
127: }
128:
129: LogSupport.log("MimetypesFileTypeMap: load JAR");
130: // load from the app's jar file
131: loadAllResources(dbv, "META-INF/mime.types");
132:
133: LogSupport.log("MimetypesFileTypeMap: load DEF");
134: synchronized (MimetypesFileTypeMap.class) {
135: // see if another instance has created this yet.
136: if (defDB == null)
137: defDB = loadResource("/META-INF/mimetypes.default");
138: }
139:
140: if (defDB != null)
141: dbv.addElement(defDB);
142:
143: DB = new MimeTypeFile[dbv.size()];
144: dbv.copyInto(DB);
145: }
146:
147: /**
148: * Load from the named resource.
149: */
150: private MimeTypeFile loadResource(String name) {
151: InputStream clis = null;
152: try {
153: clis = SecuritySupport.getResourceAsStream(this .getClass(),
154: name);
155: if (clis != null) {
156: MimeTypeFile mf = new MimeTypeFile(clis);
157: if (LogSupport.isLoggable())
158: LogSupport
159: .log("MimetypesFileTypeMap: successfully "
160: + "loaded mime types file: " + name);
161: return mf;
162: } else {
163: if (LogSupport.isLoggable())
164: LogSupport.log("MimetypesFileTypeMap: not loading "
165: + "mime types file: " + name);
166: }
167: } catch (IOException e) {
168: if (LogSupport.isLoggable())
169: LogSupport.log("MimetypesFileTypeMap: can't load "
170: + name, e);
171: } catch (SecurityException sex) {
172: if (LogSupport.isLoggable())
173: LogSupport.log("MimetypesFileTypeMap: can't load "
174: + name, sex);
175: } finally {
176: try {
177: if (clis != null)
178: clis.close();
179: } catch (IOException ex) {
180: } // ignore it
181: }
182: return null;
183: }
184:
185: /**
186: * Load all of the named resource.
187: */
188: private void loadAllResources(Vector v, String name) {
189: boolean anyLoaded = false;
190: try {
191: URL[] urls;
192: ClassLoader cld = null;
193: // First try the "application's" class loader.
194: cld = SecuritySupport.getContextClassLoader();
195: if (cld == null)
196: cld = this .getClass().getClassLoader();
197: if (cld != null)
198: urls = SecuritySupport.getResources(cld, name);
199: else
200: urls = SecuritySupport.getSystemResources(name);
201: if (urls != null) {
202: if (LogSupport.isLoggable())
203: LogSupport
204: .log("MimetypesFileTypeMap: getResources");
205: for (int i = 0; i < urls.length; i++) {
206: URL url = urls[i];
207: InputStream clis = null;
208: if (LogSupport.isLoggable())
209: LogSupport.log("MimetypesFileTypeMap: URL "
210: + url);
211: try {
212: clis = SecuritySupport.openStream(url);
213: if (clis != null) {
214: v.addElement(new MimeTypeFile(clis));
215: anyLoaded = true;
216: if (LogSupport.isLoggable())
217: LogSupport
218: .log("MimetypesFileTypeMap: "
219: + "successfully loaded "
220: + "mime types from URL: "
221: + url);
222: } else {
223: if (LogSupport.isLoggable())
224: LogSupport
225: .log("MimetypesFileTypeMap: "
226: + "not loading "
227: + "mime types from URL: "
228: + url);
229: }
230: } catch (IOException ioex) {
231: if (LogSupport.isLoggable())
232: LogSupport.log(
233: "MimetypesFileTypeMap: can't load "
234: + url, ioex);
235: } catch (SecurityException sex) {
236: if (LogSupport.isLoggable())
237: LogSupport.log(
238: "MimetypesFileTypeMap: can't load "
239: + url, sex);
240: } finally {
241: try {
242: if (clis != null)
243: clis.close();
244: } catch (IOException cex) {
245: }
246: }
247: }
248: }
249: } catch (Exception ex) {
250: if (LogSupport.isLoggable())
251: LogSupport.log("MimetypesFileTypeMap: can't load "
252: + name, ex);
253: }
254:
255: // if failed to load anything, fall back to old technique, just in case
256: if (!anyLoaded) {
257: LogSupport.log("MimetypesFileTypeMap: !anyLoaded");
258: MimeTypeFile mf = loadResource("/" + name);
259: if (mf != null)
260: v.addElement(mf);
261: }
262: }
263:
264: /**
265: * Load the named file.
266: */
267: private MimeTypeFile loadFile(String name) {
268: MimeTypeFile mtf = null;
269:
270: try {
271: mtf = new MimeTypeFile(name);
272: } catch (IOException e) {
273: // e.printStackTrace();
274: }
275: return mtf;
276: }
277:
278: /**
279: * Construct a MimetypesFileTypeMap with programmatic entries
280: * added from the named file.
281: *
282: * @param mimeTypeFileName the file name
283: */
284: public MimetypesFileTypeMap(String mimeTypeFileName)
285: throws IOException {
286: this ();
287: DB[PROG] = new MimeTypeFile(mimeTypeFileName);
288: }
289:
290: /**
291: * Construct a MimetypesFileTypeMap with programmatic entries
292: * added from the InputStream.
293: *
294: * @param is the input stream to read from
295: */
296: public MimetypesFileTypeMap(InputStream is) {
297: this ();
298: try {
299: DB[PROG] = new MimeTypeFile(is);
300: } catch (IOException ex) {
301: // XXX - really should throw it
302: }
303: }
304:
305: /**
306: * Prepend the MIME type values to the registry.
307: *
308: * @param mime_types A .mime.types formatted string of entries.
309: */
310: public synchronized void addMimeTypes(String mime_types) {
311: // check to see if we have created the registry
312: if (DB[PROG] == null)
313: DB[PROG] = new MimeTypeFile(); // make one
314:
315: DB[PROG].appendToRegistry(mime_types);
316: }
317:
318: /**
319: * Return the MIME type of the file object.
320: * The implementation in this class calls
321: * <code>getContentType(f.getName())</code>.
322: *
323: * @param f the file
324: * @return the file's MIME type
325: */
326: public String getContentType(File f) {
327: return this .getContentType(f.getName());
328: }
329:
330: /**
331: * Return the MIME type based on the specified file name.
332: * The MIME type entries are searched as described above under
333: * <i>MIME types file search order</i>.
334: * If no entry is found, the type "application/octet-stream" is returned.
335: *
336: * @param filename the file name
337: * @return the file's MIME type
338: */
339: public synchronized String getContentType(String filename) {
340: int dot_pos = filename.lastIndexOf("."); // period index
341:
342: if (dot_pos < 0)
343: return defaultType;
344:
345: String file_ext = filename.substring(dot_pos + 1);
346: if (file_ext.length() == 0)
347: return defaultType;
348:
349: for (int i = 0; i < DB.length; i++) {
350: if (DB[i] == null)
351: continue;
352: String result = DB[i].getMIMETypeString(file_ext);
353: if (result != null)
354: return result;
355: }
356: return defaultType;
357: }
358:
359: /**
360: * for debugging...
361: *
362: public static void main(String[] argv) throws Exception {
363: MimetypesFileTypeMap map = new MimetypesFileTypeMap();
364: System.out.println("File " + argv[0] + " has MIME type " +
365: map.getContentType(argv[0]));
366: System.exit(0);
367: }
368: */
369: }
|