| // |
| // ======================================================================== |
| // Copyright (c) 1995-2012 Sabre Holdings. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.ant; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.security.CodeSource; |
| import java.security.PermissionCollection; |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.EventListener; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.jar.Manifest; |
| |
| import javax.servlet.Servlet; |
| |
| import org.apache.tools.ant.AntClassLoader; |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.types.FileSet; |
| import org.eclipse.jetty.annotations.AnnotationConfiguration; |
| import org.eclipse.jetty.ant.types.Attribute; |
| import org.eclipse.jetty.ant.types.Attributes; |
| import org.eclipse.jetty.ant.types.FileMatchingConfiguration; |
| import org.eclipse.jetty.ant.utils.TaskLog; |
| import org.eclipse.jetty.plus.webapp.EnvConfiguration; |
| import org.eclipse.jetty.plus.webapp.PlusConfiguration; |
| import org.eclipse.jetty.servlet.FilterHolder; |
| import org.eclipse.jetty.servlet.FilterMapping; |
| import org.eclipse.jetty.servlet.Holder; |
| import org.eclipse.jetty.servlet.ServletHandler; |
| import org.eclipse.jetty.servlet.ServletHolder; |
| import org.eclipse.jetty.servlet.ServletMapping; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.eclipse.jetty.util.resource.Resource; |
| import org.eclipse.jetty.webapp.Configuration; |
| import org.eclipse.jetty.webapp.FragmentConfiguration; |
| import org.eclipse.jetty.webapp.JettyWebXmlConfiguration; |
| import org.eclipse.jetty.webapp.MetaInfConfiguration; |
| import org.eclipse.jetty.webapp.WebAppClassLoader; |
| import org.eclipse.jetty.webapp.WebAppContext; |
| import org.eclipse.jetty.webapp.WebInfConfiguration; |
| import org.eclipse.jetty.webapp.WebXmlConfiguration; |
| import org.eclipse.jetty.xml.XmlConfiguration; |
| |
| /** |
| * Extension of WebAppContext to allow configuration via Ant environment. |
| */ |
| public class AntWebAppContext extends WebAppContext |
| { |
| private static final Logger LOG = Log.getLogger(WebAppContext.class); |
| |
| public final AntWebInfConfiguration antWebInfConfiguration = new AntWebInfConfiguration(); |
| public final WebXmlConfiguration webXmlConfiguration = new WebXmlConfiguration(); |
| public final MetaInfConfiguration metaInfConfiguration = new MetaInfConfiguration(); |
| public final FragmentConfiguration fragmentConfiguration = new FragmentConfiguration(); |
| public final EnvConfiguration envConfiguration = new EnvConfiguration(); |
| public final PlusConfiguration plusConfiguration = new PlusConfiguration(); |
| public final AnnotationConfiguration annotationConfiguration = new AnnotationConfiguration(); |
| public final JettyWebXmlConfiguration jettyWebXmlConfiguration = new JettyWebXmlConfiguration(); |
| |
| |
| public final Configuration[] DEFAULT_CONFIGURATIONS = |
| { |
| antWebInfConfiguration, |
| webXmlConfiguration, |
| metaInfConfiguration, |
| fragmentConfiguration, |
| envConfiguration, |
| plusConfiguration, |
| annotationConfiguration, |
| jettyWebXmlConfiguration |
| }; |
| |
| |
| public final static String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = |
| ".*/.*jsp-api-[^/]*\\.jar$|.*/.*jsp-[^/]*\\.jar$|.*/.*taglibs[^/]*\\.jar$|.*/.*jstl[^/]*\\.jar$|.*/.*jsf-impl-[^/]*\\.jar$|.*/.*javax.faces-[^/]*\\.jar$|.*/.*myfaces-impl-[^/]*\\.jar$"; |
| |
| |
| /** Location of jetty-env.xml file. */ |
| private File jettyEnvXml; |
| |
| /** List of web application libraries. */ |
| private List libraries = new ArrayList(); |
| |
| /** List of web application class directories. */ |
| private List classes = new ArrayList(); |
| |
| /** context xml file to apply to the webapp */ |
| private File contextXml; |
| |
| /** List of extra scan targets for this web application. */ |
| private FileSet scanTargets; |
| |
| /** context attributes to set **/ |
| private Attributes attributes; |
| |
| private Project project; |
| |
| private List<File> scanFiles; |
| |
| |
| |
| /** Extra scan targets. */ |
| private FileMatchingConfiguration extraScanTargetsConfiguration; |
| |
| |
| private FileMatchingConfiguration librariesConfiguration; |
| |
| |
| public static void dump(ClassLoader loader) |
| { |
| while (loader != null) |
| { |
| System.err.println(loader); |
| if (loader instanceof URLClassLoader) |
| { |
| URL[] urls = ((URLClassLoader)loader).getURLs(); |
| if (urls != null) |
| { |
| for (URL u:urls) |
| System.err.println("\t"+u+"\n"); |
| } |
| } |
| loader = loader.getParent(); |
| } |
| } |
| |
| |
| /** |
| * AntURLClassLoader |
| * |
| * Adapt the AntClassLoader which is not a URLClassLoader - this is needed for |
| * jsp to be able to search the classpath. |
| */ |
| public static class AntURLClassLoader extends URLClassLoader |
| { |
| private AntClassLoader antLoader; |
| |
| public AntURLClassLoader(AntClassLoader antLoader) |
| { |
| super(new URL[] {}, antLoader); |
| this.antLoader = antLoader; |
| } |
| |
| @Override |
| public InputStream getResourceAsStream(String name) |
| { |
| return super.getResourceAsStream(name); |
| } |
| |
| @Override |
| public void close() throws IOException |
| { |
| super.close(); |
| } |
| |
| @Override |
| protected void addURL(URL url) |
| { |
| super.addURL(url); |
| } |
| |
| @Override |
| public URL[] getURLs() |
| { |
| Set<URL> urls = new HashSet<URL>(); |
| |
| //convert urls from antLoader |
| String[] paths = antLoader.getClasspath().split(new String(new char[]{File.pathSeparatorChar})); |
| if (paths != null) |
| { |
| for (String p:paths) |
| { |
| File f = new File(p); |
| try |
| { |
| urls.add(f.toURI().toURL()); |
| } |
| catch (Exception e) |
| { |
| LOG.ignore(e); |
| } |
| } |
| } |
| |
| //add in any that may have been added to us as a URL directly |
| URL[] ourURLS = super.getURLs(); |
| if (ourURLS != null) |
| { |
| for (URL u:ourURLS) |
| urls.add(u); |
| } |
| |
| return urls.toArray(new URL[urls.size()]); |
| } |
| |
| @Override |
| protected Class<?> findClass(String name) throws ClassNotFoundException |
| { |
| return super.findClass(name); |
| } |
| |
| @Override |
| protected Package definePackage(String name, Manifest man, URL url) throws IllegalArgumentException |
| { |
| return super.definePackage(name, man, url); |
| } |
| |
| @Override |
| public URL findResource(String name) |
| { |
| return super.findResource(name); |
| } |
| |
| @Override |
| public Enumeration<URL> findResources(String name) throws IOException |
| { |
| return super.findResources(name); |
| } |
| |
| @Override |
| protected PermissionCollection getPermissions(CodeSource codesource) |
| { |
| return super.getPermissions(codesource); |
| } |
| |
| @Override |
| public Class<?> loadClass(String name) throws ClassNotFoundException |
| { |
| return super.loadClass(name); |
| } |
| |
| @Override |
| protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException |
| { |
| return super.loadClass(name, resolve); |
| } |
| |
| @Override |
| protected Object getClassLoadingLock(String className) |
| { |
| return super.getClassLoadingLock(className); |
| } |
| |
| @Override |
| public URL getResource(String name) |
| { |
| return super.getResource(name); |
| } |
| |
| @Override |
| public Enumeration<URL> getResources(String name) throws IOException |
| { |
| return super.getResources(name); |
| } |
| |
| @Override |
| protected Package definePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, |
| String implVendor, URL sealBase) throws IllegalArgumentException |
| { |
| return super.definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase); |
| } |
| |
| @Override |
| protected Package getPackage(String name) |
| { |
| return super.getPackage(name); |
| } |
| |
| @Override |
| protected Package[] getPackages() |
| { |
| return super.getPackages(); |
| } |
| |
| @Override |
| protected String findLibrary(String libname) |
| { |
| return super.findLibrary(libname); |
| } |
| |
| @Override |
| public void setDefaultAssertionStatus(boolean enabled) |
| { |
| super.setDefaultAssertionStatus(enabled); |
| } |
| |
| @Override |
| public void setPackageAssertionStatus(String packageName, boolean enabled) |
| { |
| super.setPackageAssertionStatus(packageName, enabled); |
| } |
| |
| @Override |
| public void setClassAssertionStatus(String className, boolean enabled) |
| { |
| super.setClassAssertionStatus(className, enabled); |
| } |
| |
| @Override |
| public void clearAssertionStatus() |
| { |
| super.clearAssertionStatus(); |
| } |
| } |
| |
| |
| /** |
| * AntServletHolder |
| * |
| * |
| */ |
| public static class AntServletHolder extends ServletHolder |
| { |
| |
| public AntServletHolder() |
| { |
| super(); |
| } |
| |
| |
| public AntServletHolder(Class<? extends Servlet> servlet) |
| { |
| super(servlet); |
| } |
| |
| |
| public AntServletHolder(Servlet servlet) |
| { |
| super(servlet); |
| } |
| |
| |
| public AntServletHolder(String name, Class<? extends Servlet> servlet) |
| { |
| super(name, servlet); |
| } |
| |
| |
| public AntServletHolder(String name, Servlet servlet) |
| { |
| super(name, servlet); |
| } |
| |
| protected String getSystemClassPath (ClassLoader loader) throws Exception |
| { |
| StringBuilder classpath=new StringBuilder(); |
| while (loader != null) |
| { |
| if (loader instanceof URLClassLoader) |
| { |
| URL[] urls = ((URLClassLoader)loader).getURLs(); |
| if (urls != null) |
| { |
| for (int i=0;i<urls.length;i++) |
| { |
| Resource resource = Resource.newResource(urls[i]); |
| File file=resource.getFile(); |
| if (file!=null && file.exists()) |
| { |
| if (classpath.length()>0) |
| classpath.append(File.pathSeparatorChar); |
| classpath.append(file.getAbsolutePath()); |
| } |
| } |
| } |
| } |
| else if (loader instanceof AntClassLoader) |
| { |
| classpath.append(((AntClassLoader)loader).getClasspath()); |
| } |
| |
| loader = loader.getParent(); |
| } |
| |
| return classpath.toString(); |
| } |
| |
| } |
| |
| |
| |
| /** |
| * AntServletHandler |
| * |
| * |
| */ |
| public static class AntServletHandler extends ServletHandler |
| { |
| |
| @Override |
| public ServletHolder newServletHolder(Holder.Source source) |
| { |
| return new AntServletHolder(); |
| } |
| |
| } |
| |
| |
| |
| /** |
| * Default constructor. Takes project as an argument |
| * |
| * @param project the project. |
| * @throws Exception if unable to create webapp context |
| */ |
| public AntWebAppContext(Project project) throws Exception |
| { |
| super(); |
| this.project = project; |
| setConfigurations(DEFAULT_CONFIGURATIONS); |
| setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN); |
| setParentLoaderPriority(true); |
| } |
| |
| |
| /** |
| * Adds a new Ant's attributes tag object if it have not been created yet. |
| * @param atts the attributes |
| */ |
| public void addAttributes(Attributes atts) |
| { |
| if (this.attributes != null) |
| { |
| throw new BuildException("Only one <attributes> tag is allowed!"); |
| } |
| |
| this.attributes = atts; |
| } |
| |
| |
| public void addLib(FileSet lib) |
| { |
| libraries.add(lib); |
| } |
| |
| |
| public void addClasses(FileSet classes) |
| { |
| this.classes.add(classes); |
| } |
| |
| |
| |
| @Override |
| protected ServletHandler newServletHandler() |
| { |
| return new AntServletHandler(); |
| } |
| |
| |
| public void setJettyEnvXml(File jettyEnvXml) |
| { |
| this.jettyEnvXml = jettyEnvXml; |
| TaskLog.log("jetty-env.xml file: = " + (jettyEnvXml == null ? null : jettyEnvXml.getAbsolutePath())); |
| } |
| |
| public File getJettyEnvXml () |
| { |
| return this.jettyEnvXml; |
| } |
| |
| |
| |
| |
| public List getLibraries() |
| { |
| return librariesConfiguration.getBaseDirectories(); |
| } |
| |
| |
| public void addScanTargets(FileSet scanTargets) |
| { |
| if (this.scanTargets != null) |
| { |
| throw new BuildException("Only one <scanTargets> tag is allowed!"); |
| } |
| |
| this.scanTargets = scanTargets; |
| } |
| |
| public List getScanTargetFiles () |
| { |
| if (this.scanTargets == null) |
| return null; |
| |
| |
| FileMatchingConfiguration configuration = new FileMatchingConfiguration(); |
| configuration.addDirectoryScanner(scanTargets.getDirectoryScanner(project)); |
| return configuration.getBaseDirectories(); |
| } |
| |
| public List<File> getScanFiles() |
| { |
| if (scanFiles == null) |
| scanFiles = initScanFiles(); |
| return scanFiles; |
| } |
| |
| |
| public boolean isScanned (File file) |
| { |
| List<File> files = getScanFiles(); |
| if (files == null || files.isEmpty()) |
| return false; |
| return files.contains(file); |
| } |
| |
| |
| public List<File> initScanFiles () |
| { |
| List<File> scanList = new ArrayList<File>(); |
| |
| if (getDescriptor() != null) |
| { |
| try (Resource r = Resource.newResource(getDescriptor());) |
| { |
| scanList.add(r.getFile()); |
| } |
| catch (IOException e) |
| { |
| throw new BuildException(e); |
| } |
| } |
| |
| if (getJettyEnvXml() != null) |
| { |
| try (Resource r = Resource.newResource(getJettyEnvXml());) |
| { |
| scanList.add(r.getFile()); |
| } |
| catch (IOException e) |
| { |
| throw new BuildException("Problem configuring scanner for jetty-env.xml", e); |
| } |
| } |
| |
| if (getDefaultsDescriptor() != null) |
| { |
| try (Resource r = Resource.newResource(getDefaultsDescriptor());) |
| { |
| if (!WebAppContext.WEB_DEFAULTS_XML.equals(getDefaultsDescriptor())) |
| { |
| scanList.add(r.getFile()); |
| } |
| } |
| catch (IOException e) |
| { |
| throw new BuildException("Problem configuring scanner for webdefaults.xml", e); |
| } |
| } |
| |
| if (getOverrideDescriptor() != null) |
| { |
| try |
| { |
| Resource r = Resource.newResource(getOverrideDescriptor()); |
| scanList.add(r.getFile()); |
| } |
| catch (IOException e) |
| { |
| throw new BuildException("Problem configuring scanner for webdefaults.xml", e); |
| } |
| } |
| |
| //add any extra classpath and libs |
| List<File> cpFiles = getClassPathFiles(); |
| if (cpFiles != null) |
| scanList.addAll(cpFiles); |
| |
| //any extra scan targets |
| @SuppressWarnings("unchecked") |
| List<File> scanFiles = (List<File>)getScanTargetFiles(); |
| if (scanFiles != null) |
| scanList.addAll(scanFiles); |
| |
| return scanList; |
| } |
| |
| |
| |
| @Override |
| public void setWar(String path) |
| { |
| super.setWar(path); |
| |
| try |
| { |
| Resource war = Resource.newResource(path); |
| if (war.exists() && war.isDirectory() && getDescriptor() == null) |
| { |
| Resource webXml = war.addPath("WEB-INF/web.xml"); |
| setDescriptor(webXml.toString()); |
| } |
| } |
| catch (IOException e) |
| { |
| throw new BuildException(e); |
| } |
| } |
| |
| |
| /** |
| * |
| */ |
| public void doStart() |
| { |
| try |
| { |
| TaskLog.logWithTimestamp("Starting web application "+this.getDescriptor()); |
| if (jettyEnvXml != null && jettyEnvXml.exists()) |
| envConfiguration.setJettyEnvXml(Resource.toURL(jettyEnvXml)); |
| |
| ClassLoader parentLoader = this.getClass().getClassLoader(); |
| if (parentLoader instanceof AntClassLoader) |
| parentLoader = new AntURLClassLoader((AntClassLoader)parentLoader); |
| |
| setClassLoader(new WebAppClassLoader(parentLoader, this)); |
| if (attributes != null && attributes.getAttributes() != null) |
| { |
| for (Attribute a:attributes.getAttributes()) |
| setAttribute(a.getName(), a.getValue()); |
| } |
| |
| //apply a context xml file if one was supplied |
| if (contextXml != null) |
| { |
| XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(contextXml)); |
| TaskLog.log("Applying context xml file "+contextXml); |
| xmlConfiguration.configure(this); |
| } |
| |
| super.doStart(); |
| } |
| catch (Exception e) |
| { |
| TaskLog.log(e.toString()); |
| } |
| } |
| |
| public void doStop() |
| { |
| try |
| { |
| scanFiles = null; |
| TaskLog.logWithTimestamp("Stopping web application "+this); |
| Thread.currentThread().sleep(500L); |
| super.doStop(); |
| //remove all filters, servlets and listeners. They will be recreated |
| //either via application of a context xml file or web.xml or annotation or servlet api |
| setEventListeners(new EventListener[0]); |
| getServletHandler().setFilters(new FilterHolder[0]); |
| getServletHandler().setFilterMappings(new FilterMapping[0]); |
| getServletHandler().setServlets(new ServletHolder[0]); |
| getServletHandler().setServletMappings(new ServletMapping[0]); |
| } |
| catch (InterruptedException e) |
| { |
| TaskLog.log(e.toString()); |
| } |
| catch (Exception e) |
| { |
| TaskLog.log(e.toString()); |
| } |
| } |
| |
| |
| |
| /** |
| * @return a list of classpath files (libraries and class directories). |
| */ |
| public List<File> getClassPathFiles() |
| { |
| List<File> classPathFiles = new ArrayList<File>(); |
| Iterator classesIterator = classes.iterator(); |
| while (classesIterator.hasNext()) |
| { |
| FileSet clazz = (FileSet) classesIterator.next(); |
| classPathFiles.add(clazz.getDirectoryScanner(project).getBasedir()); |
| } |
| |
| Iterator iterator = libraries.iterator(); |
| while (iterator.hasNext()) |
| { |
| FileSet library = (FileSet) iterator.next(); |
| String[] includedFiles = library.getDirectoryScanner(project).getIncludedFiles(); |
| File baseDir = library.getDirectoryScanner(project).getBasedir(); |
| |
| for (int i = 0; i < includedFiles.length; i++) |
| { |
| classPathFiles.add(new File(baseDir, includedFiles[i])); |
| } |
| } |
| |
| |
| return classPathFiles; |
| } |
| |
| |
| /** |
| * @return a <code>FileMatchingConfiguration</code> object describing the |
| * configuration of all libraries added to this particular web app |
| * (both classes and libraries). |
| */ |
| public FileMatchingConfiguration getLibrariesConfiguration() |
| { |
| FileMatchingConfiguration config = new FileMatchingConfiguration(); |
| |
| Iterator classesIterator = classes.iterator(); |
| while (classesIterator.hasNext()) |
| { |
| FileSet clazz = (FileSet) classesIterator.next(); |
| config.addDirectoryScanner(clazz.getDirectoryScanner(project)); |
| } |
| |
| Iterator librariesIterator = libraries.iterator(); |
| while (librariesIterator.hasNext()) |
| { |
| FileSet library = (FileSet) librariesIterator.next(); |
| config.addDirectoryScanner(library.getDirectoryScanner(project)); |
| } |
| |
| return config; |
| } |
| |
| |
| public File getContextXml() |
| { |
| return contextXml; |
| } |
| |
| |
| public void setContextXml(File contextXml) |
| { |
| this.contextXml = contextXml; |
| } |
| |
| } |