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.commons.Configuration; 021import org.apache.tapestry5.commons.MappedConfiguration; 022import org.apache.tapestry5.commons.OrderedConfiguration; 023import org.apache.tapestry5.http.services.HttpServletRequestFilter; 024import org.apache.tapestry5.internal.InternalConstants; 025import org.apache.tapestry5.ioc.ScopeConstants; 026import org.apache.tapestry5.ioc.annotations.Autobuild; 027import org.apache.tapestry5.ioc.annotations.Scope; 028import org.apache.tapestry5.ioc.annotations.Symbol; 029import org.apache.tapestry5.ioc.services.PerthreadManager; 030import org.apache.tapestry5.ioc.services.RegistryShutdownHub; 031import org.apache.tapestry5.services.ComponentEventRequestFilter; 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}