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    }