MIMEUtil.java
/***************************************************************************
Copyright 2008 Emily Estes
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 net.metanotion.io;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
/** Class to detect the MIME Type of a file.
This code was inspired by the MimeUtil project, available under the Apache 2.0 license at:
http://mime-util.sourceforge.net/
This class differs in several aspects.
First, it uses the Metanotion IO FileSystem framework rather than java.io.File and friends.
Second, it religiously avoids static state and public static methods.
Third, it does not do checking for magic bytes, although this is likely to
change at some point. However, this class will rely on the Metanotion IO Filesystem
framework for that functionality, OR rely on an external InputStream passed in by the caller.
(which could be backported).
This class would likely be gladly scrapped if the MimeUtil project avoided static state, and
rearranged its methods to avoid usage of java.io.File. I have not contacted the maintainers
to see if these changes would interest them, however. This code was needed on a short-term
basis, and so the decision was made to reuse the properties file they have so graciously
put together that maps file extensions to MIME types, and create a class from scratch that
met my requirements.
*/
public final class MIMEUtil {
public static final String UNKNOWN_MIME_TYPE="application/x-unknown-mime-type";
private static final AtomicReference<Properties> staticValues = new AtomicReference<Properties>(null);
private final Properties mimeTypes = new Properties();
private final boolean staticDelegate;
private static void loadDefaults() {
if(staticValues.get() == null) {
final Properties p = new Properties();
try (final java.io.InputStream in =
MIMEUtil.class.getClassLoader().getResourceAsStream("net/metanotion/io/mime-types.properties")) {
p.load(in);
} catch (final IOException ioe) {
throw new RuntimeException(ioe);
}
staticValues.compareAndSet(null, p);
}
}
/** Create an instance of MIMEUtil using the default mapping of file extentions to mime types. */
public MIMEUtil() {
loadDefaults();
staticDelegate = true;
}
/** Create an instance of MIMEUtil using a custom mapping of file extensions to mime types that overrides
the defaults, which will also be loaded.
@param extList The custom mapping.
*/
public MIMEUtil(final Properties extList) { this(extList, true); }
/** Create an instance of MIMEUtil using a custom mapping of file extensions to mime types that overrides
the defaults, which will be optionally loaded.
@param extList The custom mapping.
@param includeDefaults True to inlude the defaults, false otherwise.
*/
public MIMEUtil(final Properties extList, final boolean includeDefaults) {
mimeTypes.putAll(extList);
staticDelegate = includeDefaults;
if(includeDefaults) { loadDefaults(); }
}
/** Lookup the mime type of a file.
@param file The file to guess the mime type.
@return The String representing the mime type.
*/
public String getMIMEType(final TraverseableFile file) {
if(file.exists() && file.isDirectory()) { return "application/directory"; }
return getMIMEType(file.getShortName());
}
/** Guess the mime type of a file from it's filename.
@param filename The filename to guess the mime type from.
@return The String representing the mime type.
*/
public String getMIMEType(final String filename) {
final String ext = getFileExtension(filename.trim()).trim().toLowerCase();
final String ret = mimeTypes.getProperty(ext, (staticDelegate) ? null : UNKNOWN_MIME_TYPE);
if(ret != null) { return ret; }
return staticValues.get().getProperty(ext, UNKNOWN_MIME_TYPE);
}
private static final String MAJOR_DIVIDER = "/";
/** Get the major type of a mime type string.
@param mimeType The mime type string to split.
@return The major type of the mime type.
*/
public String getType(final String mimeType) {
final int offset = mimeType.indexOf(MAJOR_DIVIDER);
if(offset == -1) { return mimeType; }
return mimeType.substring(0, offset);
}
/** Get the "specific" sub type of a mime type string.
@param mimeType The mime type string to split.
@return The sub type of the mime type.
*/
public String getSubtype(final String mimeType) {
final int offset = mimeType.indexOf(MAJOR_DIVIDER);
if(offset == -1) { return mimeType; }
return mimeType.substring(offset+1);
}
private static final String FILE_EXTENSION_SEPARATOR = ".";
private String getFileExtension(final String fileName) {
if(fileName == null || fileName.lastIndexOf(FILE_EXTENSION_SEPARATOR) < 0) { return ""; }
return fileName.substring(fileName.lastIndexOf(FILE_EXTENSION_SEPARATOR) + 1);
}
}