1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
60
61 public class MIMEMapping {
62 private static final Logger log = LoggerFactory.getLogger(MIMEMapping.class);
63
64 public static final String ICONS_PATH = "/.resources/file-icons/";
65 public static final String DEFAULT_ICON = ICONS_PATH + "general.png";
66 private static final String NODEPATH = "/server/MIMEMapping";
67 public static final String DEFAULT_ICON_STYLE = "icon-file";
68
69 private static Map<String, MIMEMappingItem> cachedContent = new Hashtable<String, MIMEMappingItem>();
70 public static final String DEFAULT_CHAR_ENCODING = "UTF-8";
71 public static final String DEFAULT_EXTENSION = "html";
72
73
74
75
76 protected static class MIMEMappingItem {
77
78 protected String ext;
79
80 protected String mime;
81
82 protected String icon;
83
84 protected String iconStyle;
85 }
86
87
88
89
90
91 private MIMEMapping() {
92
93 }
94
95
96
97
98 public static void init() {
99 log.info("Initializing MIMEMapping from {}", NODEPATH);
100 load();
101 registerEventListener();
102 }
103
104
105
106
107 public static void load() {
108 MIMEMapping.cachedContent.clear();
109 try {
110 final HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(RepositoryConstants.CONFIG);
111
112 Collection<Content> mimeList = hm.getContent(NODEPATH).getChildren(ItemType.CONTENTNODE);
113 MIMEMapping.cacheContent(mimeList);
114 log.debug("MIMEMapping loaded from {}", NODEPATH);
115 } catch (PathNotFoundException e) {
116 log.warn("No MIMEMapping info configured at {}", NODEPATH);
117 }catch (RepositoryException e) {
118 log.error("Failed to load MIMEMapping: {}", e.getMessage(), e);
119 }
120 }
121
122 public static void reload() {
123 log.info("Reloading MIMEMapping from {}", NODEPATH);
124 MIMEMapping.load();
125 }
126
127
128
129
130 private static void registerEventListener() {
131 log.info("Registering event listener for MIMEMapping");
132
133 ObservationUtil.registerChangeListener(RepositoryConstants.CONFIG, NODEPATH, new EventListener() {
134 @Override
135 public void onEvent(EventIterator iterator) {
136
137 reload();
138 }
139 });
140 }
141
142
143
144
145 private static void cacheContent(Collection<Content> mimeList) {
146 Iterator<Content> iterator = mimeList.iterator();
147 while (iterator.hasNext()) {
148 Content c = iterator.next();
149 try {
150 MIMEMappingItem item = new MIMEMappingItem();
151 item.ext = NodeDataUtil.getString(c, "extension", c.getName());
152 item.mime = c.getNodeData("mime-type").getString();
153 item.icon = NodeDataUtil.getString(c, "icon");
154 item.iconStyle = NodeDataUtil.getString(c, "iconStyle");
155
156 MIMEMapping.cachedContent.put(item.ext, item);
157 }
158 catch (Exception e) {
159 log.error("Failed to cache MIMEMapping");
160 }
161 }
162 }
163
164
165
166
167
168
169 public static String getMIMEType(String key) {
170 if (StringUtils.isEmpty(key)) {
171 return StringUtils.EMPTY;
172 }
173
174 String loweredKey = key.toLowerCase();
175 if (MIMEMapping.cachedContent.containsKey(loweredKey)) {
176 return MIMEMapping.cachedContent.get(loweredKey).mime;
177 }
178
179
180 return null;
181
182 }
183
184
185
186
187 public static String getMIMETypeOrDefault(String extension) {
188 String mimeType = getMIMEType(extension);
189
190 if (StringUtils.isNotEmpty(mimeType)) {
191 return mimeType;
192 }
193
194 if (StringUtils.isNotEmpty(extension)) {
195 log.info("Cannot find MIME type for extension \"{}\"", extension);
196 }
197
198 String defaultExtension = ServerConfiguration.getInstance().getDefaultExtension();
199 if (StringUtils.isBlank(defaultExtension)) {
200 defaultExtension = DEFAULT_EXTENSION;
201 }
202 return getMIMEType(defaultExtension);
203 }
204
205 public static String getContentEncoding(String contentType) {
206 if (contentType != null) {
207 int index = contentType.lastIndexOf(";");
208 if (index > -1) {
209 String encoding = contentType.substring(index + 1).toLowerCase().trim();
210 encoding = encoding.replaceAll("charset=", StringUtils.EMPTY);
211 return encoding;
212 }
213 }
214 return StringUtils.EMPTY;
215 }
216
217 public static String getContentEncodingOrDefault(String contentType) {
218 final String characterEncoding = getContentEncoding(contentType);
219
220 return (StringUtils.isEmpty(characterEncoding)) ? DEFAULT_CHAR_ENCODING : characterEncoding;
221 }
222
223
224
225
226
227 public static String getMIMETypeIcon(String extension) {
228 MIMEMappingItem item = MIMEMapping.cachedContent.get(extension.toLowerCase());
229 if (item != null) {
230 return StringUtils.defaultIfEmpty(item.icon, DEFAULT_ICON);
231 }
232
233 return DEFAULT_ICON;
234
235 }
236
237
238
239
240
241 public static String getMIMETypeIconStyle(String mimeType) {
242 String genericMimeType = StringUtils.substringBefore(mimeType, "/");
243 MIMEMappingItem mimeMappingItem = null;
244 for (MIMEMappingItem item : cachedContent.values()) {
245 if (item.mime != null && item.mime.equals(mimeType) && StringUtils.isNotBlank(item.iconStyle)) {
246 mimeMappingItem = item;
247 break;
248 }
249 if (item.mime != null && item.mime.equals(genericMimeType) && StringUtils.isNotBlank(item.iconStyle)) {
250 mimeMappingItem = item;
251 }
252 }
253 if (mimeMappingItem != null && StringUtils.isNotBlank(mimeMappingItem.iconStyle)) {
254 return mimeMappingItem.iconStyle;
255 }
256 return DEFAULT_ICON_STYLE;
257 }
258 }