View Javadoc

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>&lt;media type&gt;/&lt;sub type&gt;</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>*&#47;*</code> and <code>text&#47;*</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>&lt;media type&gt;/&lt;sub type&gt;.
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 }