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.io.IOException; 020import java.io.InputStream; 021import java.io.Serializable; 022 023import org.apache.wicket.WicketRuntimeException; 024import org.apache.wicket.core.util.resource.WebExternalResourceStream; 025import org.apache.wicket.request.resource.caching.IStaticCacheableResource; 026import org.apache.wicket.util.io.IOUtils; 027import org.apache.wicket.util.io.Streams; 028import org.apache.wicket.util.lang.Args; 029import org.apache.wicket.util.resource.IResourceStream; 030import org.apache.wicket.util.resource.ResourceStreamNotFoundException; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034/** 035 * Resource served from a file relative to the context root. 036 * 037 * @author almaw 038 */ 039public class ContextRelativeResource extends AbstractResource implements IStaticCacheableResource 040{ 041 private static final String CACHE_PREFIX = "context-relative:/"; 042 private static final long serialVersionUID = 1L; 043 044 private static final Logger log = LoggerFactory.getLogger(ContextRelativeResource.class); 045 046 private final String path; 047 private boolean cachingEnabled; 048 049 /** 050 * Construct. 051 * 052 * @param pathRelativeToContextRoot 053 */ 054 public ContextRelativeResource(String pathRelativeToContextRoot) 055 { 056 Args.notNull(pathRelativeToContextRoot, "pathRelativeToContextRoot"); 057 058 // Make sure there is a leading '/'. 059 if (!pathRelativeToContextRoot.startsWith("/")) 060 { 061 pathRelativeToContextRoot = "/" + pathRelativeToContextRoot; 062 } 063 this.path = pathRelativeToContextRoot; 064 this.cachingEnabled = true; 065 } 066 067 @Override 068 public boolean isCachingEnabled() 069 { 070 return cachingEnabled; 071 } 072 073 public void setCachingEnabled(final boolean enabled) 074 { 075 this.cachingEnabled = enabled; 076 } 077 078 @Override 079 public Serializable getCacheKey() 080 { 081 return CACHE_PREFIX + path; 082 } 083 084 @Override 085 public IResourceStream getResourceStream() 086 { 087 return new WebExternalResourceStream(path); 088 } 089 090 @Override 091 protected ResourceResponse newResourceResponse(final Attributes attributes) 092 { 093 final ResourceResponse resourceResponse = new ResourceResponse(); 094 095 final WebExternalResourceStream webExternalResourceStream = 096 new WebExternalResourceStream(path); 097 resourceResponse.setContentType(webExternalResourceStream.getContentType()); 098 resourceResponse.setLastModified(webExternalResourceStream.lastModifiedTime()); 099 resourceResponse.setFileName(path); 100 resourceResponse.setWriteCallback(new WriteCallback() 101 { 102 @Override 103 public void writeData(final Attributes attributes) throws IOException 104 { 105 try 106 { 107 InputStream inputStream = webExternalResourceStream.getInputStream(); 108 try 109 { 110 Streams.copy(inputStream, attributes.getResponse().getOutputStream()); 111 } 112 finally { 113 IOUtils.closeQuietly(inputStream); 114 } 115 } 116 catch (ResourceStreamNotFoundException rsnfx) 117 { 118 throw new WicketRuntimeException(rsnfx); 119 } 120 } 121 }); 122 123 return resourceResponse; 124 } 125 126 @Override 127 public int hashCode() 128 { 129 final int prime = 31; 130 int result = 1; 131 result = prime * result + ((path == null) ? 0 : path.hashCode()); 132 return result; 133 } 134 135 @Override 136 public boolean equals(Object obj) 137 { 138 if (this == obj) 139 return true; 140 if (obj == null) 141 return false; 142 if (getClass() != obj.getClass()) 143 return false; 144 ContextRelativeResource other = (ContextRelativeResource)obj; 145 if (path == null) 146 { 147 if (other.path != null) 148 return false; 149 } 150 else if (!path.equals(other.path)) 151 return false; 152 return true; 153 } 154}