001// Copyright 2007-2013 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.modules;
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.services.ComponentEventRequestFilter;
031import org.apache.tapestry5.services.HttpServletRequestFilter;
032import org.apache.tapestry5.services.LibraryMapping;
033import org.apache.tapestry5.upload.internal.services.MultipartDecoderImpl;
034import org.apache.tapestry5.upload.internal.services.MultipartServletRequestFilter;
035import org.apache.tapestry5.upload.internal.services.UploadExceptionFilter;
036import org.apache.tapestry5.upload.services.MultipartDecoder;
037import org.apache.tapestry5.upload.services.UploadSymbols;
038
039import java.io.File;
040import java.util.concurrent.atomic.AtomicBoolean;
041
042public class UploadModule
043{
044    private static final String NO_LIMIT = "-1";
045
046    private static final AtomicBoolean needToAddShutdownListener = new AtomicBoolean(true);
047
048    public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration)
049    {
050        // Add the component to the "core" library.
051
052        configuration.add(new LibraryMapping(InternalConstants.CORE_LIBRARY, "org.apache.tapestry5.upload"));
053    }
054
055    @Scope(ScopeConstants.PERTHREAD)
056    public static MultipartDecoder buildMultipartDecoder(PerthreadManager perthreadManager,
057
058                                                         RegistryShutdownHub shutdownHub,
059
060                                                         @Autobuild
061                                                         MultipartDecoderImpl multipartDecoder)
062    {
063        // This is proabably overkill since the FileCleaner should catch temporary files, but lets
064        // be safe.
065        perthreadManager.addThreadCleanupListener(multipartDecoder);
066
067        if (needToAddShutdownListener.getAndSet(false))
068        {
069            shutdownHub.addRegistryShutdownListener(new Runnable()
070            {
071                public void run()
072                {
073                    FileCleaner.exitWhenFinished();
074                }
075            });
076        }
077
078        return multipartDecoder;
079    }
080
081    /**
082     * Contributes a filter, "MultipartFilter" after "IgnoredPaths".
083     */
084    public static void contributeHttpServletRequestHandler(
085            OrderedConfiguration<HttpServletRequestFilter> configuration, MultipartDecoder multipartDecoder)
086    {
087        configuration.add("MultipartFilter", new MultipartServletRequestFilter(multipartDecoder), "after:IgnoredPaths");
088    }
089
090    /**
091     * Adds UploadException to the pipeline, between Secure and Ajax (both provided by TapestryModule). UploadException
092     * is responsible for triggering the {@linkplain org.apache.tapestry5.upload.services.UploadEvents#UPLOAD_EXCEPTION
093     * upload exception event}.
094     */
095    public static void contributeComponentEventRequestHandler(
096            OrderedConfiguration<ComponentEventRequestFilter> configuration)
097    {
098        configuration.addInstance("UploadException", UploadExceptionFilter.class, "after:Secure", "before:Ajax");
099    }
100
101    /**
102     * The default FileItemFactory used by the MultipartDecoder is
103     * {@link org.apache.commons.fileupload.disk.DiskFileItemFactory}.
104     */
105    public static FileItemFactory buildDefaultFileItemFactory(@Symbol(UploadSymbols.REPOSITORY_THRESHOLD)
106                                                              int repositoryThreshold,
107
108                                                              @Symbol(UploadSymbols.REPOSITORY_LOCATION)
109                                                              String repositoryLocation)
110    {
111        return new DiskFileItemFactory(repositoryThreshold, new File(repositoryLocation));
112    }
113
114    public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration)
115    {
116        configuration.add(UploadSymbols.REPOSITORY_THRESHOLD, Integer
117                .toString(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD));
118        configuration.add(UploadSymbols.REPOSITORY_LOCATION, System.getProperty("java.io.tmpdir"));
119        configuration.add(UploadSymbols.REQUESTSIZE_MAX, NO_LIMIT);
120        configuration.add(UploadSymbols.FILESIZE_MAX, NO_LIMIT);
121    }
122}