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 [19/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/apach...
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JasperLoader.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JasperLoader.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JasperLoader.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JasperLoader.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,169 @@
+/*
+ * 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.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.security.PermissionCollection;
+
+import org.apache.struts2.jasper.Constants;
+
+/**
+ * Class loader for loading servlet class files (corresponding to JSP files)
+ * and tag handler class files (corresponding to tag files).
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Jean-Francois Arcand
+ */
+public class JasperLoader extends URLClassLoader {
+
+ private PermissionCollection permissionCollection;
+ private ClassLoader parent;
+ private SecurityManager securityManager;
+
+ public JasperLoader(URL[] urls, ClassLoader parent,
+ PermissionCollection permissionCollection,
+ CodeSource codeSource) {
+ super(urls, parent);
+ this.permissionCollection = permissionCollection;
+ this.parent = parent;
+ this.securityManager = System.getSecurityManager();
+ }
+
+ /**
+ * Load the class with the specified name. This method searches for
+ * classes in the same manner as <code>loadClass(String, boolean)</code>
+ * with <code>false</code> as the second argument.
+ *
+ * @param name Name of the class to be loaded
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class loadClass(String name) throws ClassNotFoundException {
+
+ return (loadClass(name, false));
+ }
+
+ /**
+ * Load the class with the specified name, searching using the following
+ * algorithm until it finds and returns the class. If the class cannot
+ * be found, returns <code>ClassNotFoundException</code>.
+ * <ul>
+ * <li>Call <code>findLoadedClass(String)</code> to check if the
+ * class has already been loaded. If it has, the same
+ * <code>Class</code> object is returned.</li>
+ * <li>If the <code>delegate</code> property is set to <code>true</code>,
+ * call the <code>loadClass()</code> method of the parent class
+ * loader, if any.</li>
+ * <li>Call <code>findClass()</code> to find this class in our locally
+ * defined repositories.</li>
+ * <li>Call the <code>loadClass()</code> method of our parent
+ * class loader, if any.</li>
+ * </ul>
+ * If the class was found using the above steps, and the
+ * <code>resolve</code> flag is <code>true</code>, this method will then
+ * call <code>resolveClass(Class)</code> on the resulting Class object.
+ *
+ * @param name Name of the class to be loaded
+ * @param resolve If <code>true</code> then resolve the class
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class loadClass(final String name, boolean resolve)
+ throws ClassNotFoundException {
+
+ Class clazz = null;
+
+ // (0) Check our previously loaded class cache
+ clazz = findLoadedClass(name);
+ if (clazz != null) {
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+
+ // (.5) Permission to access this class when using a SecurityManager
+ if (securityManager != null) {
+ int dot = name.lastIndexOf('.');
+ if (dot >= 0) {
+ try {
+ // Do not call the security manager since by default, we grant that package.
+ if (!"org.apache.struts2.jasper.runtime".equalsIgnoreCase(name.substring(0,dot))){
+ securityManager.checkPackageAccess(name.substring(0,dot));
+ }
+ } catch (SecurityException se) {
+ String error = "Security Violation, attempt to use " +
+ "Restricted Class: " + name;
+ se.printStackTrace();
+ throw new ClassNotFoundException(error);
+ }
+ }
+ }
+
+ if( !name.startsWith(Constants.JSP_PACKAGE_NAME) ) {
+ // Class is not in org.apache.jsp, therefore, have our
+ // parent load it
+ clazz = parent.loadClass(name);
+ if( resolve )
+ resolveClass(clazz);
+ return clazz;
+ }
+
+ return findClass(name);
+ }
+
+
+ /**
+ * Delegate to parent
+ *
+ * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String)
+ */
+ public InputStream getResourceAsStream(String name) {
+ InputStream is = parent.getResourceAsStream(name);
+ if (is == null) {
+ URL url = findResource(name);
+ if (url != null) {
+ try {
+ is = url.openStream();
+ } catch (IOException e) {
+ is = null;
+ }
+ }
+ }
+ return is;
+ }
+
+
+ /**
+ * Get the Permissions for a CodeSource.
+ *
+ * Since this ClassLoader is only used for a JSP page in
+ * a web application context, we just return our preset
+ * PermissionCollection for the web app context.
+ *
+ * @param codeSource Code source where the code was loaded from
+ * @return PermissionCollection for CodeSource
+ */
+ public final PermissionCollection getPermissions(CodeSource codeSource) {
+ return permissionCollection;
+ }
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspCServletContext.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspCServletContext.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspCServletContext.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspCServletContext.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,402 @@
+/*
+ * 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.servlet;
+
+
+import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+
+/**
+ * Simple <code>ServletContext</code> implementation without
+ * HTTP-specific methods.
+ *
+ * @author Peter Rossbach (pr@webapp.de)
+ */
+
+public class JspCServletContext implements ServletContext {
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * Servlet context attributes.
+ */
+ protected Hashtable myAttributes;
+
+
+ /**
+ * The log writer we will write log messages to.
+ */
+ protected PrintWriter myLogWriter;
+
+ private ClassLoaderInterface classLoaderInterface;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Create a new instance of this ServletContext implementation.
+ *
+ * @param aLogWriter PrintWriter which is used for <code>log()</code> calls
+ */
+ public JspCServletContext(PrintWriter aLogWriter, ClassLoaderInterface classLoaderInterface) {
+
+ myAttributes = new Hashtable();
+ myLogWriter = aLogWriter;
+ this.classLoaderInterface = classLoaderInterface;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Return the specified context attribute, if any.
+ *
+ * @param name Name of the requested attribute
+ */
+ public Object getAttribute(String name) {
+
+ return (myAttributes.get(name));
+
+ }
+
+
+ /**
+ * Return an enumeration of context attribute names.
+ */
+ public Enumeration getAttributeNames() {
+
+ return (myAttributes.keys());
+
+ }
+
+
+ /**
+ * Return the servlet context for the specified path.
+ *
+ * @param uripath Server-relative path starting with '/'
+ */
+ public ServletContext getContext(String uripath) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return the specified context initialization parameter.
+ *
+ * @param name Name of the requested parameter
+ */
+ public String getInitParameter(String name) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return an enumeration of the names of context initialization
+ * parameters.
+ */
+ public Enumeration getInitParameterNames() {
+
+ return (new Vector().elements());
+
+ }
+
+
+ /**
+ * Return the Servlet API major version number.
+ */
+ public int getMajorVersion() {
+
+ return (2);
+
+ }
+
+
+ /**
+ * Return the MIME type for the specified filename.
+ *
+ * @param file Filename whose MIME type is requested
+ */
+ public String getMimeType(String file) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return the Servlet API minor version number.
+ */
+ public int getMinorVersion() {
+
+ return (3);
+
+ }
+
+
+ /**
+ * Return a request dispatcher for the specified servlet name.
+ *
+ * @param name Name of the requested servlet
+ */
+ public RequestDispatcher getNamedDispatcher(String name) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return the real path for the specified context-relative
+ * virtual path.
+ *
+ * @param path The context-relative virtual path to resolve
+ */
+ public String getRealPath(String path) {
+ try {
+ return
+ (getResource(path).getFile().replace('/', File.separatorChar));
+ } catch (Throwable t) {
+ return (null);
+ }
+
+ }
+
+
+ /**
+ * Return a request dispatcher for the specified context-relative path.
+ *
+ * @param path Context-relative path for which to acquire a dispatcher
+ */
+ public RequestDispatcher getRequestDispatcher(String path) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return a URL object of a resource that is mapped to the
+ * specified context-relative path.
+ *
+ * @param path Context-relative path of the desired resource
+ *
+ * @exception MalformedURLException if the resource path is
+ * not properly formed
+ */
+ public URL getResource(String path) throws MalformedURLException {
+ return classLoaderInterface.getResource(path);
+ }
+
+
+ /**
+ * Return an InputStream allowing access to the resource at the
+ * specified context-relative path.
+ *
+ * @param path Context-relative path of the desired resource
+ */
+ public InputStream getResourceAsStream(String path) {
+
+ try {
+ return classLoaderInterface.getResourceAsStream(path);
+ } catch (Throwable t) {
+ return (null);
+ }
+
+ }
+
+
+ /**
+ * Return the set of resource paths for the "directory" at the
+ * specified context path.
+ *
+ * @param path Context-relative base path
+ */
+ public Set getResourcePaths(String path) {
+
+ Set thePaths = new HashSet();
+ if (!path.endsWith("/"))
+ path += "/";
+ String basePath = getRealPath(path);
+ if (basePath == null)
+ return (thePaths);
+ File theBaseDir = new File(basePath);
+ if (!theBaseDir.exists() || !theBaseDir.isDirectory())
+ return (thePaths);
+ String theFiles[] = theBaseDir.list();
+ for (int i = 0; i < theFiles.length; i++) {
+ File testFile = new File(basePath + File.separator + theFiles[i]);
+ if (testFile.isFile())
+ thePaths.add(path + theFiles[i]);
+ else if (testFile.isDirectory())
+ thePaths.add(path + theFiles[i] + "/");
+ }
+ return (thePaths);
+
+ }
+
+
+ /**
+ * Return descriptive information about this server.
+ */
+ public String getServerInfo() {
+
+ return ("JspCServletContext/1.0");
+
+ }
+
+
+ /**
+ * Return a null reference for the specified servlet name.
+ *
+ * @param name Name of the requested servlet
+ *
+ * @deprecated This method has been deprecated with no replacement
+ */
+ public Servlet getServlet(String name) throws ServletException {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return the name of this servlet context.
+ */
+ public String getServletContextName() {
+
+ return (getServerInfo());
+
+ }
+
+
+ /**
+ * Return an empty enumeration of servlet names.
+ *
+ * @deprecated This method has been deprecated with no replacement
+ */
+ public Enumeration getServletNames() {
+
+ return (new Vector().elements());
+
+ }
+
+
+ /**
+ * Return an empty enumeration of servlets.
+ *
+ * @deprecated This method has been deprecated with no replacement
+ */
+ public Enumeration getServlets() {
+
+ return (new Vector().elements());
+
+ }
+
+
+ /**
+ * Log the specified message.
+ *
+ * @param message The message to be logged
+ */
+ public void log(String message) {
+
+ myLogWriter.println(message);
+
+ }
+
+
+ /**
+ * Log the specified message and exception.
+ *
+ * @param exception The exception to be logged
+ * @param message The message to be logged
+ *
+ * @deprecated Use log(String,Throwable) instead
+ */
+ public void log(Exception exception, String message) {
+
+ log(message, exception);
+
+ }
+
+
+ /**
+ * Log the specified message and exception.
+ *
+ * @param message The message to be logged
+ * @param exception The exception to be logged
+ */
+ public void log(String message, Throwable exception) {
+
+ myLogWriter.println(message);
+ exception.printStackTrace(myLogWriter);
+
+ }
+
+
+ /**
+ * Remove the specified context attribute.
+ *
+ * @param name Name of the attribute to remove
+ */
+ public void removeAttribute(String name) {
+
+ myAttributes.remove(name);
+
+ }
+
+
+ /**
+ * Set or replace the specified context attribute.
+ *
+ * @param name Name of the context attribute to set
+ * @param value Corresponding attribute value
+ */
+ public void setAttribute(String name, Object value) {
+
+ myAttributes.put(name, value);
+
+ }
+
+
+
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspServlet.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspServlet.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspServlet.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspServlet.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,333 @@
+/*
+ * 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.servlet;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.Enumeration;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.struts2.jasper.Constants;
+import org.apache.struts2.jasper.EmbeddedServletOptions;
+import org.apache.struts2.jasper.Options;
+import org.apache.struts2.jasper.compiler.JspRuntimeContext;
+import org.apache.struts2.jasper.compiler.Localizer;
+
+/**
+ * The JSP engine (a.k.a Jasper).
+ *
+ * The servlet container is responsible for providing a
+ * URLClassLoader for the web application context Jasper
+ * is being used in. Jasper will try get the Tomcat
+ * ServletContext attribute for its ServletContext class
+ * loader, if that fails, it uses the parent class loader.
+ * In either case, it must be a URLClassLoader.
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Remy Maucherat
+ * @author Kin-man Chung
+ * @author Glenn Nielsen
+ */
+public class JspServlet extends HttpServlet {
+
+ // Logger
+ private Log log = LogFactory.getLog(JspServlet.class);
+
+ private ServletContext context;
+ private ServletConfig config;
+ private Options options;
+ private JspRuntimeContext rctxt;
+
+
+ /*
+ * Initializes this JspServlet.
+ */
+ public void init(ServletConfig config) throws ServletException {
+
+ super.init(config);
+ this.config = config;
+ this.context = config.getServletContext();
+
+ // Initialize the JSP Runtime Context
+ // Check for a custom Options implementation
+ String engineOptionsName =
+ config.getInitParameter("engineOptionsClass");
+ if (engineOptionsName != null) {
+ // Instantiate the indicated Options implementation
+ try {
+ ClassLoader loader = Thread.currentThread()
+ .getContextClassLoader();
+ Class engineOptionsClass = loader.loadClass(engineOptionsName);
+ Class[] ctorSig = { ServletConfig.class, ServletContext.class };
+ Constructor ctor = engineOptionsClass.getConstructor(ctorSig);
+ Object[] args = { config, context };
+ options = (Options) ctor.newInstance(args);
+ } catch (Throwable e) {
+ // Need to localize this.
+ log.warn("Failed to load engineOptionsClass", e);
+ // Use the default Options implementation
+ options = new EmbeddedServletOptions(config, context);
+ }
+ } else {
+ // Use the default Options implementation
+ options = new EmbeddedServletOptions(config, context);
+ }
+ rctxt = new JspRuntimeContext(context, options);
+
+ if (log.isDebugEnabled()) {
+ log.debug(Localizer.getMessage("jsp.message.scratch.dir.is",
+ options.getScratchDir().toString()));
+ log.debug(Localizer.getMessage("jsp.message.dont.modify.servlets"));
+ }
+ }
+
+
+ /**
+ * Returns the number of JSPs for which JspServletWrappers exist, i.e.,
+ * the number of JSPs that have been loaded into the webapp with which
+ * this JspServlet is associated.
+ *
+ * <p>This info may be used for monitoring purposes.
+ *
+ * @return The number of JSPs that have been loaded into the webapp with
+ * which this JspServlet is associated
+ */
+ public int getJspCount() {
+ return this.rctxt.getJspCount();
+ }
+
+
+ /**
+ * Resets the JSP reload counter.
+ *
+ * @param count Value to which to reset the JSP reload counter
+ */
+ public void setJspReloadCount(int count) {
+ this.rctxt.setJspReloadCount(count);
+ }
+
+
+ /**
+ * Gets the number of JSPs that have been reloaded.
+ *
+ * <p>This info may be used for monitoring purposes.
+ *
+ * @return The number of JSPs (in the webapp with which this JspServlet is
+ * associated) that have been reloaded
+ */
+ public int getJspReloadCount() {
+ return this.rctxt.getJspReloadCount();
+ }
+
+
+ /**
+ * <p>Look for a <em>precompilation request</em> as described in
+ * Section 8.4.2 of the JSP 1.2 Specification. <strong>WARNING</strong> -
+ * we cannot use <code>request.getParameter()</code> for this, because
+ * that will trigger parsing all of the request parameters, and not give
+ * a servlet the opportunity to call
+ * <code>request.setCharacterEncoding()</code> first.</p>
+ *
+ * @param request The servlet requset we are processing
+ *
+ * @exception ServletException if an invalid parameter value for the
+ * <code>jsp_precompile</code> parameter name is specified
+ */
+ boolean preCompile(HttpServletRequest request) throws ServletException {
+
+ String queryString = request.getQueryString();
+ if (queryString == null) {
+ return (false);
+ }
+ int start = queryString.indexOf(Constants.PRECOMPILE);
+ if (start < 0) {
+ return (false);
+ }
+ queryString =
+ queryString.substring(start + Constants.PRECOMPILE.length());
+ if (queryString.length() == 0) {
+ return (true); // ?jsp_precompile
+ }
+ if (queryString.startsWith("&")) {
+ return (true); // ?jsp_precompile&foo=bar...
+ }
+ if (!queryString.startsWith("=")) {
+ return (false); // part of some other name or value
+ }
+ int limit = queryString.length();
+ int ampersand = queryString.indexOf("&");
+ if (ampersand > 0) {
+ limit = ampersand;
+ }
+ String value = queryString.substring(1, limit);
+ if (value.equals("true")) {
+ return (true); // ?jsp_precompile=true
+ } else if (value.equals("false")) {
+ // Spec says if jsp_precompile=false, the request should not
+ // be delivered to the JSP page; the easiest way to implement
+ // this is to set the flag to true, and precompile the page anyway.
+ // This still conforms to the spec, since it says the
+ // precompilation request can be ignored.
+ return (true); // ?jsp_precompile=false
+ } else {
+ throw new ServletException("Cannot have request parameter " +
+ Constants.PRECOMPILE + " set to " +
+ value);
+ }
+
+ }
+
+
+ public void service (HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+
+ String jspUri = null;
+
+ String jspFile = (String) request.getAttribute(Constants.JSP_FILE);
+ if (jspFile != null) {
+ // JSP is specified via <jsp-file> in <servlet> declaration
+ jspUri = jspFile;
+ } else {
+ /*
+ * Check to see if the requested JSP has been the target of a
+ * RequestDispatcher.include()
+ */
+ jspUri = (String) request.getAttribute(Constants.INC_SERVLET_PATH);
+ if (jspUri != null) {
+ /*
+ * Requested JSP has been target of
+ * RequestDispatcher.include(). Its path is assembled from the
+ * relevant javax.servlet.include.* request attributes
+ */
+ String pathInfo = (String) request.getAttribute(
+ "javax.servlet.include.path_info");
+ if (pathInfo != null) {
+ jspUri += pathInfo;
+ }
+ } else {
+ /*
+ * Requested JSP has not been the target of a
+ * RequestDispatcher.include(). Reconstruct its path from the
+ * request's getServletPath() and getPathInfo()
+ */
+ jspUri = request.getServletPath();
+ String pathInfo = request.getPathInfo();
+ if (pathInfo != null) {
+ jspUri += pathInfo;
+ }
+ }
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("JspEngine --> " + jspUri);
+ log.debug("\t ServletPath: " + request.getServletPath());
+ log.debug("\t PathInfo: " + request.getPathInfo());
+ log.debug("\t RealPath: " + context.getRealPath(jspUri));
+ log.debug("\t RequestURI: " + request.getRequestURI());
+ log.debug("\t QueryString: " + request.getQueryString());
+ log.debug("\t Request Params: ");
+ Enumeration e = request.getParameterNames();
+ while (e.hasMoreElements()) {
+ String name = (String) e.nextElement();
+ log.debug("\t\t " + name + " = "
+ + request.getParameter(name));
+ }
+ }
+
+ try {
+ boolean precompile = preCompile(request);
+ serviceJspFile(request, response, jspUri, null, precompile);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (ServletException e) {
+ throw e;
+ } catch (IOException e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new ServletException(e);
+ }
+
+ }
+
+ public void destroy() {
+ if (log.isDebugEnabled()) {
+ log.debug("JspServlet.destroy()");
+ }
+
+ rctxt.destroy();
+ }
+
+
+ // -------------------------------------------------------- Private Methods
+
+ private void serviceJspFile(HttpServletRequest request,
+ HttpServletResponse response, String jspUri,
+ Throwable exception, boolean precompile)
+ throws ServletException, IOException {
+
+ JspServletWrapper wrapper =
+ (JspServletWrapper) rctxt.getWrapper(jspUri);
+ if (wrapper == null) {
+ synchronized(this) {
+ wrapper = (JspServletWrapper) rctxt.getWrapper(jspUri);
+ if (wrapper == null) {
+ // Check if the requested JSP page exists, to avoid
+ // creating unnecessary directories and files.
+ if (null == context.getResource(jspUri)) {
+ String includeRequestUri = (String)
+ request.getAttribute("javax.servlet.include.request_uri");
+ if (includeRequestUri != null) {
+ // This file was included. Throw an exception as
+ // a response.sendError() will be ignored
+ throw new ServletException(Localizer.getMessage(
+ "jsp.error.file.not.found",jspUri));
+ } else {
+ try {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND,
+ request.getRequestURI());
+ } catch (IllegalStateException ise) {
+ log.error(Localizer.getMessage("jsp.error.file.not.found",
+ jspUri));
+ }
+ }
+ return;
+ }
+ boolean isErrorPage = exception != null;
+ wrapper = new JspServletWrapper(config, options, jspUri,
+ isErrorPage, rctxt);
+ rctxt.addWrapper(jspUri,wrapper);
+ }
+ }
+ }
+
+ wrapper.service(request, response, precompile);
+
+ }
+
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspServletWrapper.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspServletWrapper.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspServletWrapper.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/JspServletWrapper.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,465 @@
+/*
+ * 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.servlet;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.SingleThreadModel;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.tagext.TagInfo;
+
+import org.apache.struts2.jasper.JasperException;
+import org.apache.struts2.jasper.JspCompilationContext;
+import org.apache.struts2.jasper.Options;
+import org.apache.struts2.jasper.compiler.ErrorDispatcher;
+import org.apache.struts2.jasper.compiler.JavacErrorDetail;
+import org.apache.struts2.jasper.compiler.JspRuntimeContext;
+import org.apache.struts2.jasper.compiler.Localizer;
+import org.apache.struts2.jasper.runtime.JspSourceDependent;
+
+/**
+ * The JSP engine (a.k.a Jasper).
+ *
+ * The servlet container is responsible for providing a
+ * URLClassLoader for the web application context Jasper
+ * is being used in. Jasper will try get the Tomcat
+ * ServletContext attribute for its ServletContext class
+ * loader, if that fails, it uses the parent class loader.
+ * In either case, it must be a URLClassLoader.
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Remy Maucherat
+ * @author Kin-man Chung
+ * @author Glenn Nielsen
+ * @author Tim Fennell
+ */
+
+public class JspServletWrapper {
+
+ private Servlet theServlet;
+ private String jspUri;
+ private Class servletClass;
+ private Class tagHandlerClass;
+ private JspCompilationContext ctxt;
+ private long available = 0L;
+ private ServletConfig config;
+ private Options options;
+ private boolean firstTime = true;
+ private boolean reload = true;
+ private boolean isTagFile;
+ private int tripCount;
+ private JasperException compileException;
+ private long servletClassLastModifiedTime;
+ private long lastModificationTest = 0L;
+
+ /*
+ * JspServletWrapper for JSP pages.
+ */
+ JspServletWrapper(ServletConfig config, Options options, String jspUri,
+ boolean isErrorPage, JspRuntimeContext rctxt)
+ throws JasperException {
+
+ this.isTagFile = false;
+ this.config = config;
+ this.options = options;
+ this.jspUri = jspUri;
+ ctxt = new JspCompilationContext(jspUri, isErrorPage, options,
+ config.getServletContext(),
+ this, rctxt);
+ }
+
+ /*
+ * JspServletWrapper for tag files.
+ */
+ public JspServletWrapper(ServletContext servletContext,
+ Options options,
+ String tagFilePath,
+ TagInfo tagInfo,
+ JspRuntimeContext rctxt,
+ URL tagFileJarUrl)
+ throws JasperException {
+
+ this.isTagFile = true;
+ this.config = null; // not used
+ this.options = options;
+ this.jspUri = tagFilePath;
+ this.tripCount = 0;
+ ctxt = new JspCompilationContext(jspUri, tagInfo, options,
+ servletContext, this, rctxt,
+ tagFileJarUrl);
+ }
+
+ public JspCompilationContext getJspEngineContext() {
+ return ctxt;
+ }
+
+ public void setReload(boolean reload) {
+ this.reload = reload;
+ }
+
+ public Servlet getServlet()
+ throws ServletException, IOException, FileNotFoundException
+ {
+ if (reload) {
+ synchronized (this) {
+ // Synchronizing on jsw enables simultaneous loading
+ // of different pages, but not the same page.
+ if (reload) {
+ // This is to maintain the original protocol.
+ destroy();
+
+ Servlet servlet = null;
+ try {
+ servletClass = ctxt.load();
+ servlet = (Servlet) servletClass.newInstance();
+ } catch( IllegalAccessException ex1 ) {
+ throw new JasperException( ex1 );
+ } catch( InstantiationException ex ) {
+ throw new JasperException( ex );
+ }
+
+ servlet.init(config);
+
+ if (!firstTime) {
+ ctxt.getRuntimeContext().incrementJspReloadCount();
+ }
+
+ theServlet = servlet;
+ reload = false;
+ }
+ }
+ }
+ return theServlet;
+ }
+
+ public ServletContext getServletContext() {
+ return config.getServletContext();
+ }
+
+ /**
+ * Sets the compilation exception for this JspServletWrapper.
+ *
+ * @param je The compilation exception
+ */
+ public void setCompilationException(JasperException je) {
+ this.compileException = je;
+ }
+
+ /**
+ * Sets the last-modified time of the servlet class file associated with
+ * this JspServletWrapper.
+ *
+ * @param lastModified Last-modified time of servlet class
+ */
+ public void setServletClassLastModifiedTime(long lastModified) {
+ if (this.servletClassLastModifiedTime < lastModified) {
+ synchronized (this) {
+ if (this.servletClassLastModifiedTime < lastModified) {
+ this.servletClassLastModifiedTime = lastModified;
+ reload = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Compile (if needed) and load a tag file
+ */
+ public Class loadTagFile() throws JasperException {
+
+ try {
+ if (ctxt.isRemoved()) {
+ throw new FileNotFoundException(jspUri);
+ }
+ if (options.getDevelopment() || firstTime ) {
+ synchronized (this) {
+ firstTime = false;
+ ctxt.compile();
+ }
+ } else {
+ if (compileException != null) {
+ throw compileException;
+ }
+ }
+
+ if (reload) {
+ tagHandlerClass = ctxt.load();
+ reload = false;
+ }
+ } catch (FileNotFoundException ex) {
+ throw new JasperException(ex);
+ }
+
+ return tagHandlerClass;
+ }
+
+ /**
+ * Compile and load a prototype for the Tag file. This is needed
+ * when compiling tag files with circular dependencies. A prototpe
+ * (skeleton) with no dependencies on other other tag files is
+ * generated and compiled.
+ */
+ public Class loadTagFilePrototype() throws JasperException {
+
+ ctxt.setPrototypeMode(true);
+ try {
+ return loadTagFile();
+ } finally {
+ ctxt.setPrototypeMode(false);
+ }
+ }
+
+ /**
+ * Get a list of files that the current page has source dependency on.
+ */
+ public java.util.List getDependants() {
+ try {
+ Object target;
+ if (isTagFile) {
+ if (reload) {
+ tagHandlerClass = ctxt.load();
+ reload = false;
+ }
+ target = tagHandlerClass.newInstance();
+ } else {
+ target = getServlet();
+ }
+ if (target != null && target instanceof JspSourceDependent) {
+ return ((java.util.List) ((JspSourceDependent) target).getDependants());
+ }
+ } catch (Throwable ex) {
+ }
+ return null;
+ }
+
+ public boolean isTagFile() {
+ return this.isTagFile;
+ }
+
+ public int incTripCount() {
+ return tripCount++;
+ }
+
+ public int decTripCount() {
+ return tripCount--;
+ }
+
+ public void service(HttpServletRequest request,
+ HttpServletResponse response,
+ boolean precompile)
+ throws ServletException, IOException, FileNotFoundException {
+ try {
+
+ if (ctxt.isRemoved()) {
+ throw new FileNotFoundException(jspUri);
+ }
+
+ if ((available > 0L) && (available < Long.MAX_VALUE)) {
+ if (available > System.currentTimeMillis()) {
+ response.setDateHeader("Retry-After", available);
+ response.sendError
+ (HttpServletResponse.SC_SERVICE_UNAVAILABLE,
+ Localizer.getMessage("jsp.error.unavailable"));
+ return;
+ } else {
+ // Wait period has expired. Reset.
+ available = 0;
+ }
+ }
+
+ /*
+ * (1) Compile
+ */
+ if (options.getDevelopment() || firstTime ) {
+ synchronized (this) {
+ firstTime = false;
+
+ // The following sets reload to true, if necessary
+ ctxt.compile();
+ }
+ } else {
+ if (compileException != null) {
+ // Throw cached compilation exception
+ throw compileException;
+ }
+ }
+
+ /*
+ * (2) (Re)load servlet class file
+ */
+ getServlet();
+
+ // If a page is to be precompiled only, return.
+ if (precompile) {
+ return;
+ }
+
+ /*
+ * (3) Service request
+ */
+ if (theServlet instanceof SingleThreadModel) {
+ // sync on the wrapper so that the freshness
+ // of the page is determined right before servicing
+ synchronized (this) {
+ theServlet.service(request, response);
+ }
+ } else {
+ theServlet.service(request, response);
+ }
+
+ } catch (UnavailableException ex) {
+ String includeRequestUri = (String)
+ request.getAttribute("javax.servlet.include.request_uri");
+ if (includeRequestUri != null) {
+ // This file was included. Throw an exception as
+ // a response.sendError() will be ignored by the
+ // servlet engine.
+ throw ex;
+ } else {
+ int unavailableSeconds = ex.getUnavailableSeconds();
+ if (unavailableSeconds <= 0) {
+ unavailableSeconds = 60; // Arbitrary default
+ }
+ available = System.currentTimeMillis() +
+ (unavailableSeconds * 1000L);
+ response.sendError
+ (HttpServletResponse.SC_SERVICE_UNAVAILABLE,
+ ex.getMessage());
+ }
+ } catch (ServletException ex) {
+ if(options.getDevelopment()) {
+ throw handleJspException(ex);
+ } else {
+ throw ex;
+ }
+ } catch (IOException ex) {
+ if(options.getDevelopment()) {
+ throw handleJspException(ex);
+ } else {
+ throw ex;
+ }
+ } catch (IllegalStateException ex) {
+ if(options.getDevelopment()) {
+ throw handleJspException(ex);
+ } else {
+ throw ex;
+ }
+ } catch (Exception ex) {
+ if(options.getDevelopment()) {
+ throw handleJspException(ex);
+ } else {
+ throw new JasperException(ex);
+ }
+ }
+ }
+
+ public void destroy() {
+ if (theServlet != null) {
+ theServlet.destroy();
+ }
+ }
+
+ /**
+ * @return Returns the lastModificationTest.
+ */
+ public long getLastModificationTest() {
+ return lastModificationTest;
+ }
+ /**
+ * @param lastModificationTest The lastModificationTest to set.
+ */
+ public void setLastModificationTest(long lastModificationTest) {
+ this.lastModificationTest = lastModificationTest;
+ }
+
+ /**
+ * <p>Attempts to construct a JasperException that contains helpful information
+ * about what went wrong. Uses the JSP compiler system to translate the line
+ * number in the generated servlet that originated the exception to a line
+ * number in the JSP. Then constructs an exception containing that
+ * information, and a snippet of the JSP to help debugging.
+ * Please see http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 and
+ * http://www.tfenne.com/jasper/ for more details.
+ *</p>
+ *
+ * @param ex the exception that was the cause of the problem.
+ * @return a JasperException with more detailed information
+ */
+ protected JasperException handleJspException(Exception ex) {
+ try {
+ Throwable realException = ex;
+ if (ex instanceof ServletException) {
+ realException = ((ServletException) ex).getRootCause();
+ }
+
+ // First identify the stack frame in the trace that represents the JSP
+ StackTraceElement[] frames = realException.getStackTrace();
+ StackTraceElement jspFrame = null;
+
+ for (int i=0; i<frames.length; ++i) {
+ if ( frames[i].getClassName().equals(this.getServlet().getClass().getName()) ) {
+ jspFrame = frames[i];
+ break;
+ }
+ }
+
+ if (jspFrame == null) {
+ // If we couldn't find a frame in the stack trace corresponding
+ // to the generated servlet class, we can't really add anything
+ return new JasperException(ex);
+ }
+ else {
+ int javaLineNumber = jspFrame.getLineNumber();
+ JavacErrorDetail detail = ErrorDispatcher.createJavacError(
+ jspFrame.getMethodName(),
+ this.ctxt.getCompiler().getPageNodes(),
+ null,
+ javaLineNumber,
+ this.ctxt);
+
+ // If the line number is less than one we couldn't find out
+ // where in the JSP things went wrong
+ int jspLineNumber = detail.getJspBeginLineNumber();
+ if (jspLineNumber < 1) {
+ throw new JasperException(ex);
+ }
+
+ return new JasperException("Exception in JSP: " +
+ detail.getJspFileName() + ":" + jspLineNumber + "\n\n" +
+ detail.getJspExtract() + "\n\nStacktrace:", ex);
+ }
+ } catch (Exception je) {
+ // If anything goes wrong, just revert to the original behaviour
+ if (ex instanceof JasperException) {
+ return (JasperException) ex;
+ } else {
+ return new JasperException(ex);
+ }
+ }
+ }
+
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/mbeans-descriptors.xml
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/mbeans-descriptors.xml?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/mbeans-descriptors.xml (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/servlet/mbeans-descriptors.xml Fri Jul 31 18:12:48 2009
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<mbeans-descriptors>
+
+ <mbean name="JspMonitor"
+ description="JSP Monitoring"
+ domain="Catalina"
+ group="Monitoring"
+ type="org.apache.struts2.jasper.servlet.JspServlet">
+
+ <attribute name="jspCount"
+ description="The number of JSPs that have been loaded into a webapp"
+ type="int"/>
+
+ <attribute name="jspReloadCount"
+ description="The number of JSPs that have been reloaded"
+ type="int"/>
+
+ </mbean>
+
+</mbeans-descriptors>
\ No newline at end of file
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/Util.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/Util.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/Util.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/Util.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,326 @@
+/*
+ * 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.tagplugins.jstl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.Locale;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+
+/**
+ * Util contains some often used consts, static methods and embedded class
+ * to support the JSTL tag plugin.
+ */
+
+public class Util {
+
+ public static final String VALID_SCHEME_CHAR =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
+
+ public static final String DEFAULT_ENCODING =
+ "ISO-8859-1";
+
+ public static final int HIGHEST_SPECIAL = '>';
+
+ public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][];
+
+ static {
+ specialCharactersRepresentation['&'] = "&".toCharArray();
+ specialCharactersRepresentation['<'] = "<".toCharArray();
+ specialCharactersRepresentation['>'] = ">".toCharArray();
+ specialCharactersRepresentation['"'] = """.toCharArray();
+ specialCharactersRepresentation['\''] = "'".toCharArray();
+ }
+
+ /**
+ * Converts the given string description of a scope to the corresponding
+ * PageContext constant.
+ *
+ * The validity of the given scope has already been checked by the
+ * appropriate TLV.
+ *
+ * @param scope String description of scope
+ *
+ * @return PageContext constant corresponding to given scope description
+ *
+ * taken from org.apache.taglibs.standard.tag.common.core.Util
+ */
+ public static int getScope(String scope){
+ int ret = PageContext.PAGE_SCOPE;
+
+ if("request".equalsIgnoreCase(scope)){
+ ret = PageContext.REQUEST_SCOPE;
+ }else if("session".equalsIgnoreCase(scope)){
+ ret = PageContext.SESSION_SCOPE;
+ }else if("application".equalsIgnoreCase(scope)){
+ ret = PageContext.APPLICATION_SCOPE;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Returns <tt>true</tt> if our current URL is absolute,
+ * <tt>false</tt> otherwise.
+ * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport
+ */
+ public static boolean isAbsoluteUrl(String url){
+ if(url == null){
+ return false;
+ }
+
+ int colonPos = url.indexOf(":");
+ if(colonPos == -1){
+ return false;
+ }
+
+ for(int i=0;i<colonPos;i++){
+ if(VALID_SCHEME_CHAR.indexOf(url.charAt(i)) == -1){
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the value associated with a content-type attribute.
+ * Syntax defined in RFC 2045, section 5.1.
+ * taken from org.apache.taglibs.standard.tag.common.core.Util
+ */
+ public static String getContentTypeAttribute(String input, String name) {
+ int begin;
+ int end;
+ int index = input.toUpperCase().indexOf(name.toUpperCase());
+ if (index == -1) return null;
+ index = index + name.length(); // positioned after the attribute name
+ index = input.indexOf('=', index); // positioned at the '='
+ if (index == -1) return null;
+ index += 1; // positioned after the '='
+ input = input.substring(index).trim();
+
+ if (input.charAt(0) == '"') {
+ // attribute value is a quoted string
+ begin = 1;
+ end = input.indexOf('"', begin);
+ if (end == -1) return null;
+ } else {
+ begin = 0;
+ end = input.indexOf(';');
+ if (end == -1) end = input.indexOf(' ');
+ if (end == -1) end = input.length();
+ }
+ return input.substring(begin, end).trim();
+ }
+
+ /**
+ * Strips a servlet session ID from <tt>url</tt>. The session ID
+ * is encoded as a URL "path parameter" beginning with "jsessionid=".
+ * We thus remove anything we find between ";jsessionid=" (inclusive)
+ * and either EOS or a subsequent ';' (exclusive).
+ *
+ * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport
+ */
+ public static String stripSession(String url) {
+ StringBuffer u = new StringBuffer(url);
+ int sessionStart;
+ while ((sessionStart = u.toString().indexOf(";jsessionid=")) != -1) {
+ int sessionEnd = u.toString().indexOf(";", sessionStart + 1);
+ if (sessionEnd == -1)
+ sessionEnd = u.toString().indexOf("?", sessionStart + 1);
+ if (sessionEnd == -1) // still
+ sessionEnd = u.length();
+ u.delete(sessionStart, sessionEnd);
+ }
+ return u.toString();
+ }
+
+
+ /**
+ * Performs the following substring replacements
+ * (to facilitate output to XML/HTML pages):
+ *
+ * & -> &
+ * < -> <
+ * > -> >
+ * " -> "
+ * ' -> '
+ *
+ * See also OutSupport.writeEscapedXml().
+ *
+ * taken from org.apache.taglibs.standard.tag.common.core.Util
+ */
+ public static String escapeXml(String buffer) {
+ int start = 0;
+ int length = buffer.length();
+ char[] arrayBuffer = buffer.toCharArray();
+ StringBuffer escapedBuffer = null;
+
+ for (int i = 0; i < length; i++) {
+ char c = arrayBuffer[i];
+ if (c <= HIGHEST_SPECIAL) {
+ char[] escaped = specialCharactersRepresentation[c];
+ if (escaped != null) {
+ // create StringBuffer to hold escaped xml string
+ if (start == 0) {
+ escapedBuffer = new StringBuffer(length + 5);
+ }
+ // add unescaped portion
+ if (start < i) {
+ escapedBuffer.append(arrayBuffer,start,i-start);
+ }
+ start = i + 1;
+ // add escaped xml
+ escapedBuffer.append(escaped);
+ }
+ }
+ }
+ // no xml escaping was necessary
+ if (start == 0) {
+ return buffer;
+ }
+ // add rest of unescaped portion
+ if (start < length) {
+ escapedBuffer.append(arrayBuffer,start,length-start);
+ }
+ return escapedBuffer.toString();
+ }
+
+ /** Utility methods
+ * taken from org.apache.taglibs.standard.tag.common.core.UrlSupport
+ */
+ public static String resolveUrl(
+ String url, String context, PageContext pageContext)
+ throws JspException {
+ // don't touch absolute URLs
+ if (isAbsoluteUrl(url))
+ return url;
+
+ // normalize relative URLs against a context root
+ HttpServletRequest request =
+ (HttpServletRequest) pageContext.getRequest();
+ if (context == null) {
+ if (url.startsWith("/"))
+ return (request.getContextPath() + url);
+ else
+ return url;
+ } else {
+ if (!context.startsWith("/") || !url.startsWith("/")) {
+ throw new JspTagException(
+ "In URL tags, when the \"context\" attribute is specified, values of both \"context\" and \"url\" must start with \"/\".");
+ }
+ if (context.equals("/")) {
+ // Don't produce string starting with '//', many
+ // browsers interpret this as host name, not as
+ // path on same host.
+ return url;
+ } else {
+ return (context + url);
+ }
+ }
+ }
+
+ /** Wraps responses to allow us to retrieve results as Strings.
+ * mainly taken from org.apache.taglibs.standard.tag.common.core.importSupport
+ */
+ public static class ImportResponseWrapper extends HttpServletResponseWrapper{
+
+ private StringWriter sw = new StringWriter();
+ private ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ private ServletOutputStream sos = new ServletOutputStream() {
+ public void write(int b) throws IOException {
+ bos.write(b);
+ }
+ };
+ private boolean isWriterUsed;
+ private boolean isStreamUsed;
+ private int status = 200;
+ private String charEncoding;
+
+ public ImportResponseWrapper(HttpServletResponse arg0) {
+ super(arg0);
+ // TODO Auto-generated constructor stub
+ }
+
+ public PrintWriter getWriter() {
+ if (isStreamUsed)
+ throw new IllegalStateException("Unexpected internal error during <import>: " +
+ "Target servlet called getWriter(), then getOutputStream()");
+ isWriterUsed = true;
+ return new PrintWriter(sw);
+ }
+
+ public ServletOutputStream getOutputStream() {
+ if (isWriterUsed)
+ throw new IllegalStateException("Unexpected internal error during <import>: " +
+ "Target servlet called getOutputStream(), then getWriter()");
+ isStreamUsed = true;
+ return sos;
+ }
+
+ /** Has no effect. */
+ public void setContentType(String x) {
+ // ignore
+ }
+
+ /** Has no effect. */
+ public void setLocale(Locale x) {
+ // ignore
+ }
+
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public String getCharEncoding(){
+ return this.charEncoding;
+ }
+
+ public void setCharEncoding(String ce){
+ this.charEncoding = ce;
+ }
+
+ public String getString() throws UnsupportedEncodingException {
+ if (isWriterUsed)
+ return sw.toString();
+ else if (isStreamUsed) {
+ if (this.charEncoding != null && !this.charEncoding.equals(""))
+ return bos.toString(charEncoding);
+ else
+ return bos.toString("ISO-8859-1");
+ } else
+ return ""; // target didn't write anything
+ }
+ }
+
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/Catch.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/Catch.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/Catch.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/Catch.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,72 @@
+/*
+ * 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.tagplugins.jstl.core;
+
+import org.apache.struts2.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.struts2.jasper.compiler.tagplugin.TagPluginContext;
+
+public class Catch implements TagPlugin {
+
+ public void doTag(TagPluginContext ctxt) {
+
+ //flag for the existence of the var attribute
+ boolean hasVar = ctxt.isAttributeSpecified("var");
+
+ //temp name for exception and caught
+ String exceptionName = ctxt.getTemporaryVariableName();
+ String caughtName = ctxt.getTemporaryVariableName();
+
+ //main part to generate code
+ ctxt.generateJavaSource("boolean " + caughtName + " = false;");
+ ctxt.generateJavaSource("try{");
+ ctxt.generateBody();
+ ctxt.generateJavaSource("}");
+
+ //do catch
+ ctxt.generateJavaSource("catch(Throwable " + exceptionName + "){");
+
+ //if the var specified, the exception object should
+ //be set to the attribute "var" defines in page scope
+ if(hasVar){
+ String strVar = ctxt.getConstantAttribute("var");
+ ctxt.generateJavaSource(" pageContext.setAttribute(\"" + strVar + "\", "
+ + exceptionName + ", PageContext.PAGE_SCOPE);");
+ }
+
+ //whenever there's exception caught,
+ //the flag caught should be set true;
+ ctxt.generateJavaSource(" " + caughtName + " = true;");
+ ctxt.generateJavaSource("}");
+
+ //do finally
+ ctxt.generateJavaSource("finally{");
+
+ //if var specified, the attribute it defines
+ //in page scope should be removed
+ if(hasVar){
+ String strVar = ctxt.getConstantAttribute("var");
+ ctxt.generateJavaSource(" if(!" + caughtName + "){");
+ ctxt.generateJavaSource(" pageContext.removeAttribute(\"" + strVar + "\", PageContext.PAGE_SCOPE);");
+ ctxt.generateJavaSource(" }");
+ }
+
+ ctxt.generateJavaSource("}");
+ }
+
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/Choose.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/Choose.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/Choose.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/Choose.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,34 @@
+/*
+ * 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.tagplugins.jstl.core;
+
+import org.apache.struts2.jasper.compiler.tagplugin.*;
+
+public final class Choose implements TagPlugin {
+
+ public void doTag(TagPluginContext ctxt) {
+
+ // Not much to do here, much of the work will be done in the
+ // containing tags, <c:when> and <c:otherwise>.
+
+ ctxt.generateBody();
+ // See comments in When.java for the reason "}" is generated here.
+ ctxt.generateJavaSource("}");
+ }
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/ForEach.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/ForEach.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/ForEach.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/tagplugins/jstl/core/ForEach.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,344 @@
+/*
+ * 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.tagplugins.jstl.core;
+
+import org.apache.struts2.jasper.compiler.tagplugin.*;
+
+public final class ForEach implements TagPlugin {
+
+ private boolean hasVar, hasBegin, hasEnd, hasStep;
+
+ public void doTag(TagPluginContext ctxt) {
+
+ String index = null;
+
+ boolean hasVarStatus = ctxt.isAttributeSpecified("varStatus");
+ if (hasVarStatus) {
+ ctxt.dontUseTagPlugin();
+ return;
+ }
+
+ hasVar = ctxt.isAttributeSpecified("var");
+ hasBegin = ctxt.isAttributeSpecified("begin");
+ hasEnd = ctxt.isAttributeSpecified("end");
+ hasStep = ctxt.isAttributeSpecified("step");
+
+ boolean hasItems = ctxt.isAttributeSpecified("items");
+ if (hasItems) {
+ doCollection(ctxt);
+ return;
+ }
+
+ // We must have a begin and end attributes
+ index = ctxt.getTemporaryVariableName();
+ ctxt.generateJavaSource("for (int " + index + " = ");
+ ctxt.generateAttribute("begin");
+ ctxt.generateJavaSource("; " + index + " <= ");
+ ctxt.generateAttribute("end");
+ if (hasStep) {
+ ctxt.generateJavaSource("; " + index + "+=");
+ ctxt.generateAttribute("step");
+ ctxt.generateJavaSource(") {");
+ }
+ else {
+ ctxt.generateJavaSource("; " + index + "++) {");
+ }
+
+ // If var is specified and the body contains an EL, then sycn
+ // the var attribute
+ if (hasVar /* && ctxt.hasEL() */) {
+ ctxt.generateJavaSource("_jspx_page_context.setAttribute(");
+ ctxt.generateAttribute("var");
+ ctxt.generateJavaSource(", String.valueOf(" + index + "));");
+ }
+ ctxt.generateBody();
+ ctxt.generateJavaSource("}");
+ }
+
+ /**
+ * Generate codes for Collections
+ * The pseudo code is:
+ */
+ private void doCollection(TagPluginContext ctxt) {
+
+ ctxt.generateImport("java.util.*");
+ generateIterators(ctxt);
+
+ String itemsV = ctxt.getTemporaryVariableName();
+ ctxt.generateJavaSource("Object " + itemsV + "= ");
+ ctxt.generateAttribute("items");
+ ctxt.generateJavaSource(";");
+
+ String indexV=null, beginV=null, endV=null, stepV=null;
+ if (hasBegin) {
+ beginV = ctxt.getTemporaryVariableName();
+ ctxt.generateJavaSource("int " + beginV + " = ");
+ ctxt.generateAttribute("begin");
+ ctxt.generateJavaSource(";");
+ }
+ if (hasEnd) {
+ indexV = ctxt.getTemporaryVariableName();
+ ctxt.generateJavaSource("int " + indexV + " = 0;");
+ endV = ctxt.getTemporaryVariableName();
+ ctxt.generateJavaSource("int " + endV + " = ");
+ ctxt.generateAttribute("end");
+ ctxt.generateJavaSource(";");
+ }
+ if (hasStep) {
+ stepV = ctxt.getTemporaryVariableName();
+ ctxt.generateJavaSource("int " + stepV + " = ");
+ ctxt.generateAttribute("step");
+ ctxt.generateJavaSource(";");
+ }
+
+ String iterV = ctxt.getTemporaryVariableName();
+ ctxt.generateJavaSource("Iterator " + iterV + " = null;");
+ // Object[]
+ ctxt.generateJavaSource("if (" + itemsV + " instanceof Object[])");
+ ctxt.generateJavaSource(iterV + "=toIterator((Object[])" + itemsV + ");");
+ // boolean[]
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof boolean[])");
+ ctxt.generateJavaSource(iterV + "=toIterator((boolean[])" + itemsV + ");");
+ // byte[]
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof byte[])");
+ ctxt.generateJavaSource(iterV + "=toIterator((byte[])" + itemsV + ");");
+ // char[]
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof char[])");
+ ctxt.generateJavaSource(iterV + "=toIterator((char[])" + itemsV + ");");
+ // short[]
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof short[])");
+ ctxt.generateJavaSource(iterV + "=toIterator((short[])" + itemsV + ");");
+ // int[]
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof int[])");
+ ctxt.generateJavaSource(iterV + "=toIterator((int[])" + itemsV + ");");
+ // long[]
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof long[])");
+ ctxt.generateJavaSource(iterV + "=toIterator((long[])" + itemsV + ");");
+ // float[]
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof float[])");
+ ctxt.generateJavaSource(iterV + "=toIterator((float[])" + itemsV + ");");
+ // double[]
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof double[])");
+ ctxt.generateJavaSource(iterV + "=toIterator((double[])" + itemsV + ");");
+
+ // Collection
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof Collection)");
+ ctxt.generateJavaSource(iterV + "=((Collection)" + itemsV + ").iterator();");
+
+ // Iterator
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof Iterator)");
+ ctxt.generateJavaSource(iterV + "=(Iterator)" + itemsV + ";");
+
+ // Enumeration
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof Enumeration)");
+ ctxt.generateJavaSource(iterV + "=toIterator((Enumeration)" + itemsV + ");");
+
+ // Map
+ ctxt.generateJavaSource("else if (" + itemsV + " instanceof Map)");
+ ctxt.generateJavaSource(iterV + "=((Map)" + itemsV + ").entrySet().iterator();");
+
+ if (hasBegin) {
+ String tV = ctxt.getTemporaryVariableName();
+ ctxt.generateJavaSource("for (int " + tV + "=" + beginV + ";" +
+ tV + ">0 && " + iterV + ".hasNext(); " +
+ tV + "--)");
+ ctxt.generateJavaSource(iterV + ".next();");
+ }
+
+ ctxt.generateJavaSource("while (" + iterV + ".hasNext()){");
+ if (hasVar) {
+ ctxt.generateJavaSource("_jspx_page_context.setAttribute(");
+ ctxt.generateAttribute("var");
+ ctxt.generateJavaSource(", " + iterV + ".next());");
+ }
+
+ ctxt.generateBody();
+
+ if (hasStep) {
+ String tV = ctxt.getTemporaryVariableName();
+ ctxt.generateJavaSource("for (int " + tV + "=" + stepV + "-1;" +
+ tV + ">0 && " + iterV + ".hasNext(); " +
+ tV + "--)");
+ ctxt.generateJavaSource(iterV + ".next();");
+ }
+ if (hasEnd) {
+ if (hasStep) {
+ ctxt.generateJavaSource(indexV + "+=" + stepV + ";");
+ }
+ else {
+ ctxt.generateJavaSource(indexV + "++;");
+ }
+ if (hasBegin) {
+ ctxt.generateJavaSource("if(" + beginV + "+" + indexV +
+ ">"+ endV + ")");
+ }
+ else {
+ ctxt.generateJavaSource("if(" + indexV + ">" + endV + ")");
+ }
+ ctxt.generateJavaSource("break;");
+ }
+ ctxt.generateJavaSource("}"); // while
+ }
+
+ /**
+ * Generate iterators for data types supported in items
+ */
+ private void generateIterators(TagPluginContext ctxt) {
+
+ // Object[]
+ ctxt.generateDeclaration("ObjectArrayIterator",
+ "private Iterator toIterator(final Object[] a){\n" +
+ " return (new Iterator() {\n" +
+ " int index=0;\n" +
+ " public boolean hasNext() {\n" +
+ " return index < a.length;}\n" +
+ " public Object next() {\n" +
+ " return a[index++];}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ // boolean[]
+ ctxt.generateDeclaration("booleanArrayIterator",
+ "private Iterator toIterator(final boolean[] a){\n" +
+ " return (new Iterator() {\n" +
+ " int index=0;\n" +
+ " public boolean hasNext() {\n" +
+ " return index < a.length;}\n" +
+ " public Object next() {\n" +
+ " return new Boolean(a[index++]);}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ // byte[]
+ ctxt.generateDeclaration("byteArrayIterator",
+ "private Iterator toIterator(final byte[] a){\n" +
+ " return (new Iterator() {\n" +
+ " int index=0;\n" +
+ " public boolean hasNext() {\n" +
+ " return index < a.length;}\n" +
+ " public Object next() {\n" +
+ " return new Byte(a[index++]);}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ // char[]
+ ctxt.generateDeclaration("charArrayIterator",
+ "private Iterator toIterator(final char[] a){\n" +
+ " return (new Iterator() {\n" +
+ " int index=0;\n" +
+ " public boolean hasNext() {\n" +
+ " return index < a.length;}\n" +
+ " public Object next() {\n" +
+ " return new Character(a[index++]);}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ // short[]
+ ctxt.generateDeclaration("shortArrayIterator",
+ "private Iterator toIterator(final short[] a){\n" +
+ " return (new Iterator() {\n" +
+ " int index=0;\n" +
+ " public boolean hasNext() {\n" +
+ " return index < a.length;}\n" +
+ " public Object next() {\n" +
+ " return new Short(a[index++]);}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ // int[]
+ ctxt.generateDeclaration("intArrayIterator",
+ "private Iterator toIterator(final int[] a){\n" +
+ " return (new Iterator() {\n" +
+ " int index=0;\n" +
+ " public boolean hasNext() {\n" +
+ " return index < a.length;}\n" +
+ " public Object next() {\n" +
+ " return new Integer(a[index++]);}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ // long[]
+ ctxt.generateDeclaration("longArrayIterator",
+ "private Iterator toIterator(final long[] a){\n" +
+ " return (new Iterator() {\n" +
+ " int index=0;\n" +
+ " public boolean hasNext() {\n" +
+ " return index < a.length;}\n" +
+ " public Object next() {\n" +
+ " return new Long(a[index++]);}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ // float[]
+ ctxt.generateDeclaration("floatArrayIterator",
+ "private Iterator toIterator(final float[] a){\n" +
+ " return (new Iterator() {\n" +
+ " int index=0;\n" +
+ " public boolean hasNext() {\n" +
+ " return index < a.length;}\n" +
+ " public Object next() {\n" +
+ " return new Float(a[index++]);}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ // double[]
+ ctxt.generateDeclaration("doubleArrayIterator",
+ "private Iterator toIterator(final double[] a){\n" +
+ " return (new Iterator() {\n" +
+ " int index=0;\n" +
+ " public boolean hasNext() {\n" +
+ " return index < a.length;}\n" +
+ " public Object next() {\n" +
+ " return new Double(a[index++]);}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ // Enumeration
+ ctxt.generateDeclaration("enumIterator",
+ "private Iterator toIterator(final Enumeration e){\n" +
+ " return (new Iterator() {\n" +
+ " public boolean hasNext() {\n" +
+ " return e.hasMoreElements();}\n" +
+ " public Object next() {\n" +
+ " return e.nextElement();}\n" +
+ " public void remove() {}\n" +
+ " });\n" +
+ "}"
+ );
+
+ }
+}