001 // Copyright 2007, 2008, 2009 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.ioc.Configuration;
021 import org.apache.tapestry5.ioc.MappedConfiguration;
022 import org.apache.tapestry5.ioc.OrderedConfiguration;
023 import org.apache.tapestry5.ioc.ScopeConstants;
024 import org.apache.tapestry5.ioc.annotations.Autobuild;
025 import org.apache.tapestry5.ioc.annotations.Inject;
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("core", "org.apache.tapestry5.upload"));
052 }
053
054 @Scope(ScopeConstants.PERTHREAD)
055 public static MultipartDecoder buildMultipartDecoder(PerthreadManager perthreadManager,
056
057 RegistryShutdownHub shutdownHub,
058
059 @Autobuild MultipartDecoderImpl multipartDecoder)
060 {
061 // This is proabably overkill since the FileCleaner should catch temporary files, but lets
062 // be safe.
063 perthreadManager.addThreadCleanupListener(multipartDecoder);
064
065 if (needToAddShutdownListener.getAndSet(false))
066 {
067 shutdownHub.addRegistryShutdownListener(new RegistryShutdownListener()
068 {
069 public void registryDidShutdown()
070 {
071 FileCleaner.exitWhenFinished();
072 }
073 });
074 }
075
076 return multipartDecoder;
077 }
078
079 /**
080 * Contributes a filter, "MultipartFilter" after "IgnoredPaths".
081 */
082 public static void contributeHttpServletRequestHandler(OrderedConfiguration<HttpServletRequestFilter> configuration,
083 MultipartDecoder multipartDecoder)
084 {
085 configuration.add("MultipartFilter", new MultipartServletRequestFilter(multipartDecoder), "after:IgnoredPaths");
086 }
087
088 /**
089 * Adds UploadException to the pipeline, between Secure and Ajax (both provided by TapestryModule). UploadException
090 * is responsible for triggering the {@linkplain org.apache.tapestry5.upload.services.UploadEvents#UPLOAD_EXCEPTION
091 * upload exception event}.
092 */
093 public static void contributeComponentEventRequestHandler(
094 OrderedConfiguration<ComponentEventRequestFilter> configuration)
095 {
096 configuration.addInstance("UploadException", UploadExceptionFilter.class, "after:Secure",
097 "before:Ajax");
098 }
099
100 /**
101 * The default FileItemFactory used by the MultipartDecoder is {@link org.apache.commons.fileupload.disk.DiskFileItemFactory}.
102 */
103 public static FileItemFactory buildDefaultFileItemFactory(
104 @Symbol(UploadSymbols.REPOSITORY_THRESHOLD)
105 int repositoryThreshold,
106
107 @Inject @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 }