2 * Copyright (C) 2001, 2002 The Mir-coders group
4 * This file is part of Mir.
6 * Mir is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Mir is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Mir; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * In addition, as a special exception, The Mir-coders gives permission to link
21 * the code of this program with the com.oreilly.servlet library, any library
22 * licensed under the Apache Software License, The Sun (tm) Java Advanced
23 * Imaging library (JAI), The Sun JIMI library (or with modified versions of
24 * the above that use the same license as the above), and distribute linked
25 * combinations including the two. You must obey the GNU General Public
26 * License in all respects for all of the code used other than the above
27 * mentioned libraries. If you modify this file, you may extend this exception
28 * to your version of the file, but you are not obligated to do so. If you do
29 * not wish to do so, delete this exception statement from your version.
32 package mircoders.servlet;
39 import java.lang.reflect.*;
40 import javax.servlet.*;
41 import javax.servlet.http.*;
43 import freemarker.template.*;
44 import com.oreilly.servlet.multipart.*;
45 import com.oreilly.servlet.*;
47 import org.xml.sax.InputSource;
48 import org.xml.sax.XMLReader;
50 import org.apache.fop.apps.Driver;
51 import org.apache.fop.apps.Version;
52 import org.apache.fop.apps.XSLTInputHandler;
54 import org.apache.lucene.analysis.standard.StandardAnalyzer;
55 import org.apache.lucene.search.*;
56 import org.apache.lucene.document.Document;
57 import org.apache.lucene.document.Field;
58 import org.apache.lucene.analysis.standard.*;
59 import org.apache.lucene.queryParser.*;
61 import org.apache.log.*;
71 import mircoders.entity.*;
72 import mircoders.storage.*;
73 import mircoders.module.*;
74 import mircoders.producer.*;
75 import mircoders.media.MediaRequest;
76 import mircoders.global.*;
77 import mircoders.localizer.*;
78 import mircoders.search.*;
81 * ServletModuleOpenIndy -
82 * is the open-access-servlet, which is responsible for
83 * adding comments to articles &
84 * open-postings to the newswire
86 * @author mir-coders group
87 * @version $Id: ServletModuleOpenIndy.java,v 1.46 2002/11/29 13:43:42 zapata Exp $
91 public class ServletModuleOpenIndy extends ServletModule
94 private String commentFormTemplate, commentFormDoneTemplate,
95 commentFormDupeTemplate;
96 private String postingFormTemplate, postingFormDoneTemplate,
97 postingFormDupeTemplate;
98 private String searchResultsTemplate;
99 private ModuleContent contentModule;
100 private ModuleComment commentModule;
101 private ModuleImages imageModule;
102 private ModuleTopics themenModule;
103 private String directOp ="yes";
104 private String passwdProtection ="yes";
105 // Singelton / Kontruktor
106 private static ServletModuleOpenIndy instance = new ServletModuleOpenIndy();
107 public static ServletModule getInstance() { return instance; }
109 private ServletModuleOpenIndy() {
111 logger = new LoggerWrapper("ServletModule.OpenIndy.Logfile");
112 commentFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentTemplate");
113 commentFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDoneTemplate");
114 commentFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDupeTemplate");
115 postingFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingTemplate");
116 postingFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDoneTemplate");
117 postingFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDupeTemplate");
118 searchResultsTemplate = MirConfig.getProp("ServletModule.OpenIndy.SearchResultsTemplate");
119 directOp = MirConfig.getProp("DirectOpenposting").toLowerCase();
120 passwdProtection = MirConfig.getProp("PasswdProtection").toLowerCase();
121 mainModule = new ModuleComment(DatabaseComment.getInstance());
122 contentModule = new ModuleContent(DatabaseContent.getInstance());
123 themenModule = new ModuleTopics(DatabaseTopics.getInstance());
124 imageModule = new ModuleImages(DatabaseImages.getInstance());
125 defaultAction="addposting";
128 catch (StorageObjectException e) {
129 logger.error("servletmoduleopenindy could not be initialized");
135 * Method for making a comment
138 public void addcomment(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException
140 String aid = req.getParameter("aid"); // the article id the comment will belong to
141 String language = req.getParameter("language");
143 if (aid!=null && !aid.equals(""))
145 SimpleHash mergeData = new SimpleHash();
148 if(passwdProtection.equals("yes")){
149 String passwd = this.createOneTimePasswd();
150 System.out.println(passwd);
151 HttpSession session = req.getSession(false);
152 session.setAttribute("passwd",passwd);
153 mergeData.put("passwd", passwd);
156 if (language!=null) {
157 HttpSession session = req.getSession(false);
158 session.setAttribute("Locale", new Locale(language, ""));
159 session.setAttribute("passwd",language);
162 mergeData.put("aid", aid);
163 deliver(req, res, mergeData, commentFormTemplate);
165 else throw new ServletModuleException("aid not set!");
169 * Method for inserting a comment into the Database and delivering
170 * the commentDone Page
173 public void inscomment(HttpServletRequest req, HttpServletResponse res)
174 throws ServletModuleException,ServletModuleUserException
176 String aid = req.getParameter("to_media"); // the article id the comment will belong to
177 if (aid!=null && !aid.equals(""))
179 // ok, collecting data from form
181 HashMap withValues = getIntersectingValues(req, DatabaseComment.getInstance());
183 //no html in comments(for now)
184 for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
185 String k=(String)i.next();
186 String v=(String)withValues.get(k);
188 withValues.put(k,StringUtil.removeHTMLTags(v));
190 withValues.put("is_published","1");
192 //checking the onetimepasswd
193 if(passwdProtection.equals("yes")){
194 HttpSession session = req.getSession(false);
195 String sessionPasswd = (String)session.getAttribute("passwd");
196 if ( sessionPasswd == null){
197 throw new ServletModuleUserException("Lost password");
199 String passwd = req.getParameter("passwd");
200 if ( passwd == null || (!sessionPasswd.equals(passwd))) {
201 throw new ServletModuleUserException("Missing password");
203 session.invalidate();
206 // inserting into database
207 String id = mainModule.add(withValues);
208 logger.debug("inscomment: id = "+id);
209 //insert was not successfull
211 deliver(req, res, new SimpleHash(), commentFormDupeTemplate);
213 DatabaseContent.getInstance().setUnproduced("id="+aid);
216 EntityComment comment = (EntityComment) DatabaseComment.getInstance().selectById(id);
217 MirGlobal.localizer().openPostings().afterCommentPosting(comment);
219 catch (Throwable t) {
220 throw new ServletModuleException(t.getMessage());
227 // redirecting to url
228 // should implement back to article
229 SimpleHash mergeData = new SimpleHash();
230 deliver(req, res, mergeData, commentFormDoneTemplate);
232 catch (StorageObjectException e) { throw new ServletModuleException(e.toString());}
233 catch (ModuleException e) { throw new ServletModuleException(e.toString());}
236 else throw new ServletModuleException("aid not set!");
241 * Method for delivering the form-Page for open posting
244 public void addposting(HttpServletRequest req, HttpServletResponse res)
245 throws ServletModuleException {
246 SimpleHash mergeData = new SimpleHash();
249 if(passwdProtection.equals("yes")){
250 String passwd = this.createOneTimePasswd();
251 System.out.println(passwd);
252 HttpSession session = req.getSession(false);
253 session.setAttribute("passwd",passwd);
254 mergeData.put("passwd", passwd);
257 String maxMedia = MirConfig.getProp("ServletModule.OpenIndy.MaxMediaUploadItems");
258 String numOfMedia = req.getParameter("medianum");
259 if(numOfMedia==null||numOfMedia.equals("")){
261 } else if(Integer.parseInt(numOfMedia) > Integer.parseInt(maxMedia)) {
262 numOfMedia = maxMedia;
265 int mediaNum = Integer.parseInt(numOfMedia);
266 SimpleList mediaFields = new SimpleList();
267 for(int i =0; i<mediaNum;i++){
268 Integer mNum = new Integer(i+1);
269 mediaFields.add(mNum.toString());
271 mergeData.put("medianum",numOfMedia);
272 mergeData.put("mediafields",mediaFields);
275 SimpleHash extraInfo = new SimpleHash();
277 SimpleList popUpData = DatabaseLanguage.getInstance().getPopupData();
278 extraInfo.put("languagePopUpData", popUpData );
279 extraInfo.put("themenPopupData", themenModule.getTopicsAsSimpleList());
281 extraInfo.put("topics", themenModule.getTopicsList());
284 catch (Exception e) {
285 logger.error("languagePopUpData or getTopicslist failed " + e.toString());
286 throw new ServletModuleException("OpenIndy -- failed getting language or topics: "+e.toString());
291 deliver(req, res, mergeData, extraInfo, postingFormTemplate);
295 * Method for inserting an open posting into the Database and delivering
296 * the postingDone Page
299 public void insposting(HttpServletRequest req, HttpServletResponse res)
300 throws ServletModuleException, ServletModuleUserException
302 SimpleHash mergeData = new SimpleHash();
303 boolean setMedia=false;
304 boolean setTopic = false;
308 WebdbMultipartRequest mp = null;
309 EntityList mediaList = null;
311 // new MediaRequest, "1" is the id for the openPosting user
312 MediaRequest mediaReq = new MediaRequest("1", true, true);
313 mp = new WebdbMultipartRequest(req, (FileHandler)mediaReq);
314 mediaList = mediaReq.getEntityList();
315 } catch (FileHandlerUserException e) {
316 throw new ServletModuleUserException(e.getMsg());
319 HashMap withValues = mp.getParameters();
321 //checking the onetimepasswd
322 if(passwdProtection.equals("yes")){
323 HttpSession session = req.getSession(false);
324 String sessionPasswd = (String)session.getAttribute("passwd");
325 if ( sessionPasswd == null){
326 throw new ServletModuleUserException("Lost password");
328 String passwd = (String)withValues.get("passwd");
329 if ( passwd == null || (!sessionPasswd.equals(passwd))) {
330 throw new ServletModuleUserException("Missing password");
332 session.invalidate();
335 if ((((String)withValues.get("title")).length() == 0) ||
336 (((String)withValues.get("description")).length() == 0) ||
337 (((String)withValues.get("content_data")).length() == 0))
338 throw new ServletModuleUserException("Missing field");
340 // call the routines that escape html
342 for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
343 String k=(String)i.next();
344 String v=(String)withValues.get(k);
346 if (k.equals("content_data")){
347 //this doesn't quite work yet, so for now, all html goes
348 //withValues.put(k,StringUtil.approveHTMLTags(v));
349 //withValues.put(k,StringUtil.removeHTMLTags(v));
351 withValues.put(k,StringUtil.removeHTMLTags(v));
356 withValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
357 withValues.put("publish_path", StringUtil.webdbDate2path((String)withValues.get("date")));
358 withValues.put("is_produced", "0");
359 // by default stuff is published, they can be un-published through the
361 withValues.put("is_published","1");
362 // if op direct article-type == newswire
363 if (directOp.equals("yes")) withValues.put("to_article_type","1");
365 withValues.put("to_publisher","1");
367 // owner is openposting user
368 // ML: this is not multi-language friendly and this can be done in a template
369 // if (withValues.get("creator").toString().equals(""))
370 // withValues.put("creator","Anonym");
372 // inserting content into database
373 String cid = contentModule.add(withValues);
374 logger.debug("insposting: id = "+cid);
375 //insert was not successfull
377 //How do we know that it was not succesful cause of a
378 //dupe, what if it failed cause of "No space left on device"?
379 //Or is there something I am missing? Wouldn't it be better
380 //to have an explicit dupe check and then insert? I have no
381 //idea what I am talking about. this comment is in case
382 //I forget to explicitely ask. -mh
383 deliver(req, res, mergeData, postingFormDupeTemplate);
386 String[] to_topicsArr = mp.getParameterValues("to_topic");
388 if (to_topicsArr != null && to_topicsArr.length > 0) {
390 DatabaseContentToTopics.getInstance().setTopics(cid,to_topicsArr);
393 catch (Exception e) {
394 logger.error("setting content_x_topic failed");
395 contentModule.deleteById(cid);
396 throw new ServletModuleException("smod - openindy :: insposting: setting content_x_topic failed: "+e.toString());
400 //if we're here all is ok... associate the media to the article
401 for(int i=0;i<mediaList.size();i++) {
402 Entity mediaEnt = (Entity)mediaList.elementAt(i);
403 DatabaseContentToMedia.getInstance().addMedia(cid,mediaEnt.getId());
407 MirGlobal.localizer().openPostings().afterContentPosting(
408 (EntityContent)contentModule.getById(cid));
410 catch (Throwable t) {
411 throw new ServletModuleException(t.getMessage());
414 catch (FileHandlerException e) { throw new ServletModuleException("MediaException: "+ e.toString());}
415 catch (IOException e) { throw new ServletModuleException("IOException: "+ e.toString());}
416 catch (StorageObjectException e) { throw new ServletModuleException("StorageObjectException" + e.toString());}
417 catch (ModuleException e) { throw new ServletModuleException("ModuleException"+e.toString());}
419 deliver(req, res, mergeData, postingFormDoneTemplate);
423 * Method for querying a lucene index
425 public void search(HttpServletRequest req, HttpServletResponse res)
426 throws ServletModuleException, ServletModuleUserException {
428 String queryString="";
430 SimpleHash mergeData = new SimpleHash();
432 //make the query available to subsequent iterations
434 for (Enumeration theParams = req.getParameterNames(); theParams.hasMoreElements() ;) {
435 String pName=(String)theParams.nextElement();
436 if (pName.startsWith("search_")){
437 mergeData.put(pName,new SimpleScalar(req.getParameter(pName)));
442 mergeData.put("topics", themenModule.getTopicsAsSimpleList());
444 catch(ModuleException e) {
445 logger.debug("search: Can't get topics: " + e.toString());
448 String indexPath=MirConfig.getProp("IndexPath");
451 KeywordSearchTerm dateTerm = new KeywordSearchTerm("date_formatted","search_date","webdb_create_formatted","webdbcreate_formatted","webdb_create_formatted");
453 UnIndexedSearchTerm whereTerm = new UnIndexedSearchTerm("","","","where","where");
455 TextSearchTerm creatorTerm = new TextSearchTerm("creator","search_creator","creator","creator","creator");
456 TextSearchTerm titleTerm = new TextSearchTerm("title","search_content","title","title","title");
457 TextSearchTerm descriptionTerm = new TextSearchTerm("description","search_content","description","description","description");
459 ContentSearchTerm contentTerm = new ContentSearchTerm("content_data","search_content","content","","");
461 TopicSearchTerm topicTerm = new TopicSearchTerm();
463 ImagesSearchTerm imagesTerm = new ImagesSearchTerm();
465 AudioSearchTerm audioTerm = new AudioSearchTerm();
467 VideoSearchTerm videoTerm = new VideoSearchTerm();
469 String creatorFragment = creatorTerm.makeTerm(req);
470 if (creatorFragment != null){
471 queryString = queryString + " +" + creatorFragment;
474 // search title, description, and content for something
475 // the contentTerm uses "search_boolean" to combine its terms
476 String contentFragment = contentTerm.makeTerm(req);
477 if (contentFragment != null){
478 logger.debug("search: contentFragment: " + contentFragment);
479 queryString = queryString + " +" + contentFragment;
482 String topicFragment = topicTerm.makeTerm(req);
483 if (topicFragment != null){
484 queryString = queryString + " +" + topicFragment;
487 String imagesFragment = imagesTerm.makeTerm(req);
488 if (imagesFragment != null){
489 queryString = queryString + " +" + imagesFragment;
492 String audioFragment = audioTerm.makeTerm(req);
493 if (audioFragment != null){
494 queryString = queryString + " +" + audioFragment;
497 String videoFragment = videoTerm.makeTerm(req);
498 if (videoFragment != null){
499 queryString = queryString + " +" + videoFragment;
502 if (queryString == null || queryString == ""){
508 Searcher searcher = null;
510 searcher = new IndexSearcher(indexPath);
512 catch(IOException e) {
513 logger.error("search: Can't open indexPath: " + indexPath + ": " + e.getMessage());
514 throw new ServletModuleUserException("Problem with Search Index!");
517 // parse the query String.
520 query = QueryParser.parse(queryString, "content", new StandardAnalyzer());
524 logger.error("search: Query don't parse: " + queryString + ": " + e.getMessage());
525 throw new ServletModuleUserException("Problem with Query String! (was '"+queryString+"')");
530 hits = searcher.search(query);
531 } catch(IOException e) {
533 logger.error("search: Can't get hits: " + e.getMessage());
534 throw new ServletModuleUserException("Problem getting hits!");
538 // this is what needs to change in order to get sorting by date
539 // iterate over the results
540 // the results are an array of document
541 // associate this with session so we don't need to reduplicate searches
542 // make a map from date to position
543 // make an list of dates
545 // grab low+n entries from the list of dates,
546 // iterate over these, using hash to get hit position,
547 // and hit position to get hit
548 // shove hit into SimpleList of SimpleHashes
554 int end = hits.length();
555 mergeData.put("numberOfHits", (new Integer(end)).toString());
556 SimpleList theHits = new SimpleList();
557 for(int i = start; i < end; i++) {
558 SimpleHash h = new SimpleHash();
559 Document theHit = hits.doc(i);
560 whereTerm.returnMeta(h,theHit);
561 creatorTerm.returnMeta(h,theHit);
562 titleTerm.returnMeta(h,theHit);
563 descriptionTerm.returnMeta(h,theHit);
564 dateTerm.returnMeta(h,theHit);
565 imagesTerm.returnMeta(h,theHit);
566 audioTerm.returnMeta(h,theHit);
567 videoTerm.returnMeta(h,theHit);
570 mergeData.put("hits",theHits);
572 catch (Exception e) {
574 logger.error("search: Can't iterate over hits: " + e.getMessage());
575 throw new ServletModuleUserException("Problem getting hits!");
579 catch (IOException e){
580 logger.error("search: Can't close searcher: " + e.toString());
581 throw new ServletModuleUserException("Problem closing searcher!");
584 mergeData.put("queryString",queryString);
585 deliver(req,res,mergeData,searchResultsTemplate);
589 * Method for dynamically generating a pdf from a fo file
591 public void getpdf(HttpServletRequest req, HttpServletResponse res)
592 throws ServletModuleException, ServletModuleUserException {
593 String ID_REQUEST_PARAM = "id";
595 String generateFO=MirConfig.getProp("GenerateFO");
596 String generatePDF=MirConfig.getProp("GeneratePDF");
598 //don't do anything if we are not making FO files, or if we are
599 //pregenerating PDF's
600 if (generateFO.equals("yes") && generatePDF.equals("no")){
601 //fop complains unless you do the logging this way
602 org.apache.log.Logger log = null;
603 Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
604 log = hierarchy.getLoggerFor("fop");
605 log.setPriority(Priority.WARN);
607 String producerStorageRoot=MirConfig.getProp("Producer.StorageRoot");
608 String producerDocRoot=MirConfig.getProp("Producer.DocRoot");
609 String templateDir=MirConfig.getPropWithHome("HTMLTemplateProcessor.Dir");
610 String xslSheet=templateDir + "/"
611 + MirConfig.getProp("Producer.PrintableContent.html2foStyleSheetName");
613 String idParam = req.getParameter(ID_REQUEST_PARAM);
614 if (idParam != null) {
615 EntityContent contentEnt =
616 (EntityContent)contentModule.getById(idParam);
617 String publishPath = contentEnt.getValue("publish_path");
618 String foFile = producerStorageRoot + producerDocRoot + "/"
619 + publishPath + "/" + idParam + ".fo";
620 XSLTInputHandler input = new XSLTInputHandler(new File(foFile),
623 ByteArrayOutputStream out = new ByteArrayOutputStream();
624 res.setContentType("application/pdf");
626 Driver driver = new Driver();
627 driver.setLogger(log);
628 driver.setRenderer(Driver.RENDER_PDF);
629 driver.setOutputStream(out);
630 driver.render(input.getParser(), input.getInputSource());
632 byte[] content = out.toByteArray();
633 res.setContentLength(content.length);
634 res.getOutputStream().write(content);
635 res.getOutputStream().flush();
637 throw new ServletModuleUserException("Missing id parameter.");
639 } catch (Exception ex) {
640 throw new ServletModuleException(ex.toString());
643 throw new ServletModuleUserException("Can't generate a PDF because the config tells me not to.");
647 private void _throwBadContentType (String fileName, String contentType)
648 throws ServletModuleUserException {
650 logger.error("Wrong file type uploaded!: " + fileName + " (" + contentType + ")");
651 throw new ServletModuleUserException("A file you uploaded is of the "
652 +"following mime-type: " + contentType + ". Unfortunately we do not support this type. ");
655 protected String createOneTimePasswd(){
656 Random r = new Random();
657 int random = r.nextInt();
658 long l = System.currentTimeMillis();
659 l = (l*l*l*l)/random;
661 String returnString = ""+l;
662 return returnString.substring(5);
666 /* this is an overwritten method of ServletModule in order
667 to use different bundles for open and admin */
668 public void deliver(HttpServletRequest req, HttpServletResponse res,
669 TemplateModelRoot rtm, TemplateModelRoot popups,
670 String templateFilename)
671 throws ServletModuleException {
672 if (rtm == null) rtm = new SimpleHash();
674 PrintWriter out = res.getWriter();
675 HTMLTemplateProcessor.process(res, templateFilename, rtm, popups, out,
676 getLocale(req), "bundles.open");
678 } catch (HTMLParseException e) {
679 throw new ServletModuleException(e.toString());
680 } catch (IOException e) {
681 throw new ServletModuleException(e.toString());