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

org.eclipse.jetty.jspc.plugin.JspcMojo Maven / Gradle / Ivy

There is a newer version: 9.4.8.v20171121
Show newest version
//
//  ========================================================================
//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  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.jspc.plugin;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.jasper.JspC;
import org.apache.jasper.servlet.JspCServletContext;
import org.apache.jasper.servlet.TldScanner;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.tomcat.JarScanner;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;

/**
 * This goal will compile jsps for a webapp so that they can be included in a
 * war.
 * 

* At runtime, the plugin will use the jspc compiler to precompile jsps and tags. *

*

* Note that the same java compiler will be used as for on-the-fly compiled * jsps, which will be the Eclipse java compiler. *

* See Usage * Guide for instructions on using this plugin. *

* @goal jspc * @phase process-classes * @requiresDependencyResolution compile+runtime * @description Runs jspc compiler to produce .java and .class files */ public class JspcMojo extends AbstractMojo { public static final String END_OF_WEBAPP = ""; public static final String PRECOMPILED_FLAG = "org.eclipse.jetty.jsp.precompiled"; /** * JettyJspC * * Add some extra setters to standard JspC class to help configure it * for running in maven. * * TODO move all setters on the plugin onto this jspc class instead. */ public static class JettyJspC extends JspC { private boolean scanAll; public void setClassLoader (ClassLoader loader) { this.loader = loader; } public void setScanAllDirectories (boolean scanAll) { this.scanAll = scanAll; } public boolean getScanAllDirectories () { return this.scanAll; } @Override protected TldScanner newTldScanner(JspCServletContext context, boolean namespaceAware, boolean validate, boolean blockExternal) { if (context != null && context.getAttribute(JarScanner.class.getName()) == null) { StandardJarScanner jarScanner = new StandardJarScanner(); jarScanner.setScanAllDirectories(getScanAllDirectories()); context.setAttribute(JarScanner.class.getName(), jarScanner); } return super.newTldScanner(context, namespaceAware, validate, blockExternal); } } /** * Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope> * Use WITH CAUTION as you may wind up with duplicate jars/classes. * * @since jetty-7.6.3 * @parameter default-value="false" */ private boolean useProvidedScope; /** * The artifacts for the project. * * @since jetty-7.6.3 * @parameter default-value="${project.artifacts}" * @readonly */ private Set projectArtifacts; /** * The maven project. * * @parameter default-value="${project}" * @required * @readonly */ private MavenProject project; /** * The artifacts for the plugin itself. * * @parameter default-value="${plugin.artifacts}" * @readonly */ private List pluginArtifacts; /** * File into which to generate the <servlet> and * <servlet-mapping> tags for the compiled jsps * * @parameter default-value="${basedir}/target/webfrag.xml" */ private String webXmlFragment; /** * Optional. A marker string in the src web.xml file which indicates where * to merge in the generated web.xml fragment. Note that the marker string * will NOT be preserved during the insertion. Can be left blank, in which * case the generated fragment is inserted just before the </web-app> * line * * @parameter */ private String insertionMarker; /** * Merge the generated fragment file with the web.xml from * webAppSourceDirectory. The merged file will go into the same directory as * the webXmlFragment. * * @parameter default-value="true" */ private boolean mergeFragment; /** * The destination directory into which to put the compiled jsps. * * @parameter default-value="${project.build.outputDirectory}" */ private String generatedClasses; /** * Controls whether or not .java files generated during compilation will be * preserved. * * @parameter default-value="false" */ private boolean keepSources; /** * Root directory for all html/jsp etc files * * @parameter default-value="${basedir}/src/main/webapp" * */ private String webAppSourceDirectory; /** * Location of web.xml. Defaults to src/main/webapp/web.xml. * @parameter default-value="${basedir}/src/main/webapp/WEB-INF/web.xml" */ private String webXml; /** * The comma separated list of patterns for file extensions to be processed. By default * will include all .jsp and .jspx files. * * @parameter default-value="**\/*.jsp, **\/*.jspx" */ private String includes; /** * The comma separated list of file name patters to exclude from compilation. * * @parameter default_value="**\/.svn\/**"; */ private String excludes; /** * The location of the compiled classes for the webapp * * @parameter default-value="${project.build.outputDirectory}" */ private File classesDirectory; /** * Patterns of jars on the system path that contain tlds. Use | to separate each pattern. * * @parameter default-value=".*taglibs[^/]*\.jar|.*jstl[^/]*\.jar$ */ private String tldJarNamePatterns; /** * Source version - if not set defaults to jsp default (currently 1.7) * @parameter */ private String sourceVersion; /** * Target version - if not set defaults to jsp default (currently 1.7) * @parameter */ private String targetVersion; /** * * The JspC instance being used to compile the jsps. * * @parameter */ private JettyJspC jspc; /** * Whether dirs on the classpath should be scanned as well as jars. * True by default. This allows for scanning for tlds of dependent projects that * are in the reactor as unassembled jars. * * @parameter default-value=true */ private boolean scanAllDirectories; public void execute() throws MojoExecutionException, MojoFailureException { if (getLog().isDebugEnabled()) { getLog().info("webAppSourceDirectory=" + webAppSourceDirectory); getLog().info("generatedClasses=" + generatedClasses); getLog().info("webXmlFragment=" + webXmlFragment); getLog().info("webXml="+webXml); getLog().info("insertionMarker="+ (insertionMarker == null || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker)); getLog().info("keepSources=" + keepSources); getLog().info("mergeFragment=" + mergeFragment); if (sourceVersion != null) getLog().info("sourceVersion="+sourceVersion); if (targetVersion != null) getLog().info("targetVersion="+targetVersion); } try { prepare(); compile(); cleanupSrcs(); mergeWebXml(); } catch (Exception e) { throw new MojoExecutionException("Failure processing jsps", e); } } public void compile() throws Exception { ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); //set up the classpath of the webapp List webAppUrls = setUpWebAppClassPath(); //set up the classpath of the container (ie jetty and jsp jars) Set pluginJars = getPluginJars(); Set providedJars = getProvidedScopeJars(pluginJars); //Make a classloader so provided jars will be on the classpath List sysUrls = new ArrayList(); sysUrls.addAll(providedJars); URLClassLoader sysClassLoader = new URLClassLoader((URL[])sysUrls.toArray(new URL[0]), currentClassLoader); //make a classloader with the webapp classpath URLClassLoader webAppClassLoader = new URLClassLoader((URL[]) webAppUrls.toArray(new URL[0]), sysClassLoader); StringBuffer webAppClassPath = new StringBuffer(); for (int i = 0; i < webAppUrls.size(); i++) { if (getLog().isDebugEnabled()) getLog().debug("webappclassloader contains: " + webAppUrls.get(i)); webAppClassPath.append(new File(webAppUrls.get(i).toURI()).getCanonicalPath()); if (getLog().isDebugEnabled()) getLog().debug("added to classpath: " + ((URL) webAppUrls.get(i)).getFile()); if (i+1 if there is no // marker boolean atInsertPoint = false; boolean atEOF = false; String marker = (insertionMarker == null || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker); while (!atInsertPoint && !atEOF) { String line = webXmlReader.readLine(); if (line == null) atEOF = true; else if (line.indexOf(marker) >= 0) { atInsertPoint = true; } else { mergedWebXmlWriter.println(line); } } if (atEOF && !atInsertPoint) throw new IllegalStateException("web.xml does not contain insertionMarker "+insertionMarker); //put in a context init-param to flag that the contents have been precompiled mergedWebXmlWriter.println(""+PRECOMPILED_FLAG+"true"); // put in the generated fragment try (BufferedReader fragmentWebXmlReader = new BufferedReader(new FileReader(fragmentWebXml))) { IO.copy(fragmentWebXmlReader, mergedWebXmlWriter); // if we inserted just before the , put it back in if (marker.equals(END_OF_WEBAPP)) mergedWebXmlWriter.println(END_OF_WEBAPP); // copy in the rest of the original web.xml file IO.copy(webXmlReader, mergedWebXmlWriter); } } } } } private void prepare() throws Exception { // For some reason JspC doesn't like it if the dir doesn't // already exist and refuses to create the web.xml fragment File generatedSourceDirectoryFile = new File(generatedClasses); if (!generatedSourceDirectoryFile.exists()) generatedSourceDirectoryFile.mkdirs(); } /** * Set up the execution classpath for Jasper. * * Put everything in the classesDirectory and all of the dependencies on the * classpath. * * @returns a list of the urls of the dependencies * @throws Exception */ private List setUpWebAppClassPath() throws Exception { //add any classes from the webapp List urls = new ArrayList(); String classesDir = classesDirectory.getCanonicalPath(); classesDir = classesDir + (classesDir.endsWith(File.pathSeparator) ? "" : File.separator); urls.add(Resource.toURL(new File(classesDir))); if (getLog().isDebugEnabled()) getLog().debug("Adding to classpath classes dir: " + classesDir); //add the dependencies of the webapp (which will form WEB-INF/lib) for (Iterator iter = project.getArtifacts().iterator(); iter.hasNext();) { Artifact artifact = (Artifact)iter.next(); // Include runtime and compile time libraries if (!Artifact.SCOPE_TEST.equals(artifact.getScope()) && !Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) { String filePath = artifact.getFile().getCanonicalPath(); if (getLog().isDebugEnabled()) getLog().debug("Adding to classpath dependency file: " + filePath); urls.add(Resource.toURL(artifact.getFile())); } } return urls; } /** * @return * @throws MalformedURLException */ private Set getPluginJars () throws MalformedURLException { HashSet pluginJars = new HashSet<>(); for (Iterator iter = pluginArtifacts.iterator(); iter.hasNext(); ) { Artifact pluginArtifact = iter.next(); if ("jar".equalsIgnoreCase(pluginArtifact.getType())) { if (getLog().isDebugEnabled()) { getLog().debug("Adding plugin artifact "+pluginArtifact);} pluginJars.add(pluginArtifact.getFile().toURI().toURL()); } } return pluginJars; } /** * @param pluginJars * @return * @throws MalformedURLException */ private Set getProvidedScopeJars (Set pluginJars) throws MalformedURLException { if (!useProvidedScope) return Collections.emptySet(); HashSet providedJars = new HashSet<>(); for ( Iterator iter = projectArtifacts.iterator(); iter.hasNext(); ) { Artifact artifact = iter.next(); if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) { //test to see if the provided artifact was amongst the plugin artifacts URL jar = artifact.getFile().toURI().toURL(); if (!pluginJars.contains(jar)) { providedJars.add(jar); if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);} } else { if (getLog().isDebugEnabled()) { getLog().debug("Skipping provided artifact: "+artifact);} } } } return providedJars; } private File getWebXmlFile () throws IOException { File file = null; File baseDir = project.getBasedir().getCanonicalFile(); File defaultWebAppSrcDir = new File (baseDir, "src/main/webapp").getCanonicalFile(); File webAppSrcDir = new File (webAppSourceDirectory).getCanonicalFile(); File defaultWebXml = new File (defaultWebAppSrcDir, "web.xml").getCanonicalFile(); //If the web.xml has been changed from the default, try that File webXmlFile = new File (webXml).getCanonicalFile(); if (webXmlFile.compareTo(defaultWebXml) != 0) { file = new File (webXml); return file; } //If the web app src directory has not been changed from the default, use whatever //is set for the web.xml location file = new File (webAppSrcDir, "web.xml"); return file; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy