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 }