1 package mircoders.servlet;
8 import java.lang.reflect.*;
9 import javax.servlet.*;
10 import javax.servlet.http.*;
12 import freemarker.template.*;
13 import com.oreilly.servlet.multipart.*;
14 import com.oreilly.servlet.*;
16 import org.xml.sax.InputSource;
17 import org.xml.sax.XMLReader;
19 import org.apache.fop.apps.Driver;
20 import org.apache.fop.apps.Version;
21 import org.apache.fop.apps.XSLTInputHandler;
23 import org.apache.log.*;
32 import mircoders.entity.*;
33 import mircoders.storage.*;
34 import mircoders.module.*;
35 import mircoders.producer.*;
38 * ServletModuleOpenIndy -
39 * is the open-access-servlet, which is responsible for
40 * adding comments to articles &
41 * open-postings to the newswire
43 * @author $Author: mh $
44 * @version $Revision: 1.36 $ $Date: 2002/06/29 15:45:20 $
46 * $Log: ServletModuleOpenIndy.java,v $
47 * Revision 1.36 2002/06/29 15:45:20 mh
53 public class ServletModuleOpenIndy extends ServletModule
56 private String commentFormTemplate, commentFormDoneTemplate,
57 commentFormDupeTemplate;
58 private String postingFormTemplate, postingFormDoneTemplate,
59 postingFormDupeTemplate;
60 private ModuleContent contentModule;
61 private ModuleImages imageModule;
62 private ModuleTopics themenModule;
63 private String directOp ="yes";
64 private String passwdProtection ="yes";
65 // Singelton / Kontruktor
66 private static ServletModuleOpenIndy instance = new ServletModuleOpenIndy();
67 public static ServletModule getInstance() { return instance; }
69 private ServletModuleOpenIndy() {
71 theLog = Logfile.getInstance(MirConfig.getProp("Home") + MirConfig.getProp("ServletModule.OpenIndy.Logfile"));
72 commentFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentTemplate");
73 commentFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDoneTemplate");
74 commentFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDupeTemplate");
75 postingFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingTemplate");
76 postingFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDoneTemplate");
77 postingFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDupeTemplate");
78 directOp = MirConfig.getProp("DirectOpenposting").toLowerCase();
79 passwdProtection = MirConfig.getProp("PasswdProtection").toLowerCase();
80 mainModule = new ModuleComment(DatabaseComment.getInstance());
81 contentModule = new ModuleContent(DatabaseContent.getInstance());
82 themenModule = new ModuleTopics(DatabaseTopics.getInstance());
83 imageModule = new ModuleImages(DatabaseImages.getInstance());
84 defaultAction="addposting";
87 catch (StorageObjectException e) {
88 theLog.printError("servletmoduleopenindy could not be initialized");
94 * Method for making a comment
97 public void addcomment(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException
99 String aid = req.getParameter("aid"); // the article id the comment will belong to
100 if (aid!=null && !aid.equals(""))
102 SimpleHash mergeData = new SimpleHash();
105 if(passwdProtection.equals("yes")){
106 String passwd = this.createOneTimePasswd();
107 System.out.println(passwd);
108 HttpSession session = req.getSession(false);
109 session.setAttribute("passwd",passwd);
110 mergeData.put("passwd", passwd);
113 mergeData.put("aid", aid);
114 deliver(req, res, mergeData, commentFormTemplate);
116 else throw new ServletModuleException("aid not set!");
120 * Method for inserting a comment into the Database and delivering
121 * the commentDone Page
124 public void inscomment(HttpServletRequest req, HttpServletResponse res)
125 throws ServletModuleException,ServletModuleUserException
127 String aid = req.getParameter("to_media"); // the article id the comment will belong to
128 if (aid!=null && !aid.equals(""))
130 // ok, collecting data from form
132 HashMap withValues = getIntersectingValues(req, DatabaseComment.getInstance());
134 //no html in comments(for now)
135 for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
136 String k=(String)i.next();
137 String v=(String)withValues.get(k);
139 withValues.put(k,StringUtil.removeHTMLTags(v));
141 withValues.put("is_published","1");
143 //checking the onetimepasswd
144 if(passwdProtection.equals("yes")){
145 HttpSession session = req.getSession(false);
146 String sessionPasswd = (String)session.getAttribute("passwd");
147 if ( sessionPasswd == null){
148 throw new ServletModuleUserException("Lost password");
150 String passwd = req.getParameter("passwd");
151 if ( passwd == null || (!sessionPasswd.equals(passwd))) {
152 throw new ServletModuleUserException("Missing password");
154 session.invalidate();
157 // inserting into database
158 String id = mainModule.add(withValues);
159 theLog.printDebugInfo("id: "+id);
160 //insert was not successfull
162 deliver(req, res, new SimpleHash(), commentFormDupeTemplate);
165 // producing new page
166 new ProducerContent().handle(null, null, true, false, aid);
169 int exitValue = Helper.rsync();
170 theLog.printDebugInfo("rsync:"+exitValue);
172 // redirecting to url
173 // should implement back to article
174 SimpleHash mergeData = new SimpleHash();
175 deliver(req, res, mergeData, commentFormDoneTemplate);
177 catch (StorageObjectException e) { throw new ServletModuleException(e.toString());}
178 catch (ModuleException e) { throw new ServletModuleException(e.toString());}
181 else throw new ServletModuleException("aid not set!");
186 * Method for delivering the form-Page for open posting
189 public void addposting(HttpServletRequest req, HttpServletResponse res)
190 throws ServletModuleException {
191 SimpleHash mergeData = new SimpleHash();
194 if(passwdProtection.equals("yes")){
195 String passwd = this.createOneTimePasswd();
196 System.out.println(passwd);
197 HttpSession session = req.getSession(false);
198 session.setAttribute("passwd",passwd);
199 mergeData.put("passwd", passwd);
202 String maxMedia = MirConfig.getProp("ServletModule.OpenIndy.MaxMediaUploadItems");
203 String numOfMedia = req.getParameter("medianum");
204 if(numOfMedia==null||numOfMedia.equals("")){
206 } else if(Integer.parseInt(numOfMedia) > Integer.parseInt(maxMedia)) {
207 numOfMedia = maxMedia;
210 int mediaNum = Integer.parseInt(numOfMedia);
211 SimpleList mediaFields = new SimpleList();
212 for(int i =0; i<mediaNum;i++){
213 Integer mNum = new Integer(i+1);
214 mediaFields.add(mNum.toString());
216 mergeData.put("medianum",numOfMedia);
217 mergeData.put("mediafields",mediaFields);
220 SimpleHash extraInfo = new SimpleHash();
222 SimpleList popUpData = DatabaseLanguage.getInstance().getPopupData();
223 extraInfo.put("languagePopUpData", popUpData );
224 extraInfo.put("themenPopupData", themenModule.getTopicsAsSimpleList());
225 } catch (Exception e) {
226 theLog.printError("languagePopUpData or getTopicslist failed "
228 throw new ServletModuleException("OpenIndy -- failed getting language or topics: "+e.toString());
231 deliver(req, res, mergeData, extraInfo, postingFormTemplate);
235 * Method for inserting an open posting into the Database and delivering
236 * the postingDone Page
239 public void insposting(HttpServletRequest req, HttpServletResponse res)
240 throws ServletModuleException, ServletModuleUserException
242 SimpleHash mergeData = new SimpleHash();
243 boolean setMedia=false;
244 boolean setTopic = false;
247 WebdbMultipartRequest mp = new WebdbMultipartRequest(req);
249 HashMap withValues = mp.getParameters();
251 //checking the onetimepasswd
252 if(passwdProtection.equals("yes")){
253 HttpSession session = req.getSession(false);
254 String sessionPasswd = (String)session.getAttribute("passwd");
255 if ( sessionPasswd == null){
256 throw new ServletModuleUserException("Lost password");
258 String passwd = (String)withValues.get("passwd");
259 if ( passwd == null || (!sessionPasswd.equals(passwd))) {
260 throw new ServletModuleUserException("Missing password");
262 session.invalidate();
265 if ((((String)withValues.get("title")).length() == 0) ||
266 (((String)withValues.get("description")).length() == 0) ||
267 (((String)withValues.get("content_data")).length() == 0))
268 throw new ServletModuleUserException("Missing field");
270 // call the routines that escape html
272 for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
273 String k=(String)i.next();
274 String v=(String)withValues.get(k);
276 if (k.equals("content_data")){
277 //this doesn't quite work yet, so for now, all html goes
278 //withValues.put(k,StringUtil.approveHTMLTags(v));
279 //withValues.put(k,StringUtil.removeHTMLTags(v));
281 withValues.put(k,StringUtil.removeHTMLTags(v));
286 withValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
287 withValues.put("publish_path", StringUtil.webdbDate2path((String)withValues.get("date")));
288 withValues.put("is_produced", "0");
289 // op-articles are not immediatly published
290 // we don't know that all is good yet (media, title is present, etc..)
291 withValues.put("is_published","0");
292 // if op direct article-type == newswire
293 if (directOp.equals("yes")) withValues.put("to_article_type","1");
295 // owner is openposting user
296 withValues.put("to_publisher","1");
297 if (withValues.get("creator").toString().equals(""))
298 withValues.put("creator","Anonym");
300 // inserting content into database
301 String cid = contentModule.add(withValues);
302 theLog.printDebugInfo("id: "+cid);
303 //insert was not successfull
305 //How do we know that it was not succesful cause of a
306 //dupe, what if it failed cause of "No space left on device"?
307 //Or is there something I am missing? Wouldn't it be better
308 //to have an explicit dupe check and then insert? I have no
309 //idea what I am talking about. this comment is in case
310 //I forget to explicitely ask. -mh
311 deliver(req, res, mergeData, postingFormDupeTemplate);
314 String[] to_topicsArr = mp.getParameterValues("to_topic");
316 if (to_topicsArr != null && to_topicsArr.length > 0) {
318 DatabaseContentToTopics.getInstance().setTopics(cid,to_topicsArr);
320 } catch (Exception e) {
321 theLog.printError("setting content_x_topic failed");
322 contentModule.deleteById(cid);
323 throw new ServletModuleException("smod - openindy :: insposting: setting content_x_topic failed: "+e.toString());
327 // if op contains uploaddata
330 for(Iterator it = mp.requestList.iterator(); it.hasNext();){
331 MpRequest mpReq = (MpRequest)it.next();
332 String fileName = mpReq.getFilename();
334 //get the content-type from what the client browser
335 //sends us. (the "Oreilly method")
336 String contentType = mpReq.getContentType();
338 theLog.printInfo("FROM BROWSER: "+contentType);
340 //if the client browser sent us unknown (text/plain is default)
341 //or if we got application/octet-stream, it's possible that
342 //the browser is in error, better check against the file extension
343 if (contentType.equals("text/plain") ||
344 contentType.equals("application/octet-stream")) {
346 * Fallback to finding the mime-type through the standard ServletApi
347 * ServletContext getMimeType() method.
349 * This is a way to get the content-type via the .extension,
350 * we could maybe use a magic method as an additional method of
351 * figuring out the content-type, by looking at the header (first
352 * few bytes) of the file. (like the file(1) command). We could
353 * also call the "file" command through Runtime. This is an
354 * option that I almost prefer as it is already implemented and
355 * exists with an up-to-date map on most modern Unix like systems.
356 * I haven't found a really nice implementation of the magic method
359 * The first method we try thought is the "Oreilly method". It
360 * relies on the content-type that the client browser sends and
361 * that sometimes is application-octet stream with
362 * broken/mis-configured browsers.
364 * The map file we use for the extensions is the standard web-app
365 * deployment descriptor file (web.xml). See Mir's web.xml or see
366 * your Servlet containers (most likely Tomcat) documentation.
367 * So if you support a new media type you have to make sure that
368 * it is in this file -mh
371 (ServletContext)MirConfig.getPropAsObject("ServletContext");
372 contentType = ctx.getMimeType(fileName);
373 if (contentType==null)
374 contentType = "text/plain"; // rfc1867 says this is the default
376 HashMap mediaValues = new HashMap();
378 theLog.printInfo("CONTENT TYPE IS: "+contentType);
380 if (contentType.equals("text/plain") ||
381 contentType.equals("application/octet-stream")) {
382 contentModule.deleteById(cid);
383 _throwBadContentType(fileName, contentType);
386 String mediaTitle=(String)withValues.get("media_title"+i);
389 if ((mediaTitle == null) || (mediaTitle.length() == 0))
390 throw new ServletModuleUserException("Missing field");
391 //mediaTitle = (String)withValues.get("title");
393 mediaValues.put("title", mediaTitle);
394 mediaValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
395 mediaValues.put("to_publisher", "1"); // op user
396 mediaValues.put("to_media_folder", "7"); // op media_folder
397 mediaValues.put("is_produced", "0");
398 mediaValues.put("is_published","0");
400 // @todo this should probably be moved to DatabaseMediaType -mh
401 String[] cTypeSplit = StringUtil.split(contentType, "/");
402 String wc = " mime_type LIKE '"+cTypeSplit[0]+"%'";
404 DatabaseMediaType mediaTypeStor = DatabaseMediaType.getInstance();
405 EntityList mediaTypesList = mediaTypeStor.selectByWhereClause(wc);
407 String mediaTypeId = null;
408 MirMedia mediaHandler;
409 Database mediaStorage;
410 ProducerMedia mediaProducer;
412 //if we didn't find an entry matching the
413 //content-type int the table.
414 if (mediaTypesList.size() == 0) {
415 contentModule.deleteById(cid);
416 _throwBadContentType(fileName, contentType);
419 Entity mediaType = null;
420 Entity mediaType2 = null;
422 // find out if we an exact content-type match if so take it.
423 // otherwise try to match majortype/*
424 // @todo this should probably be moved to DatabaseMediaType -mh
425 for(int j=0;j<mediaTypesList.size();j++) {
426 if(contentType.equals(
427 mediaTypesList.elementAt(j).getValue("mime_type")))
428 mediaType = mediaTypesList.elementAt(j);
429 else if ((mediaTypesList.elementAt(j).getValue("mime_type")).equals(
430 cTypeSplit[0]+"/*") )
431 mediaType2= mediaTypesList.elementAt(j);
434 if ( (mediaType == null) && (mediaType2 == null) ) {
435 contentModule.deleteById(cid);
436 _throwBadContentType(fileName, contentType);
438 else if( (mediaType == null) && (mediaType2 != null) )
439 mediaType = mediaType2;
441 //get the class names from the media_type table.
442 mediaTypeId = mediaType.getId();
444 // ############### @todo: merge these and the getURL call into one
445 // getURL helper call that just takes the Entity as a parameter
446 // along with media_type
447 mediaHandler = MediaHelper.getHandler(mediaType);
448 mediaStorage = MediaHelper.getStorage(mediaType,
449 "mircoders.storage.Database");
450 Class prodCls = Class.forName("mircoders.producer.Producer"
451 +mediaType.getValue("tablename"));
452 mediaProducer = (ProducerMedia)prodCls.newInstance();
453 } catch (Exception e) {
454 theLog.printError("getting media handler failed: "+e.toString());
455 contentModule.deleteById(cid);
456 throw new ServletModuleException("getting media handler failed: "
460 mediaValues.put("to_media_type",mediaTypeId);
462 //load the classes via reflection
464 Entity mediaEnt = null;
466 mediaEnt = (Entity)mediaStorage.getEntityClass().newInstance();
467 mediaEnt.setStorage(mediaStorage);
468 mediaEnt.setValues(mediaValues);
469 mediaId = mediaEnt.insert();
471 //save and store the media data/metadata
472 mediaHandler.set(mpReq.getMedia(), mediaEnt,
475 //were done with mpReq at this point, dereference it.
476 //as it contains mucho mem. -mh 01.10.2001
479 //we got this far, associate the media to the article
480 mediaEnt.setValueForProperty("is_published","1");
483 mediaProducer.handle(null, null, false, false, mediaId);
484 DatabaseContentToMedia.getInstance().addMedia(cid,mediaId);
485 } catch (Exception e) {
486 theLog.printError("setting media failed: "+e.toString());
487 contentModule.deleteById(cid);
488 throw new ServletModuleException("setting media failed: "
492 } //end for Iterator...
494 //if we're here all is ok...
495 EntityContent contentEnt = (EntityContent)contentModule.getById(cid);
496 contentEnt.setValueForProperty("is_published","1");
500 //dereference mp. -mh
503 // producing openpostinglist
504 new ProducerOpenPosting().handle(null,null,false,false);
505 // producing new page
506 new ProducerContent().handle(null, null, false, false,cid);
507 //if direct op producing startpage
508 if (directOp.equals("yes")) new ProducerStartPage().handle(null,null);
510 //produce the topicPages if set
511 //should be more intelligent
512 //if(setTopic==true) new ProducerTopics().handle(null,null);
515 //should be configureable
516 int exitValue = Helper.rsync();
517 theLog.printDebugInfo("rsync: "+exitValue);
520 catch (IOException e) { throw new ServletModuleException("IOException: "+ e.toString());}
521 catch (StorageObjectException e) { throw new ServletModuleException("StorageObjectException" + e.toString());}
522 catch (ModuleException e) { throw new ServletModuleException("ModuleException"+e.toString());}
524 deliver(req, res, mergeData, postingFormDoneTemplate);
528 * Method for dynamically generating a pdf from a fo file
532 public void getpdf(HttpServletRequest req, HttpServletResponse res)
533 throws ServletModuleException, ServletModuleUserException {
534 String ID_REQUEST_PARAM = "id";
536 String generateFO=MirConfig.getProp("GenerateFO");
537 String generatePDF=MirConfig.getProp("GeneratePDF");
539 //don't do anything if we are not making FO files, or if we are pregenerating PDF's
540 if (generateFO.equals("yes") && generatePDF.equals("no")){
542 //fop complains unless you do the logging this way
544 Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
545 log = hierarchy.getLoggerFor("fop");
546 log.setPriority(Priority.WARN);
548 String producerStorageRoot=MirConfig.getProp("Producer.StorageRoot");
549 String producerDocRoot=MirConfig.getProp("Producer.DocRoot");
550 String templateDir = MirConfig.getPropWithHome("HTMLTemplateProcessor.Dir");
551 String xslSheet=templateDir + "/"
552 + MirConfig.getProp("Producer.PrintableContent.html2foStyleSheetName");
554 String idParam = req.getParameter(ID_REQUEST_PARAM);
555 if (idParam != null){
556 EntityContent contentEnt = (EntityContent)contentModule.getById(idParam);
557 String publishPath = contentEnt.getValue("publish_path");
558 String foFile = producerStorageRoot + producerDocRoot + "/"
559 + publishPath + "/" + idParam + ".fo";
560 XSLTInputHandler input = new XSLTInputHandler(new File(foFile),
563 ByteArrayOutputStream out = new ByteArrayOutputStream();
564 res.setContentType("application/pdf");
566 Driver driver = new Driver();
567 driver.setLogger(log);
568 driver.setRenderer(Driver.RENDER_PDF);
569 driver.setOutputStream(out);
570 driver.render(input.getParser(), input.getInputSource());
572 byte[] content = out.toByteArray();
573 res.setContentLength(content.length);
574 res.getOutputStream().write(content);
575 res.getOutputStream().flush();
578 throw new ServletModuleUserException("Can't generate a PDF without an id parameter.");
581 catch (Exception ex) {
582 throw new ServletModuleException(ex.toString());
586 throw new ServletModuleUserException("Can't generate a PDF because the config tells me not to.");
590 private void _throwBadContentType (String fileName, String contentType)
591 throws ServletModuleUserException {
593 theLog.printDebugInfo("Wrong file type uploaded!: " + fileName+" "
595 throw new ServletModuleUserException("The file you uploaded is of the "
596 +"following mime-type: "+contentType
597 +", we do not support this mime-type. "
598 +"Error One or more files of unrecognized type. Sorry");
601 protected String createOneTimePasswd(){
602 Random r = new Random();
603 int random = r.nextInt();
604 long l = System.currentTimeMillis();
605 l = (l*l*l*l)/random;
607 String returnString = ""+l;
608 return returnString.substring(5);