1 /* 2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.activation; 27 28 import java.io.*; 29 import java.net.*; 30 import java.util.*; 31 import com.sun.activation.registries.MimeTypeFile; 32 import com.sun.activation.registries.LogSupport; 33 34 /** 35 * This class extends FileTypeMap and provides data typing of files 36 * via their file extension. It uses the <code>.mime.types</code> format. <p> 37 * 38 * <b>MIME types file search order:</b><p> 39 * The MimetypesFileTypeMap looks in various places in the user's 40 * system for MIME types file entries. When requests are made 41 * to search for MIME types in the MimetypesFileTypeMap, it searches 42 * MIME types files in the following order: 43 * <p> 44 * <ol> 45 * <li> Programmatically added entries to the MimetypesFileTypeMap instance. 46 * <li> The file <code>.mime.types</code> in the user's home directory. 47 * <li> The file <<i>java.home</i>><code>/lib/mime.types</code>. 48 * <li> The file or resources named <code>META-INF/mime.types</code>. 49 * <li> The file or resource named <code>META-INF/mimetypes.default</code> 50 * (usually found only in the <code>activation.jar</code> file). 51 * </ol> 52 * <p> 53 * <b>MIME types file format:</b><p> 54 * 55 * <code> 56 * # comments begin with a '#'<br> 57 * # the format is <mime type> <space separated file extensions><br> 58 * # for example:<br> 59 * text/plain txt text TXT<br> 60 * # this would map file.txt, file.text, and file.TXT to<br> 61 * # the mime type "text/plain"<br> 62 * </code> 63 * 64 * @author Bart Calder 65 * @author Bill Shannon 66 * 67 * @since 1.6 68 */ 69 public class MimetypesFileTypeMap extends FileTypeMap { 70 /* 71 * We manage a collection of databases, searched in order. 72 */ 73 private MimeTypeFile[] DB; 74 private static final int PROG = 0; // programmatically added entries 75 76 private static String defaultType = "application/octet-stream"; 77 78 /** 79 * The default constructor. 80 */ 81 public MimetypesFileTypeMap() { 82 Vector dbv = new Vector(5); // usually 5 or less databases 83 MimeTypeFile mf = null; 84 dbv.addElement(null); // place holder for PROG entry 85 86 LogSupport.log("MimetypesFileTypeMap: load HOME"); 87 try { 88 String user_home = System.getProperty("user.home"); 89 90 if (user_home != null) { 91 String path = user_home + File.separator + ".mime.types"; 92 mf = loadFile(path); 93 if (mf != null) 94 dbv.addElement(mf); 95 } 96 } catch (SecurityException ex) {} 97 98 LogSupport.log("MimetypesFileTypeMap: load SYS"); 99 try { 100 // check system's home 101 String system_mimetypes = System.getProperty("java.home") + 102 File.separator + "lib" + File.separator + "mime.types"; 103 mf = loadFile(system_mimetypes); 104 if (mf != null) 105 dbv.addElement(mf); 106 } catch (SecurityException ex) {} 107 108 LogSupport.log("MimetypesFileTypeMap: load JAR"); 109 // load from the app's jar file 110 loadAllResources(dbv, "META-INF/mime.types"); 111 112 LogSupport.log("MimetypesFileTypeMap: load DEF"); 113 mf = loadResource("/META-INF/mimetypes.default"); 114 115 if (mf != null) 116 dbv.addElement(mf); 117 118 DB = new MimeTypeFile[dbv.size()]; 119 dbv.copyInto(DB); 120 } 121 122 /** 123 * Load from the named resource. 124 */ 125 private MimeTypeFile loadResource(String name) { 126 InputStream clis = null; 127 try { 128 clis = SecuritySupport.getResourceAsStream(this.getClass(), name); 129 if (clis != null) { 130 MimeTypeFile mf = new MimeTypeFile(clis); 131 if (LogSupport.isLoggable()) 132 LogSupport.log("MimetypesFileTypeMap: successfully " + 133 "loaded mime types file: " + name); 134 return mf; 135 } else { 136 if (LogSupport.isLoggable()) 137 LogSupport.log("MimetypesFileTypeMap: not loading " + 138 "mime types file: " + name); 139 } 140 } catch (IOException e) { 141 if (LogSupport.isLoggable()) 142 LogSupport.log("MimetypesFileTypeMap: can't load " + name, e); 143 } catch (SecurityException sex) { 144 if (LogSupport.isLoggable()) 145 LogSupport.log("MimetypesFileTypeMap: can't load " + name, sex); 146 } finally { 147 try { 148 if (clis != null) 149 clis.close(); 150 } catch (IOException ex) { } // ignore it 151 } 152 return null; 153 } 154 155 /** 156 * Load all of the named resource. 157 */ 158 private void loadAllResources(Vector v, String name) { 159 boolean anyLoaded = false; 160 try { 161 URL[] urls; 162 ClassLoader cld = null; 163 // First try the "application's" class loader. 164 cld = SecuritySupport.getContextClassLoader(); 165 if (cld == null) 166 cld = this.getClass().getClassLoader(); 167 if (cld != null) 168 urls = SecuritySupport.getResources(cld, name); 169 else 170 urls = SecuritySupport.getSystemResources(name); 171 if (urls != null) { 172 if (LogSupport.isLoggable()) 173 LogSupport.log("MimetypesFileTypeMap: getResources"); 174 for (int i = 0; i < urls.length; i++) { 175 URL url = urls[i]; 176 InputStream clis = null; 177 if (LogSupport.isLoggable()) 178 LogSupport.log("MimetypesFileTypeMap: URL " + url); 179 try { 180 clis = SecuritySupport.openStream(url); 181 if (clis != null) { 182 v.addElement(new MimeTypeFile(clis)); 183 anyLoaded = true; 184 if (LogSupport.isLoggable()) 185 LogSupport.log("MimetypesFileTypeMap: " + 186 "successfully loaded " + 187 "mime types from URL: " + url); 188 } else { 189 if (LogSupport.isLoggable()) 190 LogSupport.log("MimetypesFileTypeMap: " + 191 "not loading " + 192 "mime types from URL: " + url); 193 } 194 } catch (IOException ioex) { 195 if (LogSupport.isLoggable()) 196 LogSupport.log("MimetypesFileTypeMap: can't load " + 197 url, ioex); 198 } catch (SecurityException sex) { 199 if (LogSupport.isLoggable()) 200 LogSupport.log("MimetypesFileTypeMap: can't load " + 201 url, sex); 202 } finally { 203 try { 204 if (clis != null) 205 clis.close(); 206 } catch (IOException cex) { } 207 } 208 } 209 } 210 } catch (Exception ex) { 211 if (LogSupport.isLoggable()) 212 LogSupport.log("MimetypesFileTypeMap: can't load " + name, ex); 213 } 214 215 // if failed to load anything, fall back to old technique, just in case 216 if (!anyLoaded) { 217 LogSupport.log("MimetypesFileTypeMap: !anyLoaded"); 218 MimeTypeFile mf = loadResource("/" + name); 219 if (mf != null) 220 v.addElement(mf); 221 } 222 } 223 224 /** 225 * Load the named file. 226 */ 227 private MimeTypeFile loadFile(String name) { 228 MimeTypeFile mtf = null; 229 230 try { 231 mtf = new MimeTypeFile(name); 232 } catch (IOException e) { 233 // e.printStackTrace(); 234 } 235 return mtf; 236 } 237 238 /** 239 * Construct a MimetypesFileTypeMap with programmatic entries 240 * added from the named file. 241 * 242 * @param mimeTypeFileName the file name 243 */ 244 public MimetypesFileTypeMap(String mimeTypeFileName) throws IOException { 245 this(); 246 DB[PROG] = new MimeTypeFile(mimeTypeFileName); 247 } 248 249 /** 250 * Construct a MimetypesFileTypeMap with programmatic entries 251 * added from the InputStream. 252 * 253 * @param is the input stream to read from 254 */ 255 public MimetypesFileTypeMap(InputStream is) { 256 this(); 257 try { 258 DB[PROG] = new MimeTypeFile(is); 259 } catch (IOException ex) { 260 // XXX - really should throw it 261 } 262 } 263 264 /** 265 * Prepend the MIME type values to the registry. 266 * 267 * @param mime_types A .mime.types formatted string of entries. 268 */ 269 public synchronized void addMimeTypes(String mime_types) { 270 // check to see if we have created the registry 271 if (DB[PROG] == null) 272 DB[PROG] = new MimeTypeFile(); // make one 273 274 DB[PROG].appendToRegistry(mime_types); 275 } 276 277 /** 278 * Return the MIME type of the file object. 279 * The implementation in this class calls 280 * <code>getContentType(f.getName())</code>. 281 * 282 * @param f the file 283 * @return the file's MIME type 284 */ 285 public String getContentType(File f) { 286 return this.getContentType(f.getName()); 287 } 288 289 /** 290 * Return the MIME type based on the specified file name. 291 * The MIME type entries are searched as described above under 292 * <i>MIME types file search order</i>. 293 * If no entry is found, the type "application/octet-stream" is returned. 294 * 295 * @param filename the file name 296 * @return the file's MIME type 297 */ 298 public synchronized String getContentType(String filename) { 299 int dot_pos = filename.lastIndexOf("."); // period index 300 301 if (dot_pos < 0) 302 return defaultType; 303 304 String file_ext = filename.substring(dot_pos + 1); 305 if (file_ext.length() == 0) 306 return defaultType; 307 308 for (int i = 0; i < DB.length; i++) { 309 if (DB[i] == null) 310 continue; 311 String result = DB[i].getMIMETypeString(file_ext); 312 if (result != null) 313 return result; 314 } 315 return defaultType; 316 } 317 318 /** 319 * for debugging... 320 * 321 public static void main(String[] argv) throws Exception { 322 MimetypesFileTypeMap map = new MimetypesFileTypeMap(); 323 System.out.println("File " + argv[0] + " has MIME type " + 324 map.getContentType(argv[0])); 325 System.exit(0); 326 } 327 */ 328 }