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/09/28 03:55:35 UTC

svn commit: r819444 [6/27] - in /struts/struts2/trunk/plugins/embeddedjsp: ./ src/main/java/org/apache/struts2/el/ src/main/java/org/apache/struts2/el/lang/ src/main/java/org/apache/struts2/el/parser/ src/main/java/org/apache/struts2/el/util/ src/main/...

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/ConcurrentCache.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/ConcurrentCache.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/ConcurrentCache.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/ConcurrentCache.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,55 @@
+/*
+ * 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.el.util;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+public final class ConcurrentCache<K,V> {
+
+    private final int size;
+
+    private final Map<K,V> eden;
+
+    private final Map<K,V> longterm;
+
+    public ConcurrentCache(int size) {
+        this.size = size;
+        this.eden = new ConcurrentHashMap<K,V>(size);
+        this.longterm = new WeakHashMap<K,V>(size);
+    }
+
+    public V get(K k) {
+        V v = this.eden.get(k);
+        if (v == null) {
+            v = this.longterm.get(k);
+            if (v != null) {
+                this.eden.put(k, v);
+            }
+        }
+        return v;
+    }
+
+    public void put(K k, V v) {
+        if (this.eden.size() >= size) {
+            this.longterm.putAll(this.eden);
+            this.eden.clear();
+        }
+        this.eden.put(k, v);
+    }
+}

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/MessageFactory.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/MessageFactory.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/MessageFactory.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/MessageFactory.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,70 @@
+/*
+ * 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.el.util;
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ * @author Jacob Hookom [jacob@hookom.net]
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: rjung $
+ */
+public final class MessageFactory {
+
+    protected final static ResourceBundle bundle = ResourceBundle
+            .getBundle("org.apache.el.Messages");
+    /**
+     * 
+     */
+    public MessageFactory() {
+        super();
+    }
+
+    public static String get(final String key) {
+        return bundle.getString(key);
+    }
+
+    public static String get(final String key, final Object obj0) {
+        return getArray(key, new Object[] { obj0 });
+    }
+
+    public static String get(final String key, final Object obj0,
+            final Object obj1) {
+        return getArray(key, new Object[] { obj0, obj1 });
+    }
+
+    public static String get(final String key, final Object obj0,
+            final Object obj1, final Object obj2) {
+        return getArray(key, new Object[] { obj0, obj1, obj2 });
+    }
+
+    public static String get(final String key, final Object obj0,
+            final Object obj1, final Object obj2, final Object obj3) {
+        return getArray(key, new Object[] { obj0, obj1, obj2, obj3 });
+    }
+
+    public static String get(final String key, final Object obj0,
+            final Object obj1, final Object obj2, final Object obj3,
+            final Object obj4) {
+        return getArray(key, new Object[] { obj0, obj1, obj2, obj3, obj4 });
+    }
+
+    public static String getArray(final String key, final Object[] objA) {
+        return MessageFormat.format(bundle.getString(key), objA);
+    }
+
+}

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/ReflectionUtil.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/ReflectionUtil.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/ReflectionUtil.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/el/util/ReflectionUtil.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,184 @@
+/*
+ * 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.el.util;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import javax.el.ELException;
+import javax.el.MethodNotFoundException;
+import javax.el.PropertyNotFoundException;
+
+import org.apache.struts2.el.lang.ELSupport;
+
+
+/**
+ * Utilities for Managing Serialization and Reflection
+ * 
+ * @author Jacob Hookom [jacob@hookom.net]
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: markt $
+ */
+public class ReflectionUtil {
+
+    protected static final String[] EMPTY_STRING = new String[0];
+
+    protected static final String[] PRIMITIVE_NAMES = new String[] { "boolean",
+            "byte", "char", "double", "float", "int", "long", "short", "void" };
+
+    protected static final Class[] PRIMITIVES = new Class[] { boolean.class,
+            byte.class, char.class, double.class, float.class, int.class,
+            long.class, short.class, Void.TYPE };
+
+    /**
+     * 
+     */
+    private ReflectionUtil() {
+        super();
+    }
+
+    public static Class forName(String name) throws ClassNotFoundException {
+        if (null == name || "".equals(name)) {
+            return null;
+        }
+        Class c = forNamePrimitive(name);
+        if (c == null) {
+            if (name.endsWith("[]")) {
+                String nc = name.substring(0, name.length() - 2);
+                c = Class.forName(nc, true, Thread.currentThread().getContextClassLoader());
+                c = Array.newInstance(c, 0).getClass();
+            } else {
+                c = Class.forName(name, true, Thread.currentThread().getContextClassLoader());
+            }
+        }
+        return c;
+    }
+
+    protected static Class forNamePrimitive(String name) {
+        if (name.length() <= 8) {
+            int p = Arrays.binarySearch(PRIMITIVE_NAMES, name);
+            if (p >= 0) {
+                return PRIMITIVES[p];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Converts an array of Class names to Class types
+     * @param s
+     * @return
+     * @throws ClassNotFoundException
+     */
+    public static Class[] toTypeArray(String[] s) throws ClassNotFoundException {
+        if (s == null)
+            return null;
+        Class[] c = new Class[s.length];
+        for (int i = 0; i < s.length; i++) {
+            c[i] = forName(s[i]);
+        }
+        return c;
+    }
+
+    /**
+     * Converts an array of Class types to Class names
+     * @param c
+     * @return
+     */
+    public static String[] toTypeNameArray(Class[] c) {
+        if (c == null)
+            return null;
+        String[] s = new String[c.length];
+        for (int i = 0; i < c.length; i++) {
+            s[i] = c[i].getName();
+        }
+        return s;
+    }
+
+    /**
+     * Returns a method based on the criteria
+     * @param base the object that owns the method
+     * @param property the name of the method
+     * @param paramTypes the parameter types to use
+     * @return the method specified
+     * @throws MethodNotFoundException
+     */
+    public static Method getMethod(Object base, Object property,
+            Class[] paramTypes) throws MethodNotFoundException {
+        if (base == null || property == null) {
+            throw new MethodNotFoundException(MessageFactory.get(
+                    "error.method.notfound", base, property,
+                    paramString(paramTypes)));
+        }
+
+        String methodName = (property instanceof String) ? (String) property
+                : property.toString();
+
+        Method method = null;
+        try {
+            method = base.getClass().getMethod(methodName, paramTypes);
+        } catch (NoSuchMethodException nsme) {
+            throw new MethodNotFoundException(MessageFactory.get(
+                    "error.method.notfound", base, property,
+                    paramString(paramTypes)));
+        }
+        return method;
+    }
+
+    protected static final String paramString(Class[] types) {
+        if (types != null) {
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < types.length; i++) {
+                sb.append(types[i].getName()).append(", ");
+            }
+            if (sb.length() > 2) {
+                sb.setLength(sb.length() - 2);
+            }
+            return sb.toString();
+        }
+        return null;
+    }
+
+    /**
+     * @param base
+     * @param property
+     * @return
+     * @throws ELException
+     * @throws PropertyNotFoundException
+     */
+    public static PropertyDescriptor getPropertyDescriptor(Object base,
+            Object property) throws ELException, PropertyNotFoundException {
+        String name = ELSupport.coerceToString(property);
+        PropertyDescriptor p = null;
+        try {
+            PropertyDescriptor[] desc = Introspector.getBeanInfo(
+                    base.getClass()).getPropertyDescriptors();
+            for (int i = 0; i < desc.length; i++) {
+                if (desc[i].getName().equals(name)) {
+                    return desc[i];
+                }
+            }
+        } catch (IntrospectionException ie) {
+            throw new ELException(ie);
+        }
+        throw new PropertyNotFoundException(MessageFactory.get(
+                "error.property.notfound", base, name));
+    }
+}

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/Constants.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/Constants.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/Constants.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/Constants.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,208 @@
+/*
+ * 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;
+
+
+/**
+ * Some constants and other global data that are used by the compiler and the runtime.
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Shawn Bayern
+ * @author Mark Roth
+ */
+public class Constants {
+    
+    /**
+     * The base class of the generated servlets. 
+     */
+    public static final String JSP_SERVLET_BASE = 
+        System.getProperty("org.apache.struts2.jasper.Constants.JSP_SERVLET_BASE", "org.apache.struts2.jasper.runtime.HttpJspBase");
+
+    /**
+     * _jspService is the name of the method that is called by 
+     * HttpJspBase.service(). This is where most of the code generated
+     * from JSPs go.
+     */
+    public static final String SERVICE_METHOD_NAME = 
+        System.getProperty("org.apache.struts2.jasper.Constants.SERVICE_METHOD_NAME", "_jspService");
+
+    /**
+     * Default servlet content type.
+     */
+    public static final String SERVLET_CONTENT_TYPE = "text/html";
+
+    /**
+     * These classes/packages are automatically imported by the
+     * generated code. 
+     */
+    public static final String[] STANDARD_IMPORTS = { 
+	"javax.servlet.*", 
+	"javax.servlet.http.*", 
+	"javax.servlet.jsp.*"
+    };
+
+    /**
+     * ServletContext attribute for classpath. This is tomcat specific. 
+     * Other servlet engines may choose to support this attribute if they 
+     * want to have this JSP engine running on them. 
+     */
+    public static final String SERVLET_CLASSPATH = 
+        System.getProperty("org.apache.struts2.jasper.Constants.SERVLET_CLASSPATH", "org.apache.catalina.jsp_classpath");
+
+    /**
+     * Request attribute for <code>&lt;jsp-file&gt;</code> element of a
+     * servlet definition.  If present on a request, this overrides the
+     * value returned by <code>request.getServletPath()</code> to select
+     * the JSP page to be executed.
+     */
+    public static final String JSP_FILE = 
+        System.getProperty("org.apache.struts2.jasper.Constants.JSP_FILE", "org.apache.catalina.jsp_file");
+
+
+    /**
+     * Default size of the JSP buffer.
+     */
+    public static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
+
+    /**
+     * Default size for the tag buffers.
+     */
+    public static final int DEFAULT_TAG_BUFFER_SIZE = 512;
+
+    /**
+     * Default tag handler pool size.
+     */
+    public static final int MAX_POOL_SIZE = 5;
+
+    /**
+     * The query parameter that causes the JSP engine to just
+     * pregenerated the servlet but not invoke it. 
+     */
+    public static final String PRECOMPILE = 
+        System.getProperty("org.apache.struts2.jasper.Constants.PRECOMPILE", "jsp_precompile");
+
+    /**
+     * The default package name for compiled jsp pages.
+     */
+    public static final String JSP_PACKAGE_NAME = 
+        System.getProperty("org.apache.struts2.jasper.Constants.JSP_PACKAGE_NAME", "org.apache.jsp");
+
+    /**
+     * The default package name for tag handlers generated from tag files
+     */
+    public static final String TAG_FILE_PACKAGE_NAME = 
+        System.getProperty("org.apache.struts2.jasper.Constants.TAG_FILE_PACKAGE_NAME", "org.apache.jsp.tag");
+
+    /**
+     * Servlet context and request attributes that the JSP engine
+     * uses. 
+     */
+    public static final String INC_SERVLET_PATH = "javax.servlet.include.servlet_path";
+    public static final String TMP_DIR = "javax.servlet.context.tempdir";
+
+    // Must be kept in sync with org/apache/catalina/Globals.java
+    public static final String ALT_DD_ATTR = 
+        System.getProperty("org.apache.struts2.jasper.Constants.ALT_DD_ATTR", "org.apache.catalina.deploy.alt_dd");
+
+    /**
+     * Public Id and the Resource path (of the cached copy) 
+     * of the DTDs for tag library descriptors. 
+     */
+    public static final String TAGLIB_DTD_PUBLIC_ID_11 = 
+	"-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN";
+    public static final String TAGLIB_DTD_RESOURCE_PATH_11 = 
+	"/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd";
+    public static final String TAGLIB_DTD_PUBLIC_ID_12 = 
+	"-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN";
+    public static final String TAGLIB_DTD_RESOURCE_PATH_12 = 
+	"/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd";
+
+    /**
+     * Public Id and the Resource path (of the cached copy) 
+     * of the DTDs for web application deployment descriptors
+     */
+    public static final String WEBAPP_DTD_PUBLIC_ID_22 = 
+	"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
+    public static final String WEBAPP_DTD_RESOURCE_PATH_22 = 
+	"/javax/servlet/resources/web-app_2_2.dtd";
+    public static final String WEBAPP_DTD_PUBLIC_ID_23 = 
+	"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN";
+    public static final String WEBAPP_DTD_RESOURCE_PATH_23 = 
+	"/javax/servlet/resources/web-app_2_3.dtd";
+
+    /**
+     * List of the Public IDs that we cache, and their
+     * associated location. This is used by 
+     * an EntityResolver to return the location of the
+     * cached copy of a DTD.
+     */
+    public static final String[] CACHED_DTD_PUBLIC_IDS = {
+	TAGLIB_DTD_PUBLIC_ID_11,
+	TAGLIB_DTD_PUBLIC_ID_12,
+	WEBAPP_DTD_PUBLIC_ID_22,
+	WEBAPP_DTD_PUBLIC_ID_23,
+    };
+    public static final String[] CACHED_DTD_RESOURCE_PATHS = {
+	TAGLIB_DTD_RESOURCE_PATH_11,
+	TAGLIB_DTD_RESOURCE_PATH_12,
+	WEBAPP_DTD_RESOURCE_PATH_22,
+	WEBAPP_DTD_RESOURCE_PATH_23,
+    };
+    
+    /**
+     * Default URLs to download the pluging for Netscape and IE.
+     */
+    public static final String NS_PLUGIN_URL = 
+        "http://java.sun.com/products/plugin/";
+
+    public static final String IE_PLUGIN_URL = 
+        "http://java.sun.com/products/plugin/1.2.2/jinstall-1_2_2-win.cab#Version=1,2,2,0";
+
+    /**
+     * Prefix to use for generated temporary variable names
+     */
+    public static final String TEMP_VARIABLE_NAME_PREFIX =
+        System.getProperty("org.apache.struts2.jasper.Constants.TEMP_VARIABLE_NAME_PREFIX", "_jspx_temp");
+
+    /**
+     * A replacement char for "\$".
+     * XXX This is a hack to avoid changing EL interpreter to recognize "\$"
+     * @deprecated
+     */
+    public static final char ESC = '\u001b';
+    /**
+     * @deprecated
+     */
+    public static final String ESCStr = "'\\u001b'";
+
+    /**
+     * Has security been turned on?
+     */
+    public static final boolean IS_SECURITY_ENABLED = 
+        (System.getSecurityManager() != null);
+
+    /**
+     * The name of the path parameter used to pass the session identifier
+     * back and forth with the client.
+     */
+    public static final String SESSION_PARAMETER_NAME =
+        System.getProperty("org.apache.catalina.SESSION_PARAMETER_NAME",
+                "jsessionid");
+
+}

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/CustomCompiler.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/CustomCompiler.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/CustomCompiler.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/CustomCompiler.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,37 @@
+/*
+ * $Id$
+ *
+ * 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.FileNotFoundException;
+
+public class CustomCompiler extends org.apache.struts2.jasper.compiler.Compiler {
+
+    public boolean isOutDated() {
+        return true;
+    }
+
+    public boolean isOutDated(boolean checkClass) {
+        return true;
+    }
+
+    protected void generateClass(String[] smap) throws FileNotFoundException, JasperException, Exception {
+    }
+}

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/EmbeddedServletOptions.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/EmbeddedServletOptions.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/EmbeddedServletOptions.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/EmbeddedServletOptions.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,673 @@
+/*
+ * 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.*;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+import org.apache.struts2.jasper.compiler.TldLocationsCache;
+import org.apache.struts2.jasper.compiler.JspConfig;
+import org.apache.struts2.jasper.compiler.TagPluginManager;
+import org.apache.struts2.jasper.compiler.Localizer;
+import org.apache.struts2.jasper.xmlparser.ParserUtils;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * A class to hold all init parameters specific to the JSP engine. 
+ *
+ * @author Anil K. Vijendran
+ * @author Hans Bergsten
+ * @author Pierre Delisle
+ */
+public final class EmbeddedServletOptions implements Options {
+    
+    // Logger
+    private Log log = LogFactory.getLog(EmbeddedServletOptions.class);
+    
+    private Properties settings = new Properties();
+    
+    /**
+     * Is Jasper being used in development mode?
+     */
+    private boolean development = true;
+    
+    /**
+     * Should Ant fork its java compiles of JSP pages.
+     */
+    public boolean fork = true;
+    
+    /**
+     * Do you want to keep the generated Java files around?
+     */
+    private boolean keepGenerated = true;
+    
+    /**
+     * Should white spaces between directives or actions be trimmed?
+     */
+    private boolean trimSpaces = false;
+    
+    /**
+     * Determines whether tag handler pooling is enabled.
+     */
+    private boolean isPoolingEnabled = true;
+    
+    /**
+     * Do you want support for "mapped" files? This will generate
+     * servlet that has a print statement per line of the JSP file.
+     * This seems like a really nice feature to have for debugging.
+     */
+    private boolean mappedFile = true;
+    
+    /**
+     * Do we want to include debugging information in the class file?
+     */
+    private boolean classDebugInfo = true;
+    
+    /**
+     * Background compile thread check interval in seconds.
+     */
+    private int checkInterval = 0;
+    
+    /**
+     * Is the generation of SMAP info for JSR45 debuggin suppressed?
+     */
+    private boolean isSmapSuppressed = false;
+    
+    /**
+     * Should SMAP info for JSR45 debugging be dumped to a file?
+     */
+    private boolean isSmapDumped = false;
+    
+    /**
+     * Are Text strings to be generated as char arrays?
+     */
+    private boolean genStringAsCharArray = false;
+    
+    private boolean errorOnUseBeanInvalidClassAttribute = true;
+    
+    /**
+     * I want to see my generated servlets. Which directory are they
+     * in?
+     */
+    private File scratchDir;
+    
+    /**
+     * Need to have this as is for versions 4 and 5 of IE. Can be set from
+     * the initParams so if it changes in the future all that is needed is
+     * to have a jsp initParam of type ieClassId="<value>"
+     */
+    private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
+    
+    /**
+     * What classpath should I use while compiling generated servlets?
+     */
+    private String classpath = null;
+    
+    /**
+     * Compiler to use.
+     */
+    private String compiler = null;
+    
+    /**
+     * Compiler target VM.
+     */
+    private String compilerTargetVM = "1.5";
+    
+    /**
+     * The compiler source VM.
+     */
+    private String compilerSourceVM = "1.5";
+    
+    /**
+     * The compiler class name.
+     */
+    private String compilerClassName = null;
+    
+    /**
+     * Cache for the TLD locations
+     */
+    private TldLocationsCache tldLocationsCache = null;
+    
+    /**
+     * Jsp config information
+     */
+    private JspConfig jspConfig = null;
+    
+    /**
+     * TagPluginManager
+     */
+    private TagPluginManager tagPluginManager = null;
+    
+    /**
+     * Java platform encoding to generate the JSP
+     * page servlet.
+     */
+    private String javaEncoding = "UTF8";
+    
+    /**
+     * Modification test interval.
+     */
+    private int modificationTestInterval = 4;
+    
+    /**
+     * Is generation of X-Powered-By response header enabled/disabled?
+     */
+    private boolean xpoweredBy;
+    
+    /**
+     * Should we include a source fragment in exception messages, which could be displayed
+     * to the developer ?
+     */
+    private boolean displaySourceFragment = true;
+
+    
+    public String getProperty(String name ) {
+        return settings.getProperty( name );
+    }
+    
+    public void setProperty(String name, String value ) {
+        if (name != null && value != null){ 
+            settings.setProperty( name, value );
+        }
+    }
+    
+    /**
+     * Are we keeping generated code around?
+     */
+    public boolean getKeepGenerated() {
+        return keepGenerated;
+    }
+    
+    /**
+     * Should white spaces between directives or actions be trimmed?
+     */
+    public boolean getTrimSpaces() {
+        return trimSpaces;
+    }
+    
+    public boolean isPoolingEnabled() {
+        return isPoolingEnabled;
+    }
+    
+    /**
+     * Are we supporting HTML mapped servlets?
+     */
+    public boolean getMappedFile() {
+        return mappedFile;
+    }
+    
+    /**
+     * Should errors be sent to client or thrown into stderr?
+     * @deprecated
+     */
+    @Deprecated
+    public boolean getSendErrorToClient() {
+        return true;
+    }
+    
+    /**
+     * Should class files be compiled with debug information?
+     */
+    public boolean getClassDebugInfo() {
+        return classDebugInfo;
+    }
+    
+    /**
+     * Background JSP compile thread check intervall
+     */
+    public int getCheckInterval() {
+        return checkInterval;
+    }
+    
+    /**
+     * Modification test interval.
+     */
+    public int getModificationTestInterval() {
+        return modificationTestInterval;
+    }
+    
+    /**
+     * Is Jasper being used in development mode?
+     */
+    public boolean getDevelopment() {
+        return development;
+    }
+    
+    /**
+     * Is the generation of SMAP info for JSR45 debuggin suppressed?
+     */
+    public boolean isSmapSuppressed() {
+        return isSmapSuppressed;
+    }
+    
+    /**
+     * Should SMAP info for JSR45 debugging be dumped to a file?
+     */
+    public boolean isSmapDumped() {
+        return isSmapDumped;
+    }
+    
+    /**
+     * Are Text strings to be generated as char arrays?
+     */
+    public boolean genStringAsCharArray() {
+        return this.genStringAsCharArray;
+    }
+    
+    /**
+     * Class ID for use in the plugin tag when the browser is IE. 
+     */
+    public String getIeClassId() {
+        return ieClassId;
+    }
+    
+    /**
+     * What is my scratch dir?
+     */
+    public File getScratchDir() {
+        return scratchDir;
+    }
+    
+    /**
+     * What classpath should I use while compiling the servlets
+     * generated from JSP files?
+     */
+    public String getClassPath() {
+        return classpath;
+    }
+    
+    /**
+     * Is generation of X-Powered-By response header enabled/disabled?
+     */
+    public boolean isXpoweredBy() {
+        return xpoweredBy;
+    }
+    
+    /**
+     * Compiler to use.
+     */
+    public String getCompiler() {
+        return compiler;
+    }
+    
+    /**
+     * @see Options#getCompilerTargetVM
+     */
+    public String getCompilerTargetVM() {
+        return compilerTargetVM;
+    }
+    
+    /**
+     * @see Options#getCompilerSourceVM
+     */
+    public String getCompilerSourceVM() {
+        return compilerSourceVM;
+    }
+    
+    /**
+     * Java compiler class to use.
+     */
+    public String getCompilerClassName() {
+        return compilerClassName;
+    }
+
+    public boolean getErrorOnUseBeanInvalidClassAttribute() {
+        return errorOnUseBeanInvalidClassAttribute;
+    }
+    
+    public void setErrorOnUseBeanInvalidClassAttribute(boolean b) {
+        errorOnUseBeanInvalidClassAttribute = b;
+    }
+    
+    public TldLocationsCache getTldLocationsCache() {
+        return tldLocationsCache;
+    }
+    
+    public void setTldLocationsCache( TldLocationsCache tldC ) {
+        tldLocationsCache = tldC;
+    }
+    
+    public String getJavaEncoding() {
+        return javaEncoding;
+    }
+    
+    public boolean getFork() {
+        return fork;
+    }
+    
+    public JspConfig getJspConfig() {
+        return jspConfig;
+    }
+    
+    public TagPluginManager getTagPluginManager() {
+        return tagPluginManager;
+    }
+    
+    public boolean isCaching() {
+        return false;
+    }
+    
+    public Map getCache() {
+        return null;
+    }
+
+    /**
+     * Should we include a source fragment in exception messages, which could be displayed
+     * to the developer ?
+     */
+    public boolean getDisplaySourceFragment() {
+        return displaySourceFragment;
+    }
+
+    /**
+     * Create an EmbeddedServletOptions object using data available from
+     * ServletConfig and ServletContext. 
+     */
+    public EmbeddedServletOptions(ServletConfig config,
+            ServletContext context) {
+        
+        // JVM version numbers
+        try {
+            if (Float.parseFloat(System.getProperty("java.specification.version")) > 1.4) {
+                compilerSourceVM = compilerTargetVM = "1.5";
+            } else {
+                compilerSourceVM = compilerTargetVM = "1.4";
+            }
+        } catch (NumberFormatException e) {
+            // Ignore
+        }
+        
+        Enumeration enumeration=config.getInitParameterNames();
+        while( enumeration.hasMoreElements() ) {
+            String k=(String)enumeration.nextElement();
+            String v=config.getInitParameter( k );
+            setProperty( k, v);
+        }
+        
+        // quick hack
+        String validating=config.getInitParameter( "validating");
+        if( "false".equals( validating )) ParserUtils.validating=false;
+        
+        String keepgen = config.getInitParameter("keepgenerated");
+        if (keepgen != null) {
+            if (keepgen.equalsIgnoreCase("true")) {
+                this.keepGenerated = true;
+            } else if (keepgen.equalsIgnoreCase("false")) {
+                this.keepGenerated = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.keepgen"));
+                }
+            }
+        }
+        
+        
+        String trimsp = config.getInitParameter("trimSpaces"); 
+        if (trimsp != null) {
+            if (trimsp.equalsIgnoreCase("true")) {
+                trimSpaces = true;
+            } else if (trimsp.equalsIgnoreCase("false")) {
+                trimSpaces = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.trimspaces"));
+                }
+            }
+        }
+        
+        this.isPoolingEnabled = true;
+        String poolingEnabledParam
+        = config.getInitParameter("enablePooling"); 
+        if (poolingEnabledParam != null
+                && !poolingEnabledParam.equalsIgnoreCase("true")) {
+            if (poolingEnabledParam.equalsIgnoreCase("false")) {
+                this.isPoolingEnabled = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.enablePooling"));
+                }		       	   
+            }
+        }
+        
+        String mapFile = config.getInitParameter("mappedfile"); 
+        if (mapFile != null) {
+            if (mapFile.equalsIgnoreCase("true")) {
+                this.mappedFile = true;
+            } else if (mapFile.equalsIgnoreCase("false")) {
+                this.mappedFile = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.mappedFile"));
+                }
+            }
+        }
+        
+        String debugInfo = config.getInitParameter("classdebuginfo");
+        if (debugInfo != null) {
+            if (debugInfo.equalsIgnoreCase("true")) {
+                this.classDebugInfo  = true;
+            } else if (debugInfo.equalsIgnoreCase("false")) {
+                this.classDebugInfo  = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.classDebugInfo"));
+                }
+            }
+        }
+        
+        String checkInterval = config.getInitParameter("checkInterval");
+        if (checkInterval != null) {
+            try {
+                this.checkInterval = Integer.parseInt(checkInterval);
+            } catch(NumberFormatException ex) {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.checkInterval"));
+                }
+            }
+        }
+        
+        String modificationTestInterval = config.getInitParameter("modificationTestInterval");
+        if (modificationTestInterval != null) {
+            try {
+                this.modificationTestInterval = Integer.parseInt(modificationTestInterval);
+            } catch(NumberFormatException ex) {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.modificationTestInterval"));
+                }
+            }
+        }
+        
+        String development = config.getInitParameter("development");
+        if (development != null) {
+            if (development.equalsIgnoreCase("true")) {
+                this.development = true;
+            } else if (development.equalsIgnoreCase("false")) {
+                this.development = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.development"));
+                }
+            }
+        }
+        
+        String suppressSmap = config.getInitParameter("suppressSmap");
+        if (suppressSmap != null) {
+            if (suppressSmap.equalsIgnoreCase("true")) {
+                isSmapSuppressed = true;
+            } else if (suppressSmap.equalsIgnoreCase("false")) {
+                isSmapSuppressed = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.suppressSmap"));
+                }
+            }
+        }
+        
+        String dumpSmap = config.getInitParameter("dumpSmap");
+        if (dumpSmap != null) {
+            if (dumpSmap.equalsIgnoreCase("true")) {
+                isSmapDumped = true;
+            } else if (dumpSmap.equalsIgnoreCase("false")) {
+                isSmapDumped = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.dumpSmap"));
+                }
+            }
+        }
+        
+        String genCharArray = config.getInitParameter("genStrAsCharArray");
+        if (genCharArray != null) {
+            if (genCharArray.equalsIgnoreCase("true")) {
+                genStringAsCharArray = true;
+            } else if (genCharArray.equalsIgnoreCase("false")) {
+                genStringAsCharArray = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.genchararray"));
+                }
+            }
+        }
+        
+        String errBeanClass =
+            config.getInitParameter("errorOnUseBeanInvalidClassAttribute");
+        if (errBeanClass != null) {
+            if (errBeanClass.equalsIgnoreCase("true")) {
+                errorOnUseBeanInvalidClassAttribute = true;
+            } else if (errBeanClass.equalsIgnoreCase("false")) {
+                errorOnUseBeanInvalidClassAttribute = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.errBean"));
+                }
+            }
+        }
+        
+        String ieClassId = config.getInitParameter("ieClassId");
+        if (ieClassId != null)
+            this.ieClassId = ieClassId;
+        
+        String classpath = config.getInitParameter("classpath");
+        if (classpath != null)
+            this.classpath = classpath;
+        
+        /*
+         * scratchdir
+         */
+        String dir = config.getInitParameter("scratchdir"); 
+        if (dir != null) {
+            scratchDir = new File(dir);
+        } else {
+            // First try the Servlet 2.2 javax.servlet.context.tempdir property
+            scratchDir = (File) context.getAttribute(Constants.TMP_DIR);
+            if (scratchDir == null) {
+                // Not running in a Servlet 2.2 container.
+                // Try to get the JDK 1.2 java.io.tmpdir property
+                dir = System.getProperty("java.io.tmpdir");
+                if (dir != null)
+                    scratchDir = new File(dir);
+            }
+        }      
+        if (this.scratchDir == null) {
+            log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir"));
+            return;
+        }
+        
+        if (!(scratchDir.exists() && scratchDir.canRead() &&
+                scratchDir.canWrite() && scratchDir.isDirectory()))
+            log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir",
+                    scratchDir.getAbsolutePath()));
+        
+        this.compiler = config.getInitParameter("compiler");
+        
+        String compilerTargetVM = config.getInitParameter("compilerTargetVM");
+        if(compilerTargetVM != null) {
+            this.compilerTargetVM = compilerTargetVM;
+        }
+        
+        String compilerSourceVM = config.getInitParameter("compilerSourceVM");
+        if(compilerSourceVM != null) {
+            this.compilerSourceVM = compilerSourceVM;
+        }
+        
+        String javaEncoding = config.getInitParameter("javaEncoding");
+        if (javaEncoding != null) {
+            this.javaEncoding = javaEncoding;
+        }
+        
+        String compilerClassName = config.getInitParameter("compilerClassName");
+        if (compilerClassName != null) {
+            this.compilerClassName = compilerClassName;
+        }
+        
+        String fork = config.getInitParameter("fork");
+        if (fork != null) {
+            if (fork.equalsIgnoreCase("true")) {
+                this.fork = true;
+            } else if (fork.equalsIgnoreCase("false")) {
+                this.fork = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.fork"));
+                }
+            }
+        }
+        
+        String xpoweredBy = config.getInitParameter("xpoweredBy"); 
+        if (xpoweredBy != null) {
+            if (xpoweredBy.equalsIgnoreCase("true")) {
+                this.xpoweredBy = true;
+            } else if (xpoweredBy.equalsIgnoreCase("false")) {
+                this.xpoweredBy = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.xpoweredBy"));
+                }
+            }
+        }
+        
+        String displaySourceFragment = config.getInitParameter("displaySourceFragment"); 
+        if (displaySourceFragment != null) {
+            if (displaySourceFragment.equalsIgnoreCase("true")) {
+                this.displaySourceFragment = true;
+            } else if (displaySourceFragment.equalsIgnoreCase("false")) {
+                this.displaySourceFragment = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.displaySourceFragment"));
+                }
+            }
+        }
+        
+        // Setup the global Tag Libraries location cache for this
+        // web-application.
+        tldLocationsCache = new TldLocationsCache(context);
+        
+        // Setup the jsp config info for this web app.
+        jspConfig = new JspConfig(context);
+        
+        // Create a Tag plugin instance
+        tagPluginManager = new TagPluginManager(context);
+    }
+    
+}
+

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/JasperException.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/JasperException.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/JasperException.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/JasperException.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+/**
+ * Base class for all exceptions generated by the JSP engine. Makes it
+ * convienient to catch just this at the top-level. 
+ *
+ * @author Anil K. Vijendran
+ */
+public class JasperException extends javax.servlet.ServletException {
+    
+    public JasperException(String reason) {
+	super(reason);
+    }
+
+    /**
+     * Creates a JasperException with the embedded exception and the reason for
+     * throwing a JasperException
+     */
+    public JasperException (String reason, Throwable exception) {
+   	super(reason, exception);
+    }
+
+    /**
+     * Creates a JasperException with the embedded exception
+     */
+    public JasperException (Throwable exception) {
+   	super(exception);
+    }
+}

Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/JspC.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/JspC.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/JspC.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/JspC.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,1237 @@
+/*
+ * 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.util.*;
+
+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 org.apache.struts2.jasper.xmlparser.ParserUtils;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
+
+/**
+ * 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>
+ *   &lt;taskdef classname="org.apache.struts2.jasper.JspC" name="jasper2" &gt;
+ *      &lt;classpath&gt;
+ *          &lt;pathelement location="${java.home}/../lib/tools.jar"/&gt;
+ *          &lt;fileset dir="${ENV.CATALINA_HOME}/server/lib"&gt;
+ *              &lt;include name="*.jar"/&gt;
+ *          &lt;/fileset&gt;
+ *          &lt;fileset dir="${ENV.CATALINA_HOME}/common/lib"&gt;
+ *              &lt;include name="*.jar"/&gt;
+ *          &lt;/fileset&gt;
+ *          &lt;path refid="myjars"/&gt;
+ *       &lt;/classpath&gt;
+ *  &lt;/taskdef&gt;
+ *
+ *  &lt;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" /&gt;
+ * </pre>
+ *
+ * @author Danno Ferrin
+ * @author Pierre Delisle
+ * @author Costin Manolache
+ * @author Yoav Shapira
+ */
+public class JspC implements Options {
+
+    public static final String DEFAULT_IE_CLASS_ID =
+            "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
+
+    // Logger
+    protected static Log log = LogFactory.getLog(JspC.class);
+
+    protected static final String SWITCH_VERBOSE = "-v";
+    protected static final String SWITCH_HELP = "-help";
+    protected static final String SWITCH_OUTPUT_DIR = "-d";
+    protected static final String SWITCH_PACKAGE_NAME = "-p";
+    protected static final String SWITCH_CACHE = "-cache";
+    protected static final String SWITCH_CLASS_NAME = "-c";
+    protected static final String SWITCH_FULL_STOP = "--";
+    protected static final String SWITCH_COMPILE = "-compile";
+    protected static final String SWITCH_SOURCE = "-source";
+    protected static final String SWITCH_TARGET = "-target";
+    protected static final String SWITCH_URI_BASE = "-uribase";
+    protected static final String SWITCH_URI_ROOT = "-uriroot";
+    protected static final String SWITCH_FILE_WEBAPP = "-webapp";
+    protected static final String SWITCH_WEBAPP_INC = "-webinc";
+    protected static final String SWITCH_WEBAPP_XML = "-webxml";
+    protected static final String SWITCH_MAPPED = "-mapped";
+    protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy";
+    protected static final String SWITCH_TRIM_SPACES = "-trimSpaces";
+    protected static final String SWITCH_CLASSPATH = "-classpath";
+    protected static final String SWITCH_DIE = "-die";
+    protected static final String SWITCH_POOLING = "-poolingEnabled";
+    protected static final String SWITCH_ENCODING = "-javaEncoding";
+    protected static final String SWITCH_SMAP = "-smap";
+    protected static final String SWITCH_DUMP_SMAP = "-dumpsmap";
+
+    protected static final String SHOW_SUCCESS ="-s";
+    protected static final String LIST_ERRORS = "-l";
+    protected static final int INC_WEBXML = 10;
+    protected static final int ALL_WEBXML = 20;
+    protected static final int DEFAULT_DIE_LEVEL = 1;
+    protected static final int NO_DIE_LEVEL = 0;
+
+    protected 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>" };
+
+    protected static int die;
+    protected String classPath = null;
+    protected URLClassLoader loader = null;
+    protected boolean trimSpaces = false;
+    protected boolean genStringAsCharArray = false;
+    protected boolean xpoweredBy;
+    protected boolean mappedFile = false;
+    protected boolean poolingEnabled = true;
+    protected File scratchDir;
+    protected String ieClassId = DEFAULT_IE_CLASS_ID;
+    protected String targetPackage;
+    protected String targetClassName;
+    protected String uriBase;
+    protected String uriRoot;
+    protected int dieLevel;
+    protected boolean helpNeeded = false;
+    protected boolean compile = false;
+    protected boolean smapSuppressed = true;
+    protected boolean smapDumped = false;
+    protected boolean caching = true;
+    protected Map cache = new HashMap();
+
+    protected String compiler = null;
+
+    protected String compilerTargetVM = "1.4";
+    protected String compilerSourceVM = "1.4";
+
+    protected boolean classDebugInfo = true;
+
+    /**
+     * Throw an exception if there's a compilation error, or swallow it.
+     * Default is true to preserve old behavior.
+     */
+    protected boolean failOnError = true;
+
+    /**
+     * The file extensions to be handled as JSP files.
+     * Default list is .jsp and .jspx.
+     */
+    protected List extensions;
+
+    /**
+     * The pages.
+     */
+    protected List pages = new Vector();
+
+    /**
+     * Needs better documentation, this data member does.
+     * True by default.
+     */
+    protected boolean errorOnUseBeanInvalidClassAttribute = true;
+
+    /**
+     * The java file encoding.  Default
+     * is UTF-8.  Added per bugzilla 19622.
+     */
+    protected String javaEncoding = "UTF-8";
+
+    // Generation of web.xml fragments
+    protected String webxmlFile;
+    protected int webxmlLevel;
+    protected boolean addWebXmlMappings = false;
+
+    protected Writer mapout;
+    protected CharArrayWriter servletout;
+    protected CharArrayWriter mappingout;
+
+    /**
+     * The servlet context.
+     */
+    protected JspCServletContext context;
+
+    /**
+     * The runtime context.
+     * Maintain a dummy JspRuntimeContext for compiling tag files.
+     */
+    protected JspRuntimeContext rctxt;
+
+    /**
+     * Cache for the TLD locations
+     */
+    protected TldLocationsCache tldLocationsCache = null;
+
+    protected JspConfig jspConfig = null;
+    protected TagPluginManager tagPluginManager = null;
+
+    protected boolean verbose = false;
+    protected boolean listErrors = false;
+    protected boolean showSuccess = false;
+    protected int argPos;
+    protected boolean fullstop = false;
+    protected String args[];
+
+    private String sourceCode;
+    private ClassLoaderInterface classLoaderInterface;
+
+
+    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);
+                if (die != NO_DIE_LEVEL) {
+                    System.exit(die);
+                }
+            }
+        }
+    }
+
+    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_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 String getSourceCode() {
+        return sourceCode;
+    }
+
+    public void setClassLoaderInterface(ClassLoaderInterface classLoaderInterface) {
+        this.classLoaderInterface = classLoaderInterface;
+    }
+
+    public Set<String> getTldAbsolutePaths() {
+        return tldLocationsCache.getAbsolutePathsOfLocations();
+    }
+
+    
+
+    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 getDisplaySourceFragment() {
+        return true;
+    }
+    
+    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;
+    }
+
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    public boolean getSendErrorToClient() {
+        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;
+    }
+
+    /**
+     * Compiler class name to use.
+     */
+    public String getCompilerClassName() {
+        return null;
+    }
+    
+    /**
+     * @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 ) {
+       ParserUtils.validating=b;
+    }
+
+    public void setListErrors( boolean b ) {
+        listErrors = b;
+    }
+
+    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;
+    }
+
+    public void setAddWebXmlMappings(boolean b) {
+        addWebXmlMappings = b;
+    }
+
+    /**
+     * 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");
+
+        }
+    }
+
+    /**
+     * Include the generated web.xml inside the webapp's web.xml.
+     */
+    protected void mergeIntoWebXml() throws IOException {
+
+        File webappBase = new File(uriRoot);
+        File webXml = new File(webappBase, "WEB-INF/web.xml");
+        File webXml2 = new File(webappBase, "WEB-INF/web2.xml");
+        String insertStartMarker =
+            Localizer.getMessage("jspc.webinc.insertStart");
+        String insertEndMarker =
+            Localizer.getMessage("jspc.webinc.insertEnd");
+
+        BufferedReader reader = new BufferedReader(new FileReader(webXml));
+        BufferedReader fragmentReader =
+            new BufferedReader(new FileReader(webxmlFile));
+        PrintWriter writer = new PrintWriter(new FileWriter(webXml2));
+
+        // Insert the <servlet> and <servlet-mapping> declarations
+        int pos = -1;
+        String line = null;
+        while (true) {
+            line = reader.readLine();
+            if (line == null) {
+                break;
+            }
+            // Skip anything previously generated by JSPC
+            if (line.indexOf(insertStartMarker) >= 0) {
+                while (true) {
+                    line = reader.readLine();
+                    if (line == null) {
+                        return;
+                    }
+                    if (line.indexOf(insertEndMarker) >= 0) {
+                        line = reader.readLine();
+                        line = reader.readLine();
+                        if (line == null) {
+                            return;
+                        }
+                        break;
+                    }
+                }
+            }
+            for (int i = 0; i < insertBefore.length; i++) {
+                pos = line.indexOf(insertBefore[i]);
+                if (pos >= 0)
+                    break;
+            }
+            if (pos >= 0) {
+                writer.print(line.substring(0, pos));
+                break;
+            } else {
+                writer.println(line);
+            }
+        }
+
+        writer.println(insertStartMarker);
+        while (true) {
+            String line2 = fragmentReader.readLine();
+            if (line2 == null) {
+                writer.println();
+                break;
+            }
+            writer.println(line2);
+        }
+        writer.println(insertEndMarker);
+        writer.println();
+
+        for (int i = 0; i < pos; i++) {
+            writer.print(" ");
+        }
+        writer.println(line.substring(pos));
+
+        while (true) {
+            line = reader.readLine();
+            if (line == null) {
+                break;
+            }
+            writer.println(line);
+        }
+        writer.close();
+
+        reader.close();
+        fragmentReader.close();
+
+        FileInputStream fis = new FileInputStream(webXml2);
+        FileOutputStream fos = new FileOutputStream(webXml);
+
+        byte buf[] = new byte[512];
+        while (true) {
+            int n = fis.read(buf);
+            if (n < 0) {
+                break;
+            }
+            fos.write(buf, 0, n);
+        }
+
+        fis.close();
+        fos.close();
+
+        webXml2.delete();
+        (new File(webxmlFile)).delete();
+
+    }
+
+    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, classLoaderInterface);
+
+               /* 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);
+               }
+           }
+       }
+    
+
+    /**
+     * Locate all jsp files in the webapp. Used if no explicit
+     * jsps are specified.
+     */
+    public void scanFiles( File base ) throws JasperException {
+        Stack<String> dirs = new Stack<String>();
+        dirs.push(base.toString());
+
+        // Make sure default extensions are always included
+        if ((getExtensions() == null) || (getExtensions().size() < 2)) {
+            addExtension("jsp");
+            addExtension("jspx");
+        }
+
+        while (!dirs.isEmpty()) {
+            String s = dirs.pop();
+            File f = new File(s);
+            if (f.exists() && f.isDirectory()) {
+                String[] files = f.list();
+                String ext;
+                for (int i = 0; (files != null) && i < files.length; i++) {
+                    File f2 = new File(s, files[i]);
+                    if (f2.isDirectory()) {
+                        dirs.push(f2.getPath());
+                    } else {
+                        String path = f2.getPath();
+                        String uri = path.substring(uriRoot.length());
+                        ext = files[i].substring(files[i].lastIndexOf('.') +1);
+                        if (getExtensions().contains(ext) ||
+                            jspConfig.isJspPage(uri)) {
+                            pages.add(path);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+     /**
+     * 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;
+        }
+    }
+    // ==================== protected utility methods ====================
+
+    protected String nextArg() {
+        if ((argPos >= args.length)
+            || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) {
+            return null;
+        } else {
+            return args[argPos++];
+        }
+    }
+
+    protected String nextFile() {
+        if (fullstop) argPos++;
+        if (argPos >= args.length) {
+            return null;
+        } else {
+            return args[argPos++];
+        }
+    }
+
+    protected 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) && !addWebXmlMappings) {
+                mapout.write(Localizer.getMessage("jspc.webinc.header"));
+                mapout.flush();
+            }
+        } catch (IOException ioe) {
+            mapout = null;
+            servletout = null;
+            mappingout = null;
+        }
+    }
+
+    protected 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) && !addWebXmlMappings) {
+                    mapout.write(Localizer.getMessage("jspc.webinc.footer"));
+                }
+                mapout.close();
+            } catch (IOException ioe) {
+                // noting to do if it fails since we are done with it
+            }
+        }
+    }
+
+    protected 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());
+
+    }
+
+    /**
+     * Find the WEB-INF dir by looking up in the directory tree.
+     * This is used if no explicit docbase is set, but only files.
+     * XXX Maybe we should require the docbase.
+     */
+    protected void locateUriRoot( File f ) {
+        String tUriBase = uriBase;
+        if (tUriBase == null) {
+            tUriBase = "/";
+        }
+        try {
+            if (f.exists()) {
+                f = new File(f.getAbsolutePath());
+                while (f != null) {
+                    File g = new File(f, "WEB-INF");
+                    if (g.exists() && g.isDirectory()) {
+                        uriRoot = f.getCanonicalPath();
+                        uriBase = tUriBase;
+                        if (log.isInfoEnabled()) {
+                            log.info(Localizer.getMessage(
+                                        "jspc.implicit.uriRoot",
+                                        uriRoot));
+                        }
+                        break;
+                    }
+                    if (f.exists() && f.isDirectory()) {
+                        tUriBase = "/" + f.getName() + "/" + tUriBase;
+                    }
+
+                    String fParent = f.getParent();
+                    if (fParent == null) {
+                        break;
+                    } else {
+                        f = new File(fParent);
+                    }
+
+                    // If there is no acceptible candidate, uriRoot will
+                    // remain null to indicate to the CompilerContext to
+                    // use the current working/user dir.
+                }
+
+                if (uriRoot != null) {
+                    File froot = new File(uriRoot);
+                    uriRoot = froot.getCanonicalPath();
+                }
+            }
+        } catch (IOException ioe) {
+            // since this is an optional default and a null value
+            // for uriRoot has a non-error meaning, we can just
+            // pass straight through
+        }
+    }
+}