001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.request.handler.resource; 018 019import org.apache.wicket.core.request.handler.logger.ResourceStreamLogData; 020import org.apache.wicket.request.ILoggableRequestHandler; 021import org.apache.wicket.request.IRequestCycle; 022import org.apache.wicket.request.IRequestHandler; 023import org.apache.wicket.request.resource.ContentDisposition; 024import org.apache.wicket.request.resource.IResource.Attributes; 025import org.apache.wicket.request.resource.ResourceStreamResource; 026import org.apache.wicket.util.lang.Args; 027import org.apache.wicket.util.resource.IResourceStream; 028import org.apache.wicket.util.string.Strings; 029import java.time.Duration; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033/** 034 * Request target that responds by sending its resource stream. 035 * 036 * @author Eelco Hillenius 037 */ 038public class ResourceStreamRequestHandler implements IRequestHandler, ILoggableRequestHandler 039{ 040 /** Logger */ 041 private static final Logger log = LoggerFactory.getLogger(ResourceStreamRequestHandler.class); 042 043 /** 044 * Optional filename, used to set the content disposition header. Only meaningful when using 045 * with web requests. 046 */ 047 private String fileName; 048 private ContentDisposition contentDisposition; 049 050 /** 051 * The duration fow which the resource will be cached by the browser. 052 * <p> 053 * By default is {@code null} and 054 * {@link org.apache.wicket.settings.ResourceSettings#getDefaultCacheDuration()} is used. 055 * </p> 056 */ 057 private Duration cacheDuration; 058 059 /** the resource stream for the response. */ 060 private final IResourceStream resourceStream; 061 062 private ResourceStreamLogData logData; 063 064 /** 065 * Construct. 066 * 067 * @param resourceStream 068 * the resource stream for the response 069 */ 070 public ResourceStreamRequestHandler(IResourceStream resourceStream) 071 { 072 this(resourceStream, null); 073 } 074 075 /** 076 * Construct. 077 * 078 * @param resourceStream 079 * the resource stream for the response 080 * @param fileName 081 */ 082 public ResourceStreamRequestHandler(IResourceStream resourceStream, String fileName) 083 { 084 Args.notNull(resourceStream, "resourceStream"); 085 086 this.resourceStream = resourceStream; 087 this.fileName = fileName; 088 } 089 090 @Override 091 public void detach(IRequestCycle requestCycle) 092 { 093 if (logData == null) 094 logData = getResourceStream() == null ? new ResourceStreamLogData(this) 095 : new ResourceStreamLogData(this, getResourceStream()); 096 } 097 098 /** {@inheritDoc} */ 099 @Override 100 public ResourceStreamLogData getLogData() 101 { 102 return logData; 103 } 104 105 /** 106 * @return Optional filename, used to set the content disposition header. Only meaningful when 107 * using with web requests. 108 */ 109 public final String getFileName() 110 { 111 return fileName; 112 } 113 114 /** 115 * Gets the resource stream for the response. 116 * 117 * @return the resource stream for the response 118 */ 119 public final IResourceStream getResourceStream() 120 { 121 return resourceStream; 122 } 123 124 /** 125 * Responds by sending the contents of the resource stream. 126 * 127 * @see org.apache.wicket.request.IRequestHandler#respond(org.apache.wicket.request.IRequestCycle) 128 */ 129 @Override 130 public void respond(IRequestCycle requestCycle) 131 { 132 Attributes attributes = new Attributes(requestCycle.getRequest(), 133 requestCycle.getResponse()); 134 135 ResourceStreamResource resource = new ResourceStreamResource(resourceStream); 136 137 configure(resource); 138 139 resource.respond(attributes); 140 } 141 142 /** 143 * Configures the ResourceStreamResource used by this request handler 144 * 145 * @param resource 146 * the resource to configure 147 */ 148 protected void configure(ResourceStreamResource resource) 149 { 150 resource.setFileName(fileName); 151 if (contentDisposition != null) 152 { 153 resource.setContentDisposition(contentDisposition); 154 } 155 else 156 { 157 resource.setContentDisposition(Strings.isEmpty(fileName) ? ContentDisposition.INLINE 158 : ContentDisposition.ATTACHMENT); 159 } 160 161 final Duration cacheDuration = getCacheDuration(); 162 if (cacheDuration != null) 163 { 164 resource.setCacheDuration(cacheDuration); 165 } 166 } 167 168 @Override 169 public int hashCode() 170 { 171 final int prime = 31; 172 int result = 1; 173 result = prime * result + 174 ((contentDisposition == null) ? 0 : contentDisposition.hashCode()); 175 result = prime * result + ((fileName == null) ? 0 : fileName.hashCode()); 176 result = prime * result + resourceStream.hashCode(); 177 return result; 178 } 179 180 @Override 181 public boolean equals(Object obj) 182 { 183 if (this == obj) 184 return true; 185 if (obj == null) 186 return false; 187 if (getClass() != obj.getClass()) 188 return false; 189 ResourceStreamRequestHandler other = (ResourceStreamRequestHandler)obj; 190 if (contentDisposition != other.contentDisposition) 191 return false; 192 if (fileName == null) 193 { 194 if (other.fileName != null) 195 return false; 196 } 197 else if (!fileName.equals(other.fileName)) 198 return false; 199 if (!resourceStream.equals(other.resourceStream)) 200 return false; 201 return true; 202 } 203 204 /** 205 * @param fileName 206 * Optional filename, used to set the content disposition header. Only meaningful 207 * when using with web requests. 208 * 209 * @return The this. 210 */ 211 public final ResourceStreamRequestHandler setFileName(String fileName) 212 { 213 this.fileName = fileName; 214 return this; 215 } 216 217 /** 218 * @see java.lang.Object#toString() 219 */ 220 @Override 221 public String toString() 222 { 223 return "[ResourceStreamRequestTarget[resourceStream=" + resourceStream + ",fileName=" + 224 fileName + ", contentDisposition=" + contentDisposition + "]"; 225 } 226 227 /** 228 * @return ContentDisposition 229 */ 230 public final ContentDisposition getContentDisposition() 231 { 232 return contentDisposition; 233 } 234 235 /** 236 * @param contentDisposition 237 * @return this 238 */ 239 public final ResourceStreamRequestHandler setContentDisposition( 240 ContentDisposition contentDisposition) 241 { 242 this.contentDisposition = contentDisposition; 243 return this; 244 } 245 246 /** 247 * @return the duration for which the resource will be cached by the browser 248 */ 249 public Duration getCacheDuration() 250 { 251 return cacheDuration; 252 } 253 254 /** 255 * @param cacheDuration 256 * the duration for which the resource will be cached by the browser 257 * @return this component 258 */ 259 public ResourceStreamRequestHandler setCacheDuration(Duration cacheDuration) 260 { 261 this.cacheDuration = cacheDuration; 262 return this; 263 } 264 265}