001/* 002 * Copyright 2002-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.portlet.context; 018 019import java.io.File; 020import java.io.FileNotFoundException; 021import java.io.IOException; 022import java.io.InputStream; 023import java.net.MalformedURLException; 024import java.net.URL; 025import javax.portlet.PortletContext; 026 027import org.springframework.core.io.AbstractFileResolvingResource; 028import org.springframework.core.io.ContextResource; 029import org.springframework.core.io.Resource; 030import org.springframework.util.Assert; 031import org.springframework.util.ResourceUtils; 032import org.springframework.util.StringUtils; 033import org.springframework.web.portlet.util.PortletUtils; 034 035/** 036 * {@link org.springframework.core.io.Resource} implementation for 037 * {@link javax.portlet.PortletContext} resources, interpreting 038 * relative paths within the portlet application root directory. 039 * 040 * <p>Always supports stream access and URL access, but only allows 041 * {@code java.io.File} access when the portlet application archive 042 * is expanded. 043 * 044 * @author Juergen Hoeller 045 * @author John A. Lewis 046 * @since 2.0 047 * @see javax.portlet.PortletContext#getResourceAsStream 048 * @see javax.portlet.PortletContext#getRealPath 049 */ 050public class PortletContextResource extends AbstractFileResolvingResource implements ContextResource { 051 052 private final PortletContext portletContext; 053 054 private final String path; 055 056 057 /** 058 * Create a new PortletContextResource. 059 * <p>The Portlet spec requires that resource paths start with a slash, 060 * even if many containers accept paths without leading slash too. 061 * Consequently, the given path will be prepended with a slash if it 062 * doesn't already start with one. 063 * @param portletContext the PortletContext to load from 064 * @param path the path of the resource 065 */ 066 public PortletContextResource(PortletContext portletContext, String path) { 067 // check PortletContext 068 Assert.notNull(portletContext, "Cannot resolve PortletContextResource without PortletContext"); 069 this.portletContext = portletContext; 070 071 // check path 072 Assert.notNull(path, "Path is required"); 073 String pathToUse = StringUtils.cleanPath(path); 074 if (!pathToUse.startsWith("/")) { 075 pathToUse = "/" + pathToUse; 076 } 077 this.path = pathToUse; 078 } 079 080 081 /** 082 * Return the PortletContext for this resource. 083 */ 084 public final PortletContext getPortletContext() { 085 return this.portletContext; 086 } 087 088 /** 089 * Return the path for this resource. 090 */ 091 public final String getPath() { 092 return this.path; 093 } 094 095 /** 096 * This implementation checks {@code PortletContext.getResource}. 097 * @see javax.portlet.PortletContext#getResource(String) 098 */ 099 @Override 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}, 112 * which returns {@code null} in case of a non-readable resource (e.g. a directory). 113 * @see javax.portlet.PortletContext#getResourceAsStream(String) 114 */ 115 @Override 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}, 134 * but throws a FileNotFoundException if not found. 135 * @see javax.portlet.PortletContext#getResourceAsStream(String) 136 */ 137 @Override 138 public InputStream getInputStream() throws IOException { 139 InputStream is = this.portletContext.getResourceAsStream(this.path); 140 if (is == null) { 141 throw new FileNotFoundException("Could not open " + getDescription()); 142 } 143 return is; 144 } 145 146 /** 147 * This implementation delegates to {@code PortletContext.getResource}, 148 * but throws a FileNotFoundException if no resource found. 149 * @see javax.portlet.PortletContext#getResource(String) 150 */ 151 @Override 152 public URL getURL() throws IOException { 153 URL url = this.portletContext.getResource(this.path); 154 if (url == null) { 155 throw new FileNotFoundException( 156 getDescription() + " cannot be resolved to URL because it does not exist"); 157 } 158 return url; 159 } 160 161 /** 162 * This implementation resolves "file:" URLs or alternatively delegates to 163 * {@code PortletContext.getRealPath}, throwing a FileNotFoundException 164 * if not found or not resolvable. 165 * @see javax.portlet.PortletContext#getResource(String) 166 * @see javax.portlet.PortletContext#getRealPath(String) 167 */ 168 @Override 169 public File getFile() throws IOException { 170 URL url = getURL(); 171 if (ResourceUtils.isFileURL(url)) { 172 // Proceed with file system resolution... 173 return super.getFile(); 174 } 175 else { 176 String realPath = PortletUtils.getRealPath(this.portletContext, this.path); 177 return new File(realPath); 178 } 179 } 180 181 @Override 182 public Resource createRelative(String relativePath) { 183 String pathToUse = StringUtils.applyRelativePath(this.path, relativePath); 184 return new PortletContextResource(this.portletContext, pathToUse); 185 } 186 187 @Override 188 public String getFilename() { 189 return StringUtils.getFilename(this.path); 190 } 191 192 @Override 193 public String getDescription() { 194 return "PortletContext resource [" + this.path + "]"; 195 } 196 197 @Override 198 public String getPathWithinContext() { 199 return this.path; 200 } 201 202 203 @Override 204 public boolean equals(Object obj) { 205 if (obj == this) { 206 return true; 207 } 208 if (obj instanceof PortletContextResource) { 209 PortletContextResource otherRes = (PortletContextResource) obj; 210 return (this.portletContext.equals(otherRes.portletContext) && this.path.equals(otherRes.path)); 211 } 212 return false; 213 } 214 215 @Override 216 public int hashCode() { 217 return this.path.hashCode(); 218 } 219 220}