001package org.jszip.jetty; 002 003import org.apache.commons.lang3.StringUtils; 004import org.eclipse.jetty.util.URIUtil; 005import org.eclipse.jetty.util.resource.Resource; 006 007import java.io.File; 008import java.io.IOException; 009import java.io.InputStream; 010import java.io.OutputStream; 011import java.net.MalformedURLException; 012import java.net.URL; 013import java.net.URLConnection; 014import java.net.URLStreamHandler; 015 016/** 017 * In order to support the {@link org.jszip.maven.Mapping} we need virtual resources to handle the path offset. 018 */ 019public class VirtualDirectoryResource extends Resource { 020 021 /** 022 * The resource that we are inserting a virtual path in front of. 023 */ 024 private Resource child; 025 026 /** 027 * The name of the child resource 028 */ 029 private final String name; 030 031 /** 032 * The url of the child resource. 033 */ 034 private final String pathName; 035 036 /** 037 * Creates a tree of virtual resources in order to present the child resource at the provided path. 038 * 039 * @param child the child resource. 040 * @param childPath the path at which the child resource will appear. 041 */ 042 public VirtualDirectoryResource(Resource child, String childPath) { 043 this(child, "/", childPath); 044 } 045 046 private VirtualDirectoryResource(Resource child, String path, String name) { 047 int index = name.indexOf(URIUtil.SLASH); 048 if (index == 0) { 049 name = name.substring(1); 050 index = name.indexOf(URIUtil.SLASH); 051 } 052 path = StringUtils.strip(path, "/"); 053 if (StringUtils.isBlank(path)) { 054 this.pathName = "/"; 055 } else { 056 this.pathName = "/" + path + "/"; 057 } 058 if ((index == -1) || (index == name.length() - 1)) { 059 this.child = child; 060 this.name = name; 061 } else { 062 this.name = name.substring(0, index); 063 this.child = new VirtualDirectoryResource(child, pathName + this.name + "/", name.substring(index + 1)); 064 } 065 } 066 067 /** 068 * Returns our child resource. 069 * @return our child resource. 070 */ 071 public Resource getChild() { 072 return child; 073 } 074 075 /** 076 * Sets our child resource. 077 * @param child our child resource. 078 */ 079 public void setChild(Resource child) { 080 this.child = child; 081 } 082 083 /** {@inheritDoc} */ 084 @Override 085 public boolean isContainedIn(Resource resource) throws MalformedURLException { 086 return false; 087 } 088 089 /** {@inheritDoc} */ 090 @Override 091 public void release() { 092 if (child != null) { 093 child.release(); 094 } 095 } 096 097 /** {@inheritDoc} */ 098 @Override 099 public boolean exists() { 100 return true; 101 } 102 103 /** {@inheritDoc} */ 104 @Override 105 public boolean isDirectory() { 106 return true; 107 } 108 109 /** {@inheritDoc} */ 110 @Override 111 public long lastModified() { 112 return child != null ? child.lastModified() : -1; 113 } 114 115 /** {@inheritDoc} */ 116 @Override 117 public long length() { 118 return -1; 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 public URL getURL() { 124 try { 125 return new URL("virtual", null, -1, pathName, VirtualURLStreamHandler.INSTANCE); 126 } catch (MalformedURLException e) { 127 throw new IllegalStateException( 128 "MalformedURLException should not be thrown when a URLStreamHandler is provided"); 129 } 130 } 131 132 /** {@inheritDoc} */ 133 @Override 134 public File getFile() throws IOException { 135 return null; 136 } 137 138 /** {@inheritDoc} */ 139 @Override 140 public String getName() { 141 return null; 142 } 143 144 /** {@inheritDoc} */ 145 @Override 146 public InputStream getInputStream() throws IOException { 147 return null; 148 } 149 150 /** {@inheritDoc} */ 151 @Override 152 public OutputStream getOutputStream() throws IOException, SecurityException { 153 return null; 154 } 155 156 /** {@inheritDoc} */ 157 @Override 158 public boolean delete() throws SecurityException { 159 throw new UnsupportedOperationException(); 160 } 161 162 /** {@inheritDoc} */ 163 @Override 164 public boolean renameTo(Resource resource) throws SecurityException { 165 throw new UnsupportedOperationException(); 166 } 167 168 /** {@inheritDoc} */ 169 @Override 170 public String[] list() { 171 return new String[]{child.isDirectory() ? name + "/" : name}; 172 } 173 174 /** {@inheritDoc} */ 175 @Override 176 public Resource addPath(String path) throws IOException, MalformedURLException { 177 if (path == null) { 178 throw new MalformedURLException(); 179 } 180 if (path.length() == 0 || URIUtil.SLASH.equals(path)) { 181 return this; 182 } 183 if (path.startsWith(name) || path.startsWith(URIUtil.SLASH + name)) { 184 return child.addPath(path.substring(path.indexOf(name) + name.length())); 185 } 186 return new BadResource(); 187 } 188 189 /** {@inheritDoc} */ 190 @Override 191 public String toString() { 192 final StringBuilder sb = new StringBuilder(); 193 sb.append("VirtualDirectoryResource"); 194 sb.append("{url='virtual:").append(pathName).append('\''); 195 sb.append(", name='").append(name).append('\''); 196 sb.append(", child=").append(child); 197 sb.append('}'); 198 return sb.toString(); 199 } 200 201 /** {@inheritDoc} */ 202 @Override 203 public boolean equals(Object o) { 204 if (this == o) { 205 return true; 206 } 207 if (!(o instanceof VirtualDirectoryResource)) { 208 return false; 209 } 210 211 VirtualDirectoryResource that = (VirtualDirectoryResource) o; 212 213 if (child != null ? !child.equals(that.child) : that.child != null) { 214 return false; 215 } 216 if (name != null ? !name.equals(that.name) : that.name != null) { 217 return false; 218 } 219 220 return true; 221 } 222 223 /** {@inheritDoc} */ 224 @Override 225 public int hashCode() { 226 int result = child != null ? child.hashCode() : 0; 227 result = 31 * result + (name != null ? name.hashCode() : 0); 228 return result; 229 } 230 231 /** 232 * In order to ensure that we can create URLs with the {@code virtual:} protocol, we need to provide a dummy 233 * {@link URLStreamHandler} otherwise Java will try to look up the protocol and fail thereby throwing the 234 * dreaded {@link MalformedURLException}. 235 */ 236 private static class VirtualURLStreamHandler extends URLStreamHandler { 237 /** 238 * The singleton instance. 239 */ 240 private static final VirtualURLStreamHandler INSTANCE = new VirtualURLStreamHandler(); 241 242 /** 243 * {@inheritDoc} 244 */ 245 @Override 246 protected URLConnection openConnection(URL u) throws IOException { 247 throw new IOException("virtual:" + u.getPath() + " is a virtual URL"); 248 } 249 } 250 251}