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} 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 * <ol> 44 * <li> Programmatically added entries to the MimetypesFileTypeMap instance. 45 * <li> The file {@code .mime.types} in the user's home directory. 46 * <li> The file {@literal <}<i>java.home</i>{@literal >}{@code /lib/mime.types}. 47 * <li> The file or resources named {@code META-INF/mime.types}. 48 * <li> The file or resource named {@code META-INF/mimetypes.default} 49 * (usually found only in the {@code activation.jar} file). 50 * </ol> 51 * <p> 52 * <b>MIME types file format:</b> 53 * 54 * <pre>{@code 55 * # comments begin with a '#' 56 * # the format is <mime type> <space separated file extensions> 57 * # for example: 58 * text/plain txt text TXT 59 * # this would map file.txt, file.text, and file.TXT to 60 * # the mime type "text/plain" 61 * }</pre> 62 * 63 * @author Bart Calder 64 * @author Bill Shannon 65 * 66 * @since 1.6 67 */ 68 public class MimetypesFileTypeMap extends FileTypeMap { 69 /* 70 * We manage a collection of databases, searched in order. 71 */ 72 private MimeTypeFile[] DB; 73 private static final int PROG = 0; // programmatically added entries 74 75 private static String defaultType = "application/octet-stream"; 76 77 /** 78 * The default constructor. 79 */ 80 public MimetypesFileTypeMap() { 81 Vector dbv = new Vector(5); // usually 5 or less databases 82 MimeTypeFile mf = null; 83 dbv.addElement(null); // place holder for PROG entry 84 85 LogSupport.log("MimetypesFileTypeMap: load HOME"); 86 try { 87 String user_home = System.getProperty("user.home"); 88 89 if (user_home != null) { 90 String path = user_home + File.separator + ".mime.types"; 91 mf = loadFile(path); 92 if (mf != null) 93 dbv.addElement(mf); 94 } 95 } catch (SecurityException ex) {} 96 97 LogSupport.log("MimetypesFileTypeMap: load SYS"); 98 try { 99 // check system's home 100 String system_mimetypes = System.getProperty("java.home") + 101 File.separator + "lib" + File.separator + "mime.types"; 102 mf = loadFile(system_mimetypes); 103 if (mf != null) 104 dbv.addElement(mf); 105 } catch (SecurityException ex) {} 106 107 LogSupport.log("MimetypesFileTypeMap: load JAR"); 108 // load from the app's jar file 109 loadAllResources(dbv, "META-INF/mime.types"); 110 111 LogSupport.log("MimetypesFileTypeMap: load DEF"); 112 mf = loadResource("/META-INF/mimetypes.default"); 113 114 if (mf != null) 115 dbv.addElement(mf); 116 117 DB = new MimeTypeFile[dbv.size()]; 118 dbv.copyInto(DB); 119 } 120 121 /** 122 * Load from the named resource. 123 */ 124 private MimeTypeFile loadResource(String name) { 125 InputStream clis = null; 126 try { 127 clis = SecuritySupport.getResourceAsStream(this.getClass(), name); 128 if (clis != null) { 129 MimeTypeFile mf = new MimeTypeFile(clis); 130 if (LogSupport.isLoggable()) 131 LogSupport.log("MimetypesFileTypeMap: successfully " + 132 "loaded mime types file: " + name); 133 return mf; 134 } else { 135 if (LogSupport.isLoggable()) 136 LogSupport.log("MimetypesFileTypeMap: not loading " + 137 "mime types file: " + name); 138 } 139 } catch (IOException e) { 140 if (LogSupport.isLoggable()) 141 LogSupport.log("MimetypesFileTypeMap: can't load " + name, e); 142 } catch (SecurityException sex) { 143 if (LogSupport.isLoggable()) 144 LogSupport.log("MimetypesFileTypeMap: can't load " + name, sex); 145 } finally { 146 try { 147 if (clis != null) 148 clis.close(); 149 } catch (IOException ex) { } // ignore it 150 } 151 return null; 152 } 153 154 /** 155 * Load all of the named resource. 156 */ 157 private void loadAllResources(Vector v, String name) { 158 boolean anyLoaded = false; 159 try { 160 URL[] urls; 161 ClassLoader cld = null; 162 // First try the "application's" class loader. 163 cld = SecuritySupport.getContextClassLoader(); 164 if (cld == null) 165 cld = this.getClass().getClassLoader(); 166 if (cld != null) 167 urls = SecuritySupport.getResources(cld, name); 168 else 169 urls = SecuritySupport.getSystemResources(name); 170 if (urls != null) { 171 if (LogSupport.isLoggable()) 172 LogSupport.log("MimetypesFileTypeMap: getResources"); 173 for (int i = 0; i < urls.length; i++) { 174 URL url = urls[i]; 175 InputStream clis = null; 176 if (LogSupport.isLoggable()) 177 LogSupport.log("MimetypesFileTypeMap: URL " + url); 178 try { 179 clis = SecuritySupport.openStream(url); 180 if (clis != null) { 181 v.addElement(new MimeTypeFile(clis)); 182 anyLoaded = true; 183 if (LogSupport.isLoggable()) 184 LogSupport.log("MimetypesFileTypeMap: " + 185 "successfully loaded " + 186 "mime types from URL: " + url); 187 } else { 188 if (LogSupport.isLoggable()) 189 LogSupport.log("MimetypesFileTypeMap: " + 190 "not loading " + 191 "mime types from URL: " + url); 192 } 193 } catch (IOException ioex) { 194 if (LogSupport.isLoggable()) 195 LogSupport.log("MimetypesFileTypeMap: can't load " + 196 url, ioex); 197 } catch (SecurityException sex) { 198 if (LogSupport.isLoggable()) 199 LogSupport.log("MimetypesFileTypeMap: can't load " + 200 url, sex); 201 } finally { 202 try { 203 if (clis != null) 204 clis.close(); 205 } catch (IOException cex) { } 206 } 207 } 208 } 209 } catch (Exception ex) { 210 if (LogSupport.isLoggable()) 211 LogSupport.log("MimetypesFileTypeMap: can't load " + name, ex); 212 } 213 214 // if failed to load anything, fall back to old technique, just in case 215 if (!anyLoaded) { 216 LogSupport.log("MimetypesFileTypeMap: !anyLoaded"); 217 MimeTypeFile mf = loadResource("/" + name); 218 if (mf != null) 219 v.addElement(mf); 220 } 221 } 222 223 /** 224 * Load the named file. 225 */ 226 private MimeTypeFile loadFile(String name) { 227 MimeTypeFile mtf = null; 228 229 try { 230 mtf = new MimeTypeFile(name); 231 } catch (IOException e) { 232 // e.printStackTrace(); 233 } 234 return mtf; 235 } 236 237 /** 238 * Construct a MimetypesFileTypeMap with programmatic entries 239 * added from the named file. 240 * 241 * @param mimeTypeFileName the file name 242 */ 243 public MimetypesFileTypeMap(String mimeTypeFileName) throws IOException { 244 this(); 245 DB[PROG] = new MimeTypeFile(mimeTypeFileName); 246 } 247 248 /** 249 * Construct a MimetypesFileTypeMap with programmatic entries 250 * added from the InputStream. 251 * 252 * @param is the input stream to read from 253 */ 254 public MimetypesFileTypeMap(InputStream is) { 255 this(); 256 try { 257 DB[PROG] = new MimeTypeFile(is); 258 } catch (IOException ex) { 259 // XXX - really should throw it 260 } 261 } 262 263 /** 264 * Prepend the MIME type values to the registry. 265 * 266 * @param mime_types A .mime.types formatted string of entries. 267 */ 268 public synchronized void addMimeTypes(String mime_types) { 269 // check to see if we have created the registry 270 if (DB[PROG] == null) 271 DB[PROG] = new MimeTypeFile(); // make one 272 273 DB[PROG].appendToRegistry(mime_types); 274 } 275 276 /** 277 * Return the MIME type of the file object. 278 * The implementation in this class calls 279 * {@code getContentType(f.getName())}. 280 * 281 * @param f the file 282 * @return the file's MIME type 283 */ 284 public String getContentType(File f) { 285 return this.getContentType(f.getName()); 286 } 287 288 /** 289 * Return the MIME type based on the specified file name. 290 * The MIME type entries are searched as described above under 291 * <i>MIME types file search order</i>. 292 * If no entry is found, the type "application/octet-stream" is returned. 293 * 294 * @param filename the file name 295 * @return the file's MIME type 296 */ 297 public synchronized String getContentType(String filename) { 298 int dot_pos = filename.lastIndexOf("."); // period index 299 300 if (dot_pos < 0) 301 return defaultType; 302 303 String file_ext = filename.substring(dot_pos + 1); 304 if (file_ext.length() == 0) 305 return defaultType; 306 307 for (int i = 0; i < DB.length; i++) { 308 if (DB[i] == null) 309 continue; 310 String result = DB[i].getMIMETypeString(file_ext); 311 if (result != null) 312 return result; 313 } 314 return defaultType; 315 } 316 317 /** 318 * for debugging... 319 * 320 public static void main(String[] argv) throws Exception { 321 MimetypesFileTypeMap map = new MimetypesFileTypeMap(); 322 System.out.println("File " + argv[0] + " has MIME type " + 323 map.getContentType(argv[0])); 324 System.exit(0); 325 } 326 */ 327 }