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
015package org.apache.tapestry5.upload.services;
016
017import org.apache.commons.fileupload.FileItemFactory;
018import org.apache.commons.fileupload.disk.DiskFileItemFactory;
019import org.apache.commons.io.FileCleaner;
020import org.apache.tapestry5.internal.InternalConstants;
021import org.apache.tapestry5.ioc.Configuration;
022import org.apache.tapestry5.ioc.MappedConfiguration;
023import org.apache.tapestry5.ioc.OrderedConfiguration;
024import org.apache.tapestry5.ioc.ScopeConstants;
025import org.apache.tapestry5.ioc.annotations.Autobuild;
026import org.apache.tapestry5.ioc.annotations.Scope;
027import org.apache.tapestry5.ioc.annotations.Symbol;
028import org.apache.tapestry5.ioc.services.PerthreadManager;
029import org.apache.tapestry5.ioc.services.RegistryShutdownHub;
030import org.apache.tapestry5.ioc.services.RegistryShutdownListener;
031import org.apache.tapestry5.services.ComponentEventRequestFilter;
032import org.apache.tapestry5.services.HttpServletRequestFilter;
033import org.apache.tapestry5.services.LibraryMapping;
034import org.apache.tapestry5.upload.internal.services.MultipartDecoderImpl;
035import org.apache.tapestry5.upload.internal.services.MultipartServletRequestFilter;
036import org.apache.tapestry5.upload.internal.services.UploadExceptionFilter;
037
038import java.io.File;
039import java.util.concurrent.atomic.AtomicBoolean;
040
041public 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}