001    package org.apache.fulcrum.mimetype;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.io.File;
023    import java.io.IOException;
024    import java.util.Locale;
025    
026    import org.apache.avalon.framework.activity.Initializable;
027    import org.apache.avalon.framework.configuration.Configurable;
028    import org.apache.avalon.framework.configuration.Configuration;
029    import org.apache.avalon.framework.context.Context;
030    import org.apache.avalon.framework.context.ContextException;
031    import org.apache.avalon.framework.context.Contextualizable;
032    import org.apache.avalon.framework.logger.AbstractLogEnabled;
033    import org.apache.fulcrum.mimetype.util.CharSetMap;
034    import org.apache.fulcrum.mimetype.util.MimeType;
035    import org.apache.fulcrum.mimetype.util.MimeTypeMap;
036    /**
037     * The MimeType Service maintains mappings between MIME types and
038     * the corresponding file name extensions, and between locales and
039     * character encodings.
040     *
041     * <p>The MIME type mappings can be defined in MIME type files
042     * located in user's home directory, Java home directory or
043     * the current class jar. The default mapping file is defined
044     * with the mime.type.file property. In addition, the service maintains
045     * a set of most common mappings.
046     *
047     * <p>The charset mappings can be defined in property files
048     * located in user's home directory, Java home directory or
049     * the current class jar. The default mapping file is defined
050     * with the charset.file property. In addition, the service maintains
051     * a set of most common mappings.
052     *
053     * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
054     * @author <a href="mailto:mcconnell@apache.org">Stephen McConnell</a>
055     * @version $Id: DefaultMimeTypeService.java 813677 2009-09-11 06:48:11Z tv $
056     *
057     * @avalon.component name="mimetype" lifestyle="singleton"
058     * @avalon.service type="org.apache.fulcrum.mimetype.MimeTypeService"
059     */
060    public class DefaultMimeTypeService
061        extends AbstractLogEnabled
062        implements MimeTypeService, Configurable, Initializable, Contextualizable
063    {
064        private String applicationRoot;
065        /**
066         * The MIME type file property.
067         */
068        public static final String MIME_TYPES = "mimetypes";
069        /**
070         * The charset file property.
071         */
072        public static final String CHARSETS = "charsets";
073        // path to a mimetypes-file_extension mapping file
074        private String mimetypePath;
075        // path to a charset-language mapping file
076        private String charsetPath;
077        /**
078         * The MIME type map used by the service.
079         */
080        private MimeTypeMap mimeTypeMap;
081        /**
082         * The charset map used by the service.
083         */
084        private CharSetMap charSetMap;
085    
086        /**
087         * Constructs a new service.
088         */
089        public DefaultMimeTypeService()
090        {
091            // empty
092        }
093        /**
094         * Sets a MIME content type mapping to extensions to the map.
095         * The extension is specified by a MIME type name followed
096         * by a list of file name extensions separated by a whitespace.
097         *
098         * @param spec a MIME type extension specification to add.
099         */
100        public void setContentType(String spec)
101        {
102            mimeTypeMap.setContentType(spec);
103        }
104        /**
105         * Gets the MIME content type for a file as a string.
106         *
107         * @param file The file to look up a MIME type mapping for.
108         * @return the MIME type string.
109         */
110        public String getContentType(File file)
111        {
112            return mimeTypeMap.getContentType(file);
113        }
114        /**
115         * Gets the MIME content type for a named file as a string.
116         *
117         * @param fileName The name of the file to look up a MIME type
118         * mapping for.
119         * @return the MIME type string.
120         */
121        public String getContentType(String fileName)
122        {
123            return mimeTypeMap.getContentType(fileName);
124        }
125        /**
126         * Gets the MIME content type for a file name extension as a string.
127         *
128         * @param fileName The name of the file to look up a MIME type
129         * mapping for.
130         * @param def The default MIME type to use if no mapping exists.
131         * @return the MIME type string.
132         */
133        public String getContentType(String fileName, String def)
134        {
135            return mimeTypeMap.getContentType(fileName, def);
136        }
137        /**
138         * Gets the MIME content type for a file.
139         *
140         * @param file the file.
141         * @return the MIME type.
142         */
143        public MimeType getMimeContentType(File file)
144        {
145            return mimeTypeMap.getMimeContentType(file);
146        }
147        /**
148         * Gets the MIME content type for a named file.
149         *
150         * @param name the name of the file.
151         * @return the MIME type.
152         */
153        public MimeType getMimeContentType(String name)
154        {
155            return mimeTypeMap.getMimeContentType(name);
156        }
157        /**
158         * Gets the MIME content type for a file name extension.
159         *
160         * @param ext the file name extension.
161         * @param def the default type if none is found.
162         * @return the MIME type.
163         */
164        public MimeType getMimeContentType(String ext, String def)
165        {
166            return mimeTypeMap.getMimeContentType(ext, def);
167        }
168        /**
169         * Gets the default file name extension for a MIME type.
170         * Note that the mappers are called in the reverse order.
171         *
172         * @param type the MIME type as a string.
173         * @return the file name extension or null.
174         */
175        public String getDefaultExtension(String type)
176        {
177            return mimeTypeMap.getDefaultExtension(type);
178        }
179        /**
180         * Gets the default file name extension for a MIME type.
181         * Note that the mappers are called in the reverse order.
182         *
183         * @param mime the MIME type.
184         * @return the file name extension or null.
185         */
186        public String getDefaultExtension(MimeType mime)
187        {
188            return mimeTypeMap.getDefaultExtension(mime);
189        }
190        /**
191         * Sets a locale-charset mapping.
192         *
193         * @param key the key for the charset.
194         * @param charset the corresponding charset.
195         */
196        public void setCharSet(String key, String charset)
197        {
198            charSetMap.setCharSet(key, charset);
199        }
200        /**
201         * Gets the charset for a locale. First a locale specific charset
202         * is searched for, then a country specific one and lastly a language
203         * specific one. If none is found, the default charset is returned.
204         *
205         * @param locale the locale.
206         * @return the charset.
207         */
208        public String getCharSet(Locale locale)
209        {
210            return charSetMap.getCharSet(locale);
211        }
212        /**
213         * Gets the charset for a locale with a variant. The search
214         * is performed in the following order:
215         * "lang"_"country"_"variant"="charset",
216         * _"counry"_"variant"="charset",
217         * "lang"__"variant"="charset",
218         * __"variant"="charset",
219         * "lang"_"country"="charset",
220         * _"country"="charset",
221         * "lang"="charset".
222         * If nothing of the above is found, the default charset is returned.
223         *
224         * @param locale the locale.
225         * @param variant a variant field.
226         * @return the charset.
227         */
228        public String getCharSet(Locale locale, String variant)
229        {
230            return charSetMap.getCharSet(locale, variant);
231        }
232        /**
233         * Gets the charset for a specified key.
234         *
235         * @param key the key for the charset.
236         * @return the found charset or the default one.
237         */
238        public String getCharSet(String key)
239        {
240            return charSetMap.getCharSet(key);
241        }
242        /**
243         * Gets the charset for a specified key.
244         *
245         * @param key the key for the charset.
246         * @param def the default charset if none is found.
247         * @return the found charset or the given default.
248         */
249        public String getCharSet(String key, String def)
250        {
251            return charSetMap.getCharSet(key, def);
252        }
253    
254        private String getRealPath(String path)
255        {
256            String absolutePath = null;
257            if (applicationRoot == null)
258            {
259                absolutePath = new File(path).getAbsolutePath();
260            }
261            else
262            {
263                absolutePath = new File(applicationRoot, path).getAbsolutePath();
264            }
265            return absolutePath;
266        }
267        // ---------------- Avalon Lifecycle Methods ---------------------
268        /**
269         * Avalon component lifecycle method
270         */
271        public void configure(Configuration conf)
272        {
273            mimetypePath = conf.getAttribute(MIME_TYPES, null);
274            charsetPath = conf.getAttribute(CHARSETS, null);
275            if (mimetypePath != null)
276            {
277                mimetypePath = getRealPath(mimetypePath);
278            }
279            if (charsetPath != null)
280            {
281                charsetPath = getRealPath(charsetPath);
282            }
283        }
284        /**
285         * Avalon component lifecycle method
286         */
287        public void initialize() throws Exception
288        {
289            if (mimetypePath != null)
290            {
291                try
292                {
293                    mimeTypeMap = new MimeTypeMap(mimetypePath);
294                }
295                catch (IOException x)
296                {
297                    throw new Exception(mimetypePath, x);
298                }
299            }
300            else
301            {
302                mimeTypeMap = new MimeTypeMap();
303            }
304            if (charsetPath != null)
305            {
306                try
307                {
308                    charSetMap = new CharSetMap(charsetPath);
309                }
310                catch (IOException x)
311                {
312                    throw new Exception(charsetPath, x);
313                }
314            }
315            else
316            {
317                charSetMap = new CharSetMap();
318            }
319        }
320    
321        /**
322         * @see org.apache.avalon.framework.context.Contextualizable
323         * @avalon.entry key="urn:avalon:home" type="java.io.File"
324         */
325        public void contextualize(Context context) throws ContextException
326        {
327            this.applicationRoot = context.get( "urn:avalon:home" ).toString();
328        }
329    
330    }