Author: konstantin.mishin
Date: 2010-10-20 11:39:47 -0400 (Wed, 20 Oct 2010)
New Revision: 19617
Added:
sandbox/trunk/ui/fileupload/ui/src/main/java/org/
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/application/
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/application/FileUploadPhaselistener.java
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/exception/
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/exception/FileUploadException.java
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/ByteSequenceMatcher.java
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/FileParam.java
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/MultipartRequest.java
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/MultipartRequestRegistry.java
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/Param.java
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/ValueParam.java
Log:
RF-9497
Added:
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/application/FileUploadPhaselistener.java
===================================================================
---
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/application/FileUploadPhaselistener.java
(rev 0)
+++
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/application/FileUploadPhaselistener.java 2010-10-20
15:39:47 UTC (rev 19617)
@@ -0,0 +1,229 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright ${year}, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.URLDecoder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PhaseEvent;
+import javax.faces.event.PhaseId;
+import javax.faces.event.PhaseListener;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.richfaces.exception.FileUploadException;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+import org.richfaces.request.MultipartRequest;
+
+/**
+ * @author Konstantin Mishin
+ *
+ */
+public class FileUploadPhaselistener implements PhaseListener {
+
+ private static final long serialVersionUID = 138000954953175986L;
+
+ /** Multipart request start */
+ private static final String MULTIPART = "multipart/";
+
+ private static final Pattern AMPERSAND = Pattern.compile("&+");
+
+ private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
+
+ /** Flag indicating whether a temporary file should be used to cache the uploaded
file */
+ private boolean createTempFiles = false;
+
+ private String tempFilesDirectory;
+
+ /** The maximum size of a file upload request. 0 means no limit. */
+ private int maxRequestSize = 0;
+
+ public FileUploadPhaselistener() {
+ ExternalContext context =
FacesContext.getCurrentInstance().getExternalContext();
+ String param = context.getInitParameter("createTempFiles");
+ if (param != null) {
+ this.createTempFiles = Boolean.parseBoolean(param);
+ } else {
+ this.createTempFiles = true;
+ }
+
+ this.tempFilesDirectory =
context.getInitParameter("tempFilesDirectory");
+
+ param = context.getInitParameter("maxRequestSize");
+ if (param != null) {
+ this.maxRequestSize = Integer.parseInt(param);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
+ */
+ public void afterPhase(PhaseEvent event) {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
+ */
+ public void beforePhase(PhaseEvent event) {
+ FacesContext facesContext = event.getFacesContext();
+ ExternalContext externalContext = facesContext.getExternalContext();
+ HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
+ Map<String, String> queryParamMap =
parseQueryString(request.getQueryString());
+ String uid = queryParamMap.get(MultipartRequest.UPLOAD_FILES_ID);
+ if (uid != null && isMultipartRequest(request)) {
+ if (maxRequestSize != 0 && request.getContentLength() >
maxRequestSize) {
+ boolean sendError =
Boolean.parseBoolean(queryParamMap.get(MultipartRequest.SEND_HTTP_ERROR));
+ if (sendError) {
+ printResponse(facesContext,
HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, null);
+ } else {
+ printResponse(facesContext, HttpServletResponse.SC_OK,
+ "<html
id=\"_richfaces_file_upload_size_restricted\"></html>");
+ }
+ } else if (!checkFileCount(request, queryParamMap.get("id"))) {
+ printResponse(facesContext, HttpServletResponse.SC_OK,
+ "<html
id=\"_richfaces_file_upload_forbidden\"></html>");
+ } else {
+ MultipartRequest multipartRequest = new MultipartRequest(request,
createTempFiles,
+ tempFilesDirectory, maxRequestSize, uid);
+ try {
+ multipartRequest.parseRequest();
+ if (!multipartRequest.isDone()) {
+ printResponse(facesContext, HttpServletResponse.SC_OK,
+ "<html
id=\"_richfaces_file_upload_stopped\"></html>");
+ }
+ } catch (FileUploadException e) {
+ printResponse(facesContext,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null);
+ throw e; //TODO remove it
+ } finally {
+ multipartRequest.clearRequestData();
+ }
+ }
+ }
+ }
+
+ private boolean checkFileCount(HttpServletRequest request, String idParameter) {
+ //TODO implement this method
+// HttpSession session = request.getSession(false);
+//
+// if (session != null) {
+// Map<String, Integer> map = (Map<String, Integer>) session
+// .getAttribute(FileUploadConstants.UPLOADED_COUNTER);
+//
+// if (map != null) {
+// String id = idParameter;
+// if (id != null) {
+// Integer i = map.get(id);
+// if (i != null && i == 0) {
+// return false;
+// }
+// }
+// }
+// }
+ return true;
+ }
+
+ private Map<String, String> parseQueryString(String queryString) {
+ if (queryString != null) {
+ Map<String, String> parameters = new HashMap<String, String>();
+ String[] nvPairs = AMPERSAND.split(queryString);
+ for (String nvPair : nvPairs) {
+ if (nvPair.length() == 0) {
+ continue;
+ }
+
+ int eqIdx = nvPair.indexOf('=');
+ if (eqIdx >= 0) {
+ try {
+ String name = URLDecoder.decode(nvPair.substring(0, eqIdx),
"UTF-8");
+ if (!parameters.containsKey(name)) {
+ String value = URLDecoder.decode(nvPair.substring(eqIdx + 1),
"UTF-8");
+
+ parameters.put(name, value);
+ }
+ } catch (UnsupportedEncodingException e) {
+ //log warning and skip this parameter
+ LOGGER.warn(e.getLocalizedMessage(), e);
+ }
+ }
+ }
+ return parameters;
+ } else {
+ return Collections.emptyMap();
+ }
+ }
+
+ private boolean isMultipartRequest(HttpServletRequest request) {
+ if (!"post".equals(request.getMethod().toLowerCase())) {
+ return false;
+ }
+
+ String contentType = request.getContentType();
+ if (contentType == null) {
+ return false;
+ }
+
+ if (contentType.toLowerCase().startsWith(MULTIPART)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void printResponse(FacesContext facesContext, int statusCode, String message)
{
+ facesContext.responseComplete();
+ ExternalContext externalContext = facesContext.getExternalContext();
+ externalContext.setResponseStatus(statusCode);
+ if (statusCode == HttpServletResponse.SC_OK) {
+ externalContext.setResponseContentType(MultipartRequest.TEXT_HTML);
+ try {
+ Writer writer = externalContext.getResponseOutputWriter();
+ writer.write(message);
+ writer.close();
+ } catch (IOException e) {
+ LOGGER.error(e);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.event.PhaseListener#getPhaseId()
+ */
+ public PhaseId getPhaseId() {
+ return PhaseId.RESTORE_VIEW;
+ }
+
+}
Added:
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/exception/FileUploadException.java
===================================================================
---
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/exception/FileUploadException.java
(rev 0)
+++
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/exception/FileUploadException.java 2010-10-20
15:39:47 UTC (rev 19617)
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright ${year}, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.exception;
+
+/**
+ * Thrown when an exception occurs while uploading a file.
+ *
+ */
+public class FileUploadException extends RuntimeException {
+
+ private static final long serialVersionUID = -3579917878909990838L;
+
+ public FileUploadException() {
+ this(null, null);
+ }
+
+ public FileUploadException(String message) {
+ this(message, null);
+ }
+
+ public FileUploadException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Added:
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/ByteSequenceMatcher.java
===================================================================
---
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/ByteSequenceMatcher.java
(rev 0)
+++
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/ByteSequenceMatcher.java 2010-10-20
15:39:47 UTC (rev 19617)
@@ -0,0 +1,191 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright ${year}, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.request;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ByteSequenceMatcher {
+
+ public interface BytesHandler {
+
+ void handle(byte[] bytes, int length) throws IOException;
+
+ }
+
+ private static final int ZERO_READS_NUMBER = 20;
+
+ private byte[] buffer;
+
+ private int readLength = 0;
+
+ private int zeroReadCounter = ZERO_READS_NUMBER;
+
+ private boolean bufferEOF = false;
+
+ private boolean isEOF = false;
+
+ private boolean isMatched = false;
+
+ private InputStream inputStream;
+
+ private BytesHandler bytesHandler;
+
+ public ByteSequenceMatcher(InputStream inputStream, int bufferSize) {
+ this.inputStream = inputStream;
+ this.buffer = new byte[bufferSize];
+ }
+
+ public BytesHandler getBytesHandler() {
+ return bytesHandler;
+ }
+
+ public void setBytesHandler(BytesHandler bytesHandler) {
+ this.bytesHandler = bytesHandler;
+ }
+
+ protected void prefillBuffer(int usedLength) throws IOException {
+ if (usedLength > readLength) {
+ throw new IllegalArgumentException();
+ }
+
+ if (usedLength != readLength && usedLength != 0) {
+ System.arraycopy(buffer, usedLength, buffer, 0, readLength - usedLength);
+ }
+
+ readLength -= usedLength;
+
+
+ while (!bufferEOF) {
+ int remaining = buffer.length - readLength;
+ if (remaining <= 0) {
+ break;
+ }
+ int read = inputStream.read(buffer, readLength, remaining);
+
+ if (read > 0) {
+ readLength += read;
+ } else if (read == 0) {
+ --zeroReadCounter;
+
+ if (zeroReadCounter == 0) {
+ throw new IllegalStateException("Maximum number of zero reads
reached");
+ }
+ } else if (read < 0) {
+ bufferEOF = true;
+ }
+ }
+ }
+
+ private boolean match(int startOffset, byte[]... sequences) {
+ int index = startOffset;
+
+ for (byte[] bs : sequences) {
+ for (byte b : bs) {
+
+ if (index >= readLength) {
+ return false;
+ }
+
+ if (buffer[index] != b) {
+ return false;
+ }
+
+ index++;
+ }
+ }
+
+ return true;
+ }
+
+ public void findSequence(int limit, byte[]... sequences) throws IOException {
+ isMatched = false;
+
+ int userLimit = limit;
+ if (userLimit <= 0) {
+ userLimit = Integer.MAX_VALUE;
+ }
+
+ prefillBuffer(0);
+
+ int sequencesLength = 0;
+ for (byte[] bs : sequences) {
+ sequencesLength += bs.length;
+ }
+
+ int i = 0;
+
+ while (!isMatched && i <= readLength - sequencesLength) {
+ if (match(i, sequences)) {
+ isMatched = true;
+ bytesHandler.handle(buffer, i);
+ prefillBuffer(i + sequencesLength);
+ } else {
+ int sequenceLimit = readLength - sequencesLength + 1;
+ int realLimit;
+
+ if (sequenceLimit < userLimit) {
+ realLimit = sequenceLimit;
+ } else {
+ realLimit = userLimit;
+ }
+
+ if (realLimit > 0 && i == realLimit - 1) {
+ // report limit
+ bytesHandler.handle(buffer, realLimit);
+ prefillBuffer(realLimit);
+
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ }
+
+ flushUnmatchedBytes();
+
+ if (this.readLength == 0) {
+ this.isEOF = true;
+ }
+ }
+
+ private void flushUnmatchedBytes() throws IOException {
+ if (!isMatched) {
+ if (readLength > 0) {
+ bytesHandler.handle(buffer, readLength);
+ prefillBuffer(readLength);
+ }
+ }
+ }
+
+ public boolean isEOF() {
+ return isEOF;
+ }
+
+ public boolean isMatched() {
+ return isMatched;
+ }
+
+ public boolean isMatchedAndNotEOF() {
+ return isMatched() && !isEOF();
+ }
+}
Added: sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/FileParam.java
===================================================================
--- sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/FileParam.java
(rev 0)
+++
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/FileParam.java 2010-10-20
15:39:47 UTC (rev 19617)
@@ -0,0 +1,206 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright ${year}, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.request;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.rmi.server.UID;
+
+import org.richfaces.exception.FileUploadException;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+
+class FileParam extends Param {
+
+ private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
+
+ private String filename;
+ private String contentType;
+ private int fileSize;
+
+ private ByteArrayOutputStream bOut = null;
+ private FileOutputStream fOut = null;
+ private File tempFile = null;
+
+ public FileParam(String name) {
+ super(name);
+ }
+
+ public Object getFile() {
+ if (null != tempFile) {
+ return tempFile;
+ } else if (null != bOut) {
+ return bOut.toByteArray();
+ }
+ return null;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public void setFilename(String filename) {
+ this.filename = filename;
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ public int getFileSize() {
+ return fileSize;
+ }
+
+ public File createTempFile(String tempFilesDirectory) {
+ try {
+ File dir = null;
+ if (tempFilesDirectory != null) {
+ dir = new File(tempFilesDirectory);
+ }
+ tempFile = File.createTempFile(new UID().toString().replace(":",
"-"), ".upload", dir);
+ fOut = new FileOutputStream(tempFile);
+ } catch (IOException ex) {
+ if (fOut != null) {
+ try {
+ fOut.close();
+ } catch (IOException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+
+ throw new FileUploadException("Could not create temporary file");
+ }
+ return tempFile;
+ }
+
+ public void deleteFile() {
+ try {
+ if (fOut != null) {
+ fOut.close();
+ }
+ if (tempFile != null) {
+ tempFile.delete();
+ }
+ } catch (Exception e) {
+ throw new FileUploadException("Could not delete temporary file");
+ }
+ }
+
+ public byte[] getData() {
+ if (bOut != null) {
+ return bOut.toByteArray();
+ } else if (tempFile != null) {
+ if (tempFile.exists()) {
+ FileInputStream fIn = null;
+ try {
+ long fileLength = tempFile.length();
+ if (fileLength > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("File content is too long
to be allocated as byte[]");
+ }
+
+ fIn = new FileInputStream(tempFile);
+
+ byte[] fileData = new byte[(int) fileLength];
+ int totalRead = 0;
+ int read = 0;
+ do {
+ read = fIn.read(fileData, totalRead, fileData.length -
totalRead);
+ if (read > 0) {
+ totalRead += read;
+ }
+ } while (read > 0);
+
+ return fileData;
+ } catch (IOException ex) { /* too bad? */
+ LOGGER.error(ex.getMessage(), ex);
+ } finally {
+ if (fIn != null) {
+ try {
+ fIn.close();
+ } catch (IOException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public InputStream getInputStream() {
+ if (bOut != null) {
+ return new ByteArrayInputStream(bOut.toByteArray());
+ } else if (tempFile != null) {
+ try {
+ return new FileInputStream(tempFile) {
+ @Override
+ public void close() throws IOException {
+ super.close();
+ tempFile.delete();
+ }
+ };
+ } catch (FileNotFoundException ex) {
+ LOGGER.error(ex.getMessage(), ex);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void complete() throws IOException {
+ if (fOut != null) {
+ try {
+ fOut.close();
+ } catch (IOException ex) {
+ LOGGER.error(ex.getMessage(), ex);
+ }
+ fOut = null;
+ }
+ }
+
+ public void handle(byte[] bytes, int length) throws IOException {
+ // read += length;
+ if (fOut != null) {
+ fOut.write(bytes, 0, length);
+ fOut.flush();
+ } else {
+ if (bOut == null) {
+ bOut = new ByteArrayOutputStream();
+ }
+ bOut.write(bytes, 0, length);
+ }
+
+ fileSize += length;
+ }
+}
\ No newline at end of file
Added:
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/MultipartRequest.java
===================================================================
---
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/MultipartRequest.java
(rev 0)
+++
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/MultipartRequest.java 2010-10-20
15:39:47 UTC (rev 19617)
@@ -0,0 +1,746 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright ${year}, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.request;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+import org.richfaces.exception.FileUploadException;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+import org.richfaces.model.UploadItem;
+import org.richfaces.request.ByteSequenceMatcher.BytesHandler;
+
+public class MultipartRequest extends HttpServletRequestWrapper {
+
+ /**
+ * Request parameter that allow to send HTTP error instead of html message
+ */
+ public static final String SEND_HTTP_ERROR = "_richfaces_send_http_error";
+
+ /** Request parameter that indicates if multipart request forced by rich file upload
component */
+ public static final String UPLOAD_FILES_ID = "_richfaces_upload_uid";
+
+ public static final String TEXT_HTML = "text/html";
+
+ private static final BytesHandler NOOP_HANDLER = new BytesHandler() {
+ public void handle(byte[] bytes, int length) {
+ // do nothing
+ }
+ };
+
+ /** Session bean name where request size will be stored */
+ private static final String REQUEST_SIZE_BEAN_NAME =
"_richfaces_request_size";
+
+ /** Session bean name where progress bar's percent map will be stored */
+ private static final String PERCENT_BEAN_NAME =
"_richfaces_upload_percents";
+
+ /** Session bean name where stop keys will be stored */
+ private static final String REQUEST_KEYS_BEAN_NAME =
"_richfaces_request_keys";
+
+ private static final String PARAM_NAME = "name";
+ private static final String PARAM_FILENAME = "filename";
+ private static final String PARAM_CONTENT_TYPE = "Content-Type";
+
+ private static final int BUFFER_SIZE = 2048;
+ private static final int CHUNK_SIZE = 1024;
+ private static final int MAX_HEADER_SIZE = 32768;
+
+ private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
+
+ private static final byte CR = 0x0d;
+ private static final byte LF = 0x0a;
+ private static final byte[] CR_LF = {CR, LF};
+ private static final byte[] HYPHENS = {0x2d, 0x2d}; // '--'
+
+ private static final Pattern PARAM_VALUE_PATTERN =
Pattern.compile("^\\s*([^\\s=]+)\\s*[=:]\\s*(.+)\\s*$");
+
+ private static final Pattern FILE_NAME_PATTERN =
Pattern.compile(".*filename=\"(.*)\"");
+
+ private boolean createTempFiles;
+
+ private String tempFilesDirectory;
+
+ private String uid;
+
+ private String encoding = null;
+
+ private Integer contentLength = 0;
+
+ private int bytesRead = 0;
+
+ // we shouldn't allow to stop until request reaches PhaseListener because of
portlets
+ private volatile boolean canStop = false;
+
+ private Map<String, Param> parameters = null;
+
+ private Map<String, Object> percentMap = null;
+
+ private Map<String, Integer> requestSizeMap = null;
+
+ private Map<String, String> requestKeysMap = null;
+
+ private String requestKey = null;
+
+ private MultipartRequestRegistry requestRegistry;
+
+ private List<String> keys = new ArrayList<String>();
+
+ private byte[] boundaryMarker;
+
+ private ByteSequenceMatcher sequenceMatcher;
+
+ private boolean shouldStop = false;
+ private boolean canceled;
+
+ private boolean initialized = false;
+
+ private HeadersHandler headersHandler = null;
+
+ public MultipartRequest(HttpServletRequest request, boolean createTempFiles, String
tempFilesDirectory,
+ int maxRequestSize, String uid) {
+ super(request);
+ this.createTempFiles = createTempFiles;
+ this.tempFilesDirectory = tempFilesDirectory;
+ this.uid = uid;
+
+ String contentLengthStr = request.getHeader("Content-Length");
+ this.contentLength = Integer.parseInt(contentLengthStr);
+ if (contentLengthStr != null && maxRequestSize > 0 &&
contentLength > maxRequestSize) {
+ // TODO : we should make decision if can generate exception in this
+ // place
+ // throw new FileUploadException(
+ // "Multipart request is larger than allowed size");
+ }
+ }
+
+ private class ControlledProgressInputStream extends FilterInputStream {
+
+ protected ControlledProgressInputStream(InputStream in) {
+ super(in);
+ }
+
+ @Override
+ public int read() throws IOException {
+ int read = super.read();
+ if (read >= 0) {
+ bytesRead++;
+ fillProgressInfo();
+ }
+ return read;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ int read = super.read(b);
+ if (read > 0) {
+ bytesRead += read;
+ fillProgressInfo();
+ }
+ return read;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int read = super.read(b, off, len);
+ if (read > 0) {
+ bytesRead += read;
+ fillProgressInfo();
+ }
+ return read;
+ }
+ }
+
+ private String decodeFileName(String name) {
+ String fileName = null;
+
+ try {
+ if (getRequest().getParameter(SEND_HTTP_ERROR) != null) {
+ fileName = new String(name.getBytes(encoding), "UTF-8");
+ } else {
+ StringBuffer buffer = new StringBuffer();
+ String[] codes = name.split(";");
+ if (codes != null) {
+ for (String code : codes) {
+ if (code.startsWith("&")) {
+ String sCode = code.replaceAll("[&#]*",
"");
+ Integer iCode = Integer.parseInt(sCode);
+ buffer.append(Character.toChars(iCode));
+ } else {
+ buffer.append(code);
+ }
+ }
+ fileName = buffer.toString();
+ }
+ }
+ } catch (Exception e) {
+ fileName = name;
+ }
+
+ return fileName;
+ }
+
+ public void cancel() {
+ this.canceled = true;
+
+ if (parameters != null) {
+ Iterator<Param> it = parameters.values().iterator();
+ while (it.hasNext()) {
+ Param p = it.next();
+ if (p instanceof FileParam) {
+ ((FileParam) p).deleteFile();
+ }
+ }
+ }
+ }
+
+ private void readNext() throws IOException {
+ Param p = readHeader();
+ if (p != null) {
+ try {
+ readData(p);
+ } finally {
+ try {
+ p.complete();
+ } catch (IOException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ private Param createParam(Map<String, String> headers) {
+ Param param = null;
+ String paramName = headers.get(PARAM_NAME);
+ if (paramName != null) {
+ if (headers.containsKey(PARAM_FILENAME)) {
+ FileParam fp = new FileParam(paramName);
+ this.keys.add(paramName);
+
+ if (createTempFiles) {
+ fp.createTempFile(tempFilesDirectory);
+ }
+ fp.setContentType(headers.get(PARAM_CONTENT_TYPE));
+ fp.setFilename(decodeFileName(headers.get(PARAM_FILENAME)));
+ param = fp;
+ } else {
+ if (parameters.containsKey(paramName)) {
+ param = parameters.get(paramName);
+ } else {
+ param = new ValueParam(paramName, encoding);
+ }
+ }
+
+ if (!parameters.containsKey(paramName)) {
+ parameters.put(paramName, param);
+ }
+ }
+
+ return param;
+ }
+
+ private class HeadersHandler implements BytesHandler {
+
+ private ByteArrayOutputStream baos = new ByteArrayOutputStream(BUFFER_SIZE);
+
+ public void handle(byte[] bytes, int length) throws IOException {
+ if (length != 0) {
+ if (baos.size() + length > MAX_HEADER_SIZE) {
+ throw new IOException("Header section is too big");
+ }
+
+ baos.write(bytes, 0, length);
+ }
+ }
+
+ public boolean dataEquals(byte[] bytes) {
+ return (baos.size() == bytes.length) && Arrays.equals(HYPHENS,
baos.toByteArray());
+ }
+
+ public String asString() throws UnsupportedEncodingException {
+ if (encoding != null) {
+ return baos.toString(encoding);
+ } else {
+ return baos.toString();
+ }
+ }
+
+ public void reset() {
+ baos.reset();
+ }
+
+ }
+
+ private Param readHeader() throws IOException {
+ if (sequenceMatcher.isEOF()) {
+ return null;
+ }
+
+ if (headersHandler == null) {
+ headersHandler = new HeadersHandler();
+ } else {
+ headersHandler.reset();
+ }
+
+ sequenceMatcher.setBytesHandler(headersHandler);
+ sequenceMatcher.findSequence(-1, CR_LF);
+
+ if (sequenceMatcher.isMatchedAndNotEOF() &&
!headersHandler.dataEquals(HYPHENS)) {
+ headersHandler.reset();
+
+ sequenceMatcher.findSequence(-1, CR_LF, CR_LF);
+
+ if (!sequenceMatcher.isMatchedAndNotEOF()) {
+ throw new IOException("Request header cannot be read");
+ }
+
+ String headersString = headersHandler.asString();
+ Map<String, String> headers = new HashMap<String, String>();
+ String[] split = headersString.split("\r\n");
+ for (String headerString : split) {
+ parseParams(headerString, "; ", headers);
+ }
+
+ return createParam(headers);
+ }
+
+ return null;
+ }
+
+ private void readProlog() throws IOException {
+ sequenceMatcher.setBytesHandler(NOOP_HANDLER);
+ sequenceMatcher.findSequence(-1, HYPHENS, boundaryMarker);
+ if (!sequenceMatcher.isMatchedAndNotEOF()) {
+ throw new IOException("Request prolog cannot be read");
+ }
+ }
+
+ private void readData(final Param param) throws IOException {
+ sequenceMatcher.setBytesHandler(param);
+ sequenceMatcher.findSequence(CHUNK_SIZE, CR_LF, HYPHENS, boundaryMarker);
+ if (!this.sequenceMatcher.isMatchedAndNotEOF()) {
+ throw new IOException("Request data cannot be read");
+ }
+ }
+
+ private void initialize() throws IOException {
+ if (!initialized) {
+ initialized = true;
+
+ this.boundaryMarker = getBoundaryMarker(super.getContentType());
+ if (this.boundaryMarker == null) {
+ throw new FileUploadException("The request was rejected because
" + "no multipart boundary was found");
+ }
+
+ if (HYPHENS.length + boundaryMarker.length + CHUNK_SIZE + CR_LF.length >
BUFFER_SIZE) {
+ throw new FileUploadException("Boundary marker is too long");
+ }
+
+ this.encoding = getCharacterEncoding();
+
+ this.parameters = new HashMap<String, Param>();
+
+ InputStream input = new ControlledProgressInputStream(getInputStream());
+
+ this.sequenceMatcher = new ByteSequenceMatcher(input, BUFFER_SIZE);
+
+ setupProgressData();
+
+ readProlog();
+ }
+ }
+
+ public void parseRequest() {
+ canStop = true;
+
+ setupProgressData();
+
+ try {
+ initialize();
+
+ while (!sequenceMatcher.isEOF()) {
+ readNext();
+ }
+ } catch (IOException e) {
+ this.cancel();
+
+ if (!this.shouldStop) {
+ throw new FileUploadException("IO Error parsing multipart
request", e);
+ }
+ } finally {
+ canStop = false;
+ }
+ }
+
+ public static MultipartRequest lookupRequest(FacesContext context, String uploadId)
{
+ Map<String, Object> sessionMap =
context.getExternalContext().getSessionMap();
+ @SuppressWarnings("unchecked")
+ Map<String, String> requestKeys = (Map<String, String>)
sessionMap.get(REQUEST_KEYS_BEAN_NAME);
+ if (requestKeys != null) {
+ String requestKey = requestKeys.get(uploadId);
+ if (requestKey != null) {
+ MultipartRequestRegistry requestRegistry =
MultipartRequestRegistry.getInstance(context);
+ if (requestRegistry != null) {
+ MultipartRequest request = requestRegistry.getRequest(requestKey);
+ if (request != null) {
+ return request;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void setupProgressData() {
+ if (percentMap == null || requestSizeMap == null || requestKeysMap == null) {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ if (facesContext != null) {
+ ExternalContext externalContext = facesContext.getExternalContext();
+ if (externalContext != null) {
+ Map<String, Object> sessionMap =
externalContext.getSessionMap();
+ if (sessionMap != null) {
+ String uploadId = getUploadId();
+
+ synchronized (sessionMap) {
+ if (percentMap == null) {
+ percentMap = (Map<String, Object>)
sessionMap.get(PERCENT_BEAN_NAME);
+ if (percentMap == null) {
+ percentMap = new ConcurrentHashMap<String,
Object>();
+ sessionMap.put(PERCENT_BEAN_NAME, percentMap);
+ }
+ }
+
+ if (requestSizeMap == null) {
+ requestSizeMap = (Map<String, Integer>)
sessionMap.get(REQUEST_SIZE_BEAN_NAME);
+ if (requestSizeMap == null) {
+ requestSizeMap = new ConcurrentHashMap<String,
Integer>();
+ sessionMap.put(REQUEST_SIZE_BEAN_NAME,
requestSizeMap);
+ }
+ }
+
+ if (requestKeysMap == null) {
+ requestKeysMap = (Map<String, String>)
sessionMap.get(REQUEST_KEYS_BEAN_NAME);
+ if (requestKeysMap == null) {
+ requestKeysMap = new ConcurrentHashMap<String,
String>();
+ sessionMap.put(REQUEST_KEYS_BEAN_NAME,
requestKeysMap);
+ }
+
+ }
+ }
+
+ percentMap.put(uploadId, Double.valueOf(0));
+
+ requestSizeMap.put(uploadId, getSize());
+
+ requestRegistry =
MultipartRequestRegistry.getInstance(facesContext);
+ requestKey = requestRegistry.registerRequest(this);
+ requestKeysMap.put(uploadId, requestKey);
+
+ }
+ }
+ }
+ }
+ }
+
+ private void fillProgressInfo() {
+ setupProgressData();
+
+ if (percentMap != null) {
+ Double percent = (Double) (100.0 * this.bytesRead / this.contentLength);
+ percentMap.put(uid, percent);
+ // this.percent = percent;
+ }
+ }
+
+ private byte[] getBoundaryMarker(String contentType) {
+ Map<String, String> params = parseParams(contentType, ";");
+ String boundaryStr = (String) params.get("boundary");
+
+ if (boundaryStr == null) {
+ return null;
+ }
+
+ try {
+ return boundaryStr.getBytes("ISO-8859-1");
+ } catch (UnsupportedEncodingException e) {
+ return boundaryStr.getBytes();
+ }
+ }
+
+ private Map<String, String> parseParams(String paramStr, String separator) {
+ Map<String, String> paramMap = new HashMap<String, String>();
+ parseParams(paramStr, separator, paramMap);
+ return paramMap;
+ }
+
+ private void parseParams(String paramStr, String separator, Map<String, String>
paramMap) {
+ String[] parts = paramStr.split(separator);
+
+ for (String part : parts) {
+ Matcher m = PARAM_VALUE_PATTERN.matcher(part);
+ if (m.matches()) {
+ String key = m.group(1);
+ String value = m.group(2);
+
+ // Strip double quotes
+ if (value.startsWith("\"") &&
value.endsWith("\"")) {
+ value = value.substring(1, value.length() - 1);
+ }
+ if (!"filename".equals(key)) {
+ paramMap.put(key, value);
+ } else {
+ paramMap.put(key, parseFileName(paramStr));
+ }
+ }
+ }
+ }
+
+ private String parseFileName(String parseStr) {
+ Matcher m = FILE_NAME_PATTERN.matcher(parseStr);
+ if (m.matches()) {
+ String name = m.group(1);
+ if (name.startsWith("&")) {
+ return decodeFileName(name);
+ } else {
+ return name;
+ }
+ }
+ return null;
+ }
+
+ private Param getParam(String name) {
+ Param param = null;
+ if (parameters != null) {
+ param = parameters.get(name);
+ }
+
+ if (param == null) {
+ if (!canceled) {
+ try {
+ initialize();
+
+ while (param == null && !sequenceMatcher.isEOF()) {
+ readNext();
+ param = parameters.get(name);
+ }
+ } catch (IOException e) {
+ this.cancel();
+ throw new FileUploadException("IO Error parsing multipart
request", e);
+ }
+ }
+ }
+
+ return param;
+ }
+
+ public Integer getSize() {
+ return contentLength;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Enumeration getParameterNames() {
+ if (parameters == null) {
+ parseRequest();
+ }
+
+ return Collections.enumeration(parameters.keySet());
+ }
+
+ public byte[] getFileBytes(String name) {
+ Param p = getParam(name);
+ return (p != null && p instanceof FileParam) ? ((FileParam) p).getData()
: null;
+ }
+
+ public InputStream getFileInputStream(String name) {
+ Param p = getParam(name);
+ return (p != null && p instanceof FileParam) ? ((FileParam)
p).getInputStream() : null;
+ }
+
+ public String getFileContentType(String name) {
+ Param p = getParam(name);
+ return (p != null && p instanceof FileParam) ? ((FileParam)
p).getContentType() : null;
+ }
+
+ public Object getFile(String name) {
+ Param p = getParam(name);
+ return (p != null && p instanceof FileParam) ? ((FileParam) p).getFile()
: null;
+ }
+
+ public String getFileName(String name) {
+ Param p = getParam(name);
+ return (p != null && p instanceof FileParam) ? ((FileParam)
p).getFilename() : null;
+ }
+
+ public int getFileSize(String name) {
+ Param p = getParam(name);
+ return (p != null && p instanceof FileParam) ? ((FileParam)
p).getFileSize() : -1;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ Param p = getParam(name);
+ if (p != null && p instanceof ValueParam) {
+ ValueParam vp = (ValueParam) p;
+ if (vp.getValue() instanceof String) {
+ return (String) vp.getValue();
+ }
+ } else if (p != null && p instanceof FileParam) {
+ return "---BINARY DATA---";
+ } else {
+ return super.getParameter(name);
+ }
+
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ parseRequest();
+
+ Param p = getParam(name);
+ if (p != null && p instanceof ValueParam) {
+ ValueParam vp = (ValueParam) p;
+ if (vp.getValue() instanceof List<?>) {
+ @SuppressWarnings("unchecked")
+ List<String> vals = (List<String>) vp.getValue();
+ String[] values = new String[vals.size()];
+ vals.toArray(values);
+ return values;
+ } else {
+ return new String[] {(String) vp.getValue() };
+ }
+ } else {
+ return super.getParameterValues(name);
+ }
+ }
+
+ @Override
+ public Map<String, Object> getParameterMap() {
+ if (parameters == null) {
+ parseRequest();
+ }
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> params = new HashMap<String,
Object>(super.getParameterMap());
+
+ for (String name : parameters.keySet()) {
+ Param p = parameters.get(name);
+ if (p instanceof ValueParam) {
+ ValueParam vp = (ValueParam) p;
+ if (vp.getValue() instanceof String) {
+ params.put(name, vp.getValue());
+ } else if (vp.getValue() instanceof List) {
+ params.put(name, getParameterValues(name));
+ }
+ }
+ }
+
+ return params;
+ }
+
+ public List<UploadItem> getUploadItems() {
+ List<UploadItem> uploadItems = new ArrayList<UploadItem>();
+ for (String k : keys) {
+ uploadItems.add(new UploadItem(getFileName(k), getFileSize(k),
getFileContentType(k), getFile(k)));
+ }
+ return uploadItems;
+ }
+
+ public boolean isFormUpload() {
+ return "_richfaces_form_upload".equals(uid);
+ }
+
+ @Override
+ public String getHeader(String name) {
+ if (!"Accept".equals(name)) {
+ return super.getHeader(name);
+ } else {
+ return TEXT_HTML;
+ }
+ }
+
+ public void stop() {
+ if (canStop) {
+ shouldStop = true;
+ }
+ }
+
+ public boolean isStopped() {
+ return this.shouldStop;
+ }
+
+ public boolean isDone() {
+ return !(this.shouldStop && (this.canceled || this.contentLength != null
+ && this.contentLength.intValue() != this.bytesRead));
+ }
+
+ @Override
+ public String getContentType() {
+ return "application/x-www-form-urlencoded";
+ }
+
+ protected String getUploadId() {
+ return uid;
+ }
+
+ public void clearRequestData() {
+ String uploadId = getUploadId();
+
+ if (percentMap != null) {
+ percentMap.remove(uploadId);
+ }
+
+ if (requestSizeMap != null) {
+ requestSizeMap.remove(uploadId);
+ }
+
+ if (requestKeysMap != null) {
+ requestKeysMap.remove(uploadId);
+ }
+
+ if (requestRegistry != null) {
+ requestRegistry.removeRequest(requestKey);
+ }
+ }
+}
\ No newline at end of file
Added:
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/MultipartRequestRegistry.java
===================================================================
---
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/MultipartRequestRegistry.java
(rev 0)
+++
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/MultipartRequestRegistry.java 2010-10-20
15:39:47 UTC (rev 19617)
@@ -0,0 +1,76 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright ${year}, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.request;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.faces.context.FacesContext;
+
+final class MultipartRequestRegistry {
+
+ private static final String REGISTRY_ATTRIBUTE_NAME =
MultipartRequestRegistry.class.getName();
+
+ private AtomicInteger atomicInteger = new AtomicInteger(0);
+
+ private String registryId = UUID.randomUUID().toString();
+
+ private Map<String, MultipartRequest> requestsMap = new
ConcurrentHashMap<String, MultipartRequest>();
+
+ private MultipartRequestRegistry() {
+
+ }
+
+ public static MultipartRequestRegistry getInstance(FacesContext context) {
+ Map<String, Object> applicationMap =
context.getExternalContext().getApplicationMap();
+ // MultipartRequestRegistry requestRegistry = (MultipartRequestRegistry)
applicationMap
+ // .get(REGISTRY_ATTRIBUTE_NAME);
+ // if (requestRegistry == null) {
+ synchronized (applicationMap) {
+ MultipartRequestRegistry requestRegistry = (MultipartRequestRegistry)
applicationMap
+ .get(REGISTRY_ATTRIBUTE_NAME);
+ if (requestRegistry == null) {
+ requestRegistry = new MultipartRequestRegistry();
+ applicationMap.put(REGISTRY_ATTRIBUTE_NAME, requestRegistry);
+ }
+ // }
+ return requestRegistry;
+ }
+ }
+
+ public String registerRequest(MultipartRequest request) {
+ String key = registryId + ":" + atomicInteger.incrementAndGet();
+ requestsMap.put(key, request);
+
+ return key;
+ }
+
+ public void removeRequest(String key) {
+ requestsMap.remove(key);
+ }
+
+ public MultipartRequest getRequest(String key) {
+ return requestsMap.get(key);
+ }
+}
Added: sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/Param.java
===================================================================
--- sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/Param.java
(rev 0)
+++
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/Param.java 2010-10-20
15:39:47 UTC (rev 19617)
@@ -0,0 +1,40 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright ${year}, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.request;
+
+import java.io.IOException;
+
+import org.richfaces.request.ByteSequenceMatcher.BytesHandler;
+
+abstract class Param implements BytesHandler {
+ private String name;
+
+ public Param(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public abstract void complete() throws IOException;
+}
\ No newline at end of file
Added: sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/ValueParam.java
===================================================================
--- sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/ValueParam.java
(rev 0)
+++
sandbox/trunk/ui/fileupload/ui/src/main/java/org/richfaces/request/ValueParam.java 2010-10-20
15:39:47 UTC (rev 19617)
@@ -0,0 +1,66 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright ${year}, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.request;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+class ValueParam extends Param {
+
+ private Object value = null;
+ private ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ private String encoding;
+
+ public ValueParam(String name, String encoding) {
+ super(name);
+ this.encoding = encoding;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void complete() throws IOException {
+ String val = this.encoding == null ? new String(buf.toByteArray()) : new
String(buf.toByteArray(),
+ this.encoding);
+ if (value == null) {
+ value = val;
+ } else {
+ if (!(value instanceof List<?>)) {
+ List<String> v = new ArrayList<String>();
+ v.add((String) value);
+ value = v;
+ }
+
+ ((List<String>) value).add(val);
+ }
+ buf.reset();
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void handle(byte[] bytes, int length) throws IOException {
+ // read += length;
+ buf.write(bytes, 0, length);
+ }
+}
\ No newline at end of file