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;
32 import mir.config.MirPropertiesConfiguration;
33 import mir.log.LoggerWrapper;
35 import mir.storage.StorageObject;
36 import mir.util.ExceptionFunctions;
37 import mir.util.FileFunctions;
38 import mircoders.global.MirGlobal;
39 import mircoders.module.ModuleMediaType;
40 import mircoders.media.UnsupportedMediaTypeExc;
46 * Extensible handler for open postings.
47 * Behaviour can be altered by overriding methods.
49 public abstract class MirBasicPostingSessionHandler implements SessionHandler {
50 protected static LoggerWrapper logger = new LoggerWrapper("Localizer.OpenPosting");
51 protected MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();;
53 /** Previously uploaded files */
54 protected List attachments;
55 /** counter to generate unique field names for uploaded files */
56 protected int uploadedFileIndex = 0;
58 private String normalResponseGenerator;
59 private String dupeResponseGenerator;
60 private String unsupportedMediaTypeResponseGenerator;
61 private String finalResponseGenerator;
63 private boolean persistentUploadedFiles;
65 public MirBasicPostingSessionHandler(boolean aPersistentUploadedFiles) {
66 attachments = new ArrayList();
67 persistentUploadedFiles = aPersistentUploadedFiles;
70 protected void setNormalResponseGenerator(String aGenerator) {
71 normalResponseGenerator = aGenerator;
74 protected void setResponseGenerators(String aNormalResponseGenerator,
75 String aDupeResponseGenerator, String anUnsupportedMediaTypeResponseGenerator,
76 String aFinalResponseGenerator) {
77 setNormalResponseGenerator(aNormalResponseGenerator);
78 dupeResponseGenerator = aDupeResponseGenerator;
79 unsupportedMediaTypeResponseGenerator = anUnsupportedMediaTypeResponseGenerator;
80 finalResponseGenerator = aFinalResponseGenerator;
83 public void processRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
84 if (MirGlobal.abuse().getOpenPostingDisabled()) {
85 makeOpenPostingDisabledResponse(aRequest, aSession, aResponse);
89 if (aSession.getAttribute("initialRequest") == null) {
90 initialRequest(aRequest, aSession, aResponse);
91 aSession.setAttribute("initialRequest", "no");
94 subsequentRequest(aRequest, aSession, aResponse);
99 protected void initialRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
100 initializeSession(aRequest, aSession);
101 initializeResponseData(aRequest, aSession, aResponse);
102 makeInitialResponse(aRequest, aSession, aResponse);
105 protected void processAttachments(Request aRequest, Session aSession, Response aResponse) {
106 Iterator i = attachments.iterator();
107 while (i.hasNext()) {
108 Attachment attachment = (Attachment) i.next();
110 processAttachment(aRequest, aSession, attachment);
112 catch (Throwable t) {
114 processAttachmentError(aRequest, aSession, attachment, t);
116 catch (Throwable u) {
122 public void subsequentRequest(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
125 List validationErrors = new ArrayList();
127 preprocessPreviousAttachments(aRequest, aSession);
128 preProcessNewAttachments(aRequest, aSession);
130 if (!shouldProcessRequest(aRequest, aSession, validationErrors)) {
131 initializeResponseData(aRequest, aSession, aResponse);
132 makeResponse(aRequest, aSession, aResponse, validationErrors);
135 preProcessRequest(aRequest, aSession);
137 processAttachments(aRequest, aSession, aResponse);
138 postProcessRequest(aRequest, aSession);
139 initializeResponseData(aRequest, aSession, aResponse);
140 makeFinalResponse(aRequest, aSession, aResponse);
141 aSession.terminate();
144 catch (Throwable t) {
145 initializeResponseData(aRequest, aSession, aResponse);
146 makeErrorResponse(aRequest, aSession, aResponse, t);
147 aSession.terminate();
150 catch (Throwable t) {
151 aSession.terminate();
153 throw new SessionFailure(t);
158 * Initializes a session.
159 * This may happen in the case of a new session being initiated, but also
160 * when an older session gets re-initiated after a session timeout.
162 protected void initializeSession(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
163 if (MirGlobal.abuse().getOpenPostingPassword()) {
164 String password = (String) aSession.getAttribute("password");
165 if (password==null) {
166 password = generateOnetimePassword();
167 aSession.setAttribute("password", password);
171 aSession.deleteAttribute("password");
174 aSession.setAttribute("referer", aRequest.getHeader("Referer"));
178 * Called every time a response is being prepared.
179 * This may be at the initial response, or on a subsequent one.
181 protected void initializeResponseData(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
182 int nrMediaItems = configuration.getInt("ServletModule.OpenIndy.DefaultMediaUploadItems", 5);
184 if (aSession.getAttribute("nrmediaitems")!=null) {
185 nrMediaItems = ((Integer) aSession.getAttribute("nrmediaitems")).intValue();
189 nrMediaItems = Math.min(configuration.getInt("ServletModule.OpenIndy.MaxMediaUploadItems"), Integer.parseInt(aRequest.getParameter("nrmediaitems")));
191 catch (Throwable t) {
194 aSession.setAttribute("nrmediaitems", new Integer(nrMediaItems));
196 List mediaItems = new ArrayList();
197 for (int i=1; i<=nrMediaItems; i++) {
198 mediaItems.add(new Integer(i));
201 aResponse.setResponseValue("nrmediaitems", new Integer(nrMediaItems));
202 aResponse.setResponseValue("mediaitems", mediaItems);
203 aResponse.setResponseValue("password", aSession.getAttribute("password"));
204 aResponse.setResponseValue("referer", aSession.getAttribute("referer"));
205 aResponse.setResponseValue("errors", null);
207 if (configuration.getBoolean("Localizer.OpenSession.AllowFTPUploads", false)) {
208 aResponse.setResponseValue("ftpfiles",
209 FileFunctions.getDirectoryContentsAsList(configuration.getFile("Localizer.OpenSession.FTPDirectory"),
210 new FilenameFilter() {
211 public boolean accept(File aDir, String aName) {
212 return !(new File(aDir, aName).isDirectory());
217 aResponse.setResponseValue("ftpfiles", null);
220 initializeAttachmentResponseData(aRequest, aSession, aResponse);
224 * Process possible changes to previously uploaded files
226 protected void initializeAttachmentResponseData(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
227 List result = new ArrayList();
228 if (persistentUploadedFiles) {
229 Iterator i = attachments.iterator();
230 while (i.hasNext()) {
231 Attachment attachment = (Attachment) i.next();
232 Map attachmentData = new HashMap();
233 attachmentData.putAll(attachment.getAllAttributes());
234 attachmentData.put("fieldname", attachment.getFieldName());
235 attachmentData.put("filename", attachment.getFileName());
236 result.add(attachmentData);
240 aResponse.setResponseValue("attachments", result);
244 * Process possible changes to previously uploaded files
246 protected void preprocessPreviousAttachments(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
247 synchronized (attachments) {
248 List previouslyUploadedFiles = new ArrayList(attachments);
251 if (persistentUploadedFiles) {
252 Iterator i = previouslyUploadedFiles.iterator();
253 while (i.hasNext()) {
254 Attachment uploadedFile = (Attachment) i.next();
255 if (!(aRequest.getParameter(uploadedFile.getFieldName()+"_cancel")!=null)) {
256 addAttachment(aRequest, aSession, uploadedFile, uploadedFile.getFieldName());
263 protected void addAttachment(Request aRequest, Session aSession, Attachment anAttachment, String aFieldName) throws SessionExc, SessionFailure {
264 List parameters = aRequest.getPrefixedParameterNames(aFieldName+"_");
265 Iterator j = parameters.iterator();
266 while (j.hasNext()) {
267 String parameter = ((String) j.next());
268 anAttachment.setAttribute(
269 parameter.substring(aFieldName.length()+1),
270 aRequest.getParameter(parameter));
272 attachments.add(anAttachment);
275 public void preprocessNewAttachment(Request aRequest, Session aSession, UploadedFile aFile) throws SessionExc, SessionFailure {
276 Attachment uploadedFile =
277 new Attachment(aFile, aFile.getFileName(), "attachment"+ ++uploadedFileIndex, aFile.getContentType());
279 addAttachment(aRequest, aSession, uploadedFile, aFile.getFieldName());
284 * Process newly uploaded files
286 protected void preProcessNewAttachments(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
287 Iterator i = aRequest.getUploadedFiles().iterator();
288 while (i.hasNext()) {
289 preprocessNewAttachment(aRequest, aSession, (UploadedFile) i.next());
292 if (configuration.getBoolean("Localizer.OpenSession.AllowFTPUploads", false)) {
293 File FTPDirectory = configuration.getFile("Localizer.OpenSession.FTPDirectory");
295 List ftpUploads = aRequest.getPrefixedParameterNames("ftpupload");
296 i = ftpUploads.iterator();
297 while (i.hasNext()) {
298 final String fieldName = (String) i.next();
300 if (fieldName.indexOf("_")<0) {
301 final String fileName = aRequest.getParameter(fieldName);
303 if (fileName!=null && fileName.trim().length()>0) {
304 final File sourceFile = new File(FTPDirectory, fileName);
306 if (sourceFile.getParentFile().equals(FTPDirectory)) {
307 preprocessNewAttachment(aRequest, aSession, new UploadedFile() {
308 public void writeToFile(File aFile) throws SessionFailure {
310 FileFunctions.move(sourceFile, aFile);
312 catch (IOException e) {
313 throw new SessionFailure(e);
317 public InputStream getInputStream() throws SessionFailure {
319 return new FileInputStream(sourceFile);
321 catch (IOException e) {
322 throw new SessionFailure(e);
326 public String getFileName() {
330 public String getFieldName() {
334 public String getContentType() {
345 protected void makeInitialResponse(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
346 aResponse.setResponseGenerator(normalResponseGenerator);
349 protected void makeResponse(Request aRequest, Session aSession, Response aResponse, List anErrors) throws SessionExc, SessionFailure {
350 aResponse.setResponseValue("errors", anErrors);
351 aResponse.setResponseGenerator(normalResponseGenerator);
354 protected void makeFinalResponse(Request aRequest, Session aSession, Response aResponse) throws SessionExc, SessionFailure {
355 aResponse.setResponseGenerator(finalResponseGenerator);
358 protected void makeErrorResponse(Request aRequest, Session aSession, Response aResponse, Throwable anError) throws SessionExc, SessionFailure {
359 Throwable rootCause = ExceptionFunctions.traceCauseException(anError);
361 if (rootCause instanceof DuplicatePostingExc)
362 aResponse.setResponseGenerator(dupeResponseGenerator);
363 if (rootCause instanceof UnsupportedMediaTypeExc) {
364 aResponse.setResponseValue("mimetype", ((UnsupportedMediaTypeExc) rootCause).getMimeType());
365 aResponse.setResponseGenerator(unsupportedMediaTypeResponseGenerator);
368 List errors = new ArrayList();
369 errors.add(new ValidationError("", "general.unexpectederror",
370 new Object[] {anError.getMessage()}));
371 makeResponse(aRequest, aSession, aResponse, errors);
375 protected void makeOpenPostingDisabledResponse(Request aRequest, Session aSession, Response aResponse) {
376 aResponse.setResponseGenerator(configuration.getString("ServletModule.OpenIndy.PostingDisabledTemplate"));
382 protected void preProcessRequest(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
384 public void processAttachment(Request aRequest, Session aSession, Attachment aFile) throws SessionExc, SessionFailure {
386 public void processAttachmentError(Request aRequest, Session aSession, Attachment aFile, Throwable anError) {
388 protected void postProcessRequest(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
392 * Determine whether the request shoudl be processed: that is, the validate,
393 * preprocess, postprocess methods should be called to perform validations,
396 protected boolean shouldProcessRequest(Request aRequest, Session aSession, List aValidationErrors) throws SessionExc, SessionFailure {
397 if (aRequest.getParameter("post")==null)
400 validate(aValidationErrors, aRequest, aSession);
401 return (aValidationErrors == null || aValidationErrors.size() == 0);
406 * Method used to validate user input.
407 * Multiple {@link ValidationError}s may be added to the
408 * <code>aResults</code> parameter.
409 * The request is considered validated if, after calling this method,
410 * <code>aResults</code> is empty.
412 protected void validate(List aResults, Request aRequest, Session aSession) throws SessionExc, SessionFailure {
413 String password = (String) aSession.getAttribute("password");
415 if (password!=null) {
416 String submittedPassword= aRequest.getParameter("password").trim();
418 if (!password.equals(submittedPassword)) {
419 aResults.add(new ValidationError("password", "passwordmismatch"));
426 * Method to generate a one-time password
428 * @return a password, to be used once
430 protected String generateOnetimePassword() {
431 Random r = new Random();
432 int random = r.nextInt();
434 long l = System.currentTimeMillis();
436 l = (l*l*l*l)/random;
440 String returnString = ""+l;
442 return returnString.substring(5);
446 * Method to filter the attributes and their values of a request
447 * based on the fields of a storage object.
449 protected static final Map getIntersectingValues(Request aRequest, StorageObject aStorage) throws SessionFailure {
450 Map result = new HashMap();
452 Iterator i = aStorage.getFieldNames().iterator();
454 while (i.hasNext()) {
455 String fieldName = (String) i.next();
456 Object value = aRequest.getParameter(fieldName);
458 result.put(fieldName, value);
465 * Exception to be thrown when an article or comment was already posted
467 protected static class DuplicatePostingExc extends SessionExc {
468 public DuplicatePostingExc(String aMessage) {
474 * A file that has been attached to a session
476 protected static class Attachment implements UploadedFile {
477 private UploadedFile uploadedFile;
478 private String filename;
479 private String fieldName;
480 private String contentType;
481 private Map attributes;
483 public Attachment(UploadedFile anUploadedFile, String aFilename, String aFieldName, String aContentType) {
484 attributes = new HashMap();
485 filename = aFilename;
486 fieldName = aFieldName;
487 contentType = aContentType;
488 uploadedFile = anUploadedFile;
491 public void writeToFile(File aFile) throws SessionExc, SessionFailure {
492 uploadedFile.writeToFile(aFile);
495 public InputStream getInputStream() throws SessionExc, SessionFailure {
496 return uploadedFile.getInputStream();
499 public String getFileName() {
503 public String getFieldName() {
507 public String getContentType() {
511 public String getAttribute(String anAttribute) {
512 return (String) attributes.get(anAttribute);
515 public void setAttribute(String anAttribute, String aValue) {
516 attributes.put(anAttribute, aValue);
519 public Map getAllAttributes() {
520 return Collections.unmodifiableMap(attributes);