1 /* 2 * Copyright 2007-2009 Medsea Business Solutions S.L. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package eu.medsea.mimeutil; 17 18 import java.io.Serializable; 19 import java.util.regex.Pattern; 20 21 import eu.medsea.mimeutil.MimeException; 22 23 /** 24 * This class represents a simple MimeType object. A mime type is made up of 25 * two parts <code><media type>/<sub type></code>. 26 * The media type can be something like <code>application</code> or <code>text</code> and 27 * the the sub type can be something like <code>xml</code> or <code>plain</code>. 28 * 29 * Both the media type and sub type can also be the wild card <code>*</code> such as 30 * <code>*/*</code> and <code>text/*</code>. Note, if the media type is the wild card 31 * then the sub type must also be a wild card. 32 * 33 * @author Steven McArdle 34 * 35 */ 36 public class MimeType implements Comparable, Serializable { 37 38 private static final long serialVersionUID = -1324243127744494894L; 39 40 private static final Pattern mimeSplitter = Pattern.compile ("[/;]++" ); 41 42 protected String mediaType = "*"; 43 protected String subType = "*"; 44 45 //This is a estimate of how specific this mime type is 46 private int specificity = 1; 47 48 /** 49 * Construct a MimeType from another MimeType instance 50 * @param mimeType 51 */ 52 public MimeType(final MimeType mimeType) { 53 this.mediaType = mimeType.mediaType; 54 this.subType = mimeType.subType; 55 this.specificity = mimeType.specificity; 56 } 57 58 /** 59 * Construct a mime type from a String such as <code>text/plain</code>. 60 * It tries to ensure that the mime type pattern passed in is correctly 61 * formatted. 62 * 63 * @param mimeType 64 * @throws MimeException 65 */ 66 public MimeType(final String mimeType) throws MimeException { 67 if(mimeType == null || mimeType.trim().length() == 0){ 68 throw new MimeException("Invalid MimeType [" + mimeType + "]"); 69 } 70 String [] parts = mimeSplitter.split(mimeType.trim()); 71 72 if(parts.length > 0) { 73 // Treat as the mediaType 74 mediaType = getValidMediaType(parts[0]); 75 } if(parts.length > 1) { 76 subType = getValidSubType(parts[1]); 77 } 78 } 79 80 /** 81 * Get the media type part of the mime type. 82 * @return media type 83 */ 84 public String getMediaType() { 85 return mediaType; 86 } 87 88 /** 89 * Get the sub type of the mime type 90 * @return sub type 91 */ 92 public String getSubType() { 93 return subType; 94 } 95 96 97 /** 98 * See if this MimeType is the same as the passed in mime type string 99 * @param mimeType as a String 100 * @return true if the MimeType passed in has the same media and sub types, else returns false. 101 */ 102 private boolean match(final String mimeType) { 103 return toString().equals(mimeType); 104 } 105 106 /** 107 * Get the hashCode of this MimeType. 108 * The hashCode is calculate as (31 * mediaType.hashCode()) + subType.hashCode() 109 * @return calculated hashCode 110 * @see Object#hashCode() 111 */ 112 public int hashCode() { 113 return (31 * mediaType.hashCode()) + subType.hashCode(); 114 } 115 116 /** 117 * Overrides the equals method of <code>java.lang.Object</code>. This is able to compare 118 * against another MimeType instance or a string representation of a mime type. 119 * @return true if the types match else false. 120 * @see Object#equals(Object o) 121 */ 122 public boolean equals(Object o) { 123 if(o instanceof MimeType) { 124 if(this.mediaType.equals(((MimeType)o).mediaType) && this.subType.equals(((MimeType)o).subType)) { 125 return true; 126 } 127 } else if(o instanceof String) { 128 return match((String)o); 129 } 130 return false; 131 } 132 133 /** 134 * Overrides the toString method of <code>java.lang.Object</code>. 135 * @return String representation i.e. <code><media type>/<sub type>. 136 * @see Object#toString() 137 */ 138 public String toString() { 139 return mediaType + "/" + subType; 140 } 141 142 /** 143 * This indicates how specific the mime types is i.e. how good a match 144 * the mime type is when returned from the getMimeTypes(...) calls. 145 * <p> 146 * This is calculated by the number of times this MimeType would be returned 147 * if the Collection was not normalised. The higher the count the more MimeDetectors 148 * have matched this type. As this can be a false positive for types such as application/octect-stream 149 * and text/plain where they would be returned by multiple MimeDetector(s). These types are referred to as root 150 * mime types where ALL mime types derive from application/octet-stream and all text/* types derive from text/plan 151 * so in these cases we set the specificity to 0 no matter how many times they match. This ensures they are regarded 152 * as the least specific in the returned Collection. 153 * </p> 154 * @return how specific this MimeType is according to the rest of the MimeTypes in a Collection. 155 */ 156 public int getSpecificity() { 157 return specificity; 158 } 159 160 /* 161 * Set the value of the specificity. The higher the value the more specific a MimeType is. 162 */ 163 void setSpecificity(final int specificity) { 164 this.specificity = specificity; 165 } 166 167 /* 168 * Check the media type at least looks valid. 169 * TODO: Enforce more rigorous checking of valid media types. 170 */ 171 private String getValidMediaType(final String mediaType) { 172 if(mediaType == null || mediaType.trim().length() == 0) { 173 return "*"; 174 } 175 return mediaType; 176 } 177 178 /* 179 * Check the sub type at least looks valid. 180 * TODO: Enforce more rigorous checking of valid sub types. 181 */ 182 private String getValidSubType(final String subType) { 183 if(subType == null || subType.trim().length() == 0 || "*".equals(mediaType)) { 184 // If the mediaType is a wild card then the sub type must also be a wild card 185 return "*"; 186 } 187 return subType; 188 } 189 190 /** 191 * Allows us to use MimeType(s) in Sortable Set's such as the TreeSet. 192 */ 193 public int compareTo(Object arg0) { 194 if(arg0 instanceof MimeType) { 195 return toString().compareTo(((MimeType)arg0).toString()); 196 } 197 return 0; 198 } 199 }