All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.simplericity.jettyconsole.creator.DefaultCreator Maven / Gradle / Ivy

package org.simplericity.jettyconsole.creator;

import org.apache.commons.io.IOUtils;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Expand;
import org.apache.tools.ant.taskdefs.Jar;
import org.apache.tools.ant.taskdefs.Manifest;
import org.apache.tools.ant.taskdefs.ManifestException;
import org.apache.tools.ant.types.FileSet;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

/**
 * Created by IntelliJ IDEA. User: bjorsnos Date: Dec 28, 2008 Time: 12:40:54 AM To change this template use File | Settings | File Templates.
 */
public class DefaultCreator implements Creator {
  private File workingDirectory;
  private File sourceWar;
  private File sourceWarDirectory;
  private URL backgroundImage;
  private File destinationWar;

  private String consoleDirectory = "META-INF/jettyconsole";
  private String name;
  private List additionalDependencies;

  private static final String NOT_FOUND_FILTER_CLASSFILE = "org/simplericity/jettyconsole/filter/NotFoundFilter.class";
  private static final String NOT_FOUND_FILTER_CLASSNAME = NOT_FOUND_FILTER_CLASSFILE.replace('/', '.').substring(0, NOT_FOUND_FILTER_CLASSFILE.lastIndexOf("."));
  private static final String MAIN_CLASS = "JettyConsoleBootstrapMainClass";
  private URL coreDependencyUrl;
  private String properties;
  private Map manifestEntries;

  public void setWorkingDirectory(File workingDirectory) {
    this.workingDirectory = workingDirectory;
  }

  public void setSourceWar(File file) {
    this.sourceWar = file;
  }

  public void setBackgroundImage(URL url) {
    this.backgroundImage = url;
  }

  public void setDestinationWar(File destinationFile) {
    this.destinationWar = destinationFile;
  }

  public void setSourceWarDirectory(File sourceWarDirectory) {
    this.sourceWarDirectory = sourceWarDirectory;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void setCoreDependency(URL coreDependencyUrl) {
    this.coreDependencyUrl = coreDependencyUrl;
  }

  public void setProperties(String properties) {
    this.properties = properties;
  }

  public void setManifestEntries(Map manifestEntries) {
    this.manifestEntries = manifestEntries;
  }

  public void setAdditionalDependecies(List additionalDependencies) {
    this.additionalDependencies = additionalDependencies;
  }

  public void create() throws CreatorExecutionException {
    // Make sure the working directory exists
    workingDirectory.mkdirs();

    File consoleDir = new File(workingDirectory, consoleDirectory);
    consoleDir.mkdirs();

    //
    // We assume here that the user already has an exploded WAR structure. In my particular case I am using
    // the maven-dependency-plugin to retrieve a runtime bundle that embeds a WAR that I want to pull out, augment
    // with a console and deploy.
    //
    if (sourceWarDirectory != null) {
      workingDirectory = sourceWarDirectory;
    } else {
      extractWar(sourceWar);
    }

    copyBackgroundImage();
    writePathDescriptor(consoleDir, copyAdditionalDependencies());
    writeDescriptor(consoleDir);
    rewriteWebXml();
    packageConsole();
  }

  /**
   * Write a txt file with one line for each unpacked class or resource from dependencies.
   */
  private void writePathDescriptor(File consoleDir, Set paths) {
    try {
      PrintWriter writer = new PrintWriter(new FileOutputStream(new File(consoleDir, "jettyconsolepaths.txt")));
      for (String path : paths) {
        writer.println(path);
      }
      writer.close();
    } catch (FileNotFoundException e) {
      throw new RuntimeException(e);
    }

  }

  private void packageConsole() throws CreatorExecutionException {
    try {
      Jar jarArchiver = new Jar();
      jarArchiver.setProject(new Project());
      jarArchiver.setDestFile(destinationWar);
      final FileSet fileSet = new FileSet();
      fileSet.setDir(workingDirectory);
      jarArchiver.addFileset(fileSet);
      jarArchiver.addConfiguredManifest(createManifest());
      jarArchiver.execute();
    } catch (ManifestException e) {
      throw new CreatorExecutionException(e.getMessage(), e);
    }
  }

  private Manifest createManifest() throws ManifestException {
    Manifest manifest = new Manifest();
    manifest.addConfiguredAttribute(new Manifest.Attribute("Main-Class", MAIN_CLASS));

    for (Map.Entry entry : manifestEntries.entrySet())
      manifest.addConfiguredAttribute(new Manifest.Attribute(entry.getKey(), entry.getValue()));

    return manifest;
  }

  private Set copyAdditionalDependencies() throws CreatorExecutionException {

    File libDirectory = new File(workingDirectory, "META-INF/jettyconsole/lib");
    libDirectory.mkdirs();

    Set libPaths = new HashSet();

    for (URL url : additionalDependencies) {
      copyIntoLib(url, libDirectory, libPaths);
    }

    copyIntoLib(coreDependencyUrl, libDirectory, libPaths);

    unpackMainClassAndFilter(coreDependencyUrl);

    return libPaths;

  }

  private void copyIntoLib(URL url, File libDirectory, Set libPaths) throws CreatorExecutionException {
    String name = url.getPath().substring(url.getPath().lastIndexOf("/"));
    File ourLibDir = new File(libDirectory, name);
    ourLibDir.mkdirs();
    try {
      JarInputStream in = new JarInputStream(url.openStream());

      java.util.jar.Manifest manifest = in.getManifest();
      if (manifest != null) {
        File manifestFile = new File(ourLibDir, "META-INF/MANIFEST.MF");
        manifestFile.getParentFile().mkdirs();
        FileOutputStream fos = new FileOutputStream(manifestFile);
        manifest.write(fos);
        fos.close();
      }
      while (true) {
        JarEntry entry = in.getNextJarEntry();
        if (entry == null) {
          break;
        }
        // Skip signature files in libraries
        if (entry.getName().startsWith("META-INF/") && entry.getName().endsWith(".SF")) {
          continue;
        }

        File destFile = new File(ourLibDir, entry.getName());
        destFile.getParentFile().mkdirs();
        if (entry.isDirectory()) {
          destFile.mkdirs();
        } else {
          libPaths.add(name + "/" + entry.getName());
          final FileOutputStream fileOutputStream = new FileOutputStream(destFile);

          try {
            IOUtils.copy(in, fileOutputStream);
          } finally {
            fileOutputStream.close();
          }
        }

      }
      in.close();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

  }

  private void unpackMainClassAndFilter(URL coredep) {
    try {
      JarInputStream in = new JarInputStream(coredep.openStream());

      while (true) {
        JarEntry entry = in.getNextJarEntry();
        if (entry == null) {
          break;
        }
        if (entry.getName().startsWith(MAIN_CLASS) && entry.getName().endsWith(".class")) {
          IOUtils.copy(in, new FileOutputStream(new File(workingDirectory, entry.getName().substring(entry.getName().lastIndexOf("/") + 1))));
        } else if (entry.getName().equals(NOT_FOUND_FILTER_CLASSFILE)) {
          File destFile = new File(new File(workingDirectory, "WEB-INF/classes"), NOT_FOUND_FILTER_CLASSFILE);
          destFile.getParentFile().mkdirs();
          IOUtils.copy(in, new FileOutputStream(destFile));
        }
      }
      in.close();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  private void copyBackgroundImage() throws CreatorExecutionException {
    try {
      if (backgroundImage == null) {
        final URL resource = getClass().getClassLoader().getResource("default-background-image.jpg");
        setBackgroundImage(resource);
      }
      
      File backgroundImageFile = new File(new File(workingDirectory, "META-INF"), "background-image.jpg");
      if(backgroundImageFile.getParentFile().exists() == false) {
        backgroundImageFile.getParentFile().mkdirs();
      }
      IOUtils.copy(backgroundImage.openStream(), new FileOutputStream(backgroundImageFile));

    } catch (IOException e) {
      throw new CreatorExecutionException("Cannot copy background image '" + backgroundImage + "'", e);
    }
  }

  private void extractWar(File file) throws CreatorExecutionException {
    Project project = new Project();
    Expand unArchiver = new Expand();
    unArchiver.setProject(project);
    unArchiver.setSrc(file);
    unArchiver.setDest(workingDirectory);
    unArchiver.execute();

  }

  private void writeDescriptor(File consoleDir) throws CreatorExecutionException {
    try {
      PrintWriter writer = new PrintWriter(new FileOutputStream(new File(consoleDir, "jettyconsole.properties")));

      writer.println("name=" + name);

      if (properties != null && properties.trim().length() > 0) {

        try {
          Properties p = new Properties();
          p.load(new ByteArrayInputStream(properties.getBytes()));
          writer.println(properties);
        } catch (IOException e) {
          throw new CreatorExecutionException("Can't parse properties: [" + properties + "]", e);
        }
      }
      writer.close();

    } catch (FileNotFoundException e) {
      throw new CreatorExecutionException("Cannot write to descriptor file", e);
    }
  }

  private void rewriteWebXml() throws CreatorExecutionException {
    File webXml = new File(workingDirectory, "WEB-INF/web.xml");
    Set beforeFilter = new HashSet();
    beforeFilter.add("icon");
    beforeFilter.add("display-name");
    beforeFilter.add("description");
    beforeFilter.add("distributable");
    beforeFilter.add("context-param");

    if (webXml.exists()) {
      try {
        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating(false);

        DocumentBuilder builder = factory.newDocumentBuilder();
        builder.setEntityResolver(new EntityResolver() {
          public InputSource resolveEntity(String s, String s1) throws SAXException, IOException {
            String file = s1.substring(s1.lastIndexOf("/"));
            String resource = "/javax/servlet/resources" + file;
            final InputStream stream = getClass().getResourceAsStream(resource);
            return new InputSource(stream);
          }
        });
        Document document = builder.parse(webXml);
        {
          final NodeList childElems = document.getDocumentElement().getChildNodes();
          for (int i = 0; i < childElems.getLength(); i++) {
            if (childElems.item(i) instanceof Element) {
              Element e = (Element) childElems.item(i);
              if (!beforeFilter.contains(e.getNodeName())) {
                Element filterElement = document.createElement("filter");
                Element filterNameElement = document.createElement("filter-name");
                filterNameElement.appendChild(document.createTextNode(NOT_FOUND_FILTER_CLASSNAME));
                Element filterClassElement = document.createElement("filter-class");
                filterClassElement.appendChild(document.createTextNode(NOT_FOUND_FILTER_CLASSNAME));
                filterElement.appendChild(filterNameElement);
                filterElement.appendChild(filterClassElement);
                document.getDocumentElement().insertBefore(filterElement, e);
                break;
              }
            }

          }
        }
        beforeFilter.add("filter");
        {
          final NodeList childElems = document.getDocumentElement().getChildNodes();
          for (int i = 0; i < childElems.getLength(); i++) {
            if (childElems.item(i) instanceof Element) {
              Element e = (Element) childElems.item(i);
              if (!beforeFilter.contains(e.getNodeName())) {
                Element filterMappingElement = document.createElement("filter-mapping");
                Element filterNameElement = document.createElement("filter-name");
                filterNameElement.appendChild(document.createTextNode(NOT_FOUND_FILTER_CLASSNAME));
                Element urlPatternElement = document.createElement("url-pattern");
                urlPatternElement.appendChild(document.createTextNode("/" + MAIN_CLASS + ".class"));
                filterMappingElement.appendChild(filterNameElement);
                filterMappingElement.appendChild(urlPatternElement);
                document.getDocumentElement().insertBefore(filterMappingElement, e);
                break;
              }
            }
          }
        }
        TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(webXml));
      } catch (ParserConfigurationException e) {
        throw new CreatorExecutionException("Exception modifying web.xml", e);
      } catch (SAXException e) {
        throw new CreatorExecutionException("Exception modifying web.xml", e);
      } catch (IOException e) {
        throw new CreatorExecutionException("Exception modifying web.xml", e);
      } catch (TransformerException e) {
        throw new CreatorExecutionException("Exception modifying web.xml", e);
      }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy