6d94e7729c85ec4b5c28cd333f9bc1a719309dbe
[mir.git] / source / mircoders / media / MediaRequest.java
1 /*\r
2  * Copyright (C) 2001, 2002  The Mir-coders group\r
3  *\r
4  * This file is part of Mir.\r
5  *\r
6  * Mir is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Mir is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with Mir; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  *\r
20  * In addition, as a special exception, The Mir-coders gives permission to link\r
21  * the code of this program with the com.oreilly.servlet library, any library\r
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced\r
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of\r
24  * the above that use the same license as the above), and distribute linked\r
25  * combinations including the two.  You must obey the GNU General Public\r
26  * License in all respects for all of the code used other than the above\r
27  * mentioned libraries.  If you modify this file, you may extend this exception\r
28  * to your version of the file, but you are not obligated to do so.  If you do\r
29  * not wish to do so, delete this exception statement from your version.\r
30  */\r
31 \r
32 package mircoders.media;\r
33 \r
34 import java.util.GregorianCalendar;\r
35 import java.util.Iterator;\r
36 import java.util.Map;\r
37 \r
38 import javax.servlet.ServletContext;\r
39 \r
40 import mir.config.MirPropertiesConfiguration;\r
41 import mir.entity.Entity;\r
42 import mir.entity.EntityList;\r
43 import mir.log.LoggerWrapper;\r
44 import mir.media.MediaHelper;\r
45 import mir.media.MirMedia;\r
46 \r
47 import mir.misc.FileHandler;\r
48 import mir.misc.StringUtil;\r
49 import mir.storage.Database;\r
50 import mir.storage.StorageObjectExc;\r
51 import mir.storage.StorageObjectFailure;\r
52 import mircoders.storage.DatabaseMediaType;\r
53 \r
54 import com.oreilly.servlet.multipart.FilePart;\r
55 \r
56 \r
57 /*\r
58  *  MediaRequest.java -\r
59  *    Takes an HTTPServletRequest from a mutltipart form and finds the files\r
60  *    uploaded via the com.oreilly.servlet.multipart package. Finally the\r
61  *    appropriate media objects are set.\r
62  *\r
63  * @author mh\r
64  * @version $Id: MediaRequest.java,v 1.17 2003/03/09 03:53:11 zapata Exp $\r
65  *\r
66  */\r
67 \r
68 public class MediaRequest implements FileHandler\r
69 {\r
70   private String _user;\r
71   private EntityList _returnList = new EntityList();\r
72   private boolean _publish;\r
73   private LoggerWrapper logger;\r
74 \r
75   public MediaRequest(String user, boolean publish) {\r
76     _user = user;\r
77     _publish = publish;\r
78     logger = new LoggerWrapper("Media.Request");\r
79   }\r
80 \r
81   public EntityList getEntityList() {\r
82     return _returnList;\r
83   }\r
84 \r
85   /*\r
86    * parses the files in the uploaded media and creates media Entity's out of\r
87    * them.  Produces them if the "produce" argument is true. The "publish"\r
88    * parameter determines if it should publish per default in the case where no\r
89    * is_published parameter (from the upload form) is supplied. (for backwards\r
90    * compatibility.)\r
91    */\r
92   public void setFile(FilePart filePart, int fileNum, Map mediaValues) throws FileHandlerExc, FileHandlerFailure {\r
93 \r
94     String mediaId=null;\r
95     MirMedia mediaHandler;\r
96     Database mediaStorage = null;\r
97 \r
98     try {\r
99       String fileName = filePart.getFileName();\r
100 \r
101       //get the content-type from what the client browser\r
102       //sends us. (the "Oreilly method")\r
103       String contentType = filePart.getContentType();\r
104 \r
105       //theLog.printInfo("FROM BROWSER: "+contentType);\r
106 \r
107       //if the client browser sent us unknown (text/plain is default)\r
108       //or if we got application/octet-stream, it's possible that\r
109       //the browser is in error, better check against the file extension\r
110       if (contentType.equals("text/plain") ||\r
111           contentType.equals("application/octet-stream")) {\r
112         /**\r
113          * Fallback to finding the mime-type through the standard ServletApi\r
114          * ServletContext getMimeType() method.\r
115          *\r
116          * This is a way to get the content-type via the .extension,\r
117          * we could maybe use a magic method as an additional method of\r
118          * figuring out the content-type, by looking at the header (first\r
119          * few bytes) of the file. (like the file(1) command). We could\r
120          * also call the "file" command through Runtime. This is an\r
121          * option that I almost prefer as it is already implemented and\r
122          * exists with an up-to-date map on most modern Unix like systems.\r
123          * I haven't found a really nice implementation of the magic method\r
124          * in pure java yet.\r
125          *\r
126          * The first method we try thought is the "Oreilly method". It\r
127          * relies on the content-type that the client browser sends and\r
128          * that sometimes is application-octet stream with\r
129          * broken/mis-configured browsers.\r
130          *\r
131          * The map file we use for the extensions is the standard web-app\r
132          * deployment descriptor file (web.xml). See Mir's web.xml or see\r
133          * your Servlet containers (most likely Tomcat) documentation.\r
134          * So if you support a new media type you have to make sure that\r
135          * it is in this file -mh\r
136          */\r
137         ServletContext ctx = MirPropertiesConfiguration.getContext();\r
138         contentType = ctx.getMimeType(fileName);\r
139         if (contentType==null)\r
140           contentType = "text/plain"; // rfc1867 says this is the default\r
141       }\r
142       //theLog.printInfo("CONTENT TYPE IS: "+contentType);\r
143 \r
144       if (contentType.equals("text/plain") ||\r
145           contentType.equals("application/octet-stream")) {\r
146         _throwBadContentType(fileName, contentType);\r
147       }\r
148 \r
149       // call the routines that escape html\r
150       for (Iterator i=mediaValues.keySet().iterator(); i.hasNext(); ){\r
151         String k=(String)i.next();\r
152         String v=(String)mediaValues.get(k);\r
153 \r
154         if (k.equals("description")) {\r
155           String tmp = StringUtil.deleteForbiddenTags(v);\r
156           mediaValues.put(k,StringUtil.deleteHTMLTableTags(tmp));\r
157         } else {\r
158           //we don't want people fucking with the author/title, etc..\r
159           mediaValues.put(k,StringUtil.removeHTMLTags(v));\r
160         }\r
161 \r
162       }\r
163 \r
164       String mediaTitle = (String)mediaValues.get("media_title"+fileNum);\r
165       if ( (mediaTitle == null) || (mediaTitle.length() == 0)) {\r
166         //  uncomment the next line and comment out the exception throw\r
167         //  if you'd rather just assign missing media titles automatically\r
168         //  mediaTitle="media item "+fileNum;\r
169 //        throw new FileHandlerUserException("Missing field: media title "+mediaTitle+fileNum);\r
170       }\r
171 \r
172       // TODO: need to add all the extra fields that can be present in the\r
173       // admin upload form. -mh\r
174       mediaValues.put("title", mediaTitle);\r
175       mediaValues.put("date", StringUtil.date2webdbDate(\r
176                                                     new GregorianCalendar()));\r
177       mediaValues.put("to_publisher", _user);\r
178       //mediaValues.put("to_media_folder", "7"); // op media_folder\r
179       mediaValues.put("is_produced", "0");\r
180 \r
181       // icky backwards compatibility code -mh\r
182       if (_publish == true) {\r
183         mediaValues.put("is_published", "1");\r
184       } else {\r
185         if (!mediaValues.containsKey("is_published"))\r
186           mediaValues.put("is_published", "0");\r
187       }\r
188 \r
189       // @todo this should probably be moved to DatabaseMediaType -mh\r
190       String[] cTypeSplit = StringUtil.split(contentType, "/");\r
191       String wc = " mime_type LIKE '"+cTypeSplit[0]+"%'";\r
192 \r
193       DatabaseMediaType mediaTypeStor = DatabaseMediaType.getInstance();\r
194       EntityList mediaTypesList = mediaTypeStor.selectByWhereClause(wc);\r
195 \r
196       String mediaTypeId = null;\r
197 \r
198       //if we didn't find an entry matching the\r
199       //content-type int the table.\r
200       if (mediaTypesList.size() == 0) {\r
201        _throwBadContentType(fileName, contentType);\r
202       }\r
203 \r
204       Entity mediaType = null;\r
205       Entity mediaType2 = null;\r
206 \r
207       // find out if we an exact content-type match if so take it.\r
208       // otherwise try to match majortype/*\r
209       // @todo this should probably be moved to DatabaseMediaType -mh\r
210       for(int j=0;j<mediaTypesList.size();j++) {\r
211         if(contentType.equals(\r
212               mediaTypesList.elementAt(j).getValue("mime_type")))\r
213           mediaType = mediaTypesList.elementAt(j);\r
214         else if ((mediaTypesList.elementAt(j).getValue("mime_type")).equals(\r
215                   cTypeSplit[0]+"/*") )\r
216           mediaType2= mediaTypesList.elementAt(j);\r
217       }\r
218 \r
219       if ( (mediaType == null) && (mediaType2 == null) ) {\r
220         _throwBadContentType(fileName, contentType);\r
221       } else if( (mediaType == null) && (mediaType2 != null) ) {\r
222         mediaType = mediaType2;\r
223       }\r
224 \r
225       //get the class names from the media_type table.\r
226       mediaTypeId = mediaType.getId();\r
227       // ############### @todo: merge these and the getURL call into one\r
228       // getURL helper call that just takes the Entity as a parameter\r
229       // along with media_type\r
230       try {\r
231         mediaHandler = MediaHelper.getHandler(mediaType);\r
232         mediaStorage = MediaHelper.getStorage(mediaType, "mircoders.storage.Database");\r
233       }\r
234       catch (Throwable e) {\r
235         throw new FileHandlerFailure(e);\r
236       }\r
237       mediaValues.put("to_media_type",mediaTypeId);\r
238 \r
239       //load the classes via reflection\r
240       String MediaId;\r
241       Entity mediaEnt = null;\r
242 \r
243       try {\r
244         mediaEnt = (Entity)mediaStorage.getEntityClass().newInstance();\r
245       }\r
246       catch (Throwable e) {\r
247         throw new FileHandlerFailure("MediaRequest.setFile: "+e.toString(), e);\r
248       }\r
249 \r
250       mediaEnt.setStorage(mediaStorage);\r
251       mediaEnt.setValues(mediaValues);\r
252       mediaId = mediaEnt.insert();\r
253 \r
254       //save and store the media data/metadata\r
255       try {\r
256         mediaHandler.set(filePart.getInputStream(), mediaEnt, mediaType);\r
257       }\r
258       catch (Throwable e) {\r
259         throw new FileHandlerFailure("MediaRequest.setFile: "+e.toString(), e);\r
260       }\r
261 \r
262       _returnList.add(mediaEnt);\r
263     }\r
264     catch (StorageObjectFailure e) {\r
265       // first try to delete it.. don't catch exception as we've already..\r
266       try {\r
267         mediaStorage.delete(mediaId);\r
268       }\r
269       catch (Exception e2) {\r
270       }\r
271       throw new FileHandlerFailure("MediaRequest.setFile: "+e.toString(), e);\r
272     }\r
273     catch (Throwable e) {\r
274       throw new FileHandlerFailure("MediaRequest.setFile: "+e.toString(), e);\r
275     } //end try/catch block\r
276 \r
277   } // method setFile()\r
278 \r
279   private void _throwBadContentType (String fileName, String contentType) throws FileHandlerExc, FileHandlerFailure {\r
280     try {\r
281       throw new UnsupportedMediaFormatExc(\r
282           "The file you uploaded is of the following mime-type: " + contentType +\r
283           ", we do not support this mime-type. "\r
284           + "Error One or more files of unrecognized type. Sorry");\r
285     }\r
286     catch (Throwable t) {\r
287       throw new FileHandlerFailure(t);\r
288     }\r
289   }\r
290 \r
291 }\r
292 \r