You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/07/31 20:12:51 UTC
svn commit: r799681 [2/24] - in /struts/sandbox/trunk/struts2-jsp-plugin: ./
src/main/java/org/apache/struts/ src/main/java/org/apache/struts2/
src/main/java/org/apache/struts2/compiler/
src/main/java/org/apache/struts2/jasper/ src/main/java/org/apache...
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/JspC.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/JspC.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/JspC.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/JspC.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,1074 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper;
+
+import java.io.BufferedReader;
+import java.io.CharArrayWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URI;
+import java.util.*;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts2.jasper.compiler.Compiler;
+import org.apache.struts2.jasper.compiler.JspConfig;
+import org.apache.struts2.jasper.compiler.JspRuntimeContext;
+import org.apache.struts2.jasper.compiler.Localizer;
+import org.apache.struts2.jasper.compiler.TagPluginManager;
+import org.apache.struts2.jasper.compiler.TldLocationsCache;
+import org.apache.struts2.jasper.servlet.JspCServletContext;
+
+import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
+
+import javax.tools.*;
+
+/**
+ * Shell for the jspc compiler. Handles all options associated with the
+ * command line and creates compilation contexts which it then compiles
+ * according to the specified options.
+ *
+ * This version can process files from a _single_ webapp at once, i.e.
+ * a single docbase can be specified.
+ *
+ * It can be used as an Ant task using:
+ * <pre>
+ * <taskdef classname="org.apache.struts.jasperJspC" name="jasper2" >
+ * <classpath>
+ * <pathelement location="${java.home}/../lib/tools.jar"/>
+ * <fileset dir="${ENV.CATALINA_HOME}/server/lib">
+ * <include name="*.jar"/>
+ * </fileset>
+ * <fileset dir="${ENV.CATALINA_HOME}/common/lib">
+ * <include name="*.jar"/>
+ * </fileset>
+ * <path refid="myjars"/>
+ * </classpath>
+ * </taskdef>
+ *
+ * <jasper2 verbose="0"
+ * package="my.package"
+ * uriroot="${webapps.dir}/${webapp.name}"
+ * webXmlFragment="${build.dir}/generated_web.xml"
+ * outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
+ * </pre>
+ *
+ * @author Danno Ferrin
+ * @author Pierre Delisle
+ * @author Costin Manolache
+ * @author Yoav Shapira
+ */
+public class JspC implements Options {
+ /** The default Microsoft Internet Explorer class ID. */
+ public static final String DEFAULT_IE_CLASS_ID =
+ "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
+
+ /** Logger (set by constructor.) */
+ private Log log;
+
+ private static final String SWITCH_VERBOSE = "-v";
+ private static final String SWITCH_HELP = "-help";
+ private static final String SWITCH_QUIET = "-q";
+ private static final String SWITCH_OUTPUT_DIR = "-d";
+ private static final String SWITCH_IE_CLASS_ID = "-ieplugin";
+ private static final String SWITCH_PACKAGE_NAME = "-p";
+ private static final String SWITCH_CACHE = "-cache";
+ private static final String SWITCH_CLASS_NAME = "-c";
+ private static final String SWITCH_FULL_STOP = "--";
+ private static final String SWITCH_COMPILE = "-compile";
+ private static final String SWITCH_SOURCE = "-source";
+ private static final String SWITCH_TARGET = "-target";
+ private static final String SWITCH_URI_BASE = "-uribase";
+ private static final String SWITCH_URI_ROOT = "-uriroot";
+ private static final String SWITCH_FILE_WEBAPP = "-webapp";
+ private static final String SWITCH_WEBAPP_INC = "-webinc";
+ private static final String SWITCH_WEBAPP_XML = "-webxml";
+ private static final String SWITCH_MAPPED = "-mapped";
+ private static final String SWITCH_XPOWERED_BY = "-xpoweredBy";
+ private static final String SWITCH_TRIM_SPACES = "-trimSpaces";
+ private static final String SWITCH_CLASSPATH = "-classpath";
+ private static final String SWITCH_DIE = "-die";
+ private static final String SWITCH_POOLING = "-poolingEnabled";
+ private static final String SWITCH_ENCODING = "-javaEncoding";
+ private static final String SWITCH_SMAP = "-smap";
+ private static final String SWITCH_DUMP_SMAP = "-dumpsmap";
+
+ private static final String SHOW_SUCCESS ="-s";
+ private static final String LIST_ERRORS = "-l";
+ private static final int NO_WEBXML = 0;
+ private static final int INC_WEBXML = 10;
+ private static final int ALL_WEBXML = 20;
+ private static final int DEFAULT_DIE_LEVEL = 1;
+ private static final int NO_DIE_LEVEL = 0;
+
+ private static final String[] insertBefore =
+ { "</web-app>", "<servlet-mapping>", "<session-config>",
+ "<mime-mapping>", "<welcome-file-list>", "<error-page>", "<taglib>",
+ "<resource-env-ref>", "<resource-ref>", "<security-constraint>",
+ "<login-config>", "<security-role>", "<env-entry>", "<ejb-ref>",
+ "<ejb-local-ref>" };
+
+ private static int die;
+ private String classPath = null;
+ private URLClassLoader loader = null;
+ private boolean trimSpaces = false;
+ private boolean genStringAsCharArray = false;
+ private boolean xpoweredBy;
+ private boolean mappedFile = false;
+ private boolean poolingEnabled = true;
+ private File scratchDir;
+ private String ieClassId = DEFAULT_IE_CLASS_ID;
+ private String targetPackage;
+ private String targetClassName;
+ private String uriBase;
+ //private String uriRoot;
+ private int dieLevel;
+ private boolean helpNeeded = false;
+ private boolean compile = false;
+ private boolean smapSuppressed = true;
+ private boolean smapDumped = false;
+ private boolean caching = true;
+ private Map cache = new HashMap();
+
+ private String compiler = null;
+
+ private ClassLoaderInterface classLoaderInterface;
+
+ private String compilerTargetVM = "1.4";
+ private String compilerSourceVM = "1.4";
+
+ private boolean classDebugInfo = true;
+
+ /**
+ * Throw an exception if there's a compilation error, or swallow it.
+ * Default is true to preserve old behavior.
+ */
+ private boolean failOnError = true;
+
+ /**
+ * The file extensions to be handled as JSP files.
+ * Default list is .jsp and .jspx.
+ */
+ private List extensions;
+
+ /**
+ * The pages.
+ */
+ private List pages = new Vector();
+
+ /**
+ * Needs better documentation, this data member does.
+ * True by default.
+ */
+ private boolean errorOnUseBeanInvalidClassAttribute = true;
+
+ /**
+ * The java file encoding. Default
+ * is UTF-8. Added per bugzilla 19622.
+ */
+ private String javaEncoding = "UTF-8";
+
+ // Generation of web.xml fragments
+ private String webxmlFile;
+ private int webxmlLevel;
+
+ private Writer mapout;
+ private CharArrayWriter servletout;
+ private CharArrayWriter mappingout;
+
+ /**
+ * The servlet context.
+ */
+ private JspCServletContext context;
+
+ /**
+ * The runtime context.
+ * Maintain a dummy JspRuntimeContext for compiling tag files.
+ */
+ private JspRuntimeContext rctxt;
+
+ /**
+ * Cache for the TLD locations
+ */
+ private TldLocationsCache tldLocationsCache = null;
+
+ private JspConfig jspConfig = null;
+ private TagPluginManager tagPluginManager = null;
+
+ private boolean verbose = false;
+ private boolean listErrors = false;
+ private boolean showSuccess = false;
+ private int argPos;
+ private boolean fullstop = false;
+ private String args[];
+ private String sourceCode;
+
+ public static void main(String arg[]) {
+ if (arg.length == 0) {
+ System.out.println(Localizer.getMessage("jspc.usage"));
+ } else {
+ try {
+ JspC jspc = new JspC();
+ jspc.setArgs(arg);
+ if (jspc.helpNeeded) {
+ System.out.println(Localizer.getMessage("jspc.usage"));
+ } else {
+ jspc.execute();
+ }
+ } catch (JasperException je) {
+ System.err.println(je);
+ //System.err.println(je.getMessage());
+ if (die != NO_DIE_LEVEL) {
+ System.exit(die);
+ }
+ }
+ }
+ }
+
+ /** Constructor. */
+ public JspC() {
+ log = LogFactory.getLog(getClass());
+ }
+
+ public String getSourceCode() {
+ return sourceCode;
+ }
+
+ public void setClassLoaderInterface(ClassLoaderInterface classLoaderInterface) {
+ this.classLoaderInterface = classLoaderInterface;
+ }
+
+ public void setArgs(String[] arg) throws JasperException {
+ args = arg;
+ String tok;
+
+ dieLevel = NO_DIE_LEVEL;
+ die = dieLevel;
+
+ while ((tok = nextArg()) != null) {
+ if (tok.equals(SWITCH_VERBOSE)) {
+ verbose = true;
+ showSuccess = true;
+ listErrors = true;
+ } else if (tok.equals(SWITCH_OUTPUT_DIR)) {
+ tok = nextArg();
+ setOutputDir( tok );
+ } else if (tok.equals(SWITCH_PACKAGE_NAME)) {
+ targetPackage = nextArg();
+ } else if (tok.equals(SWITCH_COMPILE)) {
+ compile=true;
+ } else if (tok.equals(SWITCH_CLASS_NAME)) {
+ targetClassName = nextArg();
+ } else if (tok.equals(SWITCH_URI_BASE)) {
+ uriBase=nextArg();
+ } else if ( tok.equals( SHOW_SUCCESS ) ) {
+ showSuccess = true;
+ } else if ( tok.equals( LIST_ERRORS ) ) {
+ listErrors = true;
+ } else if (tok.equals(SWITCH_WEBAPP_INC)) {
+ webxmlFile = nextArg();
+ if (webxmlFile != null) {
+ webxmlLevel = INC_WEBXML;
+ }
+ } else if (tok.equals(SWITCH_WEBAPP_XML)) {
+ webxmlFile = nextArg();
+ if (webxmlFile != null) {
+ webxmlLevel = ALL_WEBXML;
+ }
+ } else if (tok.equals(SWITCH_MAPPED)) {
+ mappedFile = true;
+ } else if (tok.equals(SWITCH_XPOWERED_BY)) {
+ xpoweredBy = true;
+ } else if (tok.equals(SWITCH_TRIM_SPACES)) {
+ setTrimSpaces(true);
+ } else if (tok.equals(SWITCH_CACHE)) {
+ tok = nextArg();
+ if ("false".equals(tok)) {
+ caching = false;
+ } else {
+ caching = true;
+ }
+ } else if (tok.equals(SWITCH_CLASSPATH)) {
+ setClassPath(nextArg());
+ } else if (tok.startsWith(SWITCH_DIE)) {
+ try {
+ dieLevel = Integer.parseInt(
+ tok.substring(SWITCH_DIE.length()));
+ } catch (NumberFormatException nfe) {
+ dieLevel = DEFAULT_DIE_LEVEL;
+ }
+ die = dieLevel;
+ } else if (tok.equals(SWITCH_HELP)) {
+ helpNeeded = true;
+ } else if (tok.equals(SWITCH_POOLING)) {
+ tok = nextArg();
+ if ("false".equals(tok)) {
+ poolingEnabled = false;
+ } else {
+ poolingEnabled = true;
+ }
+ } else if (tok.equals(SWITCH_ENCODING)) {
+ setJavaEncoding(nextArg());
+ } else if (tok.equals(SWITCH_SOURCE)) {
+ setCompilerSourceVM(nextArg());
+ } else if (tok.equals(SWITCH_TARGET)) {
+ setCompilerTargetVM(nextArg());
+ } else if (tok.equals(SWITCH_SMAP)) {
+ smapSuppressed = false;
+ } else if (tok.equals(SWITCH_DUMP_SMAP)) {
+ smapDumped = true;
+ } else {
+ if (tok.startsWith("-")) {
+ throw new JasperException("Unrecognized option: " + tok +
+ ". Use -help for help.");
+ }
+ if (!fullstop) {
+ argPos--;
+ }
+ // Start treating the rest as JSP Pages
+ break;
+ }
+ }
+
+ // Add all extra arguments to the list of files
+ while( true ) {
+ String file = nextFile();
+ if( file==null ) {
+ break;
+ }
+ pages.add( file );
+ }
+ }
+
+ public boolean getKeepGenerated() {
+ // isn't this why we are running jspc?
+ return true;
+ }
+
+ public boolean getTrimSpaces() {
+ return trimSpaces;
+ }
+
+ public void setTrimSpaces(boolean ts) {
+ this.trimSpaces = ts;
+ }
+
+ public boolean isPoolingEnabled() {
+ return poolingEnabled;
+ }
+
+ public void setPoolingEnabled(boolean poolingEnabled) {
+ this.poolingEnabled = poolingEnabled;
+ }
+
+ public boolean isXpoweredBy() {
+ return xpoweredBy;
+ }
+
+ public void setXpoweredBy(boolean xpoweredBy) {
+ this.xpoweredBy = xpoweredBy;
+ }
+
+ public boolean getErrorOnUseBeanInvalidClassAttribute() {
+ return errorOnUseBeanInvalidClassAttribute;
+ }
+
+ public void setErrorOnUseBeanInvalidClassAttribute(boolean b) {
+ errorOnUseBeanInvalidClassAttribute = b;
+ }
+
+ public int getTagPoolSize() {
+ return Constants.MAX_POOL_SIZE;
+ }
+
+ /**
+ * Are we supporting HTML mapped servlets?
+ */
+ public boolean getMappedFile() {
+ return mappedFile;
+ }
+
+ // Off-line compiler, no need for security manager
+ public Object getProtectionDomain() {
+ return null;
+ }
+
+ public boolean getSendErrorToClient() {
+ // implied send to System.err
+ return true;
+ }
+
+ public void setClassDebugInfo( boolean b ) {
+ classDebugInfo=b;
+ }
+
+ public boolean getClassDebugInfo() {
+ // compile with debug info
+ return classDebugInfo;
+ }
+
+ /**
+ * @see Options#isCaching()
+ */
+ public boolean isCaching() {
+ return caching;
+ }
+
+ /**
+ * @see Options#isCaching()
+ */
+ public void setCaching(boolean caching) {
+ this.caching = caching;
+ }
+
+ /**
+ * @see Options#getCache()
+ */
+ public Map getCache() {
+ return cache;
+ }
+
+ /**
+ * Background compilation check intervals in seconds
+ */
+ public int getCheckInterval() {
+ return 0;
+ }
+
+ /**
+ * Modification test interval.
+ */
+ public int getModificationTestInterval() {
+ return 0;
+ }
+
+ /**
+ * Is Jasper being used in development mode?
+ */
+ public boolean getDevelopment() {
+ return false;
+ }
+
+ /**
+ * Is the generation of SMAP info for JSR45 debuggin suppressed?
+ */
+ public boolean isSmapSuppressed() {
+ return smapSuppressed;
+ }
+
+ /**
+ * Set smapSuppressed flag.
+ */
+ public void setSmapSuppressed(boolean smapSuppressed) {
+ this.smapSuppressed = smapSuppressed;
+ }
+
+
+ /**
+ * Should SMAP info for JSR45 debugging be dumped to a file?
+ */
+ public boolean isSmapDumped() {
+ return smapDumped;
+ }
+
+ /**
+ * Set smapSuppressed flag.
+ */
+ public void setSmapDumped(boolean smapDumped) {
+ this.smapDumped = smapDumped;
+ }
+
+
+ /**
+ * Determines whether text strings are to be generated as char arrays,
+ * which improves performance in some cases.
+ *
+ * @param genStringAsCharArray true if text strings are to be generated as
+ * char arrays, false otherwise
+ */
+ public void setGenStringAsCharArray(boolean genStringAsCharArray) {
+ this.genStringAsCharArray = genStringAsCharArray;
+ }
+
+ /**
+ * Indicates whether text strings are to be generated as char arrays.
+ *
+ * @return true if text strings are to be generated as char arrays, false
+ * otherwise
+ */
+ public boolean genStringAsCharArray() {
+ return genStringAsCharArray;
+ }
+
+ /**
+ * Sets the class-id value to be sent to Internet Explorer when using
+ * <jsp:plugin> tags.
+ *
+ * @param ieClassId Class-id value
+ */
+ public void setIeClassId(String ieClassId) {
+ this.ieClassId = ieClassId;
+ }
+
+ /**
+ * Gets the class-id value that is sent to Internet Explorer when using
+ * <jsp:plugin> tags.
+ *
+ * @return Class-id value
+ */
+ public String getIeClassId() {
+ return ieClassId;
+ }
+
+ public File getScratchDir() {
+ return scratchDir;
+ }
+
+ public Class getJspCompilerPlugin() {
+ // we don't compile, so this is meanlingless
+ return null;
+ }
+
+ public String getJspCompilerPath() {
+ // we don't compile, so this is meanlingless
+ return null;
+ }
+
+ /**
+ * Compiler to use.
+ */
+ public String getCompiler() {
+ return compiler;
+ }
+
+ public void setCompiler(String c) {
+ compiler=c;
+ }
+
+ /**
+ * @see Options#getCompilerTargetVM
+ */
+ public String getCompilerTargetVM() {
+ return compilerTargetVM;
+ }
+
+ public void setCompilerTargetVM(String vm) {
+ compilerTargetVM = vm;
+ }
+
+ /**
+ * @see Options#getCompilerSourceVM()
+ */
+ public String getCompilerSourceVM() {
+ return compilerSourceVM;
+ }
+
+ /**
+ * @see Options#getCompilerSourceVM()
+ */
+ public void setCompilerSourceVM(String vm) {
+ compilerSourceVM = vm;
+ }
+
+ public TldLocationsCache getTldLocationsCache() {
+ return tldLocationsCache;
+ }
+
+ /**
+ * Returns the encoding to use for
+ * java files. The default is UTF-8.
+ *
+ * @return String The encoding
+ */
+ public String getJavaEncoding() {
+ return javaEncoding;
+ }
+
+ /**
+ * Sets the encoding to use for
+ * java files.
+ *
+ * @param encodingName The name, e.g. "UTF-8"
+ */
+ public void setJavaEncoding(String encodingName) {
+ javaEncoding = encodingName;
+ }
+
+ public boolean getFork() {
+ return false;
+ }
+
+ public String getClassPath() {
+ if( classPath != null )
+ return classPath;
+ return System.getProperty("java.class.path");
+ }
+
+ public void setClassPath(String s) {
+ classPath=s;
+ }
+
+ /**
+ * Returns the list of file extensions
+ * that are treated as JSP files.
+ *
+ * @return The list of extensions
+ */
+ public List getExtensions() {
+ return extensions;
+ }
+
+ /**
+ * Adds the given file extension to the
+ * list of extensions handled as JSP files.
+ *
+ * @param extension The extension to add, e.g. "myjsp"
+ */
+ protected void addExtension(final String extension) {
+ if(extension != null) {
+ if(extensions == null) {
+ extensions = new Vector();
+ }
+
+ extensions.add(extension);
+ }
+ }
+
+ /**
+ * Parses comma-separated list of JSP files to be processed. If the argument
+ * is null, nothing is done.
+ *
+ * <p>Each file is interpreted relative to uriroot, unless it is absolute,
+ * in which case it must start with uriroot.</p>
+ *
+ * @param jspFiles Comma-separated list of JSP files to be processed
+ */
+ public void setJspFiles(final String jspFiles) {
+ if(jspFiles == null) {
+ return;
+ }
+
+ StringTokenizer tok = new StringTokenizer(jspFiles, ",");
+ while (tok.hasMoreTokens()) {
+ pages.add(tok.nextToken());
+ }
+ }
+
+ /**
+ * Sets the compile flag.
+ *
+ * @param b Flag value
+ */
+ public void setCompile( final boolean b ) {
+ compile = b;
+ }
+
+ /**
+ * Sets the verbosity level. The actual number doesn't
+ * matter: if it's greater than zero, the verbose flag will
+ * be true.
+ *
+ * @param level Positive means verbose
+ */
+ public void setVerbose( final int level ) {
+ if (level > 0) {
+ verbose = true;
+ showSuccess = true;
+ listErrors = true;
+ }
+ }
+
+ public void setValidateXml( boolean b ) {
+ org.apache.struts2.jasper.xmlparser.ParserUtils.validating=b;
+ }
+
+ public void setListErrors( boolean b ) {
+ listErrors = b;
+ }
+
+ public void setOutputDir( String s ) {
+ if( s!= null ) {
+ scratchDir = resolveFile(s).getAbsoluteFile();
+ } else {
+ scratchDir=null;
+ }
+ }
+
+ public void setPackage( String p ) {
+ targetPackage=p;
+ }
+
+ /**
+ * Class name of the generated file ( without package ).
+ * Can only be used if a single file is converted.
+ * XXX Do we need this feature ?
+ */
+ public void setClassName( String p ) {
+ targetClassName=p;
+ }
+
+ /**
+ * File where we generate a web.xml fragment with the class definitions.
+ */
+ public void setWebXmlFragment( String s ) {
+ webxmlFile=resolveFile(s).getAbsolutePath();
+ webxmlLevel=INC_WEBXML;
+ }
+
+ /**
+ * File where we generate a complete web.xml with the class definitions.
+ */
+ public void setWebXml( String s ) {
+ webxmlFile=resolveFile(s).getAbsolutePath();
+ webxmlLevel=ALL_WEBXML;
+ }
+
+ /**
+ * Set the option that throws an exception in case of a compilation error.
+ */
+ public void setFailOnError(final boolean b) {
+ failOnError = b;
+ }
+
+ public boolean getFailOnError() {
+ return failOnError;
+ }
+
+ /**
+ * Obtain JSP configuration informantion specified in web.xml.
+ */
+ public JspConfig getJspConfig() {
+ return jspConfig;
+ }
+
+ public TagPluginManager getTagPluginManager() {
+ return tagPluginManager;
+ }
+
+ public void generateWebMapping( String file, JspCompilationContext clctxt )
+ throws IOException
+ {
+ if (log.isDebugEnabled()) {
+ log.debug("Generating web mapping for file " + file
+ + " using compilation context " + clctxt);
+ }
+
+ String className = clctxt.getServletClassName();
+ String packageName = clctxt.getServletPackageName();
+
+ String thisServletName;
+ if ("".equals(packageName)) {
+ thisServletName = className;
+ } else {
+ thisServletName = packageName + '.' + className;
+ }
+
+ if (servletout != null) {
+ servletout.write("\n <servlet>\n <servlet-name>");
+ servletout.write(thisServletName);
+ servletout.write("</servlet-name>\n <servlet-class>");
+ servletout.write(thisServletName);
+ servletout.write("</servlet-class>\n </servlet>\n");
+ }
+ if (mappingout != null) {
+ mappingout.write("\n <servlet-mapping>\n <servlet-name>");
+ mappingout.write(thisServletName);
+ mappingout.write("</servlet-name>\n <url-pattern>");
+ mappingout.write(file.replace('\\', '/'));
+ mappingout.write("</url-pattern>\n </servlet-mapping>\n");
+
+ }
+ }
+
+ private void processFile(String file)
+ throws JasperException
+ {
+ if (log.isDebugEnabled()) {
+ log.debug("Processing file: " + file);
+ }
+
+ ClassLoader originalClassLoader = null;
+
+ try {
+ // set up a scratch/output dir if none is provided
+ if (scratchDir == null) {
+ String temp = System.getProperty("java.io.tmpdir");
+ if (temp == null) {
+ temp = "";
+ }
+ scratchDir = new File(new File(temp).getAbsolutePath());
+ }
+
+ String jspUri=file.replace('\\','/');
+ JspCompilationContext clctxt = new JspCompilationContext
+ ( jspUri, false, this, context, null, rctxt );
+
+ /* Override the defaults */
+ if ((targetClassName != null) && (targetClassName.length() > 0)) {
+ clctxt.setServletClassName(targetClassName);
+ targetClassName = null;
+ }
+ if (targetPackage != null) {
+ clctxt.setServletPackageName(targetPackage);
+ }
+
+ originalClassLoader = Thread.currentThread().getContextClassLoader();
+ if( loader==null ) {
+ initClassLoader( clctxt );
+ }
+ Thread.currentThread().setContextClassLoader(loader);
+
+ clctxt.setClassLoader(loader);
+ clctxt.setClassPath(classPath);
+
+ Compiler clc = clctxt.createCompiler();
+
+ // If compile is set, generate both .java and .class, if
+ // .jsp file is newer than .class file;
+ // Otherwise only generate .java, if .jsp file is newer than
+ // the .java file
+ if( clc.isOutDated(compile) ) {
+ if (log.isDebugEnabled()) {
+ log.debug(jspUri + " is out dated, compiling...");
+ }
+
+ clc.compile(compile, true);
+ }
+
+ // Generate mapping
+ generateWebMapping( file, clctxt );
+ if ( showSuccess ) {
+ log.info( "Built File: " + file );
+ }
+
+ this.sourceCode = clctxt.getSourceCode();
+
+ } catch (JasperException je) {
+ Throwable rootCause = je;
+ while (rootCause instanceof JasperException
+ && ((JasperException) rootCause).getRootCause() != null) {
+ rootCause = ((JasperException) rootCause).getRootCause();
+ }
+ if (rootCause != je) {
+ log.error(Localizer.getMessage("jspc.error.generalException",
+ file),
+ rootCause);
+ }
+
+ // Bugzilla 35114.
+ if(getFailOnError()) {
+ throw je;
+ } else {
+ log.error(je.getMessage(), je);;
+ }
+
+ } catch (Exception e) {
+ if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) {
+ log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist",
+ e.getMessage()));
+ }
+ throw new JasperException(e);
+ } finally {
+ if(originalClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(originalClassLoader);
+ }
+ }
+ }
+
+
+ /**
+ * Executes the compilation.
+ *
+ * @throws JasperException If an error occurs
+ */
+ public void execute() throws JasperException {
+ if(log.isDebugEnabled()) {
+ log.debug("execute() starting for " + pages.size() + " pages.");
+ }
+
+ try {
+ if( context==null ) {
+ initServletContext();
+ }
+
+ initWebXml();
+
+ Iterator iter = pages.iterator();
+ while (iter.hasNext()) {
+ String nextjsp = iter.next().toString();
+
+ processFile(nextjsp);
+ }
+
+ completeWebXml();
+ }catch (JasperException je) {
+ Throwable rootCause = je;
+ while (rootCause instanceof JasperException
+ && ((JasperException) rootCause).getRootCause() != null) {
+ rootCause = ((JasperException) rootCause).getRootCause();
+ }
+ if (rootCause != je) {
+ rootCause.printStackTrace();
+ }
+ throw je;
+ } finally {
+ if (loader != null) {
+ LogFactory.release(loader);
+ }
+ }
+ }
+
+ // ==================== Private utility methods ====================
+
+ private String nextArg() {
+ if ((argPos >= args.length)
+ || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) {
+ return null;
+ } else {
+ return args[argPos++];
+ }
+ }
+
+ private String nextFile() {
+ if (fullstop) argPos++;
+ if (argPos >= args.length) {
+ return null;
+ } else {
+ return args[argPos++];
+ }
+ }
+
+ private void initWebXml() {
+ try {
+ if (webxmlLevel >= INC_WEBXML) {
+ File fmapings = new File(webxmlFile);
+ mapout = new FileWriter(fmapings);
+ servletout = new CharArrayWriter();
+ mappingout = new CharArrayWriter();
+ } else {
+ mapout = null;
+ servletout = null;
+ mappingout = null;
+ }
+ if (webxmlLevel >= ALL_WEBXML) {
+ mapout.write(Localizer.getMessage("jspc.webxml.header"));
+ mapout.flush();
+ } else if ((webxmlLevel>= INC_WEBXML)) {
+ mapout.write(Localizer.getMessage("jspc.webinc.header"));
+ mapout.flush();
+ }
+ } catch (IOException ioe) {
+ mapout = null;
+ servletout = null;
+ mappingout = null;
+ }
+ }
+
+ private void completeWebXml() {
+ if (mapout != null) {
+ try {
+ servletout.writeTo(mapout);
+ mappingout.writeTo(mapout);
+ if (webxmlLevel >= ALL_WEBXML) {
+ mapout.write(Localizer.getMessage("jspc.webxml.footer"));
+ } else if ((webxmlLevel >= INC_WEBXML)) {
+ mapout.write(Localizer.getMessage("jspc.webinc.footer"));
+ }
+ mapout.close();
+ } catch (IOException ioe) {
+ // noting to do if it fails since we are done with it
+ }
+ }
+ }
+
+ private void initServletContext() {
+
+ context =new JspCServletContext
+ (new PrintWriter(System.out),
+ classLoaderInterface);
+ tldLocationsCache = new TldLocationsCache(context, true);
+
+ rctxt = new JspRuntimeContext(context, this);
+ jspConfig = new JspConfig(context);
+ tagPluginManager = new TagPluginManager(context);
+ }
+
+ /**
+ * Initializes the classloader as/if needed for the given
+ * compilation context.
+ *
+ * @param clctxt The compilation context
+ * @throws IOException If an error occurs
+ */
+ private void initClassLoader(JspCompilationContext clctxt)
+ throws IOException {
+
+ classPath = getClassPath();
+
+ ClassLoader jspcLoader = getClass().getClassLoader();
+ // Turn the classPath into URLs
+ ArrayList urls = new ArrayList();
+ StringTokenizer tokenizer = new StringTokenizer(classPath,
+ File.pathSeparator);
+ while (tokenizer.hasMoreTokens()) {
+ String path = tokenizer.nextToken();
+ try {
+ File libFile = new File(path);
+ urls.add(libFile.toURL());
+ } catch (IOException ioe) {
+ // Failing a toCanonicalPath on a file that
+ // exists() should be a JVM regression test,
+ // therefore we have permission to freak uot
+ throw new RuntimeException(ioe.toString());
+ }
+ }
+
+ //TODO: add .tld files to the URLCLassLoader
+
+ URL urlsA[]=new URL[urls.size()];
+ urls.toArray(urlsA);
+ loader = new URLClassLoader(urlsA, this.getClass().getClassLoader());
+
+ }
+
+ /**
+ * Resolves the relative or absolute pathname correctly
+ * in both Ant and command-line situations. If Ant launched
+ * us, we should use the basedir of the current project
+ * to resolve relative paths.
+ *
+ * See Bugzilla 35571.
+ *
+ * @param s The file
+ * @return The file resolved
+ */
+ protected File resolveFile(final String s) {
+ //TODO: what to do with this
+ return new File(s);
+ }
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/JspCompilationContext.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/JspCompilationContext.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/JspCompilationContext.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/JspCompilationContext.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,616 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.servlet.jsp.tagext.TagInfo;
+
+import org.apache.struts2.jasper.compiler.Compiler;
+import org.apache.struts2.jasper.compiler.JspRuntimeContext;
+import org.apache.struts2.jasper.compiler.JspUtil;
+import org.apache.struts2.jasper.compiler.Localizer;
+import org.apache.struts2.jasper.compiler.ServletWriter;
+import org.apache.struts2.jasper.servlet.JasperLoader;
+import org.apache.struts2.jasper.servlet.JspServletWrapper;
+
+/**
+ * A place holder for various things that are used through out the JSP
+ * engine. This is a per-request/per-context data structure. Some of
+ * the instance variables are set at different points.
+ *
+ * Most of the path-related stuff is here - mangling names, versions, dirs,
+ * loading resources and dealing with uris.
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Pierre Delisle
+ * @author Costin Manolache
+ * @author Kin-man Chung
+ */
+public class JspCompilationContext {
+
+ protected org.apache.commons.logging.Log log =
+ org.apache.commons.logging.LogFactory.getLog(JspCompilationContext.class);
+
+ private Hashtable tagFileJarUrls;
+ private boolean isPackagedTagFile;
+
+ private String className;
+ private String jspUri;
+ private boolean isErrPage;
+ private String basePackageName;
+ private String derivedPackageName;
+ private String servletJavaFileName;
+ private String javaPath;
+ private String classFileName;
+ private String contentType;
+ private ServletWriter writer;
+ private Options options;
+ private JspServletWrapper jsw;
+ private Compiler jspCompiler;
+ private String classPath;
+
+
+ private ServletContext context;
+ private URLClassLoader loader;
+
+ private JspRuntimeContext rctxt;
+
+ private int removed = 0;
+
+ private URLClassLoader jspLoader;
+ private URL baseUrl;
+ private Class servletClass;
+
+ private boolean isTagFile;
+ private boolean protoTypeMode;
+ private TagInfo tagInfo;
+ private URL tagFileJarUrl;
+
+ private String sourceCode;
+
+ public String getSourceCode() {
+ return sourceCode;
+ }
+
+ public void setSourceCode(String sourceCode) {
+ this.sourceCode = sourceCode;
+ }
+
+ public JspCompilationContext(String jspUri,
+ boolean isErrPage,
+ Options options,
+ ServletContext context,
+ JspServletWrapper jsw,
+ JspRuntimeContext rctxt) {
+
+ this.jspUri = canonicalURI(jspUri);
+ this.isErrPage = isErrPage;
+ this.options = options;
+ this.jsw = jsw;
+ this.context = context;
+
+ this.rctxt = rctxt;
+ this.tagFileJarUrls = new Hashtable();
+ this.basePackageName = Constants.JSP_PACKAGE_NAME;
+ }
+
+ public JspCompilationContext(String tagfile,
+ TagInfo tagInfo,
+ Options options,
+ ServletContext context,
+ JspServletWrapper jsw,
+ JspRuntimeContext rctxt,
+ URL tagFileJarUrl) {
+ this(tagfile, false, options, context, jsw, rctxt);
+ this.isTagFile = true;
+ this.tagInfo = tagInfo;
+ this.tagFileJarUrl = tagFileJarUrl;
+ if (tagFileJarUrl != null) {
+ isPackagedTagFile = true;
+ }
+ }
+
+ /* ==================== Methods to override ==================== */
+
+ /** ---------- Class path and loader ---------- */
+
+ /**
+ * The classpath that is passed off to the Java compiler.
+ */
+ public String getClassPath() {
+ if( classPath != null )
+ return classPath;
+ return rctxt.getClassPath();
+ }
+
+ /**
+ * The classpath that is passed off to the Java compiler.
+ */
+ public void setClassPath(String classPath) {
+ this.classPath = classPath;
+ }
+
+ /**
+ * What class loader to use for loading classes while compiling
+ * this JSP?
+ */
+ public ClassLoader getClassLoader() {
+ if( loader != null )
+ return loader;
+ return rctxt.getParentClassLoader();
+ }
+
+ public void setClassLoader(URLClassLoader loader) {
+ this.loader = loader;
+ }
+
+ public ClassLoader getJspLoader() {
+ if( jspLoader == null ) {
+ jspLoader = new JasperLoader
+ (new URL[] {baseUrl},
+ getClassLoader(),
+ rctxt.getPermissionCollection(),
+ rctxt.getCodeSource());
+ }
+ return jspLoader;
+ }
+
+ /** ---------- Input/Output ---------- */
+
+ /**
+ * Create a "Compiler" object based on some init param data. This
+ * is not done yet. Right now we're just hardcoding the actual
+ * compilers that are created.
+ */
+ public Compiler createCompiler() throws JasperException {
+ jspCompiler = new CustomCompiler();
+ jspCompiler.init(this, jsw);
+ return jspCompiler;
+ }
+
+ private Compiler createCompiler(String className) {
+ Compiler compiler = null;
+ try {
+ compiler = (Compiler) Class.forName(className).newInstance();
+ } catch (Throwable t) {
+ if (log.isDebugEnabled()) {
+ log.debug(Localizer.getMessage("jsp.error.compiler"), t);
+ }
+ }
+ return compiler;
+ }
+
+ public Compiler getCompiler() {
+ return jspCompiler;
+ }
+
+ /** ---------- Access resources in the webapp ---------- */
+
+ /**
+ * Gets a resource as a stream, relative to the meanings of this
+ * context's implementation.
+ * @return a null if the resource cannot be found or represented
+ * as an InputStream.
+ */
+ public java.io.InputStream getResourceAsStream(String res) {
+ return context.getResourceAsStream(canonicalURI(res));
+ }
+
+
+ public URL getResource(String res) throws MalformedURLException {
+ return context.getResource(canonicalURI(res));
+ }
+
+ public Set getResourcePaths(String path) {
+ return context.getResourcePaths(canonicalURI(path));
+ }
+
+ /**
+ * Gets the actual path of a URI relative to the context of
+ * the compilation.
+ */
+ public String getRealPath(String path) {
+ if (context != null) {
+ return context.getRealPath(path);
+ }
+ return path;
+ }
+
+ /**
+ * Returns the tag-file-name-to-JAR-file map of this compilation unit,
+ * which maps tag file names to the JAR files in which the tag files are
+ * packaged.
+ *
+ * The map is populated when parsing the tag-file elements of the TLDs
+ * of any imported taglibs.
+ */
+ public Hashtable getTagFileJarUrls() {
+ return this.tagFileJarUrls;
+ }
+
+ /**
+ * Returns the JAR file in which the tag file for which this
+ * JspCompilationContext was created is packaged, or null if this
+ * JspCompilationContext does not correspond to a tag file, or if the
+ * corresponding tag file is not packaged in a JAR.
+ */
+ public URL getTagFileJarUrl() {
+ return this.tagFileJarUrl;
+ }
+
+ /* ==================== Common implementation ==================== */
+
+ /**
+ * Just the class name (does not include package name) of the
+ * generated class.
+ */
+ public String getServletClassName() {
+
+ if (className != null) {
+ return className;
+ }
+
+ if (isTagFile) {
+ className = tagInfo.getTagClassName();
+ int lastIndex = className.lastIndexOf('.');
+ if (lastIndex != -1) {
+ className = className.substring(lastIndex + 1);
+ }
+ } else {
+ int iSep = jspUri.lastIndexOf('/') + 1;
+ className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep));
+ }
+ return className;
+ }
+
+ public void setServletClassName(String className) {
+ this.className = className;
+ }
+
+ /**
+ * Path of the JSP URI. Note that this is not a file name. This is
+ * the context rooted URI of the JSP file.
+ */
+ public String getJspFile() {
+ return jspUri;
+ }
+
+ /**
+ * Are we processing something that has been declared as an
+ * errorpage?
+ */
+ public boolean isErrorPage() {
+ return isErrPage;
+ }
+
+ public void setErrorPage(boolean isErrPage) {
+ this.isErrPage = isErrPage;
+ }
+
+ public boolean isTagFile() {
+ return isTagFile;
+ }
+
+ public TagInfo getTagInfo() {
+ return tagInfo;
+ }
+
+ public void setTagInfo(TagInfo tagi) {
+ tagInfo = tagi;
+ }
+
+ /**
+ * True if we are compiling a tag file in prototype mode.
+ * ie we only generate codes with class for the tag handler with empty
+ * method bodies.
+ */
+ public boolean isPrototypeMode() {
+ return protoTypeMode;
+ }
+
+ public void setPrototypeMode(boolean pm) {
+ protoTypeMode = pm;
+ }
+
+ /**
+ * Package name for the generated class is make up of the base package
+ * name, which is user settable, and the derived package name. The
+ * derived package name directly mirrors the file heirachy of the JSP page.
+ */
+ public String getServletPackageName() {
+ if (isTagFile()) {
+ String className = tagInfo.getTagClassName();
+ int lastIndex = className.lastIndexOf('.');
+ String pkgName = "";
+ if (lastIndex != -1) {
+ pkgName = className.substring(0, lastIndex);
+ }
+ return pkgName;
+ } else {
+ return basePackageName;
+ }
+ }
+
+ private String getDerivedPackageName() {
+ if (derivedPackageName == null) {
+ int iSep = jspUri.lastIndexOf('/');
+ derivedPackageName = (iSep > 0) ?
+ JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : "";
+ }
+ return derivedPackageName;
+ }
+
+ /**
+ * The package name into which the servlet class is generated.
+ */
+ public void setServletPackageName(String servletPackageName) {
+ this.basePackageName = servletPackageName;
+ }
+
+ /**
+ * Full path name of the Java file into which the servlet is being
+ * generated.
+ */
+ public String getServletJavaFileName() {
+
+ if (servletJavaFileName == null) {
+ servletJavaFileName =
+ getServletClassName() + ".java";
+ }
+ return servletJavaFileName;
+ }
+
+ public void setServletJavaFileName(String servletJavaFileName) {
+ this.servletJavaFileName = servletJavaFileName;
+ }
+
+ /**
+ * Get hold of the Options object for this context.
+ */
+ public Options getOptions() {
+ return options;
+ }
+
+ public ServletContext getServletContext() {
+ return context;
+ }
+
+ public JspRuntimeContext getRuntimeContext() {
+ return rctxt;
+ }
+
+ /**
+ * Path of the Java file relative to the work directory.
+ */
+ public String getJavaPath() {
+
+ if (javaPath != null) {
+ return javaPath;
+ }
+
+ if (isTagFile()) {
+ String tagName = tagInfo.getTagClassName();
+ javaPath = tagName.replace('.', '/') + ".java";
+ } else {
+ javaPath = getServletPackageName().replace('.', '/') + '/' +
+ getServletClassName() + ".java";
+ }
+ return javaPath;
+ }
+
+ public String getClassFileName() {
+
+ if (classFileName == null) {
+ classFileName = getServletClassName() + ".class";
+ }
+ return classFileName;
+ }
+
+ /**
+ * Get the content type of this JSP.
+ *
+ * Content type includes content type and encoding.
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ /**
+ * Where is the servlet being generated?
+ */
+ public ServletWriter getWriter() {
+ return writer;
+ }
+
+ public void setWriter(ServletWriter writer) {
+ this.writer = writer;
+ }
+
+ /**
+ * Gets the 'location' of the TLD associated with the given taglib 'uri'.
+ *
+ * @return An array of two Strings: The first element denotes the real
+ * path to the TLD. If the path to the TLD points to a jar file, then the
+ * second element denotes the name of the TLD entry in the jar file.
+ * Returns null if the given uri is not associated with any tag library
+ * 'exposed' in the web application.
+ */
+ public String[] getTldLocation(String uri) throws JasperException {
+ String[] location =
+ getOptions().getTldLocationsCache().getLocation(uri);
+ return location;
+ }
+
+ /**
+ * Are we keeping generated code around?
+ */
+ public boolean keepGenerated() {
+ return getOptions().getKeepGenerated();
+ }
+
+ // ==================== Removal ====================
+
+ public void incrementRemoved() {
+ if (removed > 1) {
+ jspCompiler.removeGeneratedFiles();
+ if( rctxt != null )
+ rctxt.removeWrapper(jspUri);
+ }
+ removed++;
+ }
+
+ public boolean isRemoved() {
+ if (removed > 1 ) {
+ return true;
+ }
+ return false;
+ }
+
+ // ==================== Compile and reload ====================
+
+ public void compile() throws JasperException, FileNotFoundException {
+ createCompiler();
+ if (isPackagedTagFile || jspCompiler.isOutDated()) {
+ try {
+ jspLoader = null;
+ jspCompiler.compile();
+ jsw.setReload(true);
+ jsw.setCompilationException(null);
+ } catch (JasperException ex) {
+ // Cache compilation exception
+ jsw.setCompilationException(ex);
+ throw ex;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ JasperException je = new JasperException(
+ Localizer.getMessage("jsp.error.unable.compile"),
+ ex);
+ // Cache compilation exception
+ jsw.setCompilationException(je);
+ throw je;
+ }
+ }
+ }
+
+ // ==================== Manipulating the class ====================
+
+ public Class load()
+ throws JasperException, FileNotFoundException
+ {
+ try {
+ getJspLoader();
+
+ String name;
+ if (isTagFile()) {
+ name = tagInfo.getTagClassName();
+ } else {
+ name = getServletPackageName() + "." + getServletClassName();
+ }
+ servletClass = jspLoader.loadClass(name);
+ } catch (ClassNotFoundException cex) {
+ throw new JasperException(Localizer.getMessage("jsp.error.unable.load"),
+ cex);
+ } catch (Exception ex) {
+ throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"),
+ ex);
+ }
+ removed = 0;
+ return servletClass;
+ }
+
+ // ==================== Private methods ====================
+
+ static Object outputDirLock = new Object();
+
+ private static final boolean isPathSeparator(char c) {
+ return (c == '/' || c == '\\');
+ }
+
+ private static final String canonicalURI(String s) {
+ if (s == null) return null;
+ StringBuffer result = new StringBuffer();
+ final int len = s.length();
+ int pos = 0;
+ while (pos < len) {
+ char c = s.charAt(pos);
+ if ( isPathSeparator(c) ) {
+ /*
+ * multiple path separators.
+ * 'foo///bar' -> 'foo/bar'
+ */
+ while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) {
+ ++pos;
+ }
+
+ if (pos+1 < len && s.charAt(pos+1) == '.') {
+ /*
+ * a single dot at the end of the path - we are done.
+ */
+ if (pos+2 >= len) break;
+
+ switch (s.charAt(pos+2)) {
+ /*
+ * self directory in path
+ * foo/./bar -> foo/bar
+ */
+ case '/':
+ case '\\':
+ pos += 2;
+ continue;
+
+ /*
+ * two dots in a path: go back one hierarchy.
+ * foo/bar/../baz -> foo/baz
+ */
+ case '.':
+ // only if we have exactly _two_ dots.
+ if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) {
+ pos += 3;
+ int separatorPos = result.length()-1;
+ while (separatorPos >= 0 &&
+ ! isPathSeparator(result
+ .charAt(separatorPos))) {
+ --separatorPos;
+ }
+ if (separatorPos >= 0)
+ result.setLength(separatorPos);
+ continue;
+ }
+ }
+ }
+ }
+ result.append(c);
+ ++pos;
+ }
+ return result.toString();
+ }
+}
+
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/Options.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/Options.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/Options.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/Options.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.struts2.jasper.compiler.JspConfig;
+import org.apache.struts2.jasper.compiler.TagPluginManager;
+import org.apache.struts2.jasper.compiler.TldLocationsCache;
+
+/**
+ * A class to hold all init parameters specific to the JSP engine.
+ *
+ * @author Anil K. Vijendran
+ * @author Hans Bergsten
+ * @author Pierre Delisle
+ */
+public interface Options {
+
+ /**
+ * Returns true if Jasper issues a compilation error instead of a runtime
+ * Instantiation error if the class attribute specified in useBean action
+ * is invalid.
+ */
+ public boolean getErrorOnUseBeanInvalidClassAttribute();
+
+ /**
+ * Are we keeping generated code around?
+ */
+ public boolean getKeepGenerated();
+
+ /**
+ * Returns true if tag handler pooling is enabled, false otherwise.
+ */
+ public boolean isPoolingEnabled();
+
+ /**
+ * Are we supporting HTML mapped servlets?
+ */
+ public boolean getMappedFile();
+
+ /**
+ * Should errors be sent to client or thrown into stderr?
+ */
+ public boolean getSendErrorToClient();
+
+ /**
+ * Should we include debug information in compiled class?
+ */
+ public boolean getClassDebugInfo();
+
+ /**
+ * Background compile thread check interval in seconds
+ */
+ public int getCheckInterval();
+
+ /**
+ * Is Jasper being used in development mode?
+ */
+ public boolean getDevelopment();
+
+ /**
+ * Is the generation of SMAP info for JSR45 debugging suppressed?
+ */
+ public boolean isSmapSuppressed();
+
+ /**
+ * Indicates whether SMAP info for JSR45 debugging should be dumped to a
+ * file.
+ * Ignored is suppressSmap() is true
+ */
+ public boolean isSmapDumped();
+
+ /**
+ * Should white spaces between directives or actions be trimmed?
+ */
+ public boolean getTrimSpaces();
+
+ /**
+ * Class ID for use in the plugin tag when the browser is IE.
+ */
+ public String getIeClassId();
+
+ /**
+ * What is my scratch dir?
+ */
+ public File getScratchDir();
+
+ /**
+ * What classpath should I use while compiling the servlets
+ * generated from JSP files?
+ */
+ public String getClassPath();
+
+ /**
+ * Compiler to use.
+ */
+ public String getCompiler();
+
+ /**
+ * The compiler target VM, e.g. 1.1, 1.2, 1.3, 1.4, or 1.5.
+ */
+ public String getCompilerTargetVM();
+
+ /**
+ * Compiler source VM, e.g. 1.3, 1.4, or 1.5.
+ */
+ public String getCompilerSourceVM();
+
+ /**
+ * The cache for the location of the TLD's
+ * for the various tag libraries 'exposed'
+ * by the web application.
+ * A tag library is 'exposed' either explicitely in
+ * web.xml or implicitely via the uri tag in the TLD
+ * of a taglib deployed in a jar file (WEB-INF/lib).
+ *
+ * @return the instance of the TldLocationsCache
+ * for the web-application.
+ */
+ public TldLocationsCache getTldLocationsCache();
+
+ /**
+ * Java platform encoding to generate the JSP
+ * page servlet.
+ */
+ public String getJavaEncoding();
+
+ /**
+ * boolean flag to tell Ant whether to fork JSP page compilations.
+ */
+ public boolean getFork();
+
+ /**
+ * Obtain JSP configuration informantion specified in web.xml.
+ */
+ public JspConfig getJspConfig();
+
+ /**
+ * Is generation of X-Powered-By response header enabled/disabled?
+ */
+ public boolean isXpoweredBy();
+
+ /**
+ * Obtain a Tag Plugin Manager
+ */
+ public TagPluginManager getTagPluginManager();
+
+ /**
+ * Are Text strings to be generated as char arrays?
+ */
+ public boolean genStringAsCharArray();
+
+ /**
+ * Modification test interval.
+ */
+ public int getModificationTestInterval();
+
+ /**
+ * Is caching enabled (used for precompilation).
+ */
+ public boolean isCaching();
+
+ /**
+ * The web-application wide cache for the returned TreeNode
+ * by parseXMLDocument in TagLibraryInfoImpl.parseTLD,
+ * if isCaching returns true.
+ *
+ * @return the Map(String uri, TreeNode tld) instance.
+ */
+ public Map getCache();
+
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/BeanRepository.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/BeanRepository.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/BeanRepository.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/BeanRepository.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.jasper.compiler;
+
+
+import java.util.Vector;
+import java.util.Hashtable;
+
+import org.apache.struts2.jasper.JasperException;
+
+/**
+ * Repository of {page, request, session, application}-scoped beans
+ *
+ * @author Mandar Raje
+ */
+class BeanRepository {
+
+ private Vector sessionBeans;
+ private Vector pageBeans;
+ private Vector appBeans;
+ private Vector requestBeans;
+ private Hashtable beanTypes;
+ private ClassLoader loader;
+ private ErrorDispatcher errDispatcher;
+
+ /*
+ * Constructor.
+ */
+ public BeanRepository(ClassLoader loader, ErrorDispatcher err) {
+
+ this.loader = loader;
+ this.errDispatcher = err;
+
+ sessionBeans = new Vector(11);
+ pageBeans = new Vector(11);
+ appBeans = new Vector(11);
+ requestBeans = new Vector(11);
+ beanTypes = new Hashtable();
+ }
+
+ public void addBean(Node.UseBean n, String s, String type, String scope)
+ throws JasperException {
+
+ if (scope == null || scope.equals("page")) {
+ pageBeans.addElement(s);
+ } else if (scope.equals("request")) {
+ requestBeans.addElement(s);
+ } else if (scope.equals("session")) {
+ sessionBeans.addElement(s);
+ } else if (scope.equals("application")) {
+ appBeans.addElement(s);
+ } else {
+ errDispatcher.jspError(n, "jsp.error.usebean.badScope");
+ }
+
+ putBeanType(s, type);
+ }
+
+ public Class getBeanType(String bean) throws JasperException {
+ Class clazz = null;
+ try {
+ clazz = loader.loadClass ((String)beanTypes.get(bean));
+ } catch (ClassNotFoundException ex) {
+ throw new JasperException (ex);
+ }
+ return clazz;
+ }
+
+ public boolean checkVariable (String bean) {
+ // XXX Not sure if this is the correct way.
+ // After pageContext is finalised this will change.
+ return (checkPageBean(bean) || checkSessionBean(bean) ||
+ checkRequestBean(bean) || checkApplicationBean(bean));
+ }
+
+
+ private void putBeanType(String bean, String type) {
+ beanTypes.put (bean, type);
+ }
+
+ private boolean checkPageBean (String s) {
+ return pageBeans.contains (s);
+ }
+
+ private boolean checkRequestBean (String s) {
+ return requestBeans.contains (s);
+ }
+
+ private boolean checkSessionBean (String s) {
+ return sessionBeans.contains (s);
+ }
+
+ private boolean checkApplicationBean (String s) {
+ return appBeans.contains (s);
+ }
+
+}
+
+
+
+
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Collector.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Collector.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Collector.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Collector.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.compiler;
+
+import org.apache.struts2.jasper.JasperException;
+
+/**
+ * Collect info about the page and nodes, and make them availabe through
+ * the PageInfo object.
+ *
+ * @author Kin-man Chung
+ * @author Mark Roth
+ */
+
+class Collector {
+
+ /**
+ * A visitor for collecting information on the page and the body of
+ * the custom tags.
+ */
+ static class CollectVisitor extends Node.Visitor {
+
+ private boolean scriptingElementSeen = false;
+ private boolean usebeanSeen = false;
+ private boolean includeActionSeen = false;
+ private boolean paramActionSeen = false;
+ private boolean setPropertySeen = false;
+ private boolean hasScriptingVars = false;
+
+ public void visit(Node.ParamAction n) throws JasperException {
+ if (n.getValue().isExpression()) {
+ scriptingElementSeen = true;
+ }
+ paramActionSeen = true;
+ }
+
+ public void visit(Node.IncludeAction n) throws JasperException {
+ if (n.getPage().isExpression()) {
+ scriptingElementSeen = true;
+ }
+ includeActionSeen = true;
+ visitBody(n);
+ }
+
+ public void visit(Node.ForwardAction n) throws JasperException {
+ if (n.getPage().isExpression()) {
+ scriptingElementSeen = true;
+ }
+ visitBody(n);
+ }
+
+ public void visit(Node.SetProperty n) throws JasperException {
+ if (n.getValue() != null && n.getValue().isExpression()) {
+ scriptingElementSeen = true;
+ }
+ setPropertySeen = true;
+ }
+
+ public void visit(Node.UseBean n) throws JasperException {
+ if (n.getBeanName() != null && n.getBeanName().isExpression()) {
+ scriptingElementSeen = true;
+ }
+ usebeanSeen = true;
+ visitBody(n);
+ }
+
+ public void visit(Node.PlugIn n) throws JasperException {
+ if (n.getHeight() != null && n.getHeight().isExpression()) {
+ scriptingElementSeen = true;
+ }
+ if (n.getWidth() != null && n.getWidth().isExpression()) {
+ scriptingElementSeen = true;
+ }
+ visitBody(n);
+ }
+
+ public void visit(Node.CustomTag n) throws JasperException {
+ // Check to see what kinds of element we see as child elements
+ checkSeen( n.getChildInfo(), n );
+ }
+
+ /**
+ * Check all child nodes for various elements and update the given
+ * ChildInfo object accordingly. Visits body in the process.
+ */
+ private void checkSeen( Node.ChildInfo ci, Node n )
+ throws JasperException
+ {
+ // save values collected so far
+ boolean scriptingElementSeenSave = scriptingElementSeen;
+ scriptingElementSeen = false;
+ boolean usebeanSeenSave = usebeanSeen;
+ usebeanSeen = false;
+ boolean includeActionSeenSave = includeActionSeen;
+ includeActionSeen = false;
+ boolean paramActionSeenSave = paramActionSeen;
+ paramActionSeen = false;
+ boolean setPropertySeenSave = setPropertySeen;
+ setPropertySeen = false;
+ boolean hasScriptingVarsSave = hasScriptingVars;
+ hasScriptingVars = false;
+
+ // Scan attribute list for expressions
+ if( n instanceof Node.CustomTag ) {
+ Node.CustomTag ct = (Node.CustomTag)n;
+ Node.JspAttribute[] attrs = ct.getJspAttributes();
+ for (int i = 0; attrs != null && i < attrs.length; i++) {
+ if (attrs[i].isExpression()) {
+ scriptingElementSeen = true;
+ break;
+ }
+ }
+ }
+
+ visitBody(n);
+
+ if( (n instanceof Node.CustomTag) && !hasScriptingVars) {
+ Node.CustomTag ct = (Node.CustomTag)n;
+ hasScriptingVars = ct.getVariableInfos().length > 0 ||
+ ct.getTagVariableInfos().length > 0;
+ }
+
+ // Record if the tag element and its body contains any scriptlet.
+ ci.setScriptless(! scriptingElementSeen);
+ ci.setHasUseBean(usebeanSeen);
+ ci.setHasIncludeAction(includeActionSeen);
+ ci.setHasParamAction(paramActionSeen);
+ ci.setHasSetProperty(setPropertySeen);
+ ci.setHasScriptingVars(hasScriptingVars);
+
+ // Propagate value of scriptingElementSeen up.
+ scriptingElementSeen = scriptingElementSeen || scriptingElementSeenSave;
+ usebeanSeen = usebeanSeen || usebeanSeenSave;
+ setPropertySeen = setPropertySeen || setPropertySeenSave;
+ includeActionSeen = includeActionSeen || includeActionSeenSave;
+ paramActionSeen = paramActionSeen || paramActionSeenSave;
+ hasScriptingVars = hasScriptingVars || hasScriptingVarsSave;
+ }
+
+ public void visit(Node.JspElement n) throws JasperException {
+ if (n.getNameAttribute().isExpression())
+ scriptingElementSeen = true;
+
+ Node.JspAttribute[] attrs = n.getJspAttributes();
+ for (int i = 0; i < attrs.length; i++) {
+ if (attrs[i].isExpression()) {
+ scriptingElementSeen = true;
+ break;
+ }
+ }
+ visitBody(n);
+ }
+
+ public void visit(Node.JspBody n) throws JasperException {
+ checkSeen( n.getChildInfo(), n );
+ }
+
+ public void visit(Node.NamedAttribute n) throws JasperException {
+ checkSeen( n.getChildInfo(), n );
+ }
+
+ public void visit(Node.Declaration n) throws JasperException {
+ scriptingElementSeen = true;
+ }
+
+ public void visit(Node.Expression n) throws JasperException {
+ scriptingElementSeen = true;
+ }
+
+ public void visit(Node.Scriptlet n) throws JasperException {
+ scriptingElementSeen = true;
+ }
+
+ public void updatePageInfo(PageInfo pageInfo) {
+ pageInfo.setScriptless(! scriptingElementSeen);
+ }
+ }
+
+
+ public static void collect(Compiler compiler, Node.Nodes page)
+ throws JasperException {
+
+ CollectVisitor collectVisitor = new CollectVisitor();
+ page.visit(collectVisitor);
+ collectVisitor.updatePageInfo(compiler.getPageInfo());
+
+ }
+}
+