001 package org.apache.fulcrum.mimetype.util; 002 003 004 /* 005 * Licensed to the Apache Software Foundation (ASF) under one 006 * or more contributor license agreements. See the NOTICE file 007 * distributed with this work for additional information 008 * regarding copyright ownership. The ASF licenses this file 009 * to you under the Apache License, Version 2.0 (the 010 * "License"); you may not use this file except in compliance 011 * with the License. You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, 016 * software distributed under the License is distributed on an 017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 018 * KIND, either express or implied. See the License for the 019 * specific language governing permissions and limitations 020 * under the License. 021 */ 022 023 024 import java.io.File; 025 import java.io.InputStream; 026 import java.io.IOException; 027 028 /** 029 * This class maintains a set of mappers defining mappings 030 * between MIME types and the corresponding file name extensions. 031 * The mappings are defined as lines formed by a MIME type name 032 * followed by a list of extensions separated by a whitespace. 033 * The definitions can be listed in MIME type files located in user's 034 * home directory, Java home directory or the current class jar. 035 * In addition, this class maintains static default mappings 036 * and constructors support application specific mappings. 037 * 038 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a> 039 * @author Daniel Rall 040 * @version $Id: MimeTypeMap.java 826489 2009-10-18 18:54:59Z tv $ 041 */ 042 public class MimeTypeMap 043 { 044 /** 045 * The default MIME type when nothing else is applicable. 046 */ 047 public static final MimeType DEFAULT_MIMETYPE = 048 MimeType.APPLICATION_OCTET_STREAM; 049 050 /** 051 * The default MIME type as a string. 052 */ 053 public static final String DEFAULT_TYPE = DEFAULT_MIMETYPE.toString(); 054 055 /** 056 * The name for MIME type mapper resources. 057 */ 058 public static final String MIMETYPE_RESOURCE = "mime.types"; 059 060 /** 061 * Common MIME type extensions. 062 */ 063 public static final String EXT_HTML = "html"; 064 public static final String EXT_HTM = "htm"; 065 public static final String EXT_WML = "wml"; 066 public static final String EXT_HDML = "hdml"; 067 public static final String EXT_HDM = "hdm"; 068 public static final String EXT_CHTML = "chtml"; 069 public static final String EXT_TEXT = "txt"; 070 public static final String EXT_GIF = "gif"; 071 public static final String EXT_JPEG = "jpeg"; 072 public static final String EXT_JPG = "jpg"; 073 public static final String EXT_WBMP = "wbmp"; 074 075 /** 076 * Priorities of available mappers. 077 */ 078 private static final int MAP_PROG = 0; 079 private static final int MAP_HOME = 1; 080 private static final int MAP_SYS = 2; 081 private static final int MAP_JAR = 3; 082 private static final int MAP_COM = 4; 083 084 /** 085 * A common MIME type mapper. 086 */ 087 private static MimeTypeMapper commonMapper = new MimeTypeMapper(); 088 static 089 { 090 commonMapper.setContentType( 091 MimeType.TEXT_HTML.toString() + " " + EXT_HTML + " " + EXT_HTM); 092 commonMapper.setContentType( 093 MimeType.TEXT_WML.toString() + " " + EXT_WML); 094 commonMapper.setContentType( 095 MimeType.TEXT_HDML.toString() + " " + EXT_HDML + " " + EXT_HDM); 096 commonMapper.setContentType( 097 MimeType.TEXT_CHTML.toString() + " " + EXT_CHTML); 098 commonMapper.setContentType( 099 MimeType.TEXT_PLAIN.toString() + " " + EXT_TEXT); 100 commonMapper.setContentType( 101 MimeType.IMAGE_GIF.toString() + " " + EXT_GIF); 102 commonMapper.setContentType( 103 MimeType.IMAGE_JPEG.toString() + " " + EXT_JPEG + " " + EXT_JPG); 104 commonMapper.setContentType( 105 MimeType.IMAGE_WBMP.toString() + " " + EXT_WBMP); 106 } 107 108 /** 109 * An array of available MIME type mappers. 110 */ 111 private MimeTypeMapper mappers[] = new MimeTypeMapper[5]; 112 113 /** 114 * Loads mappings from a file path. 115 * 116 * @param path a file path. 117 * @return the mappings. 118 * @throws IOException for an incorrect file. 119 */ 120 protected static MimeTypeMapper loadPath(String path) 121 throws IOException 122 { 123 return new MimeTypeMapper(path); 124 } 125 126 /** 127 * Loads mappings from a resource. 128 * 129 * @param name a resource name. 130 * @return the mappings. 131 */ 132 protected static MimeTypeMapper loadResource(String name) 133 { 134 InputStream input = MimeTypeMap.class.getResourceAsStream(name); 135 if (input != null) 136 { 137 try 138 { 139 return new MimeTypeMapper(input); 140 } 141 catch (IOException x) 142 { 143 return null; 144 } 145 } 146 else 147 { 148 return null; 149 } 150 } 151 152 /** 153 * Constructs a new MIME type map with default mappers. 154 */ 155 public MimeTypeMap() 156 { 157 String path; 158 try 159 { 160 // Check whether the user directory contains mappings. 161 path = System.getProperty("user.home"); 162 if (path != null) 163 { 164 path = path + File.separator + MIMETYPE_RESOURCE; 165 mappers[MAP_HOME] = loadPath(path); 166 } 167 } 168 catch (IOException x) 169 { 170 // ignore 171 } 172 173 try 174 { 175 // Check whether the system directory contains mappings. 176 path = System.getProperty("java.home") + 177 File.separator + "lib" + File.separator + MIMETYPE_RESOURCE; 178 mappers[MAP_SYS] = loadPath(path); 179 } 180 catch (IOException x) 181 { 182 // ignore 183 } 184 185 // Check whether the current class jar contains mappings. 186 mappers[MAP_JAR] = loadResource("/META-INF/" + MIMETYPE_RESOURCE); 187 188 // Set the common mapper to have the lowest priority. 189 mappers[MAP_COM] = commonMapper; 190 } 191 192 /** 193 * Contructs a MIME type map read from a stream. 194 * 195 * @param input an input stream. 196 * @throws IOException for an incorrect stream. 197 */ 198 public MimeTypeMap(InputStream input) 199 throws IOException 200 { 201 this(); 202 mappers[MAP_PROG] = new MimeTypeMapper(input); 203 } 204 205 /** 206 * Contructs a MIME type map read from a file. 207 * 208 * @param file an input file. 209 * @throws IOException for an incorrect input file. 210 */ 211 public MimeTypeMap(File file) 212 throws IOException 213 { 214 this(); 215 mappers[MAP_PROG] = new MimeTypeMapper(file); 216 } 217 218 /** 219 * Contructs a MIME type map read from a file path. 220 * 221 * @param path an input file path. 222 * @throws IOException for an incorrect input file. 223 */ 224 public MimeTypeMap(String path) 225 throws IOException 226 { 227 this(); 228 mappers[MAP_PROG] = new MimeTypeMapper(path); 229 } 230 231 /** 232 * Sets a MIME content type mapping to extensions. 233 * 234 * @param spec a MIME type extension specification to set. 235 */ 236 public synchronized void setContentType(String spec) 237 { 238 if (mappers[MAP_PROG] == null) 239 { 240 mappers[MAP_PROG] = new MimeTypeMapper(); 241 } 242 mappers[MAP_PROG].setContentType(spec); 243 } 244 245 /** 246 * Gets the MIME content type for a file as a string. 247 * 248 * @param file The file to look up a MIME type mapping for. 249 * @return The MIME type, or {@link #DEFAULT_TYPE} if unmapped. 250 */ 251 public String getContentType(File file) 252 { 253 return getContentType(file.getName()); 254 } 255 256 /** 257 * Gets the MIME content type for a named file as a string. 258 * 259 * @param fileName The name of the file to look up a MIME type 260 * mapping for. 261 * @return The MIME type, or {@link #DEFAULT_TYPE} if unmapped. 262 */ 263 public String getContentType(String fileName) 264 { 265 return getContentType(fileName, DEFAULT_TYPE); 266 } 267 268 /** 269 * Gets the MIME content type for a file name extension as a string. 270 * 271 * @param fileName The name of the file to look up a MIME type 272 * mapping for. 273 * @param def The default MIME type to use if no mapping exists. 274 * @return The MIME type, or <code>def</code> if unmapped. 275 */ 276 public String getContentType(String fileName, String def) 277 { 278 String ext = parseFileExtension(fileName); 279 if (ext != null) 280 { 281 String mimeType; 282 MimeTypeMapper mapper; 283 for (int i = 0; i < mappers.length; i++) 284 { 285 mapper = mappers[i]; 286 if (mapper != null) 287 { 288 mimeType = mapper.getContentType(ext); 289 if (mimeType != null) 290 { 291 return mimeType; 292 } 293 } 294 } 295 } 296 return def; 297 } 298 299 /** 300 * @param fileName The name of the file to parse the extension 301 * from. Must be non-<code>null</code>. 302 * @return The file extension parsed from <code>fileName</code> 303 * (if present), or <code>null</code> if not found. 304 */ 305 private static String parseFileExtension(String fileName) 306 { 307 int i = fileName.lastIndexOf('.'); 308 return (i >= 0 && i + 2 < fileName.length() ? 309 fileName.substring(i + 1) : null); 310 } 311 312 /** 313 * Gets the MIME content type for a file. 314 * 315 * @param file the file. 316 * @return the MIME type. 317 */ 318 public MimeType getMimeContentType(File file) 319 { 320 try 321 { 322 return new MimeType(getContentType(file)); 323 } 324 catch (Exception x) 325 { 326 return DEFAULT_MIMETYPE; 327 } 328 } 329 330 /** 331 * Gets the MIME content type for a named file. 332 * 333 * @param name the name of the file. 334 * @return the MIME type. 335 */ 336 public MimeType getMimeContentType(String name) 337 { 338 try 339 { 340 return new MimeType(getContentType(name)); 341 } 342 catch (Exception x) 343 { 344 return DEFAULT_MIMETYPE; 345 } 346 } 347 348 /** 349 * Gets the MIME content type for a file name extension. 350 * 351 * @param ext the file name extension. 352 * @param def the default type if none is found. 353 * @return the MIME type. 354 */ 355 public MimeType getMimeContentType(String ext, 356 String def) 357 { 358 try 359 { 360 return new MimeType(getContentType(ext,def)); 361 } 362 catch (Exception x) 363 { 364 return DEFAULT_MIMETYPE; 365 } 366 } 367 368 /** 369 * Gets the default file name extension for a MIME type. 370 * Note that the mappers are called in the reverse order. 371 * 372 * @param type the MIME type as a string. 373 * @return the file name extension or null. 374 */ 375 public String getDefaultExtension(String type) 376 { 377 String ext; 378 MimeTypeMapper mapper; 379 int i = type.indexOf(';'); 380 if (i >= 0) 381 { 382 type = type.substring(0,i); 383 } 384 type = type.trim(); 385 for (i = mappers.length - 1; i >= 0; i--) 386 { 387 mapper = mappers[i]; 388 if (mapper != null) 389 { 390 ext = mapper.getExtension(type); 391 if (ext != null) 392 { 393 return ext; 394 } 395 } 396 } 397 return null; 398 } 399 400 /** 401 * Gets the default file name extension for a MIME type. 402 * Note that the mappers are called in the reverse order. 403 * 404 * @param mime the MIME type. 405 * @return the file name extension or null. 406 */ 407 public String getDefaultExtension(MimeType mime) 408 { 409 return getDefaultExtension(mime.getTypes()); 410 } 411 412 /** 413 * Sets a common MIME content type mapping to extensions. 414 * 415 * @param spec a MIME type extension specification to set. 416 */ 417 protected synchronized void setCommonContentType(String spec) 418 { 419 mappers[MAP_COM].setContentType(spec); 420 } 421 }