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                @Override
072                public void run()
073                {
074                    FileCleaner.exitWhenFinished();
075                }
076            });
077        }
078
079        return multipartDecoder;
080    }
081
082    /**
083     * Contributes a filter, "MultipartFilter" after "IgnoredPaths".
084     */
085    public static void contributeHttpServletRequestHandler(
086            OrderedConfiguration<HttpServletRequestFilter> configuration, MultipartDecoder multipartDecoder)
087    {
088        configuration.add("MultipartFilter", new MultipartServletRequestFilter(multipartDecoder), "after:IgnoredPaths");
089    }
090
091    /**
092     * Adds UploadException to the pipeline, between Secure and Ajax (both provided by TapestryModule). UploadException
093     * is responsible for triggering the {@linkplain org.apache.tapestry5.upload.services.UploadEvents#UPLOAD_EXCEPTION
094     * upload exception event}.
095     */
096    public static void contributeComponentEventRequestHandler(
097            OrderedConfiguration<ComponentEventRequestFilter> configuration)
098    {
099        configuration.addInstance("UploadException", UploadExceptionFilter.class, "after:Secure", "before:Ajax");
100    }
101
102    /**
103     * The default FileItemFactory used by the MultipartDecoder is
104     * {@link org.apache.commons.fileupload.disk.DiskFileItemFactory}.
105     */
106    public static FileItemFactory buildDefaultFileItemFactory(@Symbol(UploadSymbols.REPOSITORY_THRESHOLD)
107                                                              int repositoryThreshold,
108
109                                                              @Symbol(UploadSymbols.REPOSITORY_LOCATION)
110                                                              String repositoryLocation)
111    {
112        return new DiskFileItemFactory(repositoryThreshold, new File(repositoryLocation));
113    }
114
115    public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration)
116    {
117        configuration.add(UploadSymbols.REPOSITORY_THRESHOLD, Integer
118                .toString(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD));
119        configuration.add(UploadSymbols.REPOSITORY_LOCATION, System.getProperty("java.io.tmpdir"));
120        configuration.add(UploadSymbols.REQUESTSIZE_MAX, NO_LIMIT);
121        configuration.add(UploadSymbols.FILESIZE_MAX, NO_LIMIT);
122    }
123}