001: /**
002: * Servlet for handling the uploading of attachments for topics. It's behaviour is
003: * a bit different to the other servlets, in that the request parameters are hidden
004: * in the multipart upload and forwarding through the WikiServlet doesn't work, so
005: * the virtual wiki is extracted from a hidden input parameter in the form in attach.jsp.
006: *
007: * Copyright 2002 Gareth Cronin
008: * This software is subject to the GNU Lesser General Public Licence (LGPL)
009: */package vqwiki.servlets;
010:
011: import org.apache.commons.fileupload.FileItem;
012: import org.apache.commons.fileupload.FileUpload;
013: import org.apache.commons.fileupload.FileUploadException;
014: import org.apache.log4j.Logger;
015: import vqwiki.Change;
016: import vqwiki.ChangeLog;
017: import vqwiki.Environment;
018: import vqwiki.Topic;
019: import vqwiki.WikiBase;
020: import vqwiki.WikiException;
021: import vqwiki.utils.JSPUtils;
022: import vqwiki.utils.Utilities;
023:
024: import javax.servlet.ServletConfig;
025: import javax.servlet.ServletException;
026: import javax.servlet.http.HttpServletRequest;
027: import javax.servlet.http.HttpServletResponse;
028: import java.io.BufferedOutputStream;
029: import java.io.File;
030: import java.io.FileOutputStream;
031: import java.io.IOException;
032: import java.io.InputStream;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Date;
036: import java.util.Calendar;
037: import java.util.ArrayList;
038: import java.text.SimpleDateFormat;
039:
040: public class SaveAttachmentServlet extends VQWikiServlet {
041:
042: /** Logger */
043: public static final Logger logger = Logger
044: .getLogger(SaveAttachmentServlet.class);
045: /** The servlet config for this servlet (initialised during the overriden servlet init()) */
046: private ServletConfig config;
047:
048: /**
049: * Init the servlet
050: */
051: final public void init(ServletConfig config)
052: throws ServletException {
053: super .init(config);
054: this .config = config;
055: }
056:
057: /**
058: * Intercept post requests. Use the Jakarta Commons fileupload library to receive any posted files. These are
059: * stored in the file system attachments directory and the topic is modified to include a link to the attachment.
060: *
061: * @param request request
062: * @param response response.
063: * @throws ServletException
064: * @throws IOException
065: */
066: protected void doPost(HttpServletRequest request,
067: HttpServletResponse response) throws ServletException,
068: IOException {
069: Environment en = Environment.getInstance();
070: FileUpload upload = new FileUpload();
071: String tempDir = Environment.relativeDirIfNecessary(en
072: .getStringSetting(Environment.PROPERTY_TEMP_DIR));
073: File tempDirFile = new File(tempDir);
074: tempDirFile.mkdirs();
075: upload.setRepositoryPath(tempDir);
076: upload.setSizeMax(en
077: .getIntSetting(Environment.PROPERTY_MAX_FILE_SIZE));
078: List fileList = null;
079: try {
080: fileList = upload.parseRequest(request);
081: } catch (FileUploadException e) {
082: error(request, response, new WikiServletException(e
083: .getMessage()));
084: return;
085: }
086: String virtualWiki = null;
087: String topic = null;
088: String user = null;
089: Topic t = null;
090: boolean cancel = false;
091: try {
092: for (Iterator iterator = fileList.iterator(); iterator
093: .hasNext();) {
094: FileItem item = (FileItem) iterator.next();
095: if (item.isFormField()) {
096: if (item.getFieldName().equals("topic")) {
097: topic = item.getString();
098: t = new Topic(topic);
099: if (t.isReadOnlyTopic(virtualWiki)) {
100: throw new WikiException(
101: WikiException.READ_ONLY);
102: }
103: } else if (item.getFieldName().equals("user")) {
104: user = item.getString();
105: } else if (item.getFieldName()
106: .equals("virtualwiki")) {
107: virtualWiki = item.getString();
108: } else if (item.getFieldName().equals("cancel")) {
109: cancel = true;
110: }
111: }
112: }
113: WikiBase base = WikiBase.getInstance();
114: if (!cancel) {
115: // store the files
116: String[] names = storeFiles(fileList, virtualWiki, en);
117: int nameIndex = 0;
118: // Update the topic
119: StringBuffer contents = new StringBuffer(base.readRaw(
120: virtualWiki, topic));
121: for (Iterator iterator = fileList.iterator(); iterator
122: .hasNext();) {
123: FileItem item = (FileItem) iterator.next();
124: if (!item.isFormField()
125: && !item.getName().equals("")) {
126: contents.append("\nattach:");
127: if (item.getName().indexOf(' ') >= 0) {
128: contents.append("\"");
129: }
130: contents.append(names[nameIndex++]);
131: if (item.getName().indexOf(' ') >= 0) {
132: contents.append("\"");
133: }
134: contents.append("\n");
135: }
136: }
137: Change change = new Change(virtualWiki, topic, user,
138: new java.util.Date());
139: ChangeLog cl = WikiBase.getInstance()
140: .getChangeLogInstance();
141: base.write(virtualWiki, contents.toString(), false,
142: topic, user);
143: cl.logChange(change, request);
144: }
145: // Unlock and return
146: base.unlockTopic(virtualWiki, topic);
147: StringBuffer next = new StringBuffer();
148: next.append(JSPUtils.createLocalRootPath(request,
149: virtualWiki));
150: next.append("Wiki?");
151: next.append(topic);
152: response.sendRedirect(response.encodeRedirectURL(next
153: .toString()));
154: } catch (Exception e) {
155: e.printStackTrace();
156: throw new WikiServletException(e.toString());
157: }
158: }
159:
160: /**
161: * Store the given list of files for the given virtual wiki.
162: *
163: * @param fileList list of commons upload {@link FileItem}s
164: * @param virtualWiki virtual wiki
165: * @param en the environment
166: * @return the names of the files stored
167: * @throws IOException
168: */
169: private String[] storeFiles(List fileList, String virtualWiki,
170: Environment en) throws IOException {
171: int i = 0;
172: List names = new ArrayList();
173: for (Iterator iterator = fileList.iterator(); iterator
174: .hasNext(); i++) {
175: FileItem item = (FileItem) iterator.next();
176: log("FileItem: " + item);
177: if (!item.isFormField() && !item.getName().equals("")) {
178: String name = getNameOnly(item, i);
179: names.add(name);
180: File uploadedFile = en.uploadPath(virtualWiki, name);
181: logger
182: .debug("storing attached file to "
183: + uploadedFile);
184: InputStream stream = item.getInputStream();
185: FileOutputStream fileOut = new FileOutputStream(
186: uploadedFile);
187: BufferedOutputStream out = new BufferedOutputStream(
188: fileOut);
189: try {
190: while (true) {
191: int nextByte = stream.read();
192: if (nextByte == -1) {
193: break;
194: }
195: out.write(nextByte);
196: }
197: } finally {
198: try {
199: if (out != null) {
200: out.close();
201: }
202: if (fileOut != null) {
203: fileOut.close();
204: }
205: if (stream != null) {
206: stream.close();
207: }
208: } catch (IOException e) {
209: logger.warn("error closing streams", e);
210: }
211: }
212: }
213: }
214: return (String[]) names.toArray(new String[0]);
215: }
216:
217: /**
218: * Return a suitable filename with not path for the file being stored.
219: * The parsing of this varies between browsers and platforms. The name includes a timestamp so subsequent
220: * uploads do not overwrite the previous one.
221: *
222: * @param item the fileitem
223: * @return suitable name
224: */
225: private String getNameOnly(FileItem item, int index) {
226: logger.debug("creating attachment name for " + item.getName()
227: + ":index " + index);
228: String name = item.getName();
229: // the absolute path seems to get uploaded in IE
230: char lastChar = name.charAt(name.length() - 1);
231: if (lastChar == '/' || lastChar == '\\') {
232: name = name.substring(0, name.length() - 1);
233: }
234: if (name.indexOf('/') >= 0) {
235: name = name.substring(name.lastIndexOf('/') + 1);
236: } else if (name.indexOf('\\') >= 0) {
237: name = name.substring(name.lastIndexOf('\\') + 1);
238: }
239: logger
240: .debug("name after platform-specific processing: "
241: + name);
242: if (Environment.getInstance().isAttachmentTimestamp()) {
243: name = createTimeStamp() + "-" + index + "-" + name;
244: logger.debug("name with timestamp and index:" + name);
245: }
246: logger.debug("pure name:" + name);
247: return name;
248: }
249:
250: /**
251: * Produce a timestamp
252: * @return timestamp
253: */
254: private String createTimeStamp() {
255: SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
256: "yyyyddMMHHmmssSSS");
257: String timestamp = simpleDateFormat.format(new Date());
258: logger.debug("timestamp: " + timestamp);
259: return timestamp;
260: }
261: }
|