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;
39 import mir.config.MirPropertiesConfiguration;
40 import mir.log.LoggerWrapper;
41 import mir.session.Request;
42 import mir.session.Response;
43 import mir.session.Session;
44 import mir.session.SessionExc;
45 import mir.session.SessionFailure;
46 import mir.session.SessionHandler;
47 import mir.session.UploadedFile;
48 import mir.session.ValidationError;
49 import mir.storage.Database;
50 import mir.util.ExceptionFunctions;
51 import mir.util.FileFunctions;
52 import mircoders.global.MirGlobal;
53 import mircoders.media.UnsupportedMediaTypeExc;
56 * Extensible handler for open postings.
57 * Behaviour can be altered by overriding methods.
59 public abstract class MirBasicPostingSessionHandler implements SessionHandler {
60 protected static LoggerWrapper logger = new LoggerWrapper("Localizer.OpenPosting");
61 protected MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();
63 /** Previously uploaded files */
64 protected List attachments;
65 /** counter to generate unique field names for uploaded files */
66 protected int uploadedFileIndex = 0;
68 private String normalResponseGenerator;
69 private String dupeResponseGenerator;
70 private String unsupportedMediaTypeResponseGenerator;
71 private String finalResponseGenerator;
73 private boolean persistentUploadedFiles;
75 public MirBasicPostingSessionHandler(boolean aPersistentUploadedFiles) {
76 attachments = new ArrayList();
77 persistentUploadedFiles = aPersistentUploadedFiles;
80 protected void setNormalResponseGenerator(String aGenerator) {
81 normalResponseGenerator = aGenerator;
84 protected void setResponseGenerators(String aNormalResponseGenerator,
85 String aDupeResponseGenerator, String anUnsupportedMediaTypeResponseGenerator,
86 String aFinalResponseGenerator) {
87 setNormalResponseGenerator(aNormalResponseGenerator);
88 dupeResponseGenerator = aDupeResponseGenerator;
89 unsupportedMediaTypeResponseGenerator = anUnsupportedMediaTypeResponseGenerator;
90 finalResponseGenerator = aFinalResponseGenerator;
93 public void processRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
94 if (MirGlobal.abuse().getOpenPostingDisabled()) {
95 makeOpenPostingDisabledResponse(aRequest, aSession, aResponse);
99 if (aSession.getAttribute("initialRequest") == null) {
100 initialRequest(aRequest, aSession, aResponse);
101 aSession.setAttribute("initialRequest", "no");
104 subsequentRequest(aRequest, aSession, aResponse);
109 protected void initialRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
110 initializeSession(aRequest, aSession);
111 initializeResponseData(aRequest, aSession, aResponse);
112 makeInitialResponse(aRequest, aSession, aResponse);
115 protected void processAttachments(Request aRequest, Session aSession, Response aResponse) {
116 Iterator i = attachments.iterator();
117 while (i.hasNext()) {
118 Attachment attachment = (Attachment) i.next();
120 processAttachment(aRequest, aSession, attachment);
122 catch (Throwable t) {
124 processAttachmentError(aRequest, aSession, attachment, t);
126 catch (Throwable u) {
128 logger.error("Error while processing attachment", t);
133 public void subsequentRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
136 List validationErrors = new ArrayList();
138 preprocessPreviousAttachments(aRequest, aSession);
139 preProcessNewAttachments(aRequest, aSession);
141 if (!shouldProcessRequest(aRequest, aSession, validationErrors)) {
142 initializeResponseData(aRequest, aSession, aResponse);
143 makeResponse(aRequest, aSession, aResponse, validationErrors);
146 preProcessRequest(aRequest, aSession);
148 processAttachments(aRequest, aSession, aResponse);
149 postProcessRequest(aRequest, aSession);
150 initializeResponseData(aRequest, aSession, aResponse);
151 makeFinalResponse(aRequest, aSession, aResponse);
152 aSession.terminate();
155 catch (Throwable t) {
156 initializeResponseData(aRequest, aSession, aResponse);
157 makeErrorResponse(aRequest, aSession, aResponse, t);
158 aSession.terminate();
161 catch (Throwable t) {
162 aSession.terminate();
164 throw new SessionFailure(t);
169 * Initializes a session.
170 * This may happen in the case of a new session being initiated, but also
171 * when an older session gets re-initiated after a session timeout.
173 protected void initializeSession(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
174 if (MirGlobal.abuse().getOpenPostingPassword()) {
175 String password = (String) aSession.getAttribute("password");
176 if (password==null) {
177 password = generateOnetimePassword();
178 aSession.setAttribute("password", password);
182 aSession.deleteAttribute("password");
185 aSession.setAttribute("referer", aRequest.getHeader("Referer"));
189 * Called every time a response is being prepared.
190 * This may be at the initial response, or on a subsequent one.
192 protected void initializeResponseData(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
193 int nrMediaItems = configuration.getInt("ServletModule.OpenIndy.DefaultMediaUploadItems", 5);
195 if (aSession.getAttribute("nrmediaitems")!=null) {
196 nrMediaItems = ((Integer) aSession.getAttribute("nrmediaitems")).intValue();
200 nrMediaItems = Math.min(configuration.getInt("ServletModule.OpenIndy.MaxMediaUploadItems"), Integer.parseInt(aRequest.getParameter("nrmediaitems")));
202 catch (Throwable t) {
205 aSession.setAttribute("nrmediaitems", new Integer(nrMediaItems));
207 List mediaItems = new ArrayList();
208 for (int i=1; i<=nrMediaItems; i++) {
209 mediaItems.add(new Integer(i));
212 aResponse.setResponseValue("nrmediaitems", new Integer(nrMediaItems));
213 aResponse.setResponseValue("mediaitems", mediaItems);
214 aResponse.setResponseValue("password", aSession.getAttribute("password"));
215 aResponse.setResponseValue("referer", aSession.getAttribute("referer"));
216 aResponse.setResponseValue("errors", null);
218 if (configuration.getBoolean("Localizer.OpenSession.AllowFTPUploads", false)) {
219 aResponse.setResponseValue("ftpfiles",
220 FileFunctions.getDirectoryContentsAsList(configuration.getFile("Localizer.OpenSession.FTPDirectory"),
221 new FilenameFilter() {
222 public boolean accept(File aDir, String aName) {
223 return !(new File(aDir, aName).isDirectory());
228 aResponse.setResponseValue("ftpfiles", null);
231 initializeAttachmentResponseData(aRequest, aSession, aResponse);
235 * Process possible changes to previously uploaded files
237 protected void initializeAttachmentResponseData(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
238 List result = new ArrayList();
239 if (persistentUploadedFiles) {
240 Iterator i = attachments.iterator();
241 while (i.hasNext()) {
242 Attachment attachment = (Attachment) i.next();
243 Map attachmentData = new HashMap();
244 attachmentData.putAll(attachment.getAllAttributes());
245 attachmentData.put("fieldname", attachment.getFieldName());
246 attachmentData.put("filename", attachment.getFileName());
247 result.add(attachmentData);
251 aResponse.setResponseValue("attachments", result);
255 * Process possible changes to previously uploaded files
257 protected void preprocessPreviousAttachments(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
258 synchronized (attachments) {
259 List previouslyUploadedFiles = new ArrayList(attachments);
262 if (persistentUploadedFiles) {
263 Iterator i = previouslyUploadedFiles.iterator();
264 while (i.hasNext()) {
265 Attachment uploadedFile = (Attachment) i.next();
266 if (!(aRequest.getParameter(uploadedFile.getFieldName()+"_cancel")!=null)) {
267 addAttachment(aRequest, aSession, uploadedFile, uploadedFile.getFieldName());
274 protected void addAttachment(Request aRequest, Session aSession, Attachment anAttachment, String aFieldName) throws SessionExc, SessionFailure {
275 List parameters = aRequest.getPrefixedParameterNames(aFieldName+"_");
276 Iterator j = parameters.iterator();
277 while (j.hasNext()) {
278 String parameter = ((String) j.next());
279 anAttachment.setAttribute(
280 parameter.substring(aFieldName.length()+1),
281 aRequest.getParameter(parameter));
283 attachments.add(anAttachment);
286 public void preprocessNewAttachment(Request aRequest, Session aSession, UploadedFile aFile) throws SessionExc, SessionFailure {
287 Attachment uploadedFile =
288 new Attachment(aFile, aFile.getFileName(), "attachment"+ ++uploadedFileIndex, aFile.getContentType());
290 addAttachment(aRequest, aSession, uploadedFile, aFile.getFieldName());
295 * Process newly uploaded files
297 protected void preProcessNewAttachments(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
298 Iterator i = aRequest.getUploadedFiles().iterator();
299 while (i.hasNext()) {
300 preprocessNewAttachment(aRequest, aSession, (UploadedFile) i.next());
303 if (configuration.getBoolean("Localizer.OpenSession.AllowFTPUploads", false)) {
304 File FTPDirectory = configuration.getFile("Localizer.OpenSession.FTPDirectory");
306 List ftpUploads = new ArrayList(aRequest.getPrefixedParameterNames("ftpupload"));
307 Collections.sort(ftpUploads, new Comparator() {
308 public int compare(Object o1, Object o2) {
309 if (o1 instanceof String && o2 instanceof String) {
310 return ((String) o1).compareTo((String) o2);
318 i = ftpUploads.iterator();
319 while (i.hasNext()) {
320 final String fieldName = (String) i.next();
322 if (fieldName.indexOf("_")<0) {
323 final String fileName = aRequest.getParameter(fieldName);
325 if (fileName!=null && fileName.trim().length()>0) {
326 final File sourceFile = new File(FTPDirectory, fileName);
328 if (sourceFile.getParentFile().equals(FTPDirectory)) {
329 preprocessNewAttachment(aRequest, aSession, new UploadedFile() {
330 public void writeToFile(File aFile) throws SessionFailure {
332 FileFunctions.move(sourceFile, aFile);
334 catch (IOException e) {
335 throw new SessionFailure(e);
339 public InputStream getInputStream() throws SessionFailure {
341 return new FileInputStream(sourceFile);
343 catch (IOException e) {
344 throw new SessionFailure(e);
348 public String getFileName() {
352 public String getFieldName() {
356 public String getContentType() {
367 protected void makeInitialResponse(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
368 aResponse.setResponseGenerator(normalResponseGenerator);
371 protected void makeResponse(Request aRequest, Session aSession, Response aResponse, List anErrors) throws SessionExc, SessionFailure {
372 aResponse.setResponseValue("errors", anErrors);
373 aResponse.setResponseGenerator(normalResponseGenerator);
376 protected void makeFinalResponse(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
377 aResponse.setResponseGenerator(finalResponseGenerator);
380 protected void makeErrorResponse(Request aRequest, Session aSession, Response aResponse, Throwable anError) throws SessionExc, SessionFailure {
381 Throwable rootCause = ExceptionFunctions.traceCauseException(anError);
383 if (rootCause instanceof DuplicatePostingExc)
384 aResponse.setResponseGenerator(dupeResponseGenerator);
385 if (rootCause instanceof UnsupportedMediaTypeExc) {
386 aResponse.setResponseValue("mimetype", ((UnsupportedMediaTypeExc) rootCause).getMimeType());
387 aResponse.setResponseGenerator(unsupportedMediaTypeResponseGenerator);
390 List errors = new ArrayList();
391 errors.add(new ValidationError("", "general.unexpectederror",
392 new Object[] {anError.getMessage()}));
393 makeResponse(aRequest, aSession, aResponse, errors);
397 protected void makeOpenPostingDisabledResponse(Request aRequest, Session aSession, Response aResponse) {
398 aResponse.setResponseGenerator(configuration.getString("ServletModule.OpenIndy.PostingDisabledTemplate"));
404 protected void preProcessRequest(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
406 public void processAttachment(Request aRequest, Session aSession, Attachment aFile) throws SessionExc, SessionFailure {
408 public void processAttachmentError(Request aRequest, Session aSession, Attachment aFile, Throwable anError) {
410 protected void postProcessRequest(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
414 * Determine whether the request shoudl be processed: that is, the validate,
415 * preprocess, postprocess methods should be called to perform validations,
418 protected boolean shouldProcessRequest(Request aRequest, Session aSession, List aValidationErrors) throws SessionExc, SessionFailure {
419 if (aRequest.getParameter("post")==null)
421 validate(aValidationErrors, aRequest, aSession);
422 return (aValidationErrors == null || aValidationErrors.size() == 0);
426 * Method used to validate user input.
427 * Multiple {@link ValidationError}s may be added to the
428 * <code>aResults</code> parameter.
429 * The request is considered validated if, after calling this method,
430 * <code>aResults</code> is empty.
432 protected void validate(List aResults, Request aRequest, Session aSession) throws SessionExc, SessionFailure {
433 String password = (String) aSession.getAttribute("password");
435 if (password!=null) {
436 String submittedPassword= aRequest.getParameter("password").trim();
438 if (!password.equals(submittedPassword)) {
439 aResults.add(new ValidationError("password", "passwordmismatch"));
446 * Method to generate a one-time password
448 * @return a password, to be used once
450 protected String generateOnetimePassword() {
451 Random r = new Random();
452 int random = r.nextInt();
454 long l = System.currentTimeMillis();
456 l = (l*l*l*l)/random;
460 String returnString = ""+l;
462 return returnString.substring(5);
466 * Method to filter the attributes and their values of a request
467 * based on the fields of a database object.
469 protected static final Map getIntersectingValues(Request aRequest, Database aStorage) throws SessionFailure {
470 Map result = new HashMap();
472 Iterator i = aStorage.getFieldNames().iterator();
474 while (i.hasNext()) {
475 String fieldName = (String) i.next();
476 Object value = aRequest.getParameter(fieldName);
478 result.put(fieldName, value);
485 * Exception to be thrown when an article or comment was already posted
487 protected static class DuplicatePostingExc extends SessionExc {
488 public DuplicatePostingExc(String aMessage) {
494 * A file that has been attached to a session
496 protected static class Attachment implements UploadedFile {
497 private UploadedFile uploadedFile;
498 private String filename;
499 private String fieldName;
500 private String contentType;
501 private Map attributes;
503 public Attachment(UploadedFile anUploadedFile, String aFilename, String aFieldName, String aContentType) {
504 attributes = new HashMap();
505 filename = aFilename;
506 fieldName = aFieldName;
507 contentType = aContentType;
508 uploadedFile = anUploadedFile;
511 public void writeToFile(File aFile) throws SessionExc, SessionFailure {
512 uploadedFile.writeToFile(aFile);
515 public InputStream getInputStream() throws SessionExc, SessionFailure {
516 return uploadedFile.getInputStream();
519 public String getFileName() {
523 public String getFieldName() {
527 public String getContentType() {
531 public String getAttribute(String anAttribute) {
532 return (String) attributes.get(anAttribute);
535 public void setAttribute(String anAttribute, String aValue) {
536 attributes.put(anAttribute, aValue);
539 public Map getAllAttributes() {
540 return Collections.unmodifiableMap(attributes);