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 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.
30 package mircoders.localizer.basic;
33 import java.io.FileInputStream;
34 import java.io.FilenameFilter;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.HashMap;
40 import java.util.Iterator;
41 import java.util.List;
43 import java.util.Random;
45 import mir.config.MirPropertiesConfiguration;
46 import mir.log.LoggerWrapper;
47 import mir.session.Request;
48 import mir.session.Response;
49 import mir.session.Session;
50 import mir.session.SessionExc;
51 import mir.session.SessionFailure;
52 import mir.session.SessionHandler;
53 import mir.session.UploadedFile;
54 import mir.session.ValidationError;
55 import mir.storage.Database;
56 import mir.util.ExceptionFunctions;
57 import mir.util.FileFunctions;
58 import mircoders.global.MirGlobal;
59 import mircoders.media.UnsupportedMediaTypeExc;
62 * Extensible handler for open postings.
63 * Behaviour can be altered by overriding methods.
65 public abstract class MirBasicPostingSessionHandler implements SessionHandler {
66 protected static LoggerWrapper logger = new LoggerWrapper("Localizer.OpenPosting");
67 protected MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();;
69 /** Previously uploaded files */
70 protected List attachments;
71 /** counter to generate unique field names for uploaded files */
72 protected int uploadedFileIndex = 0;
74 private String normalResponseGenerator;
75 private String dupeResponseGenerator;
76 private String unsupportedMediaTypeResponseGenerator;
77 private String finalResponseGenerator;
79 private boolean persistentUploadedFiles;
81 public MirBasicPostingSessionHandler(boolean aPersistentUploadedFiles) {
82 attachments = new ArrayList();
83 persistentUploadedFiles = aPersistentUploadedFiles;
86 protected void setNormalResponseGenerator(String aGenerator) {
87 normalResponseGenerator = aGenerator;
90 protected void setResponseGenerators(String aNormalResponseGenerator,
91 String aDupeResponseGenerator, String anUnsupportedMediaTypeResponseGenerator,
92 String aFinalResponseGenerator) {
93 setNormalResponseGenerator(aNormalResponseGenerator);
94 dupeResponseGenerator = aDupeResponseGenerator;
95 unsupportedMediaTypeResponseGenerator = anUnsupportedMediaTypeResponseGenerator;
96 finalResponseGenerator = aFinalResponseGenerator;
99 public void processRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
100 if (MirGlobal.abuse().getOpenPostingDisabled()) {
101 makeOpenPostingDisabledResponse(aRequest, aSession, aResponse);
102 aSession.terminate();
105 if (aSession.getAttribute("initialRequest") == null) {
106 initialRequest(aRequest, aSession, aResponse);
107 aSession.setAttribute("initialRequest", "no");
110 subsequentRequest(aRequest, aSession, aResponse);
115 protected void initialRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
116 initializeSession(aRequest, aSession);
117 initializeResponseData(aRequest, aSession, aResponse);
118 makeInitialResponse(aRequest, aSession, aResponse);
121 protected void processAttachments(Request aRequest, Session aSession, Response aResponse) {
122 Iterator i = attachments.iterator();
123 while (i.hasNext()) {
124 Attachment attachment = (Attachment) i.next();
126 processAttachment(aRequest, aSession, attachment);
128 catch (Throwable t) {
130 processAttachmentError(aRequest, aSession, attachment, t);
132 catch (Throwable u) {
138 public void subsequentRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
141 List validationErrors = new ArrayList();
143 preprocessPreviousAttachments(aRequest, aSession);
144 preProcessNewAttachments(aRequest, aSession);
146 if (!shouldProcessRequest(aRequest, aSession, validationErrors)) {
147 initializeResponseData(aRequest, aSession, aResponse);
148 makeResponse(aRequest, aSession, aResponse, validationErrors);
151 preProcessRequest(aRequest, aSession);
153 processAttachments(aRequest, aSession, aResponse);
154 postProcessRequest(aRequest, aSession);
155 initializeResponseData(aRequest, aSession, aResponse);
156 makeFinalResponse(aRequest, aSession, aResponse);
157 aSession.terminate();
160 catch (Throwable t) {
161 initializeResponseData(aRequest, aSession, aResponse);
162 makeErrorResponse(aRequest, aSession, aResponse, t);
163 aSession.terminate();
166 catch (Throwable t) {
167 aSession.terminate();
169 throw new SessionFailure(t);
174 * Initializes a session.
175 * This may happen in the case of a new session being initiated, but also
176 * when an older session gets re-initiated after a session timeout.
178 protected void initializeSession(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
179 if (MirGlobal.abuse().getOpenPostingPassword()) {
180 String password = (String) aSession.getAttribute("password");
181 if (password==null) {
182 password = generateOnetimePassword();
183 aSession.setAttribute("password", password);
187 aSession.deleteAttribute("password");
190 aSession.setAttribute("referer", aRequest.getHeader("Referer"));
194 * Called every time a response is being prepared.
195 * This may be at the initial response, or on a subsequent one.
197 protected void initializeResponseData(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
198 int nrMediaItems = configuration.getInt("ServletModule.OpenIndy.DefaultMediaUploadItems", 5);
200 if (aSession.getAttribute("nrmediaitems")!=null) {
201 nrMediaItems = ((Integer) aSession.getAttribute("nrmediaitems")).intValue();
205 nrMediaItems = Math.min(configuration.getInt("ServletModule.OpenIndy.MaxMediaUploadItems"), Integer.parseInt(aRequest.getParameter("nrmediaitems")));
207 catch (Throwable t) {
210 aSession.setAttribute("nrmediaitems", new Integer(nrMediaItems));
212 List mediaItems = new ArrayList();
213 for (int i=1; i<=nrMediaItems; i++) {
214 mediaItems.add(new Integer(i));
217 aResponse.setResponseValue("nrmediaitems", new Integer(nrMediaItems));
218 aResponse.setResponseValue("mediaitems", mediaItems);
219 aResponse.setResponseValue("password", aSession.getAttribute("password"));
220 aResponse.setResponseValue("referer", aSession.getAttribute("referer"));
221 aResponse.setResponseValue("errors", null);
223 if (configuration.getBoolean("Localizer.OpenSession.AllowFTPUploads", false)) {
224 aResponse.setResponseValue("ftpfiles",
225 FileFunctions.getDirectoryContentsAsList(configuration.getFile("Localizer.OpenSession.FTPDirectory"),
226 new FilenameFilter() {
227 public boolean accept(File aDir, String aName) {
228 return !(new File(aDir, aName).isDirectory());
233 aResponse.setResponseValue("ftpfiles", null);
236 initializeAttachmentResponseData(aRequest, aSession, aResponse);
240 * Process possible changes to previously uploaded files
242 protected void initializeAttachmentResponseData(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
243 List result = new ArrayList();
244 if (persistentUploadedFiles) {
245 Iterator i = attachments.iterator();
246 while (i.hasNext()) {
247 Attachment attachment = (Attachment) i.next();
248 Map attachmentData = new HashMap();
249 attachmentData.putAll(attachment.getAllAttributes());
250 attachmentData.put("fieldname", attachment.getFieldName());
251 attachmentData.put("filename", attachment.getFileName());
252 result.add(attachmentData);
256 aResponse.setResponseValue("attachments", result);
260 * Process possible changes to previously uploaded files
262 protected void preprocessPreviousAttachments(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
263 synchronized (attachments) {
264 List previouslyUploadedFiles = new ArrayList(attachments);
267 if (persistentUploadedFiles) {
268 Iterator i = previouslyUploadedFiles.iterator();
269 while (i.hasNext()) {
270 Attachment uploadedFile = (Attachment) i.next();
271 if (!(aRequest.getParameter(uploadedFile.getFieldName()+"_cancel")!=null)) {
272 addAttachment(aRequest, aSession, uploadedFile, uploadedFile.getFieldName());
279 protected void addAttachment(Request aRequest, Session aSession, Attachment anAttachment, String aFieldName) throws SessionExc, SessionFailure {
280 List parameters = aRequest.getPrefixedParameterNames(aFieldName+"_");
281 Iterator j = parameters.iterator();
282 while (j.hasNext()) {
283 String parameter = ((String) j.next());
284 anAttachment.setAttribute(
285 parameter.substring(aFieldName.length()+1),
286 aRequest.getParameter(parameter));
288 attachments.add(anAttachment);
291 public void preprocessNewAttachment(Request aRequest, Session aSession, UploadedFile aFile) throws SessionExc, SessionFailure {
292 Attachment uploadedFile =
293 new Attachment(aFile, aFile.getFileName(), "attachment"+ ++uploadedFileIndex, aFile.getContentType());
295 addAttachment(aRequest, aSession, uploadedFile, aFile.getFieldName());
300 * Process newly uploaded files
302 protected void preProcessNewAttachments(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
303 Iterator i = aRequest.getUploadedFiles().iterator();
304 while (i.hasNext()) {
305 preprocessNewAttachment(aRequest, aSession, (UploadedFile) i.next());
308 if (configuration.getBoolean("Localizer.OpenSession.AllowFTPUploads", false)) {
309 File FTPDirectory = configuration.getFile("Localizer.OpenSession.FTPDirectory");
311 List ftpUploads = aRequest.getPrefixedParameterNames("ftpupload");
312 i = ftpUploads.iterator();
313 while (i.hasNext()) {
314 final String fieldName = (String) i.next();
316 if (fieldName.indexOf("_")<0) {
317 final String fileName = aRequest.getParameter(fieldName);
319 if (fileName!=null && fileName.trim().length()>0) {
320 final File sourceFile = new File(FTPDirectory, fileName);
322 if (sourceFile.getParentFile().equals(FTPDirectory)) {
323 preprocessNewAttachment(aRequest, aSession, new UploadedFile() {
324 public void writeToFile(File aFile) throws SessionFailure {
326 FileFunctions.move(sourceFile, aFile);
328 catch (IOException e) {
329 throw new SessionFailure(e);
333 public InputStream getInputStream() throws SessionFailure {
335 return new FileInputStream(sourceFile);
337 catch (IOException e) {
338 throw new SessionFailure(e);
342 public String getFileName() {
346 public String getFieldName() {
350 public String getContentType() {
361 protected void makeInitialResponse(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
362 aResponse.setResponseGenerator(normalResponseGenerator);
365 protected void makeResponse(Request aRequest, Session aSession, Response aResponse, List anErrors) throws SessionExc, SessionFailure {
366 aResponse.setResponseValue("errors", anErrors);
367 aResponse.setResponseGenerator(normalResponseGenerator);
370 protected void makeFinalResponse(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
371 aResponse.setResponseGenerator(finalResponseGenerator);
374 protected void makeErrorResponse(Request aRequest, Session aSession, Response aResponse, Throwable anError) throws SessionExc, SessionFailure {
375 Throwable rootCause = ExceptionFunctions.traceCauseException(anError);
377 if (rootCause instanceof DuplicatePostingExc)
378 aResponse.setResponseGenerator(dupeResponseGenerator);
379 if (rootCause instanceof UnsupportedMediaTypeExc) {
380 aResponse.setResponseValue("mimetype", ((UnsupportedMediaTypeExc) rootCause).getMimeType());
381 aResponse.setResponseGenerator(unsupportedMediaTypeResponseGenerator);
384 List errors = new ArrayList();
385 errors.add(new ValidationError("", "general.unexpectederror",
386 new Object[] {anError.getMessage()}));
387 makeResponse(aRequest, aSession, aResponse, errors);
391 protected void makeOpenPostingDisabledResponse(Request aRequest, Session aSession, Response aResponse) {
392 aResponse.setResponseGenerator(configuration.getString("ServletModule.OpenIndy.PostingDisabledTemplate"));
398 protected void preProcessRequest(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
400 public void processAttachment(Request aRequest, Session aSession, Attachment aFile) throws SessionExc, SessionFailure {
402 public void processAttachmentError(Request aRequest, Session aSession, Attachment aFile, Throwable anError) {
404 protected void postProcessRequest(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
408 * Determine whether the request shoudl be processed: that is, the validate,
409 * preprocess, postprocess methods should be called to perform validations,
412 protected boolean shouldProcessRequest(Request aRequest, Session aSession, List aValidationErrors) throws SessionExc, SessionFailure {
413 if (aRequest.getParameter("post")==null)
416 validate(aValidationErrors, aRequest, aSession);
417 return (aValidationErrors == null || aValidationErrors.size() == 0);
422 * Method used to validate user input.
423 * Multiple {@link ValidationError}s may be added to the
424 * <code>aResults</code> parameter.
425 * The request is considered validated if, after calling this method,
426 * <code>aResults</code> is empty.
428 protected void validate(List aResults, Request aRequest, Session aSession) throws SessionExc, SessionFailure {
429 String password = (String) aSession.getAttribute("password");
431 if (password!=null) {
432 String submittedPassword= aRequest.getParameter("password").trim();
434 if (!password.equals(submittedPassword)) {
435 aResults.add(new ValidationError("password", "passwordmismatch"));
442 * Method to generate a one-time password
444 * @return a password, to be used once
446 protected String generateOnetimePassword() {
447 Random r = new Random();
448 int random = r.nextInt();
450 long l = System.currentTimeMillis();
452 l = (l*l*l*l)/random;
456 String returnString = ""+l;
458 return returnString.substring(5);
462 * Method to filter the attributes and their values of a request
463 * based on the fields of a database object.
465 protected static final Map getIntersectingValues(Request aRequest, Database aStorage) throws SessionFailure {
466 Map result = new HashMap();
468 Iterator i = aStorage.getFieldNames().iterator();
470 while (i.hasNext()) {
471 String fieldName = (String) i.next();
472 Object value = aRequest.getParameter(fieldName);
474 result.put(fieldName, value);
481 * Exception to be thrown when an article or comment was already posted
483 protected static class DuplicatePostingExc extends SessionExc {
484 public DuplicatePostingExc(String aMessage) {
490 * A file that has been attached to a session
492 protected static class Attachment implements UploadedFile {
493 private UploadedFile uploadedFile;
494 private String filename;
495 private String fieldName;
496 private String contentType;
497 private Map attributes;
499 public Attachment(UploadedFile anUploadedFile, String aFilename, String aFieldName, String aContentType) {
500 attributes = new HashMap();
501 filename = aFilename;
502 fieldName = aFieldName;
503 contentType = aContentType;
504 uploadedFile = anUploadedFile;
507 public void writeToFile(File aFile) throws SessionExc, SessionFailure {
508 uploadedFile.writeToFile(aFile);
511 public InputStream getInputStream() throws SessionExc, SessionFailure {
512 return uploadedFile.getInputStream();
515 public String getFileName() {
519 public String getFieldName() {
523 public String getContentType() {
527 public String getAttribute(String anAttribute) {
528 return (String) attributes.get(anAttribute);
531 public void setAttribute(String anAttribute, String aValue) {
532 attributes.put(anAttribute, aValue);
535 public Map getAllAttributes() {
536 return Collections.unmodifiableMap(attributes);