001//======================================================================== 002//$Id: JettyWebAppContext.java 6624 2011-05-27 04:51:32Z gregw $ 003//Copyright 2006 Mort Bay Consulting Pty. Ltd. 004//------------------------------------------------------------------------ 005//Licensed under the Apache License, Version 2.0 (the "License"); 006//you may not use this file except in compliance with the License. 007//You may obtain a copy of the License at 008//http://www.apache.org/licenses/LICENSE-2.0 009//Unless required by applicable law or agreed to in writing, software 010//distributed under the License is distributed on an "AS IS" BASIS, 011//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012//See the License for the specific language governing permissions and 013//limitations under the License. 014//======================================================================== 015 016package org.jszip.jetty; 017 018import java.io.File; 019import java.io.IOException; 020import java.net.MalformedURLException; 021import java.net.URL; 022import java.util.ArrayList; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027import java.util.TreeSet; 028 029import org.apache.commons.lang3.StringUtils; 030import org.eclipse.jetty.plus.webapp.EnvConfiguration; 031import org.eclipse.jetty.util.URIUtil; 032import org.eclipse.jetty.util.log.Log; 033import org.eclipse.jetty.util.resource.Resource; 034import org.eclipse.jetty.util.resource.ResourceCollection; 035import org.eclipse.jetty.webapp.Configuration; 036import org.eclipse.jetty.webapp.FragmentConfiguration; 037import org.eclipse.jetty.webapp.JettyWebXmlConfiguration; 038import org.eclipse.jetty.webapp.MetaInfConfiguration; 039import org.eclipse.jetty.webapp.WebAppContext; 040import org.eclipse.jetty.webapp.WebInfConfiguration; 041import org.eclipse.jetty.webapp.WebXmlConfiguration; 042 043/** 044 * JettyWebAppContext 045 * 046 * Extends the WebAppContext to specialize for the maven environment. 047 * We pass in the list of files that should form the classpath for 048 * the webapp when executing in the plugin, and any jetty-env.xml file 049 * that may have been configured. 050 * 051 */ 052public class JettyWebAppContext extends WebAppContext 053{ 054 private static final String WEB_INF_CLASSES_PREFIX = "/WEB-INF/classes"; 055 private static final String WEB_INF_LIB_PREFIX = "/WEB-INF/lib"; 056 057 private final List<File> webInfClasses = new ArrayList<File>(); 058 private final List<File> webInfJars = new ArrayList<File>(); 059 private final Map<String, File> webInfJarMap = new HashMap<String, File>(); 060 private final EnvConfiguration envConfig; 061 private List<File> classpathFiles; 062 private String jettyEnvXml; 063 private List<Resource> overlays; 064 private boolean unpackOverlays; 065 private String containerIncludeJarPattern = ".*/servlet-api-[^/]*\\.jar$"; 066 067 public JettyWebAppContext () 068 throws Exception 069 { 070 super(); 071 setConfigurations(new Configuration[]{ 072 new WebXmlConfiguration(), 073 new MetaInfConfiguration(), 074 new FragmentConfiguration(), 075 envConfig = new EnvConfiguration(), 076 new org.eclipse.jetty.plus.webapp.PlusConfiguration(), 077 new JettyWebXmlConfiguration(), 078 }); 079 } 080 public void setContainerIncludeJarPattern(String pattern) 081 { 082 containerIncludeJarPattern = pattern; 083 } 084 085 public String getContainerIncludeJarPattern() 086 { 087 return containerIncludeJarPattern; 088 } 089 090 public boolean getUnpackOverlays() 091 { 092 return unpackOverlays; 093 } 094 095 public void setUnpackOverlays(boolean unpackOverlays) 096 { 097 this.unpackOverlays = unpackOverlays; 098 } 099 100 public void setClassPathFiles(List<File> classpathFiles) 101 { 102 this.classpathFiles = classpathFiles; 103 } 104 105 public List<File> getClassPathFiles() 106 { 107 return this.classpathFiles; 108 } 109 110 public void setOverlays (List<Resource> overlays) 111 { 112 this.overlays = overlays; 113 } 114 115 public List<Resource> getOverlays () 116 { 117 return this.overlays; 118 } 119 120 public void setJettyEnvXml (String jettyEnvXml) 121 { 122 this.jettyEnvXml = jettyEnvXml; 123 } 124 125 public String getJettyEnvXml() 126 { 127 return this.jettyEnvXml; 128 } 129 130 131 public void setWebInfClasses(List<File> dirs) 132 { 133 webInfClasses.addAll(dirs); 134 } 135 136 public List<File> getWebInfClasses() 137 { 138 return webInfClasses; 139 } 140 141 public void setWebInfLib (List<File> jars) 142 { 143 webInfJars.addAll(jars); 144 } 145 146 /* ------------------------------------------------------------ */ 147 /** 148 * This method is provided as a conveniance for jetty maven plugin configuration 149 * @param resourceBases Array of resources strings to set as a {@link ResourceCollection}. Each resource string may be a comma separated list of resources 150 * @see Resource 151 */ 152 public void setResourceBases(String[] resourceBases) 153 { 154 List<String> resources = new ArrayList<String>(); 155 for (String rl:resourceBases) 156 { 157 String[] rs = rl.split(" *, *"); 158 for (String r:rs) 159 resources.add(r); 160 } 161 162 setBaseResource(new ResourceCollection(resources.toArray(new String[resources.size()]))); 163 } 164 165 public List<File> getWebInfLib() 166 { 167 return webInfJars; 168 } 169 170 public void doStart () throws Exception 171 { 172 setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, containerIncludeJarPattern); 173 174 175 // Initialize map containing all jars in /WEB-INF/lib 176 webInfJarMap.clear(); 177 for (File file : webInfJars) 178 { 179 // Return all jar files from class path 180 String fileName = file.getName(); 181 if (fileName.endsWith(".jar")) 182 webInfJarMap.put(fileName, file); 183 } 184 185 if (this.jettyEnvXml != null) 186 envConfig.setJettyEnvXml(new File(this.jettyEnvXml).toURL()); 187 setShutdown(false); 188 super.doStart(); 189 } 190 191 public void doStop () throws Exception 192 { 193 setShutdown(true); 194 //just wait a little while to ensure no requests are still being processed 195 Thread.currentThread().sleep(500L); 196 super.doStop(); 197 } 198 199 @Override 200 public Resource getResource(String uriInContext) throws MalformedURLException 201 { 202 Resource resource = null; 203 // Try to get regular resource 204 resource = super.getResource(uriInContext); 205 206 // If no regular resource exists check for access to /WEB-INF/lib or /WEB-INF/classes 207 if ((resource == null || !resource.exists()) && uriInContext != null && webInfClasses != null) 208 { 209 String uri = URIUtil.canonicalPath(uriInContext); 210 211 try 212 { 213 // Replace /WEB-INF/classes with real classes directory 214 if (uri.startsWith(WEB_INF_CLASSES_PREFIX)) 215 { 216 Resource res = null; 217 int i=0; 218 while (res == null && (i < webInfClasses.size())) 219 { 220 String newPath = uri.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath()); 221 res = Resource.newResource(newPath); 222 if (!res.exists()) 223 { 224 res = null; 225 i++; 226 } 227 } 228 return res; 229 } 230 // Return the real jar file for all accesses to 231 // /WEB-INF/lib/*.jar 232 else if (uri.startsWith(WEB_INF_LIB_PREFIX)) 233 { 234 String jarName = uri.replace(WEB_INF_LIB_PREFIX, ""); 235 if (jarName.startsWith("/") || jarName.startsWith("\\")) 236 jarName = jarName.substring(1); 237 if (jarName.length()==0) 238 return null; 239 File jarFile = webInfJarMap.get(jarName); 240 if (jarFile != null) 241 return Resource.newResource(jarFile.getPath()); 242 243 return null; 244 } 245 } 246 catch (MalformedURLException e) 247 { 248 throw e; 249 } 250 catch (IOException e) 251 { 252 Log.ignore(e); 253 } 254 } 255 return resource; 256 } 257 258 @Override 259 public Set<String> getResourcePaths(String path) 260 { 261 // Try to get regular resource paths 262 Set<String> paths = super.getResourcePaths(path); 263 264 // If no paths are returned check for virtual paths /WEB-INF/classes and /WEB-INF/lib 265 if (paths.isEmpty() && path != null) 266 { 267 path = URIUtil.canonicalPath(path); 268 if (path.startsWith(WEB_INF_LIB_PREFIX)) 269 { 270 paths = new TreeSet<String>(); 271 for (String fileName : webInfJarMap.keySet()) 272 { 273 // Return all jar files from class path 274 paths.add(WEB_INF_LIB_PREFIX + "/" + fileName); 275 } 276 } 277 else if (path.startsWith(WEB_INF_CLASSES_PREFIX)) 278 { 279 int i=0; 280 281 while (paths.isEmpty() && (i < webInfClasses.size())) 282 { 283 String newPath = path.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath()); 284 paths = super.getResourcePaths(newPath); 285 i++; 286 } 287 } 288 } 289 return paths; 290 } 291 292 /** 293 * {@inheritDoc} 294 */ 295 @Override 296 public Resource newResource(URL url) throws IOException { 297 if (url != null && StringUtils.equals("virtual", url.getProtocol())) { 298 // serve virtual URLs if asked to 299 return getBaseResource().getResource(url.getPath()); 300 } 301 return super.newResource(url); 302 } 303 304 /** 305 * {@inheritDoc} 306 */ 307 @Override 308 public Resource newResource(String urlOrPath) throws IOException { 309 if (urlOrPath != null && urlOrPath.startsWith("virtual:")) { 310 // serve virtual URLs if asked to 311 return getBaseResource().getResource(urlOrPath.substring("virtual:".length())); 312 } 313 return super.newResource(urlOrPath); 314 } 315}