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.resource; 018 019import java.net.URLConnection; 020import java.time.Instant; 021import javax.servlet.http.HttpServletResponse; 022import org.apache.wicket.request.Response; 023 024/** 025 * An abstract resource that can deliver static data - passed to the constructor, or dynamic - 026 * returned by {@link #getData(org.apache.wicket.request.resource.IResource.Attributes)} 027 * 028 * @param <T> 029 * The type of the data this resource can deliver 030 */ 031public abstract class BaseDataResource<T> extends AbstractResource 032{ 033 private static final long serialVersionUID = 1L; 034 035 /** the content type */ 036 private final String contentType; 037 038 /** the data to deliver */ 039 private T data; 040 041 /** the time that this resource was last modified; same as construction time. */ 042 private final Instant lastModified = Instant.now(); 043 044 private final String filename; 045 046 /** 047 * Creates a {@link org.apache.wicket.request.resource.BaseDataResource} which will provide its 048 * data dynamically with 049 * {@link #getData(org.apache.wicket.request.resource.IResource.Attributes)} 050 * 051 * @param contentType 052 * The Content type of the array. 053 */ 054 public BaseDataResource(final String contentType) 055 { 056 this(contentType, null, null); 057 } 058 059 /** 060 * Creates a Resource from the given data with its content type 061 * 062 * @param contentType 063 * The Content type of the array. 064 * @param data 065 * The data 066 */ 067 public BaseDataResource(final String contentType, final T data) 068 { 069 this(contentType, data, null); 070 } 071 072 /** 073 * Creates a Resource from the given data with its content type and filename 074 * 075 * @param contentType 076 * The Content type of the array. 077 * @param data 078 * The data 079 * @param filename 080 * The filename that will be set as the Content-Disposition header. 081 */ 082 public BaseDataResource(final String contentType, final T data, final String filename) 083 { 084 this.contentType = contentType; 085 this.data = data; 086 this.filename = filename; 087 } 088 089 /** 090 * Post-configures the given response, e.g. set/override response headers. 091 * 092 * @param response 093 * The response to configure 094 * @param attributes 095 * The request attributes (web request, web response, parameters) 096 */ 097 protected void configureResponse(final ResourceResponse response, final Attributes attributes) 098 { 099 } 100 101 @Override 102 protected ResourceResponse newResourceResponse(final Attributes attributes) 103 { 104 final ResourceResponse response = new ResourceResponse(); 105 106 String contentType = this.contentType; 107 String filename = getFilename(); 108 109 if (contentType == null) 110 { 111 if (filename != null) 112 { 113 contentType = URLConnection.getFileNameMap().getContentTypeFor(filename); 114 } 115 116 if (contentType == null) 117 { 118 contentType = "application/octet-stream"; 119 } 120 } 121 122 response.setContentType(contentType); 123 response.setLastModified(lastModified); 124 125 final T data = getData(attributes); 126 if (data == null) 127 { 128 response.setError(HttpServletResponse.SC_NOT_FOUND); 129 } 130 else 131 { 132 Long length = getLength(data); 133 if (length != null) 134 { 135 response.setContentLength(length); 136 } 137 138 if (response.dataNeedsToBeWritten(attributes)) 139 { 140 if (filename != null) 141 { 142 response.setFileName(filename); 143 response.setContentDisposition(ContentDisposition.ATTACHMENT); 144 } 145 else 146 { 147 response.setContentDisposition(ContentDisposition.INLINE); 148 } 149 150 response.setWriteCallback(new WriteCallback() 151 { 152 @Override 153 public void writeData(final Attributes attributes) 154 { 155 BaseDataResource.this.writeData(attributes.getResponse(), data); 156 } 157 }); 158 159 configureResponse(response, attributes); 160 } 161 } 162 163 return response; 164 } 165 166 /** 167 * Writes the given data to the response 168 * 169 * @param response 170 * The response to write to 171 * @param data 172 * The data to write 173 */ 174 protected abstract void writeData(Response response, T data); 175 176 /** 177 * @param data 178 * The data to be written 179 * @return The length of the data to be written. Used to set "Content-Length" response header 180 */ 181 protected abstract Long getLength(T data); 182 183 /** 184 * Gets the data for this resource. 185 * 186 * @param attributes 187 * the context bringing the request, response and the parameters 188 * 189 * @return The data for this resource 190 */ 191 protected T getData(final Attributes attributes) 192 { 193 return data; 194 } 195 196 /** 197 * Returns the filename that will be set as the Content-Disposition header. 198 * 199 * @return the filename 200 */ 201 protected String getFilename() 202 { 203 return filename; 204 } 205}