added better support for article urls in PDF files
[mir.git] / source / mircoders / servlet / ServletModuleOpenIndy.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
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.
10  *
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.f
15  *
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
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30
31 package mircoders.servlet;
32
33 import gnu.regexp.RE;
34 import gnu.regexp.REMatch;
35 import mir.bundle.Bundle;
36 import mir.generator.Generator;
37 import mir.misc.StringUtil;
38 import mir.servlet.ServletModule;
39 import mir.servlet.ServletModuleExc;
40 import mir.servlet.ServletModuleFailure;
41 import mir.servlet.ServletModuleUserExc;
42 import mir.session.HTTPAdapters;
43 import mir.session.Request;
44 import mir.session.Session;
45 import mir.session.SessionHandler;
46 import mir.session.SimpleResponse;
47 import mir.util.FileRoutines;
48 import mir.util.HTTPParsedRequest;
49 import mir.util.HTTPRequestParser;
50 import mir.util.StringRoutines;
51 import mir.module.ModuleExc;
52 import mircoders.entity.EntityContent;
53 import mircoders.global.CacheKey;
54 import mircoders.global.MirGlobal;
55 import mircoders.module.ModuleContent;
56 import mircoders.pdf.PDFGenerator;
57 import mircoders.search.AudioSearchTerm;
58 import mircoders.search.ContentSearchTerm;
59 import mircoders.search.ImagesSearchTerm;
60 import mircoders.search.KeywordSearchTerm;
61 import mircoders.search.TextSearchTerm;
62 import mircoders.search.TopicMatrixSearchTerm;
63 import mircoders.search.TopicSearchTerm;
64 import mircoders.search.UnIndexedSearchTerm;
65 import mircoders.search.VideoSearchTerm;
66 import mircoders.storage.DatabaseTopics;
67 import mircoders.localizer.MirLocalizerExc;
68 import org.apache.commons.net.smtp.SMTPClient;
69 import org.apache.commons.net.smtp.SMTPReply;
70 import org.apache.lucene.analysis.standard.StandardAnalyzer;
71 import org.apache.lucene.document.Document;
72 import org.apache.lucene.queryParser.QueryParser;
73 import org.apache.lucene.search.Hits;
74 import org.apache.lucene.search.IndexSearcher;
75 import org.apache.lucene.search.Query;
76 import org.apache.lucene.search.Searcher;
77 import org.apache.lucene.store.FSDirectory;
78
79 import javax.servlet.http.HttpServletRequest;
80 import javax.servlet.http.HttpServletResponse;
81 import javax.servlet.http.HttpSession;
82 import java.io.ByteArrayOutputStream;
83 import java.io.File;
84 import java.io.IOException;
85 import java.io.PrintWriter;
86 import java.io.StringWriter;
87 import java.util.ArrayList;
88 import java.util.Arrays;
89 import java.util.Collections;
90 import java.util.GregorianCalendar;
91 import java.util.HashMap;
92 import java.util.Iterator;
93 import java.util.List;
94 import java.util.ListIterator;
95 import java.util.Locale;
96 import java.util.Map;
97 import java.util.Random;
98 import java.util.Set;
99
100 /*
101  */
102
103 public class ServletModuleOpenIndy extends ServletModule {
104   private String        searchResultsTemplate;
105   private String        prepareMailTemplate,sentMailTemplate,emailAnArticleTemplate;
106   private ModuleContent contentModule;
107
108   public ServletModuleOpenIndy() {
109     searchResultsTemplate = getConfiguration().getString("ServletModule.OpenIndy.SearchResultsTemplate");
110     prepareMailTemplate = getConfiguration().getString("ServletModule.OpenIndy.PrepareMailTemplate");
111     emailAnArticleTemplate = getConfiguration().getString("ServletModule.OpenIndy.MailableArticleTemplate");
112     sentMailTemplate = getConfiguration().getString("ServletModule.OpenIndy.SentMailTemplate");
113
114     contentModule = new ModuleContent();
115   }
116
117   /**
118    * Perform the default open posting action
119    */
120   public void defaultAction(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
121     opensession(aRequest, aResponse);
122   }
123
124   /**
125    * Method to return an out of service notice when open postings are disabled
126    *
127    * @param aRequest
128    * @param aResponse
129    * @throws ServletModuleExc
130    * @throws ServletModuleUserExc
131    * @throws ServletModuleFailure
132    */
133   public void openPostingDisabled(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
134     deliver(aRequest, aResponse, null, null, getConfiguration().getString("ServletModule.OpenIndy.PostingDisabledTemplate"));
135   }
136
137   /**
138    * Due to a serious shortcoming of Tomcat 3.3, an extra sessionid parameter is
139    *   generated into open session urls. Tomcat 3.3 makes it impossible to
140    *   distinguish between sessions that are identified using a url and those
141    *   that are identified using cookies: if both a sessionid cookie and a sessionid
142    *   url are available, tomcat 3.3 pretends the url wasn't there...
143    */
144   private static final String SESSION_REQUEST_KEY="sessionid";
145
146   /**
147    * Determines the Locale to be used for the current session
148    */
149   protected Locale getResponseLocale(HttpSession aSession, HttpServletRequest aRequest) {
150     String requestLanguage = aRequest.getParameter("language");
151     String sessionLanguage = (String) aSession.getAttribute("language");
152     String acceptLanguage = aRequest.getLocale().getLanguage();
153     String defaultLanguage = getConfiguration().getString("Mir.Login.DefaultLanguage", "en");
154
155     String language = requestLanguage;
156
157     if (language==null)
158       language = sessionLanguage;
159
160     if (language==null)
161       language = acceptLanguage;
162
163     if (language==null)
164       language = defaultLanguage;
165
166     aSession.setAttribute("language", language);
167
168     return new Locale(language, "");
169   }
170
171   /**
172    * Dispatch method for open sessions: a flexible extensible and customizable way
173    *   for open access. Can be used for postings, but also for lots of other stuff.
174    *
175    * @param aRequest
176    * @param aResponse
177    * @throws ServletModuleExc
178    * @throws ServletModuleUserExc
179    * @throws ServletModuleFailure
180    */
181   public void opensession(HttpServletRequest aRequest, HttpServletResponse aResponse)
182       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
183
184     try {
185       Request request =
186           new HTTPAdapters.HTTPParsedRequestAdapter(new HTTPParsedRequest(aRequest,
187               getConfiguration().getString("Mir.DefaultEncoding"),
188               getConfiguration().getInt("MaxMediaUploadSize")*1024,
189               getConfiguration().getString("TempDir")));
190
191       if (aRequest.isRequestedSessionIdValid() && !aRequest.isRequestedSessionIdFromURL() &&
192           !aRequest.getRequestedSessionId().equals(aRequest.getParameter(SESSION_REQUEST_KEY))) {
193         aRequest.getSession().invalidate();
194       }
195
196       Session session = new HTTPAdapters.HTTPSessionAdapter(aRequest.getSession());
197
198       SimpleResponse response = new SimpleResponse(
199           ServletHelper.makeGenerationData(aRequest, aResponse,
200               new Locale[] {
201                   getResponseLocale(aRequest.getSession(), aRequest),
202                   getFallbackLocale(aRequest)
203               },
204              "etc/bundles/open"));
205
206       response.setResponseValue("actionURL", aResponse.encodeURL(MirGlobal.config().getString("RootUri") + "/servlet/OpenMir")+"?"+SESSION_REQUEST_KEY+"="+aRequest.getSession().getId());
207
208       SessionHandler handler = MirGlobal.localizer().openPostings().getOpenSessionHandler(request, session);
209
210       handler.processRequest(request, session, response);
211       ServletHelper.generateOpenPostingResponse(aResponse.getWriter(), response.getResponseValues(), response.getResponseGenerator());
212     }
213     catch (Throwable t) {
214       getLogger().error(t.toString(), t);
215
216       throw new ServletModuleFailure(t);
217     }
218   }
219
220   /**
221    * Method for preparing and sending a content as an email message
222    */
223   public void mail(HttpServletRequest aRequest, HttpServletResponse aResponse)
224       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
225     String aid = aRequest.getParameter("mail_aid");
226     if (aid == null){
227       throw new ServletModuleExc("An article id must be specified in requests " +
228           "to email an article.  Something therefore went badly wrong....");
229     }
230
231     String to = aRequest.getParameter("mail_to");
232     String from = aRequest.getParameter("mail_from");
233     String from_name = aRequest.getParameter("mail_from_name");
234     String from_ip = aRequest.getRemoteAddr();
235     String comment = aRequest.getParameter("mail_comment");
236     String mail_language = aRequest.getParameter("mail_language");
237
238     Map mergeData = new HashMap();
239     mergeData.put("mail_to",to);
240     mergeData.put("mail_from",from);
241     mergeData.put("mail_from_name",from_name);
242     mergeData.put("mail_comment",comment);
243     mergeData.put("mail_aid",aid);
244     mergeData.put("mail_language",mail_language);
245
246
247     if (to == null || from == null || from_name == null|| to.equals("") || from.equals("") || from_name.equals("") || mail_language == null || mail_language.equals("")){
248       deliver(aRequest, aResponse, mergeData, null, prepareMailTemplate);
249     }
250     else {
251       //run checks on to and from and mail_language to make sure no monkey business occurring
252       if (mail_language.indexOf('.') != -1 || mail_language.indexOf('/') != -1 ) {
253         throw new ServletModuleExc("Invalid language");
254       }
255       if (to.indexOf('\n') != -1
256           || to.indexOf('\r') != -1
257           || to.indexOf(',') != -1) {
258         throw new ServletModuleUserExc("email.error.invalidtoaddress", new String[] {to});
259       }
260       if (from.indexOf('\n') != -1 || from.indexOf('\r') != -1 || from.indexOf(',') != -1 ) {
261         throw new ServletModuleUserExc("email.error.invalidfromaddress", new String[] {from});
262       }
263
264       CacheKey theCacheKey=new CacheKey("email",aid+mail_language);
265       String theEmailText;
266
267       EntityContent article;
268       try {
269         article = (EntityContent) contentModule.getById(aid);
270       }
271       catch (ModuleExc e) {
272         throw new ServletModuleExc("Couldn't retrieve article " + aid);
273       }
274
275       if (!MirGlobal.localizer().openPostings().allowArticlePublication(article)) {
276         throw new ServletModuleExc("Illegal article");
277       }
278
279       if (MirGlobal.mruCache().hasObject(theCacheKey)){
280         getLogger().info("fetching email text for article "+aid+" from cache");
281         theEmailText = (String) MirGlobal.mruCache().getObject(theCacheKey);
282       }
283       else {
284         StringWriter theEMailTextWriter = new StringWriter();
285         PrintWriter dest = new PrintWriter(theEMailTextWriter);
286         try {
287           Map articleData = new HashMap();
288           try {
289             articleData.put("article",
290                 MirGlobal.localizer().dataModel().adapterModel().makeEntityAdapter("content", article));
291           }
292           catch (MirLocalizerExc e) {
293             throw new ServletModuleExc("Can't retrieve article " + aid, e);
294           }
295           articleData.put("languagecode", mail_language);
296           deliver(dest, aRequest, aResponse, articleData, null, emailAnArticleTemplate, mail_language);
297         }
298         finally {
299           dest.close();
300         }
301         theEmailText = theEMailTextWriter.toString();
302         MirGlobal.mruCache().storeObject(theCacheKey, theEmailText);
303       }
304
305       String content = theEmailText;
306
307       // add some headers
308       content = "To: " + to + "\nReply-To: "+ from + "\nX-Originating-IP: "+ from_ip + "\n" + content;
309       // put in the comment where it should go
310       if (comment != null) {
311         String commentTextToInsert = "\n\nAttached comment from " + from_name + ":\n" + comment;
312         try {
313           content=StringRoutines.performRegularExpressionReplacement(content,"!COMMENT!",commentTextToInsert);
314         }
315         catch (Throwable e){
316           throw new ServletModuleFailure("Problem doing regular expression replacement " + e.toString(), e);
317         }
318       }
319       else{
320         try {
321           content=StringRoutines.performRegularExpressionReplacement(content,"!COMMENT!","");
322         }
323         catch (Throwable e){
324           throw new ServletModuleFailure("Problem doing regular expression replacement " + e.toString(), e);
325         }
326       }
327
328       SMTPClient client=new SMTPClient();
329       try {
330         int reply;
331         client.connect(getConfiguration().getString("ServletModule.OpenIndy.SMTPServer"));
332
333         reply = client.getReplyCode();
334
335         if (!SMTPReply.isPositiveCompletion(reply)) {
336           client.disconnect();
337           throw new ServletModuleExc("SMTP server refused connection.");
338         }
339
340         client.sendSimpleMessage(getConfiguration().getString("ServletModule.OpenIndy.EmailIsFrom"), to, content);
341
342         client.disconnect();
343         //mission accomplished
344         deliver(aRequest, aResponse, mergeData, null, sentMailTemplate);
345       }
346       catch(IOException e) {
347         if(client.isConnected()) {
348           try {
349             client.disconnect();
350           } catch(IOException f) {
351             // do nothing
352           }
353         }
354         throw new ServletModuleFailure(e);
355       }
356     }
357   }
358
359
360
361   /**
362    * Method for querying a lucene index
363    *
364    * @param req
365    * @param res
366    * @throws ServletModuleExc
367    * @throws ServletModuleUserExc
368    * @throws ServletModuleFailure
369    */
370
371   public void search(HttpServletRequest req, HttpServletResponse res) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
372     try {
373       final String[] search_variables = {
374           "search_content", "search_boolean", "search_creator",
375           "search_topic", "search_hasImages", "search_hasAudio", "search_hasVideo", "search_sort",
376           "search_submit", "search_back", "search_forward"};
377       HTTPRequestParser requestParser = new HTTPRequestParser(req);
378
379       int increment = 10;
380
381       HttpSession session = req.getSession(false);
382
383       String queryString = "";
384
385       Map mergeData = new HashMap();
386
387       KeywordSearchTerm dateTerm = new KeywordSearchTerm("date_formatted", "search_date", "webdb_create_formatted", "webdb_create_formatted", "webdb_create_formatted");
388       UnIndexedSearchTerm whereTerm = new UnIndexedSearchTerm("", "", "", "where", "where");
389       TextSearchTerm creatorTerm = new TextSearchTerm("creator", "search_creator", "creator", "creator", "creator");
390       TextSearchTerm titleTerm = new TextSearchTerm("title", "search_content", "title", "title", "title");
391       TextSearchTerm descriptionTerm = new TextSearchTerm("description", "search_content", "description", "description", "description");
392       ContentSearchTerm contentTerm = new ContentSearchTerm("content_data", "search_content", "content", "", "");
393       TopicSearchTerm topicTerm = new TopicSearchTerm();
394       TopicMatrixSearchTerm topicMatrixTerm = new TopicMatrixSearchTerm();
395       ImagesSearchTerm imagesTerm = new ImagesSearchTerm();
396       AudioSearchTerm audioTerm = new AudioSearchTerm();
397       VideoSearchTerm videoTerm = new VideoSearchTerm();
398
399       //make the query available to subsequent iterations
400
401       Iterator j = Arrays.asList(search_variables).iterator();
402       while (j.hasNext()) {
403         String variable = (String) j.next();
404
405         mergeData.put(variable, requestParser.getParameter(variable));
406       }
407
408       try {
409         mergeData.put("topics", DatabaseTopics.getInstance().getPopupData());
410       }
411       catch (Throwable e) {
412         getLogger().debug("Can't get topics: " + e.toString());
413       }
414
415       String searchBackValue = req.getParameter("search_back");
416       String searchForwardValue = req.getParameter("search_forward");
417
418       if (searchBackValue != null) {
419         int totalHits = ( (Integer) session.getAttribute("numberOfHits")).intValue();
420         int newPosition = ( (Integer) session.getAttribute("positionInResults")).intValue() - increment;
421         if (newPosition < 0)
422           newPosition = 0;
423         if (newPosition >= totalHits)
424           newPosition = totalHits - 1;
425         session.setAttribute("positionInResults", new Integer(newPosition));
426       }
427       else {
428         if (searchForwardValue != null) {
429           int totalHits = ( (Integer) session.getAttribute("numberOfHits")).intValue();
430           int newPosition = ( (Integer) session.getAttribute("positionInResults")).intValue() + increment;
431           if (newPosition < 0)
432             newPosition = 0;
433           if (newPosition >= totalHits)
434             newPosition = totalHits - 1;
435
436           session.setAttribute("positionInResults", new Integer(newPosition));
437         }
438         else {
439           File indexFile = FileRoutines.getAbsoluteOrRelativeFile(getConfiguration().getHome(), getConfiguration().getString("IndexPath"));
440
441           String creatorFragment = creatorTerm.makeTerm(req);
442           if (creatorFragment != null) {
443             queryString = queryString + " +" + creatorFragment;
444           }
445
446           // search title, description, and content for something
447           // the contentTerm uses param "search_boolean" to combine its terms
448           String contentFragment = contentTerm.makeTerm(req);
449           if (contentFragment != null) {
450             getLogger().debug("contentFragment: " + contentFragment);
451             queryString = queryString + " +" + contentFragment;
452           }
453
454           String topicFragment = topicTerm.makeTerm(req);
455           if (topicFragment != null) {
456             queryString = queryString + " +" + topicFragment;
457           }
458
459           String topicMatrixFragment = topicMatrixTerm.makeTerm(req);
460           if (topicMatrixFragment != null) {
461             queryString = queryString + " +" + topicMatrixFragment;
462           }
463
464           String imagesFragment = imagesTerm.makeTerm(req);
465           if (imagesFragment != null) {
466             queryString = queryString + " +" + imagesFragment;
467           }
468
469           String audioFragment = audioTerm.makeTerm(req);
470           if (audioFragment != null) {
471             queryString = queryString + " +" + audioFragment;
472           }
473
474           String videoFragment = videoTerm.makeTerm(req);
475           if (videoFragment != null) {
476             queryString = queryString + " +" + videoFragment;
477           }
478
479           if (queryString == null || queryString.length()==0) {
480             queryString = "";
481           }
482           else {
483             try {
484               Searcher searcher = null;
485
486               try {
487                 searcher = new IndexSearcher(FSDirectory.getDirectory(indexFile,false));
488               }
489               catch (IOException e) {
490                 getLogger().debug("Can't open indexPath: " + indexFile.getAbsolutePath());
491                 throw new ServletModuleExc("Problem with Search Index! : " + e.toString());
492               }
493
494               Query query;
495               try {
496                 query = QueryParser.parse(queryString, "content", new StandardAnalyzer());
497               }
498               catch (Exception e) {
499                 searcher.close();
500                 getLogger().debug("Query don't parse: " + queryString);
501                 throw new ServletModuleExc("Problem with Query String! (was '" + queryString + "')");
502               }
503
504               Hits hits = null;
505               try {
506                 hits = searcher.search(query);
507               }
508               catch (IOException e) {
509                 searcher.close();
510                 getLogger().debug("Can't get hits: " + e.toString());
511                 throw new ServletModuleExc("Problem getting hits!");
512               }
513
514               int start = 0;
515               int end = hits.length();
516
517               String sortBy = req.getParameter("search_sort");
518               if (sortBy == null || sortBy.equals("")) {
519                 throw new ServletModuleExc("Please let me sort by something!(missing search_sort)");
520               }
521
522               // here is where the documents will go for database across sessions
523               ArrayList theDocumentsSorted = new ArrayList();
524
525               if (sortBy.equals("score")) {
526                 for (int i = start; i < end; i++) {
527                   theDocumentsSorted.add(hits.doc(i));
528                 }
529               }
530               else {
531                 // then we'll sort by date!
532                 Map dateToPosition = new HashMap(end, 1.0F); //we know how big it will be
533                 for (int i = start; i < end; i++) {
534                   String creationDate = (hits.doc(i)).get("creationDate");
535                   // do a little dance in case two contents created at the same second!
536                   if (dateToPosition.containsKey(creationDate)) {
537                     ( (ArrayList) (dateToPosition.get(creationDate))).add(new Integer(i));
538                   }
539                   else {
540                     ArrayList thePositions = new ArrayList();
541                     thePositions.add(new Integer(i));
542                     dateToPosition.put(creationDate, thePositions);
543                   }
544                 }
545                 Set keys = dateToPosition.keySet();
546                 ArrayList keyList = new ArrayList(keys);
547                 Collections.sort(keyList);
548                 if (sortBy.equals("date_desc")) {
549                   Collections.reverse(keyList);
550                 }
551                 else {
552                   if (!sortBy.equals("date_asc")) {
553                     throw new ServletModuleExc("don't know how to sort by: " + sortBy);
554                   }
555                 }
556                 ListIterator keyTraverser = keyList.listIterator();
557                 while (keyTraverser.hasNext()) {
558                   ArrayList positions = (ArrayList) dateToPosition.get( (keyTraverser.next()));
559                   ListIterator positionsTraverser = positions.listIterator();
560                   while (positionsTraverser.hasNext()) {
561                     theDocumentsSorted.add(hits.doc( ( (Integer) (positionsTraverser.next())).intValue()));
562                   }
563                 }
564               }
565
566               try {
567                 searcher.close();
568               }
569               catch (IOException e) {
570                 getLogger().debug("Can't close searcher: " + e.toString());
571                 throw new ServletModuleFailure("Problem closing searcher(normal):" + e.getMessage(), e);
572               }
573
574               session.removeAttribute("numberOfHits");
575               session.removeAttribute("theDocumentsSorted");
576               session.removeAttribute("positionInResults");
577
578               session.setAttribute("numberOfHits", new Integer(end));
579               session.setAttribute("theDocumentsSorted", theDocumentsSorted);
580               session.setAttribute("positionInResults", new Integer(0));
581
582             }
583             catch (IOException e) {
584               getLogger().debug("Can't close searcher: " + e.toString());
585               throw new ServletModuleFailure("Problem closing searcher: " + e.getMessage(), e);
586             }
587           }
588         }
589       }
590
591       try {
592         ArrayList theDocs = (ArrayList) session.getAttribute("theDocumentsSorted");
593         if (theDocs != null) {
594
595           mergeData.put("numberOfHits", (session.getAttribute("numberOfHits")).toString());
596           List theHits = new ArrayList();
597           int pIR = ( (Integer) session.getAttribute("positionInResults")).intValue();
598           int terminus;
599           int numHits = ( (Integer) session.getAttribute("numberOfHits")).intValue();
600
601           if (! (pIR + increment >= numHits)) {
602             mergeData.put("hasNext", "y");
603           }
604           else {
605             mergeData.put("hasNext", null);
606           }
607           if (pIR > 0) {
608             mergeData.put("hasPrevious", "y");
609           }
610           else {
611             mergeData.put("hasPrevious", null);
612           }
613
614           if ( (pIR + increment) > numHits) {
615             terminus = numHits;
616           }
617           else {
618             terminus = pIR + increment;
619           }
620           for (int i = pIR; i < terminus; i++) {
621             Map h = new HashMap();
622             Document theHit = (Document) theDocs.get(i);
623             whereTerm.returnMeta(h, theHit);
624             creatorTerm.returnMeta(h, theHit);
625             titleTerm.returnMeta(h, theHit);
626             descriptionTerm.returnMeta(h, theHit);
627             dateTerm.returnMeta(h, theHit);
628             imagesTerm.returnMeta(h, theHit);
629             audioTerm.returnMeta(h, theHit);
630             videoTerm.returnMeta(h, theHit);
631             theHits.add(h);
632           }
633           mergeData.put("hits", theHits);
634         }
635       }
636       catch (Throwable e) {
637         getLogger().error("Can't iterate over hits: " + e.toString());
638
639         throw new ServletModuleFailure("Problem getting hits: " + e.getMessage(), e);
640       }
641
642       mergeData.put("queryString", queryString);
643
644       deliver(req, res, mergeData, null, searchResultsTemplate);
645     }
646     catch (NullPointerException n) {
647       throw new ServletModuleFailure("Null Pointer: " + n.toString(), n);
648     }
649   }
650
651   /*
652    * Method for dynamically generating a pdf using iText
653    */
654
655   public void getpdf(HttpServletRequest aRequest, HttpServletResponse aResponse)
656       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {
657
658     long starttime = System.currentTimeMillis();
659
660     String ID_REQUEST_PARAM = "id";
661     int maxArticlesInNewsleter = 15; // it is nice not to be dos'ed
662     try {
663       String idParam = aRequest.getParameter(ID_REQUEST_PARAM);
664       if (idParam != null) {
665         RE re = new RE("[0-9]+");
666
667         REMatch[] idMatches = re.getAllMatches(idParam);
668         String cacheSelector = "";
669
670         for (int i = 0; i < idMatches.length; i++) {
671           cacheSelector = cacheSelector + "," + idMatches[i].toString();
672         }
673
674         String cacheType = "pdf";
675
676         CacheKey theCacheKey = new CacheKey(cacheType, cacheSelector);
677
678         byte[] thePDF;
679
680         if (MirGlobal.mruCache().hasObject(theCacheKey)) {
681           getLogger().debug("fetching pdf from cache");
682           thePDF = (byte[]) MirGlobal.mruCache().getObject(theCacheKey);
683         }
684         else {
685           getLogger().debug("generating pdf and caching it");
686           ByteArrayOutputStream out = new ByteArrayOutputStream();
687           PDFGenerator pdfMaker = new PDFGenerator(out);
688
689           if (idMatches.length > 1) {
690             pdfMaker.addLine();
691             for (int i = 0; i < idMatches.length && i < maxArticlesInNewsleter; i++) {
692               REMatch aMatch = idMatches[i];
693               String id = aMatch.toString();
694               EntityContent contentEnt = (EntityContent) contentModule.getById(id);
695
696
697               pdfMaker.addIndexItem(contentEnt);
698             }
699           }
700
701           for (int i = 0; i < idMatches.length; i++) {
702             REMatch aMatch = idMatches[i];
703             String id = aMatch.toString();
704             EntityContent article = (EntityContent) contentModule.getById(id);
705
706             if (!MirGlobal.localizer().openPostings().allowArticlePublication(article)) {
707               throw new ServletModuleExc("Illegal article");
708             }
709
710             pdfMaker.add(article, getLocale(aRequest));
711           }
712
713           pdfMaker.stop();
714           thePDF = out.toByteArray();
715
716           //and save all our hard work!
717           MirGlobal.mruCache().storeObject(theCacheKey, thePDF);
718         }
719
720         aResponse.setContentType("application/pdf");
721         aResponse.setContentLength(thePDF.length);
722         aResponse.getOutputStream().write(thePDF);
723         aResponse.getOutputStream().flush();
724         String elapsedtime = (new Long(System.currentTimeMillis() - starttime)).toString();
725         getLogger().info("pdf retireval took " + elapsedtime + " milliseconds");
726
727       }
728       else {
729         throw new ServletModuleExc("Missing id.");
730       }
731     }
732     catch (Throwable t) {
733       getLogger().error(t.toString());
734
735       throw new ServletModuleFailure(t);
736     }
737   }
738
739
740   public String generateOnetimePassword() {
741     Random r = new Random();
742     int random = r.nextInt();
743
744     long l = System.currentTimeMillis();
745
746     l = (l * l * l * l) / random;
747     if (l < 0)
748       l = l * -1;
749
750     String returnString = "" + l;
751
752     return returnString.substring(5);
753   }
754
755   public void deliver(HttpServletRequest aRequest, HttpServletResponse aResponse, Map aData, Map anExtra, String aGenerator) throws ServletModuleFailure {
756     try {
757       deliver(aResponse.getWriter(), aRequest, aResponse, aData, anExtra, aGenerator);
758     }
759     catch (Throwable t) {
760       throw new ServletModuleFailure(t);
761     }
762   }
763
764   public void deliver(PrintWriter anOutputWriter, HttpServletRequest aRequest, HttpServletResponse aResponse, Map aData, Map anExtra, String aGenerator)
765       throws ServletModuleFailure {
766     try {
767       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)}, "etc/bundles/open");
768       responseData.put("data", aData);
769       responseData.put("extra", anExtra);
770
771
772       Generator generator =
773           MirGlobal.localizer().generators().makeOpenPostingGeneratorLibrary().makeGenerator(aGenerator, null);
774       generator.generate(anOutputWriter, responseData, getLogger());
775
776       anOutputWriter.close();
777     }
778     catch (Throwable e) {
779       getLogger().error("Error while generating " + aGenerator + ": " + e.getMessage());
780
781       throw new ServletModuleFailure(e);
782     }
783   }
784
785   public void deliver(PrintWriter anOutputWriter, HttpServletRequest aRequest, HttpServletResponse aResponse, Map aData, Map anExtra, String aGenerator,String aLocaleString)
786       throws ServletModuleFailure {
787     try {
788       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { new Locale(aLocaleString,""), getFallbackLocale(aRequest)}, "etc/bundles/open");
789       responseData.put("data", aData);
790       responseData.put("extra", anExtra);
791
792
793       Generator generator =
794           MirGlobal.localizer().generators().
795               makeOpenPostingGeneratorLibrary().makeGenerator(aGenerator, null);
796       generator.generate(anOutputWriter, responseData, getLogger());
797
798       anOutputWriter.close();
799     }
800     catch (Throwable e) {
801       getLogger().error("Error while generating " + aGenerator + ": " + e.getMessage());
802
803       throw new ServletModuleFailure(e);
804     }
805   }
806
807
808   public void handleError(HttpServletRequest aRequest, HttpServletResponse aResponse,PrintWriter out, Throwable anException) {
809     try {
810       getLogger().error("Error during open action", anException);
811       Map data = new HashMap();
812
813       data.put("errorstring", anException.getMessage());
814       data.put("date", StringUtil.date2readableDateTime(new GregorianCalendar()));
815
816       deliver(out, aRequest, aResponse, data, null, getConfiguration().getString("ServletModule.OpenIndy.ErrorTemplate"));
817     }
818     catch (Throwable e) {
819       throw new ServletModuleFailure(e);
820     }
821   }
822
823   public void handleUserError(HttpServletRequest aRequest, HttpServletResponse aResponse,
824                                PrintWriter out, ServletModuleUserExc anException) {
825     try {
826       getLogger().warn("user error: " + anException.getMessage());
827       Map data = new HashMap();
828
829       Bundle bundle =
830           MirGlobal.getBundleFactory().getBundle("etc/bundles/open", new
831               String[] { getLocale(aRequest).getLanguage() });
832       data.put("errorstring", bundle.getValue(anException.getMessage(), Arrays.asList(anException.getParameters())));
833       data.put("date", StringUtil.date2readableDateTime(new GregorianCalendar()));
834
835       deliver(out, aRequest, aResponse, data, null, getConfiguration().getString("ServletModule.OpenIndy.UserErrorTemplate"));
836     }
837     catch (Throwable e) {
838       throw new ServletModuleFailure(e);
839     }
840   }
841 }