You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2010/04/01 09:41:29 UTC
svn commit: r929871 - in /myfaces/trinidad/branches/trinidad-1.2.x: ./
trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/
trinidad-examples/trinidad-demo/
trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/
trinid...
Author: matzew
Date: Thu Apr 1 07:41:28 2010
New Revision: 929871
URL: http://svn.apache.org/viewvc?rev=929871&view=rev
Log:
TRINIDAD-1757 - Allow (or support) decorator pattern for the UploadedFileProcessor
thanks to Girish Kumar Balachandran for the patch
Added:
myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/ChainedUploadedFileProcessor.java
myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ProfanityScanner.java
myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/CompositeUploadedFileProcessorImpl.java
Modified:
myfaces/trinidad/branches/trinidad-1.2.x/pom.xml
myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UploadedFileProcessor.java
myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/pom.xml
myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/UIBean.java
myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/trinidad-config.xml
myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigParser.java
myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/UploadedFileProcessorImpl.java
Modified: myfaces/trinidad/branches/trinidad-1.2.x/pom.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/pom.xml?rev=929871&r1=929870&r2=929871&view=diff
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/pom.xml (original)
+++ myfaces/trinidad/branches/trinidad-1.2.x/pom.xml Thu Apr 1 07:41:28 2010
@@ -870,46 +870,5 @@
</profiles>
</settings>
-->
- <profile>
- <id>java5compilerFor6</id>
- <activation>
- <jdk>1.6</jdk>
- </activation>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <inherited>true</inherited>
- <configuration>
- <fork>true</fork>
- <executable>${jdk5.home}/bin/javac</executable>
- <compilerVersion>${jdk.version}</compilerVersion>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
- <!-- repeat for JDK 1.7 -->
- <profile>
- <id>java5compilerFor7</id>
- <activation>
- <jdk>1.7</jdk>
- </activation>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <inherited>true</inherited>
- <configuration>
- <fork>true</fork>
- <executable>${jdk5.home}/bin/javac</executable>
- <compilerVersion>${jdk.version}</compilerVersion>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
</profiles>
</project>
Added: myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/ChainedUploadedFileProcessor.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/ChainedUploadedFileProcessor.java?rev=929871&view=auto
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/ChainedUploadedFileProcessor.java (added)
+++ myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/ChainedUploadedFileProcessor.java Thu Apr 1 07:41:28 2010
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.webapp;
+
+import java.io.IOException;
+import org.apache.myfaces.trinidad.model.UploadedFile;
+
+/**
+ * Interface responsible for processing file uploads by multiple processors one
+ * after another in a chained fashion. An Apache Trinidad application could have
+ * multiple <code>ChainedUploadedFileProcessor</code> instances. A composite UploadedFileProcessor
+ * is accessible from the {@link org.apache.myfaces.trinidad.context.RequestContext},
+ * but will be invoked automatically by the framework as needed. Developers
+ * can implement this interface and chain many of them up together using space
+ * separated class names in <code>trinidad-config.xml</code> file under
+ * <code>uploaded-file-processor</code> element. The order in which the processors
+ * will be instantated and called will be the same as how it appears inside the element.
+ * <p>
+ * To configure file uploads, the default instance supports three context
+ * initialization parameters :
+ * <ul>
+ * <li>org.apache.myfaces.trinidad.UPLOAD_MAX_MEMORY: the maximum amount of memory
+ * that can be used in a single request to store
+ * uploaded files. (Default of 100K)
+ * <li>org.apache.myfaces.trinidad.UPLOAD_MAX_DISK_SPACE: the maximum amount of
+ * disk space that can be used in a single request to store
+ * uploaded files. (Default of 2000K)
+ * <li>org.apache.myfaces.trinidad.UPLOAD_TEMP_DIR: the name of a directory
+ * to store temporary files. (Defaults to the user's temporary directory)
+ * </ul>
+ *
+ * @see org.apache.myfaces.trinidad.model.UploadedFile
+ */
+public interface ChainedUploadedFileProcessor extends UploadedFileProcessor
+{
+ /**
+ * Initialize the ChainedUploadedFileProcessor with access to the current
+ * web application context. The order of call is same as it
+ * appears in trinidad-config.xml
+ *
+ * @param context the current ServletContext or PortletContext
+ */
+ public void init(Object context);
+
+ /**
+ * Process a single uploaded file. An implementation of this
+ * method must process an incoming <code>UploadedFile</code> object
+ * and return a new <code>UploadedFile</code> instance that will
+ * remain valid for the duration of this request. The properties of the incoming
+ * <code>UploadedFile</code> object depends on the implementation detail of
+ * the previous ChainedUploadedFileProcessor in the chain. In general all the
+ * implementations must strive to return a <code>UploadedFile</code> that
+ * should at the least comply to following:
+ * <ul>
+ * <li>{@link UploadedFile#getInputStream} may only be called once</li>
+ * <li>{@link UploadedFile#getLength} returns length as it should be available</li>
+ * <li>{@link UploadedFile#getFilename} may have been internationalized; users should not
+ * rely on its value, but simply use it unmodified in the
+ * outgoing <code>UploadedFile</code></li>
+ * </ul>
+ * <p>
+ * First ChainedUploadedFileProcessor in the list gets an <code>UploadedFile</code> implementation
+ * from the framework with the above properties and the following few more:
+ * <ul>
+ * <li>{@link UploadedFile#getInputStream} may be called multiple times. Each call gives a new InputStream</li>
+ * <li>{@link UploadedFile#getLength} returns length</li>
+ * </ul>
+ * Due to the above properties, if there was no change made to the underlying stream
+ * significantly by the current ChainedUploadedFileProcessor, this <code>UploadedFile</code> object could
+ * be returned intact for subsequent processing by the framework. This avoids creation of
+ * new <code>UploadedFile</code> for simple ChainedUploadedFileProcessor implementations.
+ * </p>
+ * <p>
+ * The framework guarantees that {@link UploadedFile#dispose}</code> will be called before
+ * the request completes for each UploadedFile returned by every ChainedUploadedFileProcessor.
+ * The order in which dispose() will be called is the revers of the order
+ * they are declared in trinidad-config.xml. If same UploadedFile
+ * was returned by more than one processors, dispose() will be called only once
+ * on it. Any exception that happenes during dispose() call will be logged
+ * as warning and the processing continues with the rest of the UploadedFile(s).
+ * </p>
+ * @param request the current servlet or portlet request
+ * @param file a temporary file object
+ * @return a new instance of UploadedFile. It is legal to return null,
+ * in which case the file will not be available later in the request.
+ */
+ public UploadedFile processFile(
+ Object request, UploadedFile file) throws IOException;
+}
Modified: myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UploadedFileProcessor.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UploadedFileProcessor.java?rev=929871&r1=929870&r2=929871&view=diff
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UploadedFileProcessor.java (original)
+++ myfaces/trinidad/branches/trinidad-1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/webapp/UploadedFileProcessor.java Thu Apr 1 07:41:28 2010
@@ -24,8 +24,10 @@ import org.apache.myfaces.trinidad.model
/**
* Interface responsible for processing file uploads. An Apache Trinidad
- * application has a single <code>UploadedFileProcessor</code> instance.
- * It is accessible from the {@link org.apache.myfaces.trinidad.context.RequestContext},
+ * application has a single <code>UploadedFileProcessor</code> instance. For
+ * more simpler, multiple chained UploadedFileProcessor option please look at
+ * {@link org.apache.myfaces.trinidad.webapp.ChainedUploadedFileProcessor}.
+ * UploadedFileProcessor is accessible from the {@link org.apache.myfaces.trinidad.context.RequestContext},
* but will be invoked automatically by the framework as needed. Developers
* can replace the standard processor using the
* <code>trinidad-config.xml</code> file.
Modified: myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/pom.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/pom.xml?rev=929871&r1=929870&r2=929871&view=diff
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/pom.xml (original)
+++ myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/pom.xml Thu Apr 1 07:41:28 2010
@@ -157,6 +157,12 @@
</profile>
<!-- To run jetty, issue "mvn clean -PjettyConfig jetty:run" -->
+ <!-- To Debug using a remote debugger, issue
+ "export MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000"
+ and then issue
+ "mvn clean -PjettyConfig jetty:run"
+ Then connect the remote debugger to localhost:8000 -->
+
<profile>
<id>pluto-embedded</id>
<dependencyManagement>
Added: myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ProfanityScanner.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ProfanityScanner.java?rev=929871&view=auto
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ProfanityScanner.java (added)
+++ myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ProfanityScanner.java Thu Apr 1 07:41:28 2010
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidaddemo;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.myfaces.trinidad.model.UploadedFile;
+import org.apache.myfaces.trinidad.webapp.ChainedUploadedFileProcessor;
+
+/**
+ * This class checks if the uploaded file contains the word "crap" in it and
+ * rejects if found.
+ *
+ */
+public class ProfanityScanner implements ChainedUploadedFileProcessor
+{
+
+ public void init(Object context)
+ {
+ _LOG.log(Level.INFO, "ProfanityScanner just got initialized...");
+ }
+
+ public UploadedFile processFile(Object request, UploadedFile file) throws IOException
+ {
+ _LOG.log(Level.INFO, "Scanning for profanity...");
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(file.getInputStream()));
+ String line;
+ try
+ {
+ while ((line = br.readLine()) != null)
+ {
+ if (line.indexOf("crap") != -1)
+ {
+ throw new IOException("ProfanityScanner rejected this file as " +
+ "it contained the word \"crap\" in it!!!\n" + request);
+ }
+ }
+ }
+ finally
+ {
+ br.close();
+ }
+
+ _LOG.log(Level.INFO, "Done Scanning for profanity...");
+
+ /**
+ * Since we did not change anything in the Inputstream we got from the parameter
+ * its ok to return the same object. The file argument is backed by the buffer
+ * hence subsequent processors will be able to access the stream again.
+ */
+ return file;
+ }
+
+ static private final Logger _LOG =
+ Logger.getLogger(ProfanityScanner.class.getName());
+}
Modified: myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/UIBean.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/UIBean.java?rev=929871&r1=929870&r2=929871&view=diff
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/UIBean.java (original)
+++ myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/UIBean.java Thu Apr 1 07:41:28 2010
@@ -59,7 +59,7 @@ public class UIBean
_panelPage = panelPage;
}
- public void fileUploaded(ValueChangeEvent event)
+ public void fileUploaded(ValueChangeEvent event) throws IOException
{
UploadedFile file = (UploadedFile) event.getNewValue();
if (file != null)
@@ -67,7 +67,8 @@ public class UIBean
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage message = new FacesMessage(
"Uploaded file " + file.getFilename() +
- " (" + file.getLength() + " bytes)");
+ " (" + file.getLength() + " bytes)"+". Bytes available to read: " +
+ file.getInputStream().available());
context.addMessage(event.getComponent().getClientId(context), message);
}
}
Modified: myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/trinidad-config.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/trinidad-config.xml?rev=929871&r1=929870&r2=929871&view=diff
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/trinidad-config.xml (original)
+++ myfaces/trinidad/branches/trinidad-1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/trinidad-config.xml Thu Apr 1 07:41:28 2010
@@ -33,6 +33,9 @@
<skin-family>#{prefs.proxy.skinFamily}</skin-family>
+ <uploaded-file-processor>org.apache.myfaces.trinidaddemo.ProfanityScanner org.apache.myfaces.trinidaddemo.ProfanityScanner</uploaded-file-processor>
+
+ <!--uploaded-file-processor>org.apache.myfaces.trinidaddemo.ProfanityScanner</uploaded-file-processor-->
<!--
<output-mode>portlet</output-mode>
Modified: myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigParser.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigParser.java?rev=929871&r1=929870&r2=929871&view=diff
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigParser.java (original)
+++ myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigParser.java Thu Apr 1 07:41:28 2010
@@ -20,6 +20,9 @@ package org.apache.myfaces.trinidadinter
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
@@ -36,8 +39,9 @@ import org.apache.myfaces.trinidad.conte
import org.apache.myfaces.trinidad.context.RequestContext;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
+import org.apache.myfaces.trinidad.webapp.ChainedUploadedFileProcessor;
import org.apache.myfaces.trinidad.webapp.UploadedFileProcessor;
-import org.apache.myfaces.trinidadinternal.config.upload.UploadedFileProcessorImpl;
+import org.apache.myfaces.trinidadinternal.config.upload.CompositeUploadedFileProcessorImpl;
import org.apache.myfaces.trinidadinternal.context.RequestContextBean;
import org.apache.myfaces.trinidadinternal.util.nls.LocaleUtils;
import org.apache.myfaces.trinidadinternal.util.DateUtils;
@@ -102,29 +106,78 @@ public class ConfigParser
}
}
- String className = (String)
+ String classNameString = (String)
bean.getProperty(RequestContextBean.UPLOADED_FILE_PROCESSOR_KEY);
- if (className != null)
+ if (classNameString != null)
{
- className = className.trim();
+ classNameString = classNameString.trim();
+ //check if this contains multiple class names for chained processors usecase.
+ // Usually the class named are separated by space char.
+ String classNames[] = classNameString.split("[ ]+");
+ if(classNames.length == 1)
+ {
+ //This could be a single processor full override usecase or a chained
+ //processor usecase that has only one processor.
try
{
- Class<?> clazz = ClassLoaderUtils.loadClass(className);
+ Class<UploadedFileProcessor> clazz = (Class<UploadedFileProcessor>)
+ ClassLoaderUtils.loadClass(classNames[0]);
+ if(ChainedUploadedFileProcessor.class.isAssignableFrom(clazz))
+ {
+ //this single chained processor case
+ ChainedUploadedFileProcessor cufp[] =
+ {
+ (ChainedUploadedFileProcessor) clazz.newInstance()
+ };
bean.setProperty(RequestContextBean.UPLOADED_FILE_PROCESSOR_KEY,
+ new CompositeUploadedFileProcessorImpl(Arrays.asList(cufp)));
+ }
+ else
+ {
+ //this is full override usecase
+ bean.setProperty(RequestContextBean.UPLOADED_FILE_PROCESSOR_KEY,
clazz.newInstance());
}
+
+
+ }
catch (Exception e)
{
_LOG.severe("CANNOT_INSTANTIATE_UPLOADEDFILEPROCESSOR", e);
bean.setProperty(RequestContextBean.UPLOADED_FILE_PROCESSOR_KEY,
- new UploadedFileProcessorImpl());
+ new CompositeUploadedFileProcessorImpl());
+ }
+ }
+ else
+ {
+ try
+ {
+ //chained processors usecase, Multiple processors
+ List<ChainedUploadedFileProcessor> processors =
+ new ArrayList<ChainedUploadedFileProcessor>(classNames.length);
+ for (String className : classNames)
+ {
+ Class<ChainedUploadedFileProcessor> clazz =
+ (Class<ChainedUploadedFileProcessor>) ClassLoaderUtils.loadClass(className);
+ processors.add(clazz.newInstance());
+ }
+ bean.setProperty(RequestContextBean.UPLOADED_FILE_PROCESSOR_KEY,
+ new CompositeUploadedFileProcessorImpl(processors));
+ }
+ catch(Exception e)
+ {
+ _LOG.severe("CANNOT_INSTANTIATE_UPLOADEDFILEPROCESSOR", e);
+ bean.setProperty(RequestContextBean.UPLOADED_FILE_PROCESSOR_KEY,
+ new CompositeUploadedFileProcessorImpl());
+ }
}
}
else
{
+ //nothing specified, hence use default.
bean.setProperty(RequestContextBean.UPLOADED_FILE_PROCESSOR_KEY,
- new UploadedFileProcessorImpl());
+ new CompositeUploadedFileProcessorImpl());
}
UploadedFileProcessor ufp = (UploadedFileProcessor)
Added: myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/CompositeUploadedFileProcessorImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/CompositeUploadedFileProcessorImpl.java?rev=929871&view=auto
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/CompositeUploadedFileProcessorImpl.java (added)
+++ myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/CompositeUploadedFileProcessorImpl.java Thu Apr 1 07:41:28 2010
@@ -0,0 +1,474 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.config.upload;
+
+
+import java.io.File;
+import java.io.IOException;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.portlet.ActionRequest;
+import javax.portlet.PortletContext;
+import javax.portlet.PortletRequest;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.model.UploadedFile;
+import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
+import org.apache.myfaces.trinidad.webapp.UploadedFileProcessor;
+import org.apache.myfaces.trinidadinternal.context.external.PortletApplicationMap;
+import org.apache.myfaces.trinidadinternal.context.external.PortletInitParameterMap;
+import org.apache.myfaces.trinidadinternal.context.external.PortletRequestMap;
+import org.apache.myfaces.trinidadinternal.context.external.ServletApplicationMap;
+import org.apache.myfaces.trinidadinternal.context.external.ServletInitParameterMap;
+import org.apache.myfaces.trinidadinternal.context.external.ServletRequestMap;
+
+/**
+ * This is the default implementaion of UploadedFileProcessor. It works with
+ * multiple ChainedUploadedFileProcessor declared in trinidad-config.xml by dispatching
+ * the lifecycle calls to them in the order of declaration.
+ **/
+public class CompositeUploadedFileProcessorImpl implements UploadedFileProcessor
+{
+
+ public CompositeUploadedFileProcessorImpl()
+ {
+ chainedProcessors = Collections.emptyList();
+ }
+
+ public CompositeUploadedFileProcessorImpl(
+ List<? extends UploadedFileProcessor> chainedProcessors)
+ {
+ this.chainedProcessors = chainedProcessors;
+ }
+
+ @Override
+ public void init(Object context)
+ {
+ _init(context);
+ for(UploadedFileProcessor processor: chainedProcessors)
+ {
+ //call other chained processor's init
+ processor.init(context);
+ }
+
+ }
+
+ @Override
+ public UploadedFile processFile(Object request, UploadedFile tempFile) throws IOException
+ {
+ //NOTE: The following optimization was suggested at one point:
+ // Check if there are any processors in the list. If yes then call _processFile
+ // else just return tempFile we got. Calling _processFile buffers the entire
+ // file content. tempFile arg however is not buffered. If there are no
+ // ChainedUploadedFileProcessor in the list, then there is no need to buffer.
+ // BUT, the call to getLength() and dispose() on tempFile fails.
+ // This is becasue, the impl of these 2 methods are not complete -
+ // Bug - https://issues.apache.org/jira/browse/TRINIDAD-1765
+ // This bug could not be fixed due to the explanatio in the bug.
+
+ //call _processFile first. This will create the auto buffer that we want.
+ UploadedFile original = _processFile(request, tempFile);
+ if(chainedProcessors.isEmpty())
+ {
+ return original;
+ }
+ else
+ {
+ List<UploadedFile> files = new ArrayList<UploadedFile>(chainedProcessors.size()+1);
+ files.add(original);
+ for(UploadedFileProcessor processor: chainedProcessors)
+ {
+ original = processor.processFile(request, original);
+ files.add(original);
+ }
+ //the dispose order should be reverse!
+ Collections.reverse(files);
+ return new WrappedUploadedFileImpl(original, files);
+ }
+ }
+
+
+ /**
+ * Wrapper around UploadedFileImpl to listen for dispose() call and dispatch to
+ * other UploadedFileImpls returned by other chained processors
+ */
+ private static class WrappedUploadedFileImpl implements UploadedFile{
+
+ public WrappedUploadedFileImpl(UploadedFile original, List<UploadedFile> files)
+ {
+ this.original = original;
+ this.files = files;
+ }
+
+ public void dispose()
+ {
+ try
+ {
+ original.dispose();
+ }
+ catch(Exception e)
+ {
+ _LOG.warning("Exception while disposing!", e);
+ //log and continue disposing the rest.
+ }
+ if(!files.isEmpty())
+ {
+ List<UploadedFile> disposed = new ArrayList<UploadedFile>();
+ disposed.add(original);
+ for(UploadedFile file: files)
+ {
+ if(!disposed.contains(file))
+ {
+ try
+ {
+ file.dispose();
+ }
+ catch(Exception e)
+ {
+ _LOG.warning("Exception while disposing!", e);
+ //log and continue disposing the rest.
+ }
+ disposed.add(file);
+ }
+ }
+ }
+ }
+
+ public String getFilename()
+ {
+ return original.getFilename();
+ }
+
+ public String getContentType()
+ {
+ return original.getContentType();
+ }
+
+ public long getLength()
+ {
+ return original.getLength();
+ }
+
+ public Object getOpaqueData()
+ {
+ return original.getOpaqueData();
+ }
+
+ public InputStream getInputStream() throws IOException
+ {
+ return original.getInputStream();
+ }
+
+ private final UploadedFile original;
+ private final List<UploadedFile> files;
+ }
+
+ private void _init(Object context)
+ {
+ ContextInfo info;
+ if(_PORTLET_CONTEXT_CLASS != null && _PORTLET_CONTEXT_CLASS.isInstance(context))
+ {
+ info = _getPortletContextInfo(context);
+ }
+ else
+ {
+ info = _getServletContextInfo(context);
+ }
+
+ //
+ // Get MaxMemory and TempDir properties from servlet init params
+ //
+ if (_maxMemory == -1)
+ {
+ String maxMemory = info.initParams.get(MAX_MEMORY_PARAM_NAME);
+ if (maxMemory != null)
+ {
+ try
+ {
+ _maxMemory = Long.parseLong(maxMemory);
+ }
+ catch (NumberFormatException nfe)
+ {
+ _maxMemory = _DEFAULT_MAX_MEMORY;
+ }
+ }
+ else
+ {
+ _maxMemory = _DEFAULT_MAX_MEMORY;
+ }
+ }
+
+ if (_maxDiskSpace == -1)
+ {
+ String maxDiskSpace = info.initParams.get(MAX_DISK_SPACE_PARAM_NAME);
+ if (maxDiskSpace != null)
+ {
+ try
+ {
+ _maxDiskSpace = Long.parseLong(maxDiskSpace);
+ }
+ catch (NumberFormatException nfe)
+ {
+ _maxDiskSpace = _DEFAULT_MAX_DISK_SPACE;
+ }
+ }
+ else
+ {
+ _maxDiskSpace = _DEFAULT_MAX_DISK_SPACE;
+ }
+ }
+
+ if (_tempDir == null)
+ {
+ _tempDir = info.initParams.get(TEMP_DIR_PARAM_NAME);
+ // Use the webapp temporary directory if the temporary directory
+ // has not been explicitly set.
+ if (_tempDir == null)
+ {
+ File tempDirFile = (File)
+ info.attributes.get("javax.servlet.context.tempdir");
+ if (tempDirFile != null)
+ _tempDir = tempDirFile.getAbsolutePath();
+ }
+ }
+ }
+
+ private UploadedFile _processFile(
+ Object request, UploadedFile tempFile) throws IOException
+ {
+ RequestInfo info = _getRequestInfo(request);
+ int contentLength = getContentLength(request);
+ Map<String, Object> requestMap;
+
+ if (_isPortletRequestClass(request))
+ requestMap = _getPortletRequestMap(request);
+ else
+ requestMap = _getServletRequestMap(request);
+
+ Long maxMemory = (Long)requestMap.get(MAX_MEMORY_PARAM_NAME);
+ Long maxDiskSpace = (Long)requestMap.get(MAX_DISK_SPACE_PARAM_NAME);
+ String tempDir = (String)requestMap.get(TEMP_DIR_PARAM_NAME);
+
+ if (maxMemory != null)
+ {
+ _maxMemory = maxMemory;
+ }
+
+ if (maxDiskSpace != null)
+ {
+ _maxDiskSpace = maxDiskSpace;
+ }
+
+ if (tempDir != null)
+ _tempDir = tempDir;
+
+ if(contentLength>_maxDiskSpace)
+ {
+ return new ErrorFile();
+ }
+ // Process one new file, loading only as much as can fit
+ // in the remaining memory and disk space.
+ UploadedFileImpl file = new UploadedFileImpl();
+ try
+ {
+ file.loadFile(tempFile,
+ _maxMemory - info.totalBytesInMemory,
+ _maxDiskSpace - info.totalBytesOnDisk,
+ _tempDir);
+ }
+ catch(IOException ioe)
+ {
+ _LOG.severe(ioe);
+ return new ErrorFile();
+ }
+
+ // Keep a tally of how much we've stored in memory and on disk.
+ long length = file.getLength();
+ if (file.__isInMemory())
+ {
+ info.totalBytesInMemory += length;
+ }
+ else
+ {
+ info.totalBytesOnDisk += length;
+ }
+
+ return file;
+ }
+
+ private int getContentLength(Object request)
+ {
+ int length = -1;
+ if (_isPortletRequestClass(request))
+ {
+ length = _getPortletRequestLength(request);
+ }
+ else
+ {
+ length = _getServletRequestLength(request);
+ }
+
+ return length;
+ }
+
+ private RequestInfo _getRequestInfo(Object request)
+ {
+ Map<String, Object> attributes;
+ if (_isPortletRequestClass(request))
+ {
+ attributes = _getPortletRequestMap(request);
+ }
+ else
+ {
+ attributes = _getServletRequestMap(request);
+ }
+
+
+ RequestInfo info = (RequestInfo) attributes.get(_REQUEST_INFO_KEY);
+
+ if (info == null)
+ {
+ info = new RequestInfo();
+ attributes.put(_REQUEST_INFO_KEY, info);
+ }
+
+ return info;
+ }
+
+ private boolean _isPortletRequestClass(Object request)
+ {
+ return (_PORTLET_REQUEST_CLASS != null && _PORTLET_REQUEST_CLASS.isInstance(request));
+ }
+
+ private static final ContextInfo _getServletContextInfo(final Object context)
+ {
+ assert(context instanceof ServletContext);
+
+ final ServletContext sContext = (ServletContext)context;
+ return new ContextInfo(
+ new ServletInitParameterMap(sContext),
+ new ServletApplicationMap(sContext));
+ }
+
+ private static final ContextInfo _getPortletContextInfo(final Object context)
+ {
+ assert(context instanceof PortletContext);
+
+ final PortletContext pContext = (PortletContext)context;
+ return new ContextInfo(
+ new PortletInitParameterMap(pContext),
+ new PortletApplicationMap(pContext));
+ }
+
+ private static final Map<String, Object> _getServletRequestMap(final Object request)
+ {
+ assert(request instanceof ServletRequest);
+
+ return new ServletRequestMap((ServletRequest) request);
+ }
+
+ private static final Map<String, Object> _getPortletRequestMap(final Object request)
+ {
+ assert(request instanceof PortletRequest);
+
+ return new PortletRequestMap((PortletRequest) request);
+ }
+
+ private static final int _getServletRequestLength(final Object request)
+ {
+ assert(request instanceof ServletRequest);
+
+ return ((ServletRequest) request).getContentLength();
+ }
+
+ private static final int _getPortletRequestLength(final Object request)
+ {
+ if (!(request instanceof ActionRequest))
+ return -1;
+
+ return ((ActionRequest) request).getContentLength();
+ }
+
+ static private class RequestInfo
+ {
+ public long totalBytesInMemory;
+ public long totalBytesOnDisk;
+ }
+
+ static private class ContextInfo
+ {
+ public ContextInfo(Map<String,String> init, Map<String, Object> attrib)
+ {
+ initParams= init;
+ attributes = attrib;
+ }
+
+ public Map<String, String> initParams;
+ public Map<String, Object> attributes;
+ }
+
+ private long _maxMemory = -1;
+ private long _maxDiskSpace = -1;
+ private String _tempDir = null;
+
+ private static final long _DEFAULT_MAX_MEMORY = 102400;
+ private static final long _DEFAULT_MAX_DISK_SPACE = 2048000;
+
+ private static final String _REQUEST_INFO_KEY = CompositeUploadedFileProcessorImpl.class.getName()+
+ ".UploadedFilesInfo";
+
+ private static final TrinidadLogger _LOG =
+ TrinidadLogger.createTrinidadLogger(CompositeUploadedFileProcessorImpl.class);
+
+ private static final Class<?> _PORTLET_CONTEXT_CLASS;
+ private static final Class<?> _PORTLET_REQUEST_CLASS;
+
+ static
+ {
+ Class<?> context;
+ Class<?> request;
+ try
+ {
+ context = ClassLoaderUtils.loadClass("javax.portlet.PortletContext");
+ request = ClassLoaderUtils.loadClass("javax.portlet.PortletRequest");
+ }
+ catch (final ClassNotFoundException e)
+ {
+ _LOG
+ .fine("Portlet API is not available on the classpath. Portlet configurations are disabled.");
+ context = null;
+ request = null;
+ }
+
+ _PORTLET_CONTEXT_CLASS = context;
+ _PORTLET_REQUEST_CLASS = request;
+ }
+
+
+ private final List<? extends UploadedFileProcessor> chainedProcessors;
+
+}
Modified: myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/UploadedFileProcessorImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/UploadedFileProcessorImpl.java?rev=929871&r1=929870&r2=929871&view=diff
==============================================================================
--- myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/UploadedFileProcessorImpl.java (original)
+++ myfaces/trinidad/branches/trinidad-1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/upload/UploadedFileProcessorImpl.java Thu Apr 1 07:41:28 2010
@@ -41,7 +41,11 @@ import org.apache.myfaces.trinidadintern
import org.apache.myfaces.trinidadinternal.context.external.ServletInitParameterMap;
import org.apache.myfaces.trinidadinternal.context.external.ServletRequestMap;
-
+/**
+ * @deprecated This implementation is merged to CompositeUploadedFileProcessorImpl.
+ * This class will be removed in the next release.
+ *
+ */
public class UploadedFileProcessorImpl implements UploadedFileProcessor
{
public UploadedFileProcessorImpl()