1 /* 2 * Copyright 2002-2014 the original author or authors. 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 17 package org.springframework.mail.javamail; 18 19 import java.io.File; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import javax.activation.FileTypeMap; 23 import javax.activation.MimetypesFileTypeMap; 24 25 import org.springframework.beans.factory.InitializingBean; 26 import org.springframework.core.io.ClassPathResource; 27 import org.springframework.core.io.Resource; 28 29 /** 30 * Spring-configurable {@code FileTypeMap} implementation that will read 31 * MIME type to file extension mappings from a standard JavaMail MIME type 32 * mapping file, using a standard {@code MimetypesFileTypeMap} underneath. 33 * 34 * <p>The mapping file should be in the following format, as specified by the 35 * Java Activation Framework: 36 * 37 * <pre class="code"> 38 * # map text/html to .htm and .html files 39 * text/html html htm HTML HTM</pre> 40 * 41 * Lines starting with {@code #} are treated as comments and are ignored. All 42 * other lines are treated as mappings. Each mapping line should contain the MIME 43 * type as the first entry and then each file extension to map to that MIME type 44 * as subsequent entries. Each entry is separated by spaces or tabs. 45 * 46 * <p>By default, the mappings in the {@code mime.types} file located in the 47 * same package as this class are used, which cover many common file extensions 48 * (in contrast to the out-of-the-box mappings in {@code activation.jar}). 49 * This can be overridden using the {@code mappingLocation} property. 50 * 51 * <p>Additional mappings can be added via the {@code mappings} bean property, 52 * as lines that follow the {@code mime.types} file format. 53 * 54 * @author Rob Harrop 55 * @author Juergen Hoeller 56 * @since 1.2 57 * @see #setMappingLocation 58 * @see #setMappings 59 * @see javax.activation.MimetypesFileTypeMap 60 */ 61 public class ConfigurableMimeFileTypeMap extends FileTypeMap implements InitializingBean { 62 63 /** 64 * The {@code Resource} to load the mapping file from. 65 */ 66 private Resource mappingLocation = new ClassPathResource("mime.types", getClass()); 67 68 /** 69 * Used to configure additional mappings. 70 */ 71 private String[] mappings; 72 73 /** 74 * The delegate FileTypeMap, compiled from the mappings in the mapping file 75 * and the entries in the {@code mappings} property. 76 */ 77 private FileTypeMap fileTypeMap; 78 79 80 /** 81 * Specify the {@code Resource} from which mappings are loaded. 82 * <p>Needs to follow the {@code mime.types} file format, as specified 83 * by the Java Activation Framework, containing lines such as:<br> 84 * {@code text/html html htm HTML HTM} 85 */ 86 public void setMappingLocation(Resource mappingLocation) { 87 this.mappingLocation = mappingLocation; 88 } 89 90 /** 91 * Specify additional MIME type mappings as lines that follow the 92 * {@code mime.types} file format, as specified by the 93 * Java Activation Framework, for example:<br> 94 * {@code text/html html htm HTML HTM} 95 */ 96 public void setMappings(String... mappings) { 97 this.mappings = mappings; 98 } 99 100 101 /** 102 * Creates the final merged mapping set. 103 */ 104 @Override 105 public void afterPropertiesSet() { 106 getFileTypeMap(); 107 } 108 109 /** 110 * Return the delegate FileTypeMap, compiled from the mappings in the mapping file 111 * and the entries in the {@code mappings} property. 112 * @see #setMappingLocation 113 * @see #setMappings 114 * @see #createFileTypeMap 115 */ 116 protected final FileTypeMap getFileTypeMap() { 117 if (this.fileTypeMap == null) { 118 try { 119 this.fileTypeMap = createFileTypeMap(this.mappingLocation, this.mappings); 120 } 121 catch (IOException ex) { 122 throw new IllegalStateException( 123 "Could not load specified MIME type mapping file: " + this.mappingLocation, ex); 124 } 125 } 126 return this.fileTypeMap; 127 } 128 129 /** 130 * Compile a {@link FileTypeMap} from the mappings in the given mapping file 131 * and the given mapping entries. 132 * <p>The default implementation creates an Activation Framework {@link MimetypesFileTypeMap}, 133 * passing in an InputStream from the mapping resource (if any) and registering 134 * the mapping lines programmatically. 135 * @param mappingLocation a {@code mime.types} mapping resource (can be {@code null}) 136 * @param mappings MIME type mapping lines (can be {@code null}) 137 * @return the compiled FileTypeMap 138 * @throws IOException if resource access failed 139 * @see javax.activation.MimetypesFileTypeMap#MimetypesFileTypeMap(java.io.InputStream) 140 * @see javax.activation.MimetypesFileTypeMap#addMimeTypes(String) 141 */ 142 protected FileTypeMap createFileTypeMap(Resource mappingLocation, String[] mappings) throws IOException { 143 MimetypesFileTypeMap fileTypeMap = null; 144 if (mappingLocation != null) { 145 InputStream is = mappingLocation.getInputStream(); 146 try { 147 fileTypeMap = new MimetypesFileTypeMap(is); 148 } 149 finally { 150 is.close(); 151 } 152 } 153 else { 154 fileTypeMap = new MimetypesFileTypeMap(); 155 } 156 if (mappings != null) { 157 for (String mapping : mappings) { 158 fileTypeMap.addMimeTypes(mapping); 159 } 160 } 161 return fileTypeMap; 162 } 163 164 165 /** 166 * Delegates to the underlying FileTypeMap. 167 * @see #getFileTypeMap() 168 */ 169 @Override 170 public String getContentType(File file) { 171 return getFileTypeMap().getContentType(file); 172 } 173 174 /** 175 * Delegates to the underlying FileTypeMap. 176 * @see #getFileTypeMap() 177 */ 178 @Override 179 public String getContentType(String fileName) { 180 return getFileTypeMap().getContentType(fileName); 181 } 182 183 }