All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.medsea.mimeutil.MimeUtil Maven / Gradle / Ivy

/*
 * Copyright 2007-2009 Medsea Business Solutions S.L.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package eu.medsea.mimeutil;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLConnection;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import eu.medsea.mimeutil.detector.MimeDetector;
import eu.medsea.util.StringUtil;

/**
 * 

* The MimeUtil utility is a utility class that allows applications to detect, work with and manipulate mime types. *

*

* A mime or "Multipurpose Internet Mail Extension" type is an Internet standard that is important outside of just e-mail use. * Mime is used extensively in other communications protocols such as HTTP for web communications. * IANA "Internet Assigned Numbers Authority" is responsible for the standardisation and publication of mime types. Basically any * resource on any computer that can be located via a URI can be assigned a mime type. So for instance, JPEG images have a mime type * of image/jpg. Some resources can have multiple mime types associated with them such as files with an XML extension have the mime types * text/xml and application/xml and even specialised versions of xml such as image/svg+xml for SVG image files. *

*

* To do this MimeUtil uses registered MimeDetector(s) that are delegated too in sequence to actually * perform the detection. There a three MimeDetector(s) registered by default that * perform detection based on file extensions, file globing and magic number detection using * the Unix file(1) magic.mime files. * Please refer to the java doc for each of these MimeDetector(s) for a description of how they * actually perform their particular detection process. *

*

* It is important to note that mime matching is not an exact science, meaning * that a positive match does not guarantee that the returned mime type is actually correct. * It is a best guess method of matching and the matched mime types should be used with this in * mind. *

*

* New MimeDetector(s) can easily be created and registered with MimeUtil to extend it's * functionality beyond these initial detection strategies by extending the AbstractMimeDetector class. * To see how to implement your own MimeDetector and register it with MimeUtil take a look * at the java doc and source code for the {@link ExtensionMimeDetector}, {@link MagicMimeMimeDetector} and * {@link GlobingMimeDetector} classes. Previously registered MimeDetector(s) can also be un-registered at * any time. *

*

* The order that the MimeDetector(s) are executed is defined by the priority of the individual MimeDetector(s) * and MimeDetector(s) with the same priority are executed in the order they are registered. *

*

* The resulting Collection of mime types returned in response to a getMimeTypes(...) call is a normalised list of the * accumulation of mime types returned by each of the registered MimeDetector(s) that implement the specified getMimeTypes(...) * methods. This Collection of mime types can be influenced using MimeHandler(s) that can be registered against one or more MimeDetector(s) that * are able to manipulate the Collection of mime types that will be returned to the client. *

*

* All methods in this class that return a Collection object actually return a {@link MimeTypeHashSet} that implements both the {@link Set} and {@link Collection} * interfaces. *

* * @author Steven McArdle. * */ public class MimeUtil { private static Log log = LogFactory.getLog(MimeUtil.class); /** * Mime type used to identify a directory */ public static final MimeType DIRECTORY_MIME_TYPE = new MimeType("application/directory"); /** * Mime type used to identify a directory */ public static final MimeType UNKNOWN_MIME_TYPE = new MimeType("application/octet-stream"); private static final Pattern mimeSplitter = Pattern.compile("[/;]++"); // All mime types know to the utility private static Map mimeTypes = new HashMap(); private static MimeUtilMimeDetectorRegistry mimeUtilMimeDetector = new MimeUtilMimeDetectorRegistry(); // the native byte order of the underlying OS. "BIG" or "little" Endian private static ByteOrder nativeByteOrder = ByteOrder.nativeOrder(); // Register all know internal mime detectors. static { InputStream is = MimeUtil.class.getResourceAsStream("/MimeDetectors"); BufferedReader br = new BufferedReader(new InputStreamReader(is)); if(is != null) { try { String line = null; while((line = br.readLine()) != null) { if(line.trim().startsWith("#")) { continue; } Class.forName(line); } }catch(Exception e) { e.printStackTrace(); } } } /** * While MimeType(s) are being loaded by the MimeDetector(s) they should be * added to the list of known mime types. It is not mandatory for MimeDetector(s) * to do so but they should where possible so that the list is as complete as possible. * You can add other mime types to this list using this method. You can then use the * isMimeTypeKnown(...) utility method to see if a mime type you have * matches one that the utility has already seen. *

* This can be used to limit the mime types you work with i.e. if its not been loaded * then don't bother using it as it won't match. This is no guarantee that a match will not * be found as it is possible that a particular MimeDetector does not have an initialisation * phase that loads all of the mime types it will match. *

*

* For instance if you had a mime type of abc/xyz and passed this to * isMimeTypeKnown(...) it would return false unless you specifically add * this to the know mime types using this method. *

* * @param mimeType * a mime type you want to add to the known mime types. * Duplicates are ignored. * @see #isMimeTypeKnown(String mimetype) */ public static void addKnownMimeType(final MimeType mimeType) { addKnownMimeType(mimeType.toString()); } /** * While MimeType(s) are being loaded by the MimeDetector(s) they should be * added to the list of known mime types. It is not mandatory for MimeDetector(s) * to do so but they should where possible so that the list is as complete as possible. * You can add other mime types to this list using this method. You can then use the * isMimeTypeKnown(...) utility method to see if a mime type you have * matches one that the utility has already seen. *

* This can be used to limit the mime types you work with i.e. if its not been loaded * then don't bother using it as it won't match. This is no guarantee that a match will not * be found as it is possible that a particular MimeDetector does not have an initialisation * phase that loads all of the mime types it will match. *

*

* For instance if you had a mime type of abc/xyz and passed this to * isMimeTypeKnown(...) it would return false unless you specifically add * this to the know mime types using this method. *

* * @param mimeType * a mime type you want to add to the known mime types. * Duplicates are ignored. * @see #isMimeTypeKnown(String mimetype) */ public static void addKnownMimeType(final String mimeType) { try { String key = getMediaType(mimeType); Set s = (Set) mimeTypes.get(key); if (s == null) { s = new TreeSet(); } s.add(getSubType(mimeType)); mimeTypes.put(key, s); } catch (MimeException ignore) { // A couple of entries in the magic mime file don't follow the rules // so ignore them } } /** * Add a MimeDetector to the MimeDetector registry. * MimeDetector(s) are effectively singletons as they are keyed against their * fully qualified class name. * @param mimeDetector. This must be an AbstractMimeDetector class and not * a MimeUtil interface. This enforces that all custom MimeDetector(s) extend * the AbstractMimeDetector rather than just implementing the MimeDetector interface. * @see MimeDetector * @see MimeDetector */ public static void addMimeDetector(final MimeDetector mimeDetector) { mimeUtilMimeDetector.addMimeDetector(mimeDetector); } /** * Get the extension part of a file name defined by the file parameter. * * @param file * a file object * @return the file extension or null if it does not have one. */ public static String getExtension(final File file) { return MimeUtil.getExtension(file.getName()); } /** * Get the extension part of a file name defined by the fileName parameter. * There may be no extension or it could be a single part extension such as * .bat or a multi-part extension such as tar.gz * * @param fileName * a relative or absolute path to a file * @return the file extension or null if it does not have one. */ public static String getExtension(final String fileName) { // Remove any path element from this name File file = new File(fileName); String fname = file.getName(); if (fname == null || fname.indexOf(".") < 0) { return ""; } return fname.substring(fname.indexOf(".") + 1); } /** * Get the first in a comma separated list of mime types. Useful when using * extension mapping that can return multiple mime types separate by commas * and you only want the first one. * * @param mimeTypes * comma separated list of mime types * @return first in a comma separated list of mime types or null if the mimeTypes string is null or empty */ public static MimeType getFirstMimeType(final String mimeTypes) { if (mimeTypes != null && mimeTypes.trim().length() != 0) { return new MimeType(mimeTypes.split(",")[0].trim()); } return null; } /** * Utility method to get the major or media part of a mime type i.e. the bit before * the '/' character * * @param mimeType * you want to get the media part from * @return media type of the mime type * @throws MimeException * if you pass in an invalid mime type structure */ public static String getMediaType(final String mimeType) throws MimeException { return new MimeType(mimeType).getMediaType(); } /** * * Utility method to get the quality part of a mime type. If it does not * exist then it is always set to q=1.0 unless it's a wild card. For the * major component wild card the value is set to 0.01 For the minor * component wild card the value is set to 0.02 *

* Thanks to the Apache organisation or these settings. * * @param mimeType * a valid mime type string with or without a valid q parameter * @return the quality value of the mime type either calculated from the * rules above or the actual value defined. * @throws MimeException * this is thrown if the mime type pattern is invalid. */ public static double getMimeQuality(final String mimeType) throws MimeException { if (mimeType == null) { throw new MimeException("Invalid MimeType [" + mimeType + "]."); } String[] parts = mimeSplitter.split(mimeType); if (parts.length < 2) { throw new MimeException("Invalid MimeType [" + mimeType + "]."); } if (parts.length > 2) { for (int i = 2; i < parts.length; i++) { if (parts[i].trim().startsWith("q=")) { // Get the number part try { // Get the quality factor double d = Double.parseDouble(parts[i].split("=")[1] .trim()); return d > 1.0 ? 1.0 : d; } catch (NumberFormatException e) { throw new MimeException( "Invalid Mime quality indicator [" + parts[i].trim() + "]. Must be a valid double between 0 and 1"); } catch (Exception e) { throw new MimeException( "Error parsing Mime quality indicator.", e); } } } } // No quality indicator so always assume its 1 unless a wild card is used if (parts[0].contains("*")) { return 0.01; } else if (parts[1].contains("*")) { return 0.02; } else { // Assume q value of 1 return 1.0; } } /** * Get a registered MimeDetector by name. * @param name the name of a registered MimeDetector. This is always the fully qualified * name of the class implementing the MimeDetector. * @return */ public static MimeDetector getMimeDetector(final String name) { return mimeUtilMimeDetector.getMimeDetector(name); } /** * TODO: Add description * @param data * @return * @throws MimeException */ public static Collection getMimeTypes(final byte [] data) throws MimeException { return getMimeTypes(data, UNKNOWN_MIME_TYPE); } /** * TODO: Add desription * @param data * @param unknownMimeType * @throws MimeException */ public static Collection getMimeTypes(final byte [] data, final MimeType unknownMimeType) throws MimeException { if(log.isDebugEnabled()) { try { log.debug("Getting mime types for byte array [" + StringUtil.getHexString(data)+ "]."); }catch(UnsupportedEncodingException uee) { throw new MimeException(uee); } } return mimeUtilMimeDetector.getMimeTypes(data, unknownMimeType); } /** * Get all of the matching mime types for this file object. * The method delegates down to each of the registered MimeHandler(s) and returns a * normalised list of all matching mime types. If no matching mime types are found the returned * Collection will contain the default UNKNOWN_MIME_TYPE * @param file the File object to detect. * @return collection of matching MimeType(s) * @throws MimeException if there are problems such as reading files generated when the MimeHandler(s) * executed. */ public static Collection getMimeTypes(final File file) throws MimeException { return getMimeTypes(file, UNKNOWN_MIME_TYPE); } /** * Get all of the matching mime types for this file object. * The method delegates down to each of the registered MimeHandler(s) and returns a * normalised list of all matching mime types. If no matching mime types are found the returned * Collection will contain the unknownMimeType passed in. * @param file the File object to detect. * @param unknownMimeType. * @return the Collection of matching mime types. If the collection would be empty i.e. no matches then this will * contain the passed in parameter unknownMimeType * @throws MimeException if there are problems such as reading files generated when the MimeHandler(s) * executed. */ public static Collection getMimeTypes(final File file, final MimeType unknownMimeType) throws MimeException { if(log.isDebugEnabled()) { log.debug("Getting mime types for file [" + file.getAbsolutePath() + "]."); } return mimeUtilMimeDetector.getMimeTypes(file, unknownMimeType); } /** * Get all of the matching mime types for this InputStream object. * The method delegates down to each of the registered MimeHandler(s) and returns a * normalised list of all matching mime types. If no matching mime types are found the returned * Collection will contain the default UNKNOWN_MIME_TYPE * @param in InputStream to detect. * @return * @throws MimeException if there are problems such as reading files generated when the MimeHandler(s) * executed. */ public static Collection getMimeTypes(final InputStream in) throws MimeException { return getMimeTypes(in, UNKNOWN_MIME_TYPE); } /** * Get all of the matching mime types for this InputStream object. * The method delegates down to each of the registered MimeHandler(s) and returns a * normalised list of all matching mime types. If no matching mime types are found the returned * Collection will contain the unknownMimeType passed in. * @param in the InputStream object to detect. * @param unknownMimeType. * @return the Collection of matching mime types. If the collection would be empty i.e. no matches then this will * contain the passed in parameter unknownMimeType * @throws MimeException if there are problems such as reading files generated when the MimeHandler(s) * executed. */ public static Collection getMimeTypes(final InputStream in, final MimeType unknownMimeType) throws MimeException { if(log.isDebugEnabled()) { log.debug("Getting mime types for InputSteam [" + in + "]."); } if (!in.markSupported()) throw new MimeException("InputStream does not support mark and reset!"); return mimeUtilMimeDetector.getMimeTypes(in, unknownMimeType); } /** * Get all of the matching mime types for this file name. * The method delegates down to each of the registered MimeHandler(s) and returns a * normalised list of all matching mime types. If no matching mime types are found the returned * Collection will contain the default UNKNOWN_MIME_TYPE * @param fileName the name of a file to detect. * @return collection of matching MimeType(s) * @throws MimeException if there are problems such as reading files generated when the MimeHandler(s) * executed. */ public static Collection getMimeTypes(final String fileName) throws MimeException { return getMimeTypes(fileName, UNKNOWN_MIME_TYPE); } /** * Get all of the matching mime types for this file name . * The method delegates down to each of the registered MimeHandler(s) and returns a * normalised list of all matching mime types. If no matching mime types are found the returned * Collection will contain the unknownMimeType passed in. * @param fileName the name of a file to detect. * @param unknownMimeType. * @return the Collection of matching mime types. If the collection would be empty i.e. no matches then this will * contain the passed in parameter unknownMimeType * @throws MimeException if there are problems such as reading files generated when the MimeHandler(s) * executed. */ public static Collection getMimeTypes(final String fileName, final MimeType unknownMimeType) throws MimeException { if(log.isDebugEnabled()) { log.debug("Getting mime types for file name [" + fileName + "]."); } return mimeUtilMimeDetector.getMimeTypes(fileName, unknownMimeType); } /** * Get all of the matching mime types for this URLConnection object. * The method delegates down to each of the registered MimeHandler(s) and returns a * normalised list of all matching mime types. If no matching mime types are found the returned * Collection will contain the default UNKNOWN_MIME_TYPE * @param url a URL to detect. * @return collection of matching MimeType(s) * @throws MimeException if there are problems such as reading files generated when the MimeHandler(s) * executed. */ public static Collection getMimeTypes(final URLConnection url) throws MimeException { return getMimeTypes(url, UNKNOWN_MIME_TYPE); } /** * Get all of the matching mime types for this URLConnection object. * The method delegates down to each of the registered MimeHandler(s) and returns a * normalised list of all matching mime types. If no matching mime types are found the returned * Collection will contain the unknownMimeType passed in. * @param url the URL to detect. * @param unknownMimeType. * @return the Collection of matching mime types. If the collection would be empty i.e. no matches then this will * contain the passed in parameter unknownMimeType * @throws MimeException if there are problems such as reading files generated when the MimeHandler(s) * executed. */ public static Collection getMimeTypes(final URLConnection url, final MimeType unknownMimeType) throws MimeException { if(log.isDebugEnabled()) { log.debug("Getting mime types for URL [" + url + "]."); } try { return mimeUtilMimeDetector.getMimeTypes(new BufferedInputStream(url.getInputStream()), unknownMimeType); }catch(Exception e) { throw new MimeException(e); } } /** * Get the native byte order of the OS on which you are running. It will be * either big or little endian. This is used internally for the magic mime * rules mapping. * * @return ByteOrder */ public static ByteOrder getNativeOrder() { return MimeUtil.nativeByteOrder; } /** * Gives you the best match for your requirements. *

* You can pass the accept header from a browser request to this method * along with a comma separated list of possible mime types returned from * say getExtensionMimeTypes(...) and the best match according to the accept * header will be returned. *

*

* The following is typical of what may be specified in an HTTP Accept * header: *

*

* Accept: text/xml, application/xml, application/xhtml+xml, * text/html;q=0.9, text/plain;q=0.8, video/x-mng, image/png, image/jpeg, * image/gif;q=0.2, text/css, */*;q=0.1 *

*

* The quality parameter (q) indicates how well the user agent handles the * MIME type. A value of 1 indicates the MIME type is understood perfectly, * and a value of 0 indicates the MIME type isn't understood at all. *

*

* The reason the image/gif MIME type contains a quality parameter of 0.2, * is to indicate that PNG & JPEG are preferred over GIF if the server is * using content negotiation to deliver either a PNG or a GIF to user * agents. Similarly, the text/html quality parameter has been lowered a * little, to ensure that the XML MIME types are given in preference if * content negotiation is being used to serve an XHTML document. *

* * @param accept * is a comma separated list of mime types you can accept * including QoS parameters. Can pass the Accept: header * directly. * @param canProvide * is a comma separated list of mime types that can be provided * such as that returned from a call to * getExtensionMimeTypes(...) * @return the best matching mime type possible. */ public static MimeType getPreferedMimeType(String accept, final String canProvide) { if (canProvide == null || canProvide.trim().length() == 0) { throw new MimeException( "Must specify at least one mime type that can be provided."); } if (accept == null || accept.trim().length() == 0) { accept = "*/*"; } // If an accept header is passed in then lets remove the Accept part if (accept.indexOf(":") > 0) { accept = accept.substring(accept.indexOf(":") + 1); } // Remove any unwanted spaces from the wanted mime types for instance // text/html; q=0.4 accept = accept.replaceAll(" ", ""); return getBestMatch(accept, getList(canProvide)); } /** * Get the most specific match of the Collection of mime types passed in. * The Collection * @param mimeTypes this should be the Collection of mime types returned * from a getMimeTypes(...) call. * @return the most specific MimeType. If more than one of the mime types in the Collection * have the same value then the first one found with this value in the Collection is returned. */ public static MimeType getMostSpecificMimeType(final Collection mimeTypes) { MimeType mimeType = null; int specificity = 0; for(Iterator it = mimeTypes.iterator(); it.hasNext();) { MimeType mt = (MimeType)it.next(); if(mt.getSpecificity() > specificity) { mimeType = mt; } } return mimeType; } /** * Utility method to get the minor part of a mime type i.e. the bit after * the '/' character * * @param mimeType * you want to get the minor part from * @return sub type of the mime type * @throws MimeException * if you pass in an invalid mime type structure */ public static String getSubType(final String mimeType) throws MimeException { return new MimeType(mimeType).getSubType(); } /** * Check to see if this mime type is one of the types seen during * initialisation or has been added at some later stage using * addKnownMimeType(...) * * @param mimeType * @return true if the mimeType is in the list else false is returned * @see #addKnownMimeType(String mimetype) */ public static boolean isMimeTypeKnown(final MimeType mimeType) { try { Set s = (Set) mimeTypes.get(mimeType.getMediaType()); if (s == null) { return false; } return s.contains(mimeType.getSubType()); } catch (MimeException e) { return false; } } /** * Check to see if this mime type is one of the types seen during * initialisation or has been added at some later stage using * addKnownMimeType(...) * * @param mimeType * @return true if the mimeType is in the list else false is returned * @see #addKnownMimeType(String mimetype) */ public static boolean isMimeTypeKnown(final String mimeType) { return isMimeTypeKnown(new MimeType(mimeType)); } /** * Utility convenience method to check if a particular MimeType instance is actually a TextMimeType. * Used when iterating over a collection of MimeType's to help with casting to enable access * the the TextMimeType methods not available to a standard MimeType. * @param mimeType * @return true if the passed in instance is a TextMimeType * @see MimeType * @see TextMimeType */ public static boolean isTextMimeType(final MimeType mimeType) { return mimeType instanceof TextMimeType; } /** * Remove a previously registered MimeDetector * @param mimeDetector * @return the MimeDetector that was removed from the registry else null. */ public static MimeDetector removeMimeDetector(final MimeDetector mimeDetector) { return mimeUtilMimeDetector.removeMimeDetector(mimeDetector); } /** * Get the quality parameter of this mime type i.e. the q= property. * This method implements a value system similar to that used by the apache server i.e. * if the media type is a * then it's q value is set to 0.01 and if the sub type is * a * then the q value is set to 0.02 unless a specific q * value is specified. If a q property is set it is limited to a max value of 1.0 * * @param mimeType * @return the quality value as a double between 0.0 and 1.0 * @throws MimeException */ public static double getQuality(final String mimeType) throws MimeException { if(mimeType == null || mimeType.trim().length() == 0) { return 0.0; } String [] parts = mimeSplitter.split(mimeType); // Now check to see if a quality indicator was part of the passed in type if (parts.length > 2) { for (int i = 2; i < parts.length; i++) { if (parts[i].trim().startsWith("q=")) { // Get the number part try { // Get the quality factor double d = Double.parseDouble(parts[i].split("=")[1].trim()); return d > 1.0 ? 1.0 : d; } catch (NumberFormatException e) { throw new MimeException( "Invalid Mime quality indicator [" + parts[i].trim() + "]. Must be a valid double between 0 and 1"); } catch (Exception e) { throw new MimeException( "Error parsing Mime quality indicator.", e); } } } } // No quality indicator so always assume its 1 unless a wild card is used if (parts[0].contains("*")) { return 0.01; } else if (parts[1].contains("*")) { return 0.02; } else { // Assume q value of 1 return 1.0; } } // Check each entry in each of the wanted lists against the entries in the // can provide list. // We take into consideration the QoS indicator private static MimeType getBestMatch(final String accept, final List canProvideList) { if (canProvideList.size() == 1) { // If we only have one mime type that can be provided then thats // what we provide even if // the wanted list does not contain this entry or it's the worst // QoS. // This will cover the majority of cases return new MimeType((String) canProvideList.get(0)); } Map wantedMap = normaliseWantedMap(accept, canProvideList); MimeType bestMatch = null; double qos = 0.0; Iterator it = wantedMap.keySet().iterator(); while (it.hasNext()) { List wantedList = (List) wantedMap.get(it.next()); Iterator it2 = wantedList.iterator(); while (it2.hasNext()) { String mimeType = (String) it2.next(); double q = getMimeQuality(mimeType); String majorComponent = getMediaType(mimeType); String minorComponent = getSubType(mimeType); if (q > qos) { qos = q; bestMatch = new MimeType(majorComponent + "/" + minorComponent); } } } // Gone through all the wanted list and found the best match possible return bestMatch; } // Turn a comma separated string into a list private static List getList(final String options) { List list = new ArrayList(); String[] array = options.split(","); for (int i = 0; i < array.length; i++) { list.add(array[i].trim()); } return list; } // Turn a comma separated string of accepted mime types into a Map // based on the list of mime types that can be provided private static Map normaliseWantedMap(final String accept, final List canProvide) { Map map = new LinkedHashMap(); String[] array = accept.split(","); for (int i = 0; i < array.length; i++) { String mimeType = array[i].trim(); String major = getMediaType(mimeType); String minor = getSubType(mimeType); double qos = getMimeQuality(mimeType); if (major.contains("*")) { // All canProvide types are acceptable with the qos defined OR // 0.01 if not defined Iterator it = canProvide.iterator(); while (it.hasNext()) { String mt = (String) it.next(); List list = (List) map.get(MimeUtil.getMediaType(mt)); if (list == null) { list = new ArrayList(); } list.add(mt + ";q=" + qos); map.put(MimeUtil.getMediaType(mt), list); } } else if (minor.contains("*")) { Iterator it = canProvide.iterator(); while (it.hasNext()) { String mt = (String) it.next(); if (getMediaType(mt).equals(major)) { List list = (List) map.get(major); if (list == null) { list = new ArrayList(); } list.add(major + "/" + getSubType(mt) + ";q=" + qos); map.put(major, list); } } } else { if (canProvide.contains(major + "/" + minor)) { List list = (List) map.get(major); if (list == null) { list = new ArrayList(); } list.add(major + "/" + minor + ";q=" + qos); map.put(major, list); } } } return map; } } /** *

* All methods in this class that return a Collection object actually return a {@link MimeTypeHashSet} that implements both the {@link Set} and {@link Collection} * interfaces. *

* @author Steven McArdle * */ class MimeUtilMimeDetectorRegistry { private static Log log = LogFactory.getLog(MimeUtilMimeDetectorRegistry.class); private Map mimeDetectors = new TreeMap(); MimeDetector addMimeDetector(final MimeDetector mimeDetector) { if(mimeDetectors.containsKey(mimeDetector.getName())) { log.error("MimeDetector [" + mimeDetector.getName() + "] will not be registered as a MimeDetector with this name is already registered."); return (MimeDetector)mimeDetectors.get(mimeDetector.getName()); } if(log.isDebugEnabled()) { log.debug("Registering MimeDetect with name [" + mimeDetector.getName() + "] and description [" + mimeDetector.getDescription() + "]"); } return (MimeDetector)mimeDetectors.put(mimeDetector.getName(), mimeDetector); } MimeDetector getMimeDetector(final String name) { return (MimeDetector)mimeDetectors.get(name); } Collection getMimeTypes(final byte [] data, final MimeType unknownMimeType) throws MimeException { Collection mimeTypes = new MimeTypeHashSet(); if(data != null) { for(Iterator it = mimeDetectors.values().iterator();it.hasNext();) { try { MimeDetector md = (MimeDetector)it.next(); mimeTypes.addAll(md.getMimeTypes(data)); }catch(UnsupportedOperationException usoe) { // We ignore this as it indicates that this MimeDetector does not support // Getting mime types from files }catch(Exception e) { log.error(e, e); } } } if(mimeTypes.isEmpty()) { mimeTypes.add(unknownMimeType); } if(log.isDebugEnabled()) { log.debug("Retrieved mime types [" + mimeTypes.toString() + "]"); } return mimeTypes; } Collection getMimeTypes(final File file, final MimeType unknownMimeType) throws MimeException { Collection mimeTypes = new MimeTypeHashSet(); for(Iterator it = mimeDetectors.values().iterator();it.hasNext();) { try { MimeDetector md = (MimeDetector)it.next(); mimeTypes.addAll(md.getMimeTypes(file)); }catch(UnsupportedOperationException usoe) { // We ignore this as it indicates that this MimeDetector does not support // Getting mime types from files }catch(Exception e) { log.error(e, e); } } if(mimeTypes.isEmpty()) { mimeTypes.add(unknownMimeType); } if(log.isDebugEnabled()) { log.debug("Retrieved mime types [" + mimeTypes.toString() + "]"); } return mimeTypes; } Collection getMimeTypes(final InputStream in, final MimeType unknownMimeType) throws MimeException { Collection mimeTypes = new MimeTypeHashSet(); for(Iterator it = mimeDetectors.values().iterator();it.hasNext();) { try { MimeDetector md = (MimeDetector)it.next(); mimeTypes.addAll(md.getMimeTypes(in)); }catch(UnsupportedOperationException usoe) { // We ignore this as it indicates that this MimeDetector does not support // Getting mime types from streams }catch(Exception e) { log.error(e, e); } } if(mimeTypes.isEmpty()) { mimeTypes.add(unknownMimeType); } if(log.isDebugEnabled()) { log.debug("Retrieved mime types [" + mimeTypes.toString() + "]"); } return mimeTypes; } Collection getMimeTypes(final String fileName, final MimeType unknownMimeType) throws MimeException { Collection mimeTypes = new MimeTypeHashSet(); for(Iterator it = mimeDetectors.values().iterator();it.hasNext();) { try { MimeDetector md = (MimeDetector)it.next(); mimeTypes.addAll(md.getMimeTypes(fileName)); }catch(UnsupportedOperationException usoe) { // We ignore this as it indicates that this MimeDetector does not support // Getting mime types from file names }catch(Exception e) { log.error(e, e); } } if(mimeTypes.isEmpty()) { mimeTypes.add(unknownMimeType); } if(log.isDebugEnabled()) { log.debug("Retrieved mime types [" + mimeTypes.toString() + "]"); } return mimeTypes; } MimeDetector removeMimeDetector(final MimeDetector mimeDetector) { if(mimeDetector == null) { log.error("Cannot remove NULL from MimeDetector registry."); return null; } if(log.isDebugEnabled()) { log.debug("Removing MimeDetector [" + mimeDetector.getName() + "] from registry."); } return (MimeDetector)mimeDetectors.remove(mimeDetector.getName()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy