View Javadoc
1   /**
2    * This file Copyright (c) 2003-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.cms.beans.config;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.cms.core.HierarchyManager;
38  import info.magnolia.cms.core.ItemType;
39  import info.magnolia.cms.util.NodeDataUtil;
40  import info.magnolia.cms.util.ObservationUtil;
41  import info.magnolia.context.MgnlContext;
42  import info.magnolia.repository.RepositoryConstants;
43  
44  import java.util.Collection;
45  import java.util.Hashtable;
46  import java.util.Iterator;
47  import java.util.Map;
48  
49  import javax.jcr.PathNotFoundException;
50  import javax.jcr.RepositoryException;
51  import javax.jcr.observation.EventIterator;
52  import javax.jcr.observation.EventListener;
53  
54  import org.apache.commons.lang3.StringUtils;
55  import org.slf4j.Logger;
56  import org.slf4j.LoggerFactory;
57  
58  /**
59   * Manages mappings of file extensions with their MIME types and icon.
60   *
61   * @deprecated since 5.4.6. This class will be replaced (see MAGNOLIA-6576).
62   */
63  @Deprecated
64  public class MIMEMapping {
65      private static final Logger log = LoggerFactory.getLogger(MIMEMapping.class);
66  
67      public static final String ICONS_PATH = "/.resources/file-icons/";
68      public static final String DEFAULT_ICON = ICONS_PATH + "general.png";
69      private static final String NODEPATH = "/server/MIMEMapping";
70      public static final String DEFAULT_ICON_STYLE = "icon-file";
71  
72      private static Map<String, MIMEMappingItem> cachedContent = new Hashtable<String, MIMEMappingItem>();
73      public static final String DEFAULT_CHAR_ENCODING = "UTF-8";
74      public static final String DEFAULT_EXTENSION = "html";
75  
76      /**
77       * Used to keep the configuration in memory.
78       */
79      protected static class MIMEMappingItem {
80  
81          protected String ext;
82  
83          protected String mime;
84  
85          protected String icon;
86  
87          protected String iconStyle;
88      }
89  
90  
91      /**
92       * Utility class, don't instantiate.
93       */
94      private MIMEMapping() {
95          // unused
96      }
97  
98      /**
99       * Reads all configured mime mapping (config/server/MIMEMapping).
100      */
101     public static void init() {
102         log.info("Initializing MIMEMapping from {}", NODEPATH);
103         load();
104         registerEventListener();
105     }
106 
107     /**
108      * Reads all configured mime mapping (config/server/MIMEMapping).
109      */
110     public static void load() {
111         MIMEMapping.cachedContent.clear();
112         try {
113             final HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(RepositoryConstants.CONFIG);
114 
115             Collection<Content> mimeList = hm.getContent(NODEPATH).getChildren(ItemType.CONTENTNODE);
116             MIMEMapping.cacheContent(mimeList);
117             log.debug("MIMEMapping loaded from {}", NODEPATH);
118         } catch (PathNotFoundException e) {
119             log.warn("No MIMEMapping info configured at {}", NODEPATH);
120         } catch (RepositoryException e) {
121             log.error("Failed to load MIMEMapping: {}", e.getMessage(), e);
122         }
123     }
124 
125     public static void reload() {
126         log.info("Reloading MIMEMapping from {}", NODEPATH);
127         MIMEMapping.load();
128     }
129 
130     /**
131      * Register an event listener: reload cache configuration when something changes.
132      */
133     private static void registerEventListener() {
134         log.info("Registering event listener for MIMEMapping");
135 
136         ObservationUtil.registerChangeListener(RepositoryConstants.CONFIG, NODEPATH, new EventListener() {
137             @Override
138             public void onEvent(EventIterator iterator) {
139                 // reload everything
140                 reload();
141             }
142         });
143     }
144 
145     /**
146      * Cache all MIME types configured.
147      */
148     private static void cacheContent(Collection<Content> mimeList) {
149         Iterator<Content> iterator = mimeList.iterator();
150         while (iterator.hasNext()) {
151             Content c = iterator.next();
152             try {
153                 MIMEMappingItem item = new MIMEMappingItem();
154                 item.ext = NodeDataUtil.getString(c, "extension", c.getName());
155                 item.mime = c.getNodeData("mime-type").getString();
156                 item.icon = NodeDataUtil.getString(c, "icon");
157                 item.iconStyle = NodeDataUtil.getString(c, "iconStyle");
158 
159                 MIMEMapping.cachedContent.put(item.ext, item);
160             } catch (Exception e) {
161                 log.error("Failed to cache MIMEMapping");
162             }
163         }
164     }
165 
166     /**
167      * Get MIME type String.
168      *
169      * @param key extension for which MIME type is requested
170      * @return MIME type
171      */
172     public static String getMIMEType(String key) {
173         if (StringUtils.isEmpty(key)) {
174             return StringUtils.EMPTY;
175         }
176         // check that the cached content contains the key first to avoid NPE when accessing 'mime'
177         String loweredKey = key.toLowerCase();
178         if (MIMEMapping.cachedContent.containsKey(loweredKey)) {
179             return MIMEMapping.cachedContent.get(loweredKey).mime;
180         }
181 
182         // this is expected by the caller
183         return null;
184 
185     }
186 
187     /**
188      * Returns the mime-type associated with this extension, or the server's default.
189      */
190     public static String getMIMETypeOrDefault(String extension) {
191         String mimeType = getMIMEType(extension);
192 
193         if (StringUtils.isNotEmpty(mimeType)) {
194             return mimeType;
195         }
196 
197         if (StringUtils.isNotEmpty(extension)) {
198             log.info("Cannot find MIME type for extension \"{}\"", extension);
199         }
200 
201         String defaultExtension = ServerConfiguration.getInstance().getDefaultExtension();
202         if (StringUtils.isBlank(defaultExtension)) {
203             defaultExtension = DEFAULT_EXTENSION;
204         }
205         return getMIMEType(defaultExtension);
206     }
207 
208     public static String getContentEncoding(String contentType) {
209         if (contentType != null) {
210             int index = contentType.lastIndexOf(";");
211             if (index > -1) {
212                 String encoding = contentType.substring(index + 1).toLowerCase().trim();
213                 encoding = encoding.replaceAll("charset=", StringUtils.EMPTY);
214                 return encoding;
215             }
216         }
217         return StringUtils.EMPTY;
218     }
219 
220     public static String getContentEncodingOrDefault(String contentType) {
221         final String characterEncoding = getContentEncoding(contentType);
222 
223         return (StringUtils.isEmpty(characterEncoding)) ? DEFAULT_CHAR_ENCODING : characterEncoding;
224     }
225 
226     /**
227      * Returns the icon used for rendering this type.
228      *
229      * @return the icon name
230      */
231     public static String getMIMETypeIcon(String extension) {
232         MIMEMappingItem item = MIMEMapping.cachedContent.get(extension.toLowerCase());
233         if (item != null) {
234             return StringUtils.defaultIfEmpty(item.icon, DEFAULT_ICON);
235         }
236 
237         return DEFAULT_ICON;
238 
239     }
240 
241     /**
242      * Returns the icon css style name.
243      *
244      * @return icon css style name.
245      */
246     public static String getMIMETypeIconStyle(String mimeType) {
247         String genericMimeType = StringUtils.substringBefore(mimeType, "/");
248         MIMEMappingItem mimeMappingItem = null;
249         for (MIMEMappingItem item : cachedContent.values()) {
250             if (item.mime != null && item.mime.equals(mimeType) && StringUtils.isNotBlank(item.iconStyle)) {
251                 mimeMappingItem = item;
252                 break;
253             }
254             if (item.mime != null && item.mime.equals(genericMimeType) && StringUtils.isNotBlank(item.iconStyle)) {
255                 mimeMappingItem = item;
256             }
257         }
258         if (mimeMappingItem != null && StringUtils.isNotBlank(mimeMappingItem.iconStyle)) {
259             return mimeMappingItem.iconStyle;
260         }
261         return DEFAULT_ICON_STYLE;
262     }
263 }