use ServletContext.getMimeType() as fallback to find media mime-type from .extension...
[mir.git] / source / mircoders / servlet / ServletModuleUploadedMedia.java
1 package mircoders.servlet;
2
3 import freemarker.template.SimpleHash;
4 import mir.entity.Entity;
5 import mir.entity.EntityList;
6 import mir.media.MediaHelper;
7 import mir.media.MirMedia;
8 import mir.media.MirMediaException;
9 import mir.media.MirMediaUserException;
10 import mir.misc.MirConfig;
11 import mir.misc.MpRequest;
12 import mir.misc.StringUtil;
13 import mir.misc.WebdbMultipartRequest;
14 import mir.module.ModuleException;
15 import mir.servlet.ServletModule;
16 import mir.servlet.ServletModuleException;
17 import mir.servlet.ServletModuleUserException;
18 import mir.storage.Database;
19 import mir.storage.StorageObjectException;
20 import mircoders.entity.EntityUsers;
21 import mircoders.storage.DatabaseMediaType;
22 import mircoders.storage.DatabaseMediafolder;
23
24 import javax.servlet.http.HttpServletRequest;
25 import javax.servlet.http.HttpServletResponse;
26 import javax.servlet.http.HttpSession;
27 import javax.servlet.ServletContext;
28
29 import java.io.IOException;
30 import java.net.URLEncoder;
31 import java.util.GregorianCalendar;
32 import java.util.HashMap;
33
34 /*
35  *  ServletModuleBilder -
36  *  liefert HTML fuer Bilder
37  *
38  *
39  * @author RK
40  */
41
42 public abstract class ServletModuleUploadedMedia
43         extends mir.servlet.ServletModule {
44
45   //private static DatabaseRights dbRights;
46
47   public static ServletModule getInstance() {
48     return null;
49   }
50
51   public void insert(HttpServletRequest req, HttpServletResponse res)
52           throws ServletModuleException, ServletModuleUserException {
53     try {
54       WebdbMultipartRequest mp = new WebdbMultipartRequest(req);
55       HashMap parameters = mp.getParameters();
56       EntityUsers user = _getUser(req);
57       String mediaId = null;
58       MpRequest mpReq = (MpRequest) mp.requestList.get(0);
59       String mediaTypeId; //= null;
60       MirMedia mediaHandler;
61       Database mediaStorage;
62
63       // get the content-type from what the client browser
64       // sends us. (the "Oreilly method")
65       String contentType = mpReq.getContentType();
66       String fileName = mpReq.getFilename();
67       theLog.printInfo("CONTENT-TYPE FROM BROWSER: " + contentType);
68
69       // if the client browser sent us unknown (text/plain is default)
70       // or if we got application/octet-stream, it's possible that
71       // the browser is in error, better check against the file extension
72       if (contentType.equals("text/plain") ||
73               contentType.equals("application/octet-stream")) {
74         /**
75          * Fallback to finding the mime-type through the standard ServletApi
76          * ServletContext getMimeType() method.
77          *
78          * This is a way to get the content-type via the .extension,
79          * we could maybe use a magic method as an additional method of
80          * figuring out the content-type, by looking at the header (first
81          * few bytes) of the file. (like the file(1) command). We could 
82          * also call the "file" command through Runtime. This is an
83          * option that I almost prefer as it is already implemented and
84          * exists with an up-to-date map on most modern Unix like systems.
85          * I haven't found a really nice implementation of the magic method
86          * in pure java yet.
87          *
88          * The first method we try thought is the "Oreilly method". It
89          * relies on the content-type that the client browser sends and 
90          * that sometimes is application-octet stream with
91          * broken/mis-configured browsers.
92          *
93          * The map file we use for the extensions is the standard web-app
94          * deployment descriptor file (web.xml). See Mir's web.xml or see
95          * your Servlet containers (most likely Tomcat) documentation.
96          * So if you support a new media type you have to make sure that 
97          * it is in this file -mh
98          */
99         ServletContext ctx =
100           (ServletContext)MirConfig.getPropAsObject("ServletContext");
101         contentType = ctx.getMimeType(fileName);
102         if (contentType == null)
103           contentType = "text/plain"; // rfc1867 says this is the default
104       }
105       theLog.printInfo("CONTENT TYPE IS: " + contentType);
106
107       if (contentType.equals("text/plain") ||
108               contentType.equals("application/octet-stream")) {
109         _throwBadContentType(fileName, contentType);
110       }
111
112       parameters.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
113       parameters.put("to_publisher", user.getId());
114
115       //the where clause to find the media_type entry from the content-type.
116       //we use the media type entry to lookup the media Handler/Storage classes
117       // @todo this should probably be moved to DatabaseMediaType or
118       // somewhere else appropriate -mh
119       String[] contentTypeSplit = StringUtil.split(contentType, "/");
120       String wc = " mime_type LIKE '" + contentTypeSplit[0] + "%'";
121       DatabaseMediaType mediaTypeStor = DatabaseMediaType.getInstance();
122       EntityList mediaTypesList = mediaTypeStor.selectByWhereClause(wc);
123
124       // if we didn't find an entry matching the
125       // content-type in the table.
126       if (mediaTypesList.size() == 0) {
127         _throwBadContentType(fileName, contentType);
128       }
129       Entity mediaType = null;
130       Entity mediaType2 = null;
131
132       // find out if we an exact content-type match if so take it.
133       // otherwise try to match majortype/*
134       // @todo this should probably be moved to DatabaseMediaType -mh
135       for(int j=0;j<mediaTypesList.size();j++) {
136         if(contentType.equals(
137                         mediaTypesList.elementAt(j).getValue("mime_type")))
138           mediaType = mediaTypesList.elementAt(j);
139         else if ((mediaTypesList.elementAt(j).getValue("mime_type")).equals(
140                   contentTypeSplit[0]+"/*"))
141           mediaType2= mediaTypesList.elementAt(j); 
142       }
143
144       if ( (mediaType == null) && (mediaType2 == null) ) {
145         _throwBadContentType(fileName, contentType);
146       }
147       else if( (mediaType == null) && (mediaType2 != null) )
148         mediaType = mediaType2;
149
150
151       // get the class names from the media_type table.
152       mediaTypeId = mediaType.getId();
153       try {
154         // ############### @todo: merge these and the getURL call into one
155         // getURL helper call that just takes the Entity as a parameter
156         // along with media_type
157         mediaHandler = MediaHelper.getHandler(mediaType);
158         mediaStorage = MediaHelper.getStorage(mediaType,
159                                               "mircoders.storage.Database");
160       }
161       catch (Exception e) {
162         theLog.printError("getting media handler failed: " + e.toString());
163         throw new MirMediaException("getting media handler failed: "
164                                     + e.toString());
165       }
166
167       parameters.put("to_media_type", mediaTypeId);
168       //load the classes via reflection
169       Entity mediaEnt = null;
170       try {
171         mediaEnt = (Entity) mediaStorage.getEntityClass().newInstance();
172         mediaEnt.setStorage(mediaStorage);
173         mediaEnt.setValues(parameters);
174         // unfortunatly we have to insert it first because of the way
175         // Image setting works right now. that should change soon. -mh
176         mediaId = mediaEnt.insert();
177         //save and store the media data/metadata
178         mediaHandler.set(mpReq.getMedia(), mediaEnt, mediaType);
179
180         //were done with mpReq at this point, dereference it.
181         //as it contains mucho mem. -mh 01.10.2001
182         mpReq = null;
183
184         //we got this far, associate the media to the article
185         mediaEnt.setValueForProperty("is_published", "1");
186         mediaEnt.update();
187       }
188       catch (Exception e) {
189         try {
190           mediaStorage.delete(mediaId);
191         }
192         catch (Exception e2) {
193           // dont't do anything here as the error was setting the media,
194           // this just means that the entity may not have been inserted yet
195         }
196         theLog.printError("setting media failed: " + e.toString());
197         throw new MirMediaException("setting media failed: " + e.toString());
198       }
199
200       _edit(mediaId, req, res);
201     }
202     catch (MirMediaException e) {
203       throw new ServletModuleException(
204               "upload -- media handling exception " + e.toString());
205     }
206     catch (IOException e) {
207       throw new ServletModuleException("upload -- ioexception " + e.toString());
208     }
209     catch (StorageObjectException e) {
210       throw new ServletModuleException("StorageObjectException" + e.toString());
211     }
212
213   }
214
215   private void _throwBadContentType (String fileName, String contentType)
216     throws ServletModuleUserException {
217
218     theLog.printDebugInfo("Wrong file type uploaded!: " + fileName+" "
219                           +contentType);
220     throw new ServletModuleUserException("The file you uploaded is of the "
221         +"following mime-type: "+contentType
222         +", we do not support this mime-type. "
223         +"Error One or more files of unrecognized type. Sorry");
224   }
225  
226
227   public void update(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException {
228
229     try {
230       WebdbMultipartRequest mp = new WebdbMultipartRequest(req);
231       HashMap parameters = mp.getParameters();
232
233       EntityUsers user = _getUser(req);
234       parameters.put("to_publisher", user.getId());
235       parameters.put("is_produced", "0");
236       if (!parameters.containsKey("is_published"))
237         parameters.put("is_published", "0");
238
239       String id = mainModule.set(parameters);
240       theLog.printError("media ID" + id);
241       _edit(id, req, res);
242     }
243     catch (IOException e) {
244       throw new ServletModuleException("upload -- ioexception " + e.toString());
245     }
246     catch (ModuleException e) {
247       throw new ServletModuleException("upload -- moduleexception " + e.toString());
248     }
249
250   }
251
252
253   public void list(HttpServletRequest req, HttpServletResponse res)
254           throws ServletModuleException {
255     // Parameter auswerten
256     SimpleHash mergeData = new SimpleHash();
257     SimpleHash popups = new SimpleHash();
258
259     String query_text = req.getParameter("query_text");
260     mergeData.put("query_text", query_text);
261     if (query_text != null) mergeData.put("query_text_encoded", URLEncoder.encode(query_text));
262     String query_field = req.getParameter("query_field");
263     mergeData.put("query_field", query_field);
264     String query_is_published = req.getParameter("query_is_published");
265     mergeData.put("query_is_published", query_is_published);
266     String query_media_folder = req.getParameter("query_media_folder");
267     mergeData.put("query_media_folder", query_media_folder);
268     String offset = req.getParameter("offset");
269     if (offset == null || offset.equals("")) offset = "0";
270     mergeData.put("offset", offset);
271
272     String order = req.getParameter("order");
273     if (order == null) order = "webdb_lastchange desc";
274
275     // if in connection mode to content
276     String cid = req.getParameter("cid");
277     mergeData.put("cid", cid);
278
279
280     // sql basteln
281     String whereClause = "";
282     boolean isFirst = true;
283     if (query_text != null && !query_text.equalsIgnoreCase("")) {
284       whereClause += "lower(" + query_field + ") like lower('%" + query_text + "%')";
285       isFirst = false;
286     }
287     if (query_is_published != null && !query_is_published.equals("")) {
288       if (isFirst == false) whereClause += " and ";
289       whereClause += "is_published='" + query_is_published + "'";
290       isFirst = false;
291     }
292     if (query_media_folder != null && !query_media_folder.equals("")) {
293       if (isFirst == false) whereClause += " and ";
294       whereClause += "to_media_folder='" + query_media_folder + "'";
295     }
296     //theLog.printDebugInfo("sql-whereclause: " + whereClause + " order: " + order + " offset: " + offset);
297
298     // fetch und ausliefern
299     try {
300       if (query_text != null || query_is_published != null || query_media_folder != null) {
301         EntityList theList = mainModule.getByWhereClause(whereClause, order, (new Integer(offset)).intValue(), 10);
302         if (theList != null) {
303           mergeData.put("contentlist", theList);
304           if (theList.getOrder() != null) {
305             mergeData.put("order", theList.getOrder());
306             mergeData.put("order_encoded", URLEncoder.encode(theList.getOrder()));
307           }
308           mergeData.put("count", (new Integer(theList.getCount())).toString());
309           mergeData.put("from", (new Integer(theList.getFrom())).toString());
310           mergeData.put("to", (new Integer(theList.getTo())).toString());
311           if (theList.hasNextBatch())
312             mergeData.put("next", (new Integer(theList.getNextBatch())).toString());
313           if (theList.hasPrevBatch())
314             mergeData.put("prev", (new Integer(theList.getPrevBatch())).toString());
315         }
316       }
317       //fetch the popups
318       popups.put("mediafolderPopupData", DatabaseMediafolder.getInstance().getPopupData());
319       // raus damit
320       deliver(req, res, mergeData, popups, templateListString);
321     }
322     catch (ModuleException e) {
323       throw new ServletModuleException(e.toString());
324     }
325     catch (Exception e) {
326       throw new ServletModuleException(e.toString());
327     }
328   }
329
330
331   public void add(HttpServletRequest req, HttpServletResponse res)
332           throws ServletModuleException {
333     try {
334       SimpleHash mergeData = new SimpleHash();
335       mergeData.put("new", "1");
336       SimpleHash popups = new SimpleHash();
337       popups.put("mediafolderPopupData", DatabaseMediafolder.getInstance().getPopupData());
338       deliver(req, res, mergeData, popups, templateObjektString);
339     }
340     catch (Exception e) {
341       throw new ServletModuleException(e.toString());
342     }
343   }
344
345   public void edit(HttpServletRequest req, HttpServletResponse res)
346           throws ServletModuleException {
347     String idParam = req.getParameter("id");
348     _edit(idParam, req, res);
349   }
350
351   private void _edit(String idParam, HttpServletRequest req, HttpServletResponse res)
352           throws ServletModuleException {
353     if (idParam != null && !idParam.equals("")) {
354       try {
355         SimpleHash popups = new SimpleHash();
356         popups.put("mediafolderPopupData", DatabaseMediafolder.getInstance().getPopupData());
357         deliver(req, res, mainModule.getById(idParam), popups,
358                 templateObjektString);
359       }
360       catch (ModuleException e) {
361         throw new ServletModuleException(e.toString());
362       }
363       catch (StorageObjectException e) {
364         throw new ServletModuleException(e.toString());
365       }
366     }
367     else {
368       throw new ServletModuleException("ServletmoduleUploadedMedia :: _edit without id");
369     }
370   }
371
372
373   /** @todo should be in ServletModule.java */
374   private EntityUsers _getUser(HttpServletRequest req) {
375     HttpSession session = req.getSession(false);
376     return (EntityUsers) session.getAttribute("login.uid");
377   }
378
379 }
380
381