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.*;
70 import mircoders.entity.*;
71 import mircoders.storage.*;
72 import mircoders.module.*;
73 import mircoders.producer.*;
74 import mircoders.media.MediaRequest;
75 import mircoders.global.*;
76 import mircoders.localizer.*;
77 import mircoders.search.*;
80 * ServletModuleOpenIndy -
81 * is the open-access-servlet, which is responsible for
82 * adding comments to articles &
83 * open-postings to the newswire
85 * @author mir-coders group
86 * @version $Id: ServletModuleOpenIndy.java,v 1.44 2002/11/27 15:28:52 john Exp $
90 public class ServletModuleOpenIndy extends ServletModule
93 private String commentFormTemplate, commentFormDoneTemplate,
94 commentFormDupeTemplate;
95 private String postingFormTemplate, postingFormDoneTemplate,
96 postingFormDupeTemplate;
97 private String searchResultsTemplate;
98 private ModuleContent contentModule;
99 private ModuleComment commentModule;
100 private ModuleImages imageModule;
101 private ModuleTopics themenModule;
102 private String directOp ="yes";
103 private String passwdProtection ="yes";
104 // Singelton / Kontruktor
105 private static ServletModuleOpenIndy instance = new ServletModuleOpenIndy();
106 public static ServletModule getInstance() { return instance; }
108 private ServletModuleOpenIndy() {
110 theLog = Logfile.getInstance(MirConfig.getProp("Home") + MirConfig.getProp("ServletModule.OpenIndy.Logfile"));
111 commentFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentTemplate");
112 commentFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDoneTemplate");
113 commentFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDupeTemplate");
114 postingFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingTemplate");
115 postingFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDoneTemplate");
116 postingFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDupeTemplate");
117 searchResultsTemplate = MirConfig.getProp("ServletModule.OpenIndy.SearchResultsTemplate");
118 directOp = MirConfig.getProp("DirectOpenposting").toLowerCase();
119 passwdProtection = MirConfig.getProp("PasswdProtection").toLowerCase();
120 mainModule = new ModuleComment(DatabaseComment.getInstance());
121 contentModule = new ModuleContent(DatabaseContent.getInstance());
122 themenModule = new ModuleTopics(DatabaseTopics.getInstance());
123 imageModule = new ModuleImages(DatabaseImages.getInstance());
124 defaultAction="addposting";
127 catch (StorageObjectException e) {
128 theLog.printError("servletmoduleopenindy could not be initialized");
134 * Method for making a comment
137 public void addcomment(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException
139 String aid = req.getParameter("aid"); // the article id the comment will belong to
140 String language = req.getParameter("language");
142 if (aid!=null && !aid.equals(""))
144 SimpleHash mergeData = new SimpleHash();
147 if(passwdProtection.equals("yes")){
148 String passwd = this.createOneTimePasswd();
149 System.out.println(passwd);
150 HttpSession session = req.getSession(false);
151 session.setAttribute("passwd",passwd);
152 mergeData.put("passwd", passwd);
155 if (language!=null) {
156 HttpSession session = req.getSession(false);
157 session.setAttribute("Locale", new Locale(language, ""));
158 session.setAttribute("passwd",language);
161 mergeData.put("aid", aid);
162 deliver(req, res, mergeData, commentFormTemplate);
164 else throw new ServletModuleException("aid not set!");
168 * Method for inserting a comment into the Database and delivering
169 * the commentDone Page
172 public void inscomment(HttpServletRequest req, HttpServletResponse res)
173 throws ServletModuleException,ServletModuleUserException
175 String aid = req.getParameter("to_media"); // the article id the comment will belong to
176 if (aid!=null && !aid.equals(""))
178 // ok, collecting data from form
180 HashMap withValues = getIntersectingValues(req, DatabaseComment.getInstance());
182 //no html in comments(for now)
183 for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
184 String k=(String)i.next();
185 String v=(String)withValues.get(k);
187 withValues.put(k,StringUtil.removeHTMLTags(v));
189 withValues.put("is_published","1");
191 //checking the onetimepasswd
192 if(passwdProtection.equals("yes")){
193 HttpSession session = req.getSession(false);
194 String sessionPasswd = (String)session.getAttribute("passwd");
195 if ( sessionPasswd == null){
196 throw new ServletModuleUserException("Lost password");
198 String passwd = req.getParameter("passwd");
199 if ( passwd == null || (!sessionPasswd.equals(passwd))) {
200 throw new ServletModuleUserException("Missing password");
202 session.invalidate();
205 // inserting into database
206 String id = mainModule.add(withValues);
207 theLog.printDebugInfo("id: "+id);
208 //insert was not successfull
210 deliver(req, res, new SimpleHash(), commentFormDupeTemplate);
212 DatabaseContent.getInstance().setUnproduced("id="+aid);
215 EntityComment comment = (EntityComment) DatabaseComment.getInstance().selectById(id);
216 MirGlobal.localizer().openPostings().afterCommentPosting(comment);
218 catch (Throwable t) {
219 throw new ServletModuleException(t.getMessage());
226 // redirecting to url
227 // should implement back to article
228 SimpleHash mergeData = new SimpleHash();
229 deliver(req, res, mergeData, commentFormDoneTemplate);
231 catch (StorageObjectException e) { throw new ServletModuleException(e.toString());}
232 catch (ModuleException e) { throw new ServletModuleException(e.toString());}
235 else throw new ServletModuleException("aid not set!");
240 * Method for delivering the form-Page for open posting
243 public void addposting(HttpServletRequest req, HttpServletResponse res)
244 throws ServletModuleException {
245 SimpleHash mergeData = new SimpleHash();
248 if(passwdProtection.equals("yes")){
249 String passwd = this.createOneTimePasswd();
250 System.out.println(passwd);
251 HttpSession session = req.getSession(false);
252 session.setAttribute("passwd",passwd);
253 mergeData.put("passwd", passwd);
256 String maxMedia = MirConfig.getProp("ServletModule.OpenIndy.MaxMediaUploadItems");
257 String numOfMedia = req.getParameter("medianum");
258 if(numOfMedia==null||numOfMedia.equals("")){
260 } else if(Integer.parseInt(numOfMedia) > Integer.parseInt(maxMedia)) {
261 numOfMedia = maxMedia;
264 int mediaNum = Integer.parseInt(numOfMedia);
265 SimpleList mediaFields = new SimpleList();
266 for(int i =0; i<mediaNum;i++){
267 Integer mNum = new Integer(i+1);
268 mediaFields.add(mNum.toString());
270 mergeData.put("medianum",numOfMedia);
271 mergeData.put("mediafields",mediaFields);
274 SimpleHash extraInfo = new SimpleHash();
276 SimpleList popUpData = DatabaseLanguage.getInstance().getPopupData();
277 extraInfo.put("languagePopUpData", popUpData );
278 extraInfo.put("themenPopupData", themenModule.getTopicsAsSimpleList());
280 extraInfo.put("topics", themenModule.getTopicsList());
282 } catch (Exception e) {
283 theLog.printError("languagePopUpData or getTopicslist failed "
285 throw new ServletModuleException("OpenIndy -- failed getting language or topics: "+e.toString());
290 deliver(req, res, mergeData, extraInfo, postingFormTemplate);
294 * Method for inserting an open posting into the Database and delivering
295 * the postingDone Page
298 public void insposting(HttpServletRequest req, HttpServletResponse res)
299 throws ServletModuleException, ServletModuleUserException
301 SimpleHash mergeData = new SimpleHash();
302 boolean setMedia=false;
303 boolean setTopic = false;
307 WebdbMultipartRequest mp = null;
308 EntityList mediaList = null;
310 // new MediaRequest, "1" is the id for the openPosting user
311 MediaRequest mediaReq = new MediaRequest("1", true, true);
312 mp = new WebdbMultipartRequest(req, (FileHandler)mediaReq);
313 mediaList = mediaReq.getEntityList();
314 } catch (FileHandlerUserException e) {
315 throw new ServletModuleUserException(e.getMsg());
318 HashMap withValues = mp.getParameters();
320 //checking the onetimepasswd
321 if(passwdProtection.equals("yes")){
322 HttpSession session = req.getSession(false);
323 String sessionPasswd = (String)session.getAttribute("passwd");
324 if ( sessionPasswd == null){
325 throw new ServletModuleUserException("Lost password");
327 String passwd = (String)withValues.get("passwd");
328 if ( passwd == null || (!sessionPasswd.equals(passwd))) {
329 throw new ServletModuleUserException("Missing password");
331 session.invalidate();
334 if ((((String)withValues.get("title")).length() == 0) ||
335 (((String)withValues.get("description")).length() == 0) ||
336 (((String)withValues.get("content_data")).length() == 0))
337 throw new ServletModuleUserException("Missing field");
339 // call the routines that escape html
341 for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
342 String k=(String)i.next();
343 String v=(String)withValues.get(k);
345 if (k.equals("content_data")){
346 //this doesn't quite work yet, so for now, all html goes
347 //withValues.put(k,StringUtil.approveHTMLTags(v));
348 //withValues.put(k,StringUtil.removeHTMLTags(v));
350 withValues.put(k,StringUtil.removeHTMLTags(v));
355 withValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
356 withValues.put("publish_path", StringUtil.webdbDate2path((String)withValues.get("date")));
357 withValues.put("is_produced", "0");
358 // by default stuff is published, they can be un-published through the
360 withValues.put("is_published","1");
361 // if op direct article-type == newswire
362 if (directOp.equals("yes")) withValues.put("to_article_type","1");
364 withValues.put("to_publisher","1");
366 // owner is openposting user
367 // ML: this is not multi-language friendly and this can be done in a template
368 // if (withValues.get("creator").toString().equals(""))
369 // withValues.put("creator","Anonym");
371 // inserting content into database
372 String cid = contentModule.add(withValues);
373 theLog.printDebugInfo("id: "+cid);
374 //insert was not successfull
376 //How do we know that it was not succesful cause of a
377 //dupe, what if it failed cause of "No space left on device"?
378 //Or is there something I am missing? Wouldn't it be better
379 //to have an explicit dupe check and then insert? I have no
380 //idea what I am talking about. this comment is in case
381 //I forget to explicitely ask. -mh
382 deliver(req, res, mergeData, postingFormDupeTemplate);
385 String[] to_topicsArr = mp.getParameterValues("to_topic");
387 if (to_topicsArr != null && to_topicsArr.length > 0) {
389 DatabaseContentToTopics.getInstance().setTopics(cid,to_topicsArr);
391 } catch (Exception e) {
392 theLog.printError("setting content_x_topic failed");
393 contentModule.deleteById(cid);
394 throw new ServletModuleException("smod - openindy :: insposting: setting content_x_topic failed: "+e.toString());
398 //if we're here all is ok... associate the media to the article
399 for(int i=0;i<mediaList.size();i++) {
400 Entity mediaEnt = (Entity)mediaList.elementAt(i);
401 DatabaseContentToMedia.getInstance().addMedia(cid,mediaEnt.getId());
405 MirGlobal.localizer().openPostings().afterContentPosting(
406 (EntityContent)contentModule.getById(cid));
408 catch (Throwable t) {
409 throw new ServletModuleException(t.getMessage());
412 catch (FileHandlerException e) { throw new ServletModuleException("MediaException: "+ e.toString());}
413 catch (IOException e) { throw new ServletModuleException("IOException: "+ e.toString());}
414 catch (StorageObjectException e) { throw new ServletModuleException("StorageObjectException" + e.toString());}
415 catch (ModuleException e) { throw new ServletModuleException("ModuleException"+e.toString());}
417 deliver(req, res, mergeData, postingFormDoneTemplate);
421 * Method for querying a lucene index
423 public void search(HttpServletRequest req, HttpServletResponse res)
424 throws ServletModuleException, ServletModuleUserException {
426 String queryString="";
428 SimpleHash mergeData = new SimpleHash();
430 //make the query available to subsequent iterations
432 for (Enumeration theParams = req.getParameterNames(); theParams.hasMoreElements() ;) {
433 String pName=(String)theParams.nextElement();
434 if (pName.startsWith("search_")){
435 mergeData.put(pName,new SimpleScalar(req.getParameter(pName)));
440 mergeData.put("topics", themenModule.getTopicsAsSimpleList());
442 catch(ModuleException e) {
443 theLog.printDebugInfo("Can't get topics: " + e.toString());
446 //String indexPath=MirConfig.getProp("IndexPath");
447 String indexPath="/tmp/index";
449 KeywordSearchTerm dateTerm = new KeywordSearchTerm("date_formatted","search_date","webdb_create_formatted","webdbcreate_formatted","webdb_create_formatted");
451 UnIndexedSearchTerm whereTerm = new UnIndexedSearchTerm("","","","where","where");
453 TextSearchTerm creatorTerm = new TextSearchTerm("creator","search_creator","creator","creator","creator");
454 TextSearchTerm titleTerm = new TextSearchTerm("title","search_content","title","title","title");
455 TextSearchTerm descriptionTerm = new TextSearchTerm("description","search_content","description","description","description");
457 ContentSearchTerm contentTerm = new ContentSearchTerm("content_data","search_content","content","","");
459 TopicSearchTerm topicTerm = new TopicSearchTerm();
461 ImagesSearchTerm imagesTerm = new ImagesSearchTerm();
463 AudioSearchTerm audioTerm = new AudioSearchTerm();
465 VideoSearchTerm videoTerm = new VideoSearchTerm();
467 String creatorFragment = creatorTerm.makeTerm(req);
468 if (creatorFragment != null){
469 queryString = queryString + " +" + creatorFragment;
472 // search title, description, and content for something
473 // the contentTerm uses "search_boolean" to combine its terms
474 String contentFragment = contentTerm.makeTerm(req);
475 if (contentFragment != null){
476 theLog.printDebugInfo("contentFragment: " + contentFragment);
477 queryString = queryString + " +" + contentFragment;
480 String topicFragment = topicTerm.makeTerm(req);
481 if (topicFragment != null){
482 queryString = queryString + " +" + topicFragment;
485 String imagesFragment = imagesTerm.makeTerm(req);
486 if (imagesFragment != null){
487 queryString = queryString + " +" + imagesFragment;
490 String audioFragment = audioTerm.makeTerm(req);
491 if (audioFragment != null){
492 queryString = queryString + " +" + audioFragment;
495 String videoFragment = videoTerm.makeTerm(req);
496 if (videoFragment != null){
497 queryString = queryString + " +" + videoFragment;
500 if (queryString == null || queryString == ""){
506 Searcher searcher = null;
508 searcher = new IndexSearcher(indexPath);
510 catch(IOException e) {
511 theLog.printDebugInfo("Can't open indexPath: " + indexPath);
512 throw new ServletModuleUserException("Problem with Search Index!");
515 // parse the query String.
518 query = QueryParser.parse(queryString, "content", new StandardAnalyzer());
522 theLog.printDebugInfo("Query don't parse: " + queryString);
523 throw new ServletModuleUserException("Problem with Query String! (was '"+queryString+"')");
528 hits = searcher.search(query);
529 } catch(IOException e) {
531 theLog.printDebugInfo("Can't get hits: " + e.toString());
532 throw new ServletModuleUserException("Problem getting hits!");
536 // this is what needs to change in order to get sorting by date
537 // iterate over the results
538 // the results are an array of document
539 // associate this with session so we don't need to reduplicate searches
540 // make a map from date to position
541 // make an list of dates
543 // grab low+n entries from the list of dates,
544 // iterate over these, using hash to get hit position,
545 // and hit position to get hit
546 // shove hit into SimpleList of SimpleHashes
552 int end = hits.length();
553 mergeData.put("numberOfHits", (new Integer(end)).toString());
554 SimpleList theHits = new SimpleList();
555 for(int i = start; i < end; i++) {
556 SimpleHash h = new SimpleHash();
557 Document theHit = hits.doc(i);
558 whereTerm.returnMeta(h,theHit);
559 creatorTerm.returnMeta(h,theHit);
560 titleTerm.returnMeta(h,theHit);
561 descriptionTerm.returnMeta(h,theHit);
562 dateTerm.returnMeta(h,theHit);
563 imagesTerm.returnMeta(h,theHit);
564 audioTerm.returnMeta(h,theHit);
565 videoTerm.returnMeta(h,theHit);
568 mergeData.put("hits",theHits);
570 catch (Exception e) {
572 theLog.printDebugInfo("Can't iterate over hits: " + e.toString());
573 throw new ServletModuleUserException("Problem getting hits!");
577 catch (IOException e){
578 theLog.printDebugInfo("Can't close searcher: " + e.toString());
579 throw new ServletModuleUserException("Problem closing searcher!");
582 mergeData.put("queryString",queryString);
583 deliver(req,res,mergeData,searchResultsTemplate);
587 * Method for dynamically generating a pdf from a fo file
589 public void getpdf(HttpServletRequest req, HttpServletResponse res)
590 throws ServletModuleException, ServletModuleUserException {
591 String ID_REQUEST_PARAM = "id";
593 String generateFO=MirConfig.getProp("GenerateFO");
594 String generatePDF=MirConfig.getProp("GeneratePDF");
596 //don't do anything if we are not making FO files, or if we are
597 //pregenerating PDF's
598 if (generateFO.equals("yes") && generatePDF.equals("no")){
599 //fop complains unless you do the logging this way
601 Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
602 log = hierarchy.getLoggerFor("fop");
603 log.setPriority(Priority.WARN);
605 String producerStorageRoot=MirConfig.getProp("Producer.StorageRoot");
606 String producerDocRoot=MirConfig.getProp("Producer.DocRoot");
607 String templateDir=MirConfig.getPropWithHome("HTMLTemplateProcessor.Dir");
608 String xslSheet=templateDir + "/"
609 + MirConfig.getProp("Producer.PrintableContent.html2foStyleSheetName");
611 String idParam = req.getParameter(ID_REQUEST_PARAM);
612 if (idParam != null) {
613 EntityContent contentEnt =
614 (EntityContent)contentModule.getById(idParam);
615 String publishPath = contentEnt.getValue("publish_path");
616 String foFile = producerStorageRoot + producerDocRoot + "/"
617 + publishPath + "/" + idParam + ".fo";
618 XSLTInputHandler input = new XSLTInputHandler(new File(foFile),
621 ByteArrayOutputStream out = new ByteArrayOutputStream();
622 res.setContentType("application/pdf");
624 Driver driver = new Driver();
625 driver.setLogger(log);
626 driver.setRenderer(Driver.RENDER_PDF);
627 driver.setOutputStream(out);
628 driver.render(input.getParser(), input.getInputSource());
630 byte[] content = out.toByteArray();
631 res.setContentLength(content.length);
632 res.getOutputStream().write(content);
633 res.getOutputStream().flush();
635 throw new ServletModuleUserException("Missing id parameter.");
637 } catch (Exception ex) {
638 throw new ServletModuleException(ex.toString());
641 throw new ServletModuleUserException("Can't generate a PDF because the config tells me not to.");
645 private void _throwBadContentType (String fileName, String contentType)
646 throws ServletModuleUserException {
648 theLog.printDebugInfo("Wrong file type uploaded!: " + fileName+" "
650 throw new ServletModuleUserException("The file you uploaded is of the "
651 +"following mime-type: "+contentType
652 +", we do not support this mime-type. "
653 +"Error One or more files of unrecognized type. Sorry");
656 protected String createOneTimePasswd(){
657 Random r = new Random();
658 int random = r.nextInt();
659 long l = System.currentTimeMillis();
660 l = (l*l*l*l)/random;
662 String returnString = ""+l;
663 return returnString.substring(5);
667 /* this is an overwritten method of ServletModule in order
668 to use different bundles for open and admin */
669 public void deliver(HttpServletRequest req, HttpServletResponse res,
670 TemplateModelRoot rtm, TemplateModelRoot popups,
671 String templateFilename)
672 throws ServletModuleException {
673 if (rtm == null) rtm = new SimpleHash();
675 PrintWriter out = res.getWriter();
676 HTMLTemplateProcessor.process(res, templateFilename, rtm, popups, out,
677 getLocale(req), "bundles.open");
679 } catch (HTMLParseException e) {
680 throw new ServletModuleException(e.toString());
681 } catch (IOException e) {
682 throw new ServletModuleException(e.toString());