001 // Copyright 2007, 2008, 2009, 2011 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.upload.services;
016
017 import org.apache.commons.fileupload.FileItemFactory;
018 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
019 import org.apache.commons.io.FileCleaner;
020 import org.apache.tapestry5.internal.InternalConstants;
021 import org.apache.tapestry5.ioc.Configuration;
022 import org.apache.tapestry5.ioc.MappedConfiguration;
023 import org.apache.tapestry5.ioc.OrderedConfiguration;
024 import org.apache.tapestry5.ioc.ScopeConstants;
025 import org.apache.tapestry5.ioc.annotations.Autobuild;
026 import org.apache.tapestry5.ioc.annotations.Scope;
027 import org.apache.tapestry5.ioc.annotations.Symbol;
028 import org.apache.tapestry5.ioc.services.PerthreadManager;
029 import org.apache.tapestry5.ioc.services.RegistryShutdownHub;
030 import org.apache.tapestry5.ioc.services.RegistryShutdownListener;
031 import org.apache.tapestry5.services.ComponentEventRequestFilter;
032 import org.apache.tapestry5.services.HttpServletRequestFilter;
033 import org.apache.tapestry5.services.LibraryMapping;
034 import org.apache.tapestry5.upload.internal.services.MultipartDecoderImpl;
035 import org.apache.tapestry5.upload.internal.services.MultipartServletRequestFilter;
036 import org.apache.tapestry5.upload.internal.services.UploadExceptionFilter;
037
038 import java.io.File;
039 import java.util.concurrent.atomic.AtomicBoolean;
040
041 public class UploadModule
042 {
043 private static final String NO_LIMIT = "-1";
044
045 private static final AtomicBoolean needToAddShutdownListener = new AtomicBoolean(true);
046
047 public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration)
048 {
049 // Add the component to the "core" library.
050
051 configuration.add(new LibraryMapping(InternalConstants.CORE_LIBRARY, "org.apache.tapestry5.upload"));
052 }
053
054 @Scope(ScopeConstants.PERTHREAD)
055 public static MultipartDecoder buildMultipartDecoder(PerthreadManager perthreadManager,
056
057 RegistryShutdownHub shutdownHub,
058
059 @Autobuild
060 MultipartDecoderImpl multipartDecoder)
061 {
062 // This is proabably overkill since the FileCleaner should catch temporary files, but lets
063 // be safe.
064 perthreadManager.addThreadCleanupListener(multipartDecoder);
065
066 if (needToAddShutdownListener.getAndSet(false))
067 {
068 shutdownHub.addRegistryShutdownListener(new Runnable()
069 {
070 public void run()
071 {
072 FileCleaner.exitWhenFinished();
073 }
074 });
075 }
076
077 return multipartDecoder;
078 }
079
080 /**
081 * Contributes a filter, "MultipartFilter" after "IgnoredPaths".
082 */
083 public static void contributeHttpServletRequestHandler(
084 OrderedConfiguration<HttpServletRequestFilter> configuration, MultipartDecoder multipartDecoder)
085 {
086 configuration.add("MultipartFilter", new MultipartServletRequestFilter(multipartDecoder), "after:IgnoredPaths");
087 }
088
089 /**
090 * Adds UploadException to the pipeline, between Secure and Ajax (both provided by TapestryModule). UploadException
091 * is responsible for triggering the {@linkplain org.apache.tapestry5.upload.services.UploadEvents#UPLOAD_EXCEPTION
092 * upload exception event}.
093 */
094 public static void contributeComponentEventRequestHandler(
095 OrderedConfiguration<ComponentEventRequestFilter> configuration)
096 {
097 configuration.addInstance("UploadException", UploadExceptionFilter.class, "after:Secure", "before:Ajax");
098 }
099
100 /**
101 * The default FileItemFactory used by the MultipartDecoder is
102 * {@link org.apache.commons.fileupload.disk.DiskFileItemFactory}.
103 */
104 public static FileItemFactory buildDefaultFileItemFactory(@Symbol(UploadSymbols.REPOSITORY_THRESHOLD)
105 int repositoryThreshold,
106
107 @Symbol(UploadSymbols.REPOSITORY_LOCATION)
108 String repositoryLocation)
109 {
110 return new DiskFileItemFactory(repositoryThreshold, new File(repositoryLocation));
111 }
112
113 public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration)
114 {
115 configuration.add(UploadSymbols.REPOSITORY_THRESHOLD, Integer
116 .toString(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD));
117 configuration.add(UploadSymbols.REPOSITORY_LOCATION, System.getProperty("java.io.tmpdir"));
118 configuration.add(UploadSymbols.REQUESTSIZE_MAX, NO_LIMIT);
119 configuration.add(UploadSymbols.FILESIZE_MAX, NO_LIMIT);
120 }
121 }