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