1 /* 2 * Copyright 2002-2012 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.web.portlet.context; 18 19 import java.io.File; 20 import java.io.FileNotFoundException; 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.net.MalformedURLException; 24 import java.net.URL; 25 import javax.portlet.PortletContext; 26 27 import org.springframework.core.io.AbstractFileResolvingResource; 28 import org.springframework.core.io.ContextResource; 29 import org.springframework.core.io.Resource; 30 import org.springframework.util.Assert; 31 import org.springframework.util.ResourceUtils; 32 import org.springframework.util.StringUtils; 33 import org.springframework.web.portlet.util.PortletUtils; 34 35 /** 36 * {@link org.springframework.core.io.Resource} implementation for 37 * {@link javax.portlet.PortletContext} resources, interpreting 38 * relative paths within the portlet application root directory. 39 * 40 * <p>Always supports stream access and URL access, but only allows 41 * <code>java.io.File</code> access when the portlet application archive 42 * is expanded. 43 * 44 * @author Juergen Hoeller 45 * @author John A. Lewis 46 * @since 2.0 47 * @see javax.portlet.PortletContext#getResourceAsStream 48 * @see javax.portlet.PortletContext#getRealPath 49 */ 50 public class PortletContextResource extends AbstractFileResolvingResource implements ContextResource { 51 52 private final PortletContext portletContext; 53 54 private final String path; 55 56 57 /** 58 * Create a new PortletContextResource. 59 * <p>The Portlet spec requires that resource paths start with a slash, 60 * even if many containers accept paths without leading slash too. 61 * Consequently, the given path will be prepended with a slash if it 62 * doesn't already start with one. 63 * @param portletContext the PortletContext to load from 64 * @param path the path of the resource 65 */ PortletContextResource(PortletContext portletContext, String path)66 public PortletContextResource(PortletContext portletContext, String path) { 67 // check PortletContext 68 Assert.notNull(portletContext, "Cannot resolve PortletContextResource without PortletContext"); 69 this.portletContext = portletContext; 70 71 // check path 72 Assert.notNull(path, "Path is required"); 73 String pathToUse = StringUtils.cleanPath(path); 74 if (!pathToUse.startsWith("/")) { 75 pathToUse = "/" + pathToUse; 76 } 77 this.path = pathToUse; 78 } 79 80 /** 81 * Return the PortletContext for this resource. 82 */ getPortletContext()83 public final PortletContext getPortletContext() { 84 return this.portletContext; 85 } 86 87 /** 88 * Return the path for this resource. 89 */ getPath()90 public final String getPath() { 91 return this.path; 92 } 93 94 95 /** 96 * This implementation checks <code>PortletContext.getResource</code>. 97 * @see javax.portlet.PortletContext#getResource(String) 98 */ 99 @Override exists()100 public boolean exists() { 101 try { 102 URL url = this.portletContext.getResource(this.path); 103 return (url != null); 104 } 105 catch (MalformedURLException ex) { 106 return false; 107 } 108 } 109 110 /** 111 * This implementation delegates to <code>PortletContext.getResourceAsStream</code>, 112 * which returns <code>null</code> in case of a non-readable resource (e.g. a directory). 113 * @see javax.portlet.PortletContext#getResourceAsStream(String) 114 */ 115 @Override isReadable()116 public boolean isReadable() { 117 InputStream is = this.portletContext.getResourceAsStream(this.path); 118 if (is != null) { 119 try { 120 is.close(); 121 } 122 catch (IOException ex) { 123 // ignore 124 } 125 return true; 126 } 127 else { 128 return false; 129 } 130 } 131 132 /** 133 * This implementation delegates to <code>PortletContext.getResourceAsStream</code>, 134 * but throws a FileNotFoundException if not found. 135 * @see javax.portlet.PortletContext#getResourceAsStream(String) 136 */ getInputStream()137 public InputStream getInputStream() throws IOException { 138 InputStream is = this.portletContext.getResourceAsStream(this.path); 139 if (is == null) { 140 throw new FileNotFoundException("Could not open " + getDescription()); 141 } 142 return is; 143 } 144 145 /** 146 * This implementation delegates to <code>PortletContext.getResource</code>, 147 * but throws a FileNotFoundException if no resource found. 148 * @see javax.portlet.PortletContext#getResource(String) 149 */ 150 @Override getURL()151 public URL getURL() throws IOException { 152 URL url = this.portletContext.getResource(this.path); 153 if (url == null) { 154 throw new FileNotFoundException( 155 getDescription() + " cannot be resolved to URL because it does not exist"); 156 } 157 return url; 158 } 159 160 /** 161 * This implementation resolves "file:" URLs or alternatively delegates to 162 * <code>PortletContext.getRealPath</code>, throwing a FileNotFoundException 163 * if not found or not resolvable. 164 * @see javax.portlet.PortletContext#getResource(String) 165 * @see javax.portlet.PortletContext#getRealPath(String) 166 */ 167 @Override getFile()168 public File getFile() throws IOException { 169 URL url = getURL(); 170 if (ResourceUtils.isFileURL(url)) { 171 // Proceed with file system resolution... 172 return super.getFile(); 173 } 174 else { 175 String realPath = PortletUtils.getRealPath(this.portletContext, this.path); 176 return new File(realPath); 177 } 178 } 179 180 @Override createRelative(String relativePath)181 public Resource createRelative(String relativePath) { 182 String pathToUse = StringUtils.applyRelativePath(this.path, relativePath); 183 return new PortletContextResource(this.portletContext, pathToUse); 184 } 185 186 @Override getFilename()187 public String getFilename() { 188 return StringUtils.getFilename(this.path); 189 } 190 getDescription()191 public String getDescription() { 192 return "PortletContext resource [" + this.path + "]"; 193 } 194 getPathWithinContext()195 public String getPathWithinContext() { 196 return this.path; 197 } 198 199 200 @Override equals(Object obj)201 public boolean equals(Object obj) { 202 if (obj == this) { 203 return true; 204 } 205 if (obj instanceof PortletContextResource) { 206 PortletContextResource otherRes = (PortletContextResource) obj; 207 return (this.portletContext.equals(otherRes.portletContext) && this.path.equals(otherRes.path)); 208 } 209 return false; 210 } 211 212 @Override hashCode()213 public int hashCode() { 214 return this.path.hashCode(); 215 } 216 217 } 218