/* * 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.Serializable; import java.util.regex.Pattern; import eu.medsea.mimeutil.MimeException; /** * This class represents a simple MimeType object. A mime type is made up of * two parts <code><media type>/<sub type></code>. * The media type can be something like <code>application</code> or <code>text</code> and * the the sub type can be something like <code>xml</code> or <code>plain</code>. * * Both the media type and sub type can also be the wild card <code>*</code> such as * <code>*/*</code> and <code>text/*</code>. Note, if the media type is the wild card * then the sub type must also be a wild card. * * @author Steven McArdle * */ public class MimeType implements Comparable, Serializable { private static final long serialVersionUID = -1324243127744494894L; private static final Pattern mimeSplitter = Pattern.compile ("[/;]++" ); protected String mediaType = "*"; protected String subType = "*"; //This is a estimate of how specific this mime type is private int specificity = 1; /** * Construct a MimeType from another MimeType instance * @param mimeType */ public MimeType(final MimeType mimeType) { this.mediaType = mimeType.mediaType; this.subType = mimeType.subType; this.specificity = mimeType.specificity; } /** * Construct a mime type from a String such as <code>text/plain</code>. * It tries to ensure that the mime type pattern passed in is correctly * formatted. * * @param mimeType * @throws MimeException */ public MimeType(final String mimeType) throws MimeException { if(mimeType == null || mimeType.trim().length() == 0){ throw new MimeException("Invalid MimeType [" + mimeType + "]"); } String [] parts = mimeSplitter.split(mimeType.trim()); if(parts.length > 0) { // Treat as the mediaType mediaType = getValidMediaType(parts[0]); } if(parts.length > 1) { subType = getValidSubType(parts[1]); } } /** * Get the media type part of the mime type. * @return media type */ public String getMediaType() { return mediaType; } /** * Get the sub type of the mime type * @return sub type */ public String getSubType() { return subType; } /** * See if this MimeType is the same as the passed in mime type string * @param mimeType as a String * @return true if the MimeType passed in has the same media and sub types, else returns false. */ private boolean match(final String mimeType) { return toString().equals(mimeType); } /** * Get the hashCode of this MimeType. * The hashCode is calculate as (31 * mediaType.hashCode()) + subType.hashCode() * @return calculated hashCode * @see Object#hashCode() */ public int hashCode() { return (31 * mediaType.hashCode()) + subType.hashCode(); } /** * Overrides the equals method of <code>java.lang.Object</code>. This is able to compare * against another MimeType instance or a string representation of a mime type. * @return true if the types match else false. * @see Object#equals(Object o) */ public boolean equals(Object o) { if(o instanceof MimeType) { if(this.mediaType.equals(((MimeType)o).mediaType) && this.subType.equals(((MimeType)o).subType)) { return true; } } else if(o instanceof String) { return match((String)o); } return false; } /** * Overrides the toString method of <code>java.lang.Object</code>. * @return String representation i.e. <code><media type>/<sub type>. * @see Object#toString() */ public String toString() { return mediaType + "/" + subType; } /** * This indicates how specific the mime types is i.e. how good a match * the mime type is when returned from the getMimeTypes(...) calls. * <p> * This is calculated by the number of times this MimeType would be returned * if the Collection was not normalised. The higher the count the more MimeDetectors * have matched this type. As this can be a false positive for types such as application/octect-stream * and text/plain where they would be returned by multiple MimeDetector(s). These types are referred to as root * mime types where ALL mime types derive from application/octet-stream and all text/* types derive from text/plan * so in these cases we set the specificity to 0 no matter how many times they match. This ensures they are regarded * as the least specific in the returned Collection. * </p> * @return how specific this MimeType is according to the rest of the MimeTypes in a Collection. */ public int getSpecificity() { return specificity; } /* * Set the value of the specificity. The higher the value the more specific a MimeType is. */ void setSpecificity(final int specificity) { this.specificity = specificity; } /* * Check the media type at least looks valid. * TODO: Enforce more rigorous checking of valid media types. */ private String getValidMediaType(final String mediaType) { if(mediaType == null || mediaType.trim().length() == 0) { return "*"; } return mediaType; } /* * Check the sub type at least looks valid. * TODO: Enforce more rigorous checking of valid sub types. */ private String getValidSubType(final String subType) { if(subType == null || subType.trim().length() == 0 || "*".equals(mediaType)) { // If the mediaType is a wild card then the sub type must also be a wild card return "*"; } return subType; } /** * Allows us to use MimeType(s) in Sortable Set's such as the TreeSet. */ public int compareTo(Object arg0) { if(arg0 instanceof MimeType) { return toString().compareTo(((MimeType)arg0).toString()); } return 0; } }