importing jasper 6.0.20, this code will not compile

git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@819435 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Musachy Barroso
2009-09-28 00:43:34 +00:00
parent 5dc1101021
commit 57eed18d14
111 changed files with 44571 additions and 0 deletions
@@ -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.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.jasper.Constants.JSP_SERVLET_BASE", "org.apache.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.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.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.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.jasper.Constants.PRECOMPILE", "jsp_precompile");
/**
* The default package name for compiled jsp pages.
*/
public static final String JSP_PACKAGE_NAME =
System.getProperty("org.apache.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.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.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.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");
}
@@ -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.jasper;
import java.io.File;
import java.util.*;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import org.apache.jasper.compiler.TldLocationsCache;
import org.apache.jasper.compiler.JspConfig;
import org.apache.jasper.compiler.TagPluginManager;
import org.apache.jasper.compiler.Localizer;
import org.apache.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);
}
}
@@ -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.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);
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,738 @@
/*
* 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.jasper;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.jsp.tagext.TagInfo;
import org.apache.jasper.compiler.Compiler;
import org.apache.jasper.compiler.JspRuntimeContext;
import org.apache.jasper.compiler.JspUtil;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.compiler.ServletWriter;
import org.apache.jasper.servlet.JasperLoader;
import org.apache.jasper.servlet.JspServletWrapper;
/**
* A place holder for various things that are used through out the JSP
* engine. This is a per-request/per-context data structure. Some of
* the instance variables are set at different points.
*
* Most of the path-related stuff is here - mangling names, versions, dirs,
* loading resources and dealing with uris.
*
* @author Anil K. Vijendran
* @author Harish Prabandham
* @author Pierre Delisle
* @author Costin Manolache
* @author Kin-man Chung
*/
public class JspCompilationContext {
protected org.apache.juli.logging.Log log =
org.apache.juli.logging.LogFactory.getLog(JspCompilationContext.class);
protected Map<String, URL> tagFileJarUrls;
protected boolean isPackagedTagFile;
protected String className;
protected String jspUri;
protected boolean isErrPage;
protected String basePackageName;
protected String derivedPackageName;
protected String servletJavaFileName;
protected String javaPath;
protected String classFileName;
protected String contentType;
protected ServletWriter writer;
protected Options options;
protected JspServletWrapper jsw;
protected Compiler jspCompiler;
protected String classPath;
protected String baseURI;
protected String outputDir;
protected ServletContext context;
protected URLClassLoader loader;
protected JspRuntimeContext rctxt;
protected int removed = 0;
protected URLClassLoader jspLoader;
protected URL baseUrl;
protected Class servletClass;
protected boolean isTagFile;
protected boolean protoTypeMode;
protected TagInfo tagInfo;
protected URL tagFileJarUrl;
// jspURI _must_ be relative to the context
public JspCompilationContext(String jspUri,
boolean isErrPage,
Options options,
ServletContext context,
JspServletWrapper jsw,
JspRuntimeContext rctxt) {
this.jspUri = canonicalURI(jspUri);
this.isErrPage = isErrPage;
this.options = options;
this.jsw = jsw;
this.context = context;
this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1);
// hack fix for resolveRelativeURI
if (baseURI == null) {
baseURI = "/";
} else if (baseURI.charAt(0) != '/') {
// strip the basde slash since it will be combined with the
// uriBase to generate a file
baseURI = "/" + baseURI;
}
if (baseURI.charAt(baseURI.length() - 1) != '/') {
baseURI += '/';
}
this.rctxt = rctxt;
this.tagFileJarUrls = new HashMap<String, URL>();
this.basePackageName = Constants.JSP_PACKAGE_NAME;
}
public JspCompilationContext(String tagfile,
TagInfo tagInfo,
Options options,
ServletContext context,
JspServletWrapper jsw,
JspRuntimeContext rctxt,
URL tagFileJarUrl) {
this(tagfile, false, options, context, jsw, rctxt);
this.isTagFile = true;
this.tagInfo = tagInfo;
this.tagFileJarUrl = tagFileJarUrl;
if (tagFileJarUrl != null) {
isPackagedTagFile = true;
}
}
/* ==================== Methods to override ==================== */
/** ---------- Class path and loader ---------- */
/**
* The classpath that is passed off to the Java compiler.
*/
public String getClassPath() {
if( classPath != null )
return classPath;
return rctxt.getClassPath();
}
/**
* The classpath that is passed off to the Java compiler.
*/
public void setClassPath(String classPath) {
this.classPath = classPath;
}
/**
* What class loader to use for loading classes while compiling
* this JSP?
*/
public ClassLoader getClassLoader() {
if( loader != null )
return loader;
return rctxt.getParentClassLoader();
}
public void setClassLoader(URLClassLoader loader) {
this.loader = loader;
}
public ClassLoader getJspLoader() {
if( jspLoader == null ) {
jspLoader = new JasperLoader
(new URL[] {baseUrl},
getClassLoader(),
rctxt.getPermissionCollection(),
rctxt.getCodeSource());
}
return jspLoader;
}
/** ---------- Input/Output ---------- */
/**
* The output directory to generate code into. The output directory
* is make up of the scratch directory, which is provide in Options,
* plus the directory derived from the package name.
*/
public String getOutputDir() {
if (outputDir == null) {
createOutputDir();
}
return outputDir;
}
/**
* Create a "Compiler" object based on some init param data. This
* is not done yet. Right now we're just hardcoding the actual
* compilers that are created.
*/
public Compiler createCompiler() throws JasperException {
if (jspCompiler != null ) {
return jspCompiler;
}
jspCompiler = null;
if (options.getCompilerClassName() != null) {
jspCompiler = createCompiler(options.getCompilerClassName());
} else {
if (options.getCompiler() == null) {
jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
if (jspCompiler == null) {
jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
}
} else {
jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
if (jspCompiler == null) {
jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
}
}
}
if (jspCompiler == null) {
throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler"));
}
jspCompiler.init(this, jsw);
return jspCompiler;
}
protected Compiler createCompiler(String className) {
Compiler compiler = null;
try {
compiler = (Compiler) Class.forName(className).newInstance();
} catch (InstantiationException e) {
log.warn(Localizer.getMessage("jsp.error.compiler"), e);
} catch (IllegalAccessException e) {
log.warn(Localizer.getMessage("jsp.error.compiler"), e);
} catch (NoClassDefFoundError e) {
if (log.isDebugEnabled()) {
log.debug(Localizer.getMessage("jsp.error.compiler"), e);
}
} catch (ClassNotFoundException e) {
if (log.isDebugEnabled()) {
log.debug(Localizer.getMessage("jsp.error.compiler"), e);
}
}
return compiler;
}
public Compiler getCompiler() {
return jspCompiler;
}
/** ---------- Access resources in the webapp ---------- */
/**
* Get the full value of a URI relative to this compilations context
* uses current file as the base.
*/
public String resolveRelativeUri(String uri) {
// sometimes we get uri's massaged from File(String), so check for
// a root directory deperator char
if (uri.startsWith("/") || uri.startsWith(File.separator)) {
return uri;
} else {
return baseURI + uri;
}
}
/**
* Gets a resource as a stream, relative to the meanings of this
* context's implementation.
* @return a null if the resource cannot be found or represented
* as an InputStream.
*/
public java.io.InputStream getResourceAsStream(String res) {
return context.getResourceAsStream(canonicalURI(res));
}
public URL getResource(String res) throws MalformedURLException {
URL result = null;
if (res.startsWith("/META-INF/")) {
// This is a tag file packaged in a jar that is being compiled
URL jarUrl = tagFileJarUrls.get(res);
if (jarUrl == null) {
jarUrl = tagFileJarUrl;
}
if (jarUrl != null) {
result = new URL(jarUrl.toExternalForm() + res.substring(1));
}
} else if (res.startsWith("jar:file:")) {
// This is a tag file packaged in a jar that is being checked
// for a dependency
result = new URL(res);
} else {
result = context.getResource(canonicalURI(res));
}
return result;
}
public Set getResourcePaths(String path) {
return context.getResourcePaths(canonicalURI(path));
}
/**
* Gets the actual path of a URI relative to the context of
* the compilation.
*/
public String getRealPath(String path) {
if (context != null) {
return context.getRealPath(path);
}
return path;
}
/**
* Returns the tag-file-name-to-JAR-file map of this compilation unit,
* which maps tag file names to the JAR files in which the tag files are
* packaged.
*
* The map is populated when parsing the tag-file elements of the TLDs
* of any imported taglibs.
*/
public URL getTagFileJarUrl(String tagFile) {
return this.tagFileJarUrls.get(tagFile);
}
public void setTagFileJarUrl(String tagFile, URL tagFileURL) {
this.tagFileJarUrls.put(tagFile, tagFileURL);
}
/**
* Returns the JAR file in which the tag file for which this
* JspCompilationContext was created is packaged, or null if this
* JspCompilationContext does not correspond to a tag file, or if the
* corresponding tag file is not packaged in a JAR.
*/
public URL getTagFileJarUrl() {
return this.tagFileJarUrl;
}
/* ==================== Common implementation ==================== */
/**
* Just the class name (does not include package name) of the
* generated class.
*/
public String getServletClassName() {
if (className != null) {
return className;
}
if (isTagFile) {
className = tagInfo.getTagClassName();
int lastIndex = className.lastIndexOf('.');
if (lastIndex != -1) {
className = className.substring(lastIndex + 1);
}
} else {
int iSep = jspUri.lastIndexOf('/') + 1;
className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep));
}
return className;
}
public void setServletClassName(String className) {
this.className = className;
}
/**
* Path of the JSP URI. Note that this is not a file name. This is
* the context rooted URI of the JSP file.
*/
public String getJspFile() {
return jspUri;
}
/**
* Are we processing something that has been declared as an
* errorpage?
*/
public boolean isErrorPage() {
return isErrPage;
}
public void setErrorPage(boolean isErrPage) {
this.isErrPage = isErrPage;
}
public boolean isTagFile() {
return isTagFile;
}
public TagInfo getTagInfo() {
return tagInfo;
}
public void setTagInfo(TagInfo tagi) {
tagInfo = tagi;
}
/**
* True if we are compiling a tag file in prototype mode.
* ie we only generate codes with class for the tag handler with empty
* method bodies.
*/
public boolean isPrototypeMode() {
return protoTypeMode;
}
public void setPrototypeMode(boolean pm) {
protoTypeMode = pm;
}
/**
* Package name for the generated class is make up of the base package
* name, which is user settable, and the derived package name. The
* derived package name directly mirrors the file heirachy of the JSP page.
*/
public String getServletPackageName() {
if (isTagFile()) {
String className = tagInfo.getTagClassName();
int lastIndex = className.lastIndexOf('.');
String pkgName = "";
if (lastIndex != -1) {
pkgName = className.substring(0, lastIndex);
}
return pkgName;
} else {
String dPackageName = getDerivedPackageName();
if (dPackageName.length() == 0) {
return basePackageName;
}
return basePackageName + '.' + getDerivedPackageName();
}
}
protected String getDerivedPackageName() {
if (derivedPackageName == null) {
int iSep = jspUri.lastIndexOf('/');
derivedPackageName = (iSep > 0) ?
JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : "";
}
return derivedPackageName;
}
/**
* The package name into which the servlet class is generated.
*/
public void setServletPackageName(String servletPackageName) {
this.basePackageName = servletPackageName;
}
/**
* Full path name of the Java file into which the servlet is being
* generated.
*/
public String getServletJavaFileName() {
if (servletJavaFileName == null) {
servletJavaFileName = getOutputDir() + getServletClassName() + ".java";
}
return servletJavaFileName;
}
/**
* Get hold of the Options object for this context.
*/
public Options getOptions() {
return options;
}
public ServletContext getServletContext() {
return context;
}
public JspRuntimeContext getRuntimeContext() {
return rctxt;
}
/**
* Path of the Java file relative to the work directory.
*/
public String getJavaPath() {
if (javaPath != null) {
return javaPath;
}
if (isTagFile()) {
String tagName = tagInfo.getTagClassName();
javaPath = tagName.replace('.', '/') + ".java";
} else {
javaPath = getServletPackageName().replace('.', '/') + '/' +
getServletClassName() + ".java";
}
return javaPath;
}
public String getClassFileName() {
if (classFileName == null) {
classFileName = getOutputDir() + getServletClassName() + ".class";
}
return classFileName;
}
/**
* Get the content type of this JSP.
*
* Content type includes content type and encoding.
*/
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
/**
* Where is the servlet being generated?
*/
public ServletWriter getWriter() {
return writer;
}
public void setWriter(ServletWriter writer) {
this.writer = writer;
}
/**
* Gets the 'location' of the TLD associated with the given taglib 'uri'.
*
* @return An array of two Strings: The first element denotes the real
* path to the TLD. If the path to the TLD points to a jar file, then the
* second element denotes the name of the TLD entry in the jar file.
* Returns null if the given uri is not associated with any tag library
* 'exposed' in the web application.
*/
public String[] getTldLocation(String uri) throws JasperException {
String[] location =
getOptions().getTldLocationsCache().getLocation(uri);
return location;
}
/**
* Are we keeping generated code around?
*/
public boolean keepGenerated() {
return getOptions().getKeepGenerated();
}
// ==================== Removal ====================
public void incrementRemoved() {
if (removed == 0 && rctxt != null) {
rctxt.removeWrapper(jspUri);
}
removed++;
}
public boolean isRemoved() {
if (removed > 1 ) {
return true;
}
return false;
}
// ==================== Compile and reload ====================
public void compile() throws JasperException, FileNotFoundException {
createCompiler();
if (jspCompiler.isOutDated()) {
try {
jspCompiler.removeGeneratedFiles();
jspLoader = null;
jspCompiler.compile();
jsw.setReload(true);
jsw.setCompilationException(null);
} catch (JasperException ex) {
// Cache compilation exception
jsw.setCompilationException(ex);
throw ex;
} catch (Exception ex) {
JasperException je = new JasperException(
Localizer.getMessage("jsp.error.unable.compile"),
ex);
// Cache compilation exception
jsw.setCompilationException(je);
throw je;
}
}
}
// ==================== Manipulating the class ====================
public Class load()
throws JasperException, FileNotFoundException
{
try {
getJspLoader();
String name;
if (isTagFile()) {
name = tagInfo.getTagClassName();
} else {
name = getServletPackageName() + "." + getServletClassName();
}
servletClass = jspLoader.loadClass(name);
} catch (ClassNotFoundException cex) {
throw new JasperException(Localizer.getMessage("jsp.error.unable.load"),
cex);
} catch (Exception ex) {
throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"),
ex);
}
removed = 0;
return servletClass;
}
// ==================== protected methods ====================
static Object outputDirLock = new Object();
public void checkOutputDir() {
if (outputDir != null) {
if (!(new File(outputDir)).exists()) {
makeOutputDir();
}
} else {
createOutputDir();
}
}
protected boolean makeOutputDir() {
synchronized(outputDirLock) {
File outDirFile = new File(outputDir);
return (outDirFile.exists() || outDirFile.mkdirs());
}
}
protected void createOutputDir() {
String path = null;
if (isTagFile()) {
String tagName = tagInfo.getTagClassName();
path = tagName.replace('.', File.separatorChar);
path = path.substring(0, path.lastIndexOf(File.separatorChar));
} else {
path = getServletPackageName().replace('.',File.separatorChar);
}
// Append servlet or tag handler path to scratch dir
try {
File base = options.getScratchDir();
baseUrl = base.toURI().toURL();
outputDir = base.getAbsolutePath() + File.separator + path +
File.separator;
if (!makeOutputDir()) {
throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"));
}
} catch (MalformedURLException e) {
throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e);
}
}
protected static final boolean isPathSeparator(char c) {
return (c == '/' || c == '\\');
}
protected static final String canonicalURI(String s) {
if (s == null) return null;
StringBuffer result = new StringBuffer();
final int len = s.length();
int pos = 0;
while (pos < len) {
char c = s.charAt(pos);
if ( isPathSeparator(c) ) {
/*
* multiple path separators.
* 'foo///bar' -> 'foo/bar'
*/
while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) {
++pos;
}
if (pos+1 < len && s.charAt(pos+1) == '.') {
/*
* a single dot at the end of the path - we are done.
*/
if (pos+2 >= len) break;
switch (s.charAt(pos+2)) {
/*
* self directory in path
* foo/./bar -> foo/bar
*/
case '/':
case '\\':
pos += 2;
continue;
/*
* two dots in a path: go back one hierarchy.
* foo/bar/../baz -> foo/baz
*/
case '.':
// only if we have exactly _two_ dots.
if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) {
pos += 3;
int separatorPos = result.length()-1;
while (separatorPos >= 0 &&
! isPathSeparator(result
.charAt(separatorPos))) {
--separatorPos;
}
if (separatorPos >= 0)
result.setLength(separatorPos);
continue;
}
}
}
}
result.append(c);
++pos;
}
return result.toString();
}
}
@@ -0,0 +1,202 @@
/*
* 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.jasper;
import java.io.File;
import java.util.Map;
import org.apache.jasper.compiler.JspConfig;
import org.apache.jasper.compiler.TagPluginManager;
import org.apache.jasper.compiler.TldLocationsCache;
/**
* A class to hold all init parameters specific to the JSP engine.
*
* @author Anil K. Vijendran
* @author Hans Bergsten
* @author Pierre Delisle
*/
public interface Options {
/**
* Returns true if Jasper issues a compilation error instead of a runtime
* Instantiation error if the class attribute specified in useBean action
* is invalid.
*/
public boolean getErrorOnUseBeanInvalidClassAttribute();
/**
* Are we keeping generated code around?
*/
public boolean getKeepGenerated();
/**
* Returns true if tag handler pooling is enabled, false otherwise.
*/
public boolean isPoolingEnabled();
/**
* Are we supporting HTML mapped servlets?
*/
public boolean getMappedFile();
/**
* Should errors be sent to client or thrown into stderr?
* @deprecated
*/
@Deprecated
public boolean getSendErrorToClient();
/**
* Should we include debug information in compiled class?
*/
public boolean getClassDebugInfo();
/**
* Background compile thread check interval in seconds
*/
public int getCheckInterval();
/**
* Is Jasper being used in development mode?
*/
public boolean getDevelopment();
/**
* Should we include a source fragment in exception messages, which could be displayed
* to the developer ?
*/
public boolean getDisplaySourceFragment();
/**
* Is the generation of SMAP info for JSR45 debugging suppressed?
*/
public boolean isSmapSuppressed();
/**
* Indicates whether SMAP info for JSR45 debugging should be dumped to a
* file.
* Ignored is suppressSmap() is true
*/
public boolean isSmapDumped();
/**
* Should white spaces between directives or actions be trimmed?
*/
public boolean getTrimSpaces();
/**
* Class ID for use in the plugin tag when the browser is IE.
*/
public String getIeClassId();
/**
* What is my scratch dir?
*/
public File getScratchDir();
/**
* What classpath should I use while compiling the servlets
* generated from JSP files?
*/
public String getClassPath();
/**
* Compiler to use.
*/
public String getCompiler();
/**
* The compiler target VM, e.g. 1.1, 1.2, 1.3, 1.4, or 1.5.
*/
public String getCompilerTargetVM();
/**
* Compiler source VM, e.g. 1.3, 1.4, or 1.5.
*/
public String getCompilerSourceVM();
/**
* Java compiler class to use.
*/
public String getCompilerClassName();
/**
* The cache for the location of the TLD's
* for the various tag libraries 'exposed'
* by the web application.
* A tag library is 'exposed' either explicitely in
* web.xml or implicitely via the uri tag in the TLD
* of a taglib deployed in a jar file (WEB-INF/lib).
*
* @return the instance of the TldLocationsCache
* for the web-application.
*/
public TldLocationsCache getTldLocationsCache();
/**
* Java platform encoding to generate the JSP
* page servlet.
*/
public String getJavaEncoding();
/**
* boolean flag to tell Ant whether to fork JSP page compilations.
*/
public boolean getFork();
/**
* Obtain JSP configuration informantion specified in web.xml.
*/
public JspConfig getJspConfig();
/**
* Is generation of X-Powered-By response header enabled/disabled?
*/
public boolean isXpoweredBy();
/**
* Obtain a Tag Plugin Manager
*/
public TagPluginManager getTagPluginManager();
/**
* Are Text strings to be generated as char arrays?
*/
public boolean genStringAsCharArray();
/**
* Modification test interval.
*/
public int getModificationTestInterval();
/**
* Is caching enabled (used for precompilation).
*/
public boolean isCaching();
/**
* The web-application wide cache for the returned TreeNode
* by parseXMLDocument in TagLibraryInfoImpl.parseTLD,
* if isCaching returns true.
*
* @return the Map(String uri, TreeNode tld) instance.
*/
public Map getCache();
}
@@ -0,0 +1,493 @@
/*
* 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.jasper.compiler;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.StringTokenizer;
import org.apache.jasper.JasperException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Javac;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.PatternSet;
/**
* Main JSP compiler class. This class uses Ant for compiling.
*
* @author Anil K. Vijendran
* @author Mandar Raje
* @author Pierre Delisle
* @author Kin-man Chung
* @author Remy Maucherat
* @author Mark Roth
*/
public class AntCompiler extends Compiler {
protected static Object javacLock = new Object();
static {
System.setErr(new SystemLogHandler(System.err));
}
// ----------------------------------------------------- Instance Variables
protected Project project = null;
protected JasperAntLogger logger;
// ------------------------------------------------------------ Constructor
// Lazy eval - if we don't need to compile we probably don't need the project
protected Project getProject() {
if (project != null)
return project;
// Initializing project
project = new Project();
logger = new JasperAntLogger();
logger.setOutputPrintStream(System.out);
logger.setErrorPrintStream(System.err);
logger.setMessageOutputLevel(Project.MSG_INFO);
project.addBuildListener( logger);
if (System.getProperty("catalina.home") != null) {
project.setBasedir( System.getProperty("catalina.home"));
}
if( options.getCompiler() != null ) {
if( log.isDebugEnabled() )
log.debug("Compiler " + options.getCompiler() );
project.setProperty("build.compiler", options.getCompiler() );
}
project.init();
return project;
}
public class JasperAntLogger extends DefaultLogger {
protected StringBuffer reportBuf = new StringBuffer();
protected void printMessage(final String message,
final PrintStream stream,
final int priority) {
}
protected void log(String message) {
reportBuf.append(message);
reportBuf.append(System.getProperty("line.separator"));
}
protected String getReport() {
String report = reportBuf.toString();
reportBuf.setLength(0);
return report;
}
}
// --------------------------------------------------------- Public Methods
/**
* Compile the servlet from .java file to .class file
*/
protected void generateClass(String[] smap)
throws FileNotFoundException, JasperException, Exception {
long t1 = 0;
if (log.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
String javaEncoding = ctxt.getOptions().getJavaEncoding();
String javaFileName = ctxt.getServletJavaFileName();
String classpath = ctxt.getClassPath();
String sep = System.getProperty("path.separator");
StringBuffer errorReport = new StringBuffer();
StringBuffer info=new StringBuffer();
info.append("Compile: javaFileName=" + javaFileName + "\n" );
info.append(" classpath=" + classpath + "\n" );
// Start capturing the System.err output for this thread
SystemLogHandler.setThread();
// Initializing javac task
getProject();
Javac javac = (Javac) project.createTask("javac");
// Initializing classpath
Path path = new Path(project);
path.setPath(System.getProperty("java.class.path"));
info.append(" cp=" + System.getProperty("java.class.path") + "\n");
StringTokenizer tokenizer = new StringTokenizer(classpath, sep);
while (tokenizer.hasMoreElements()) {
String pathElement = tokenizer.nextToken();
File repository = new File(pathElement);
path.setLocation(repository);
info.append(" cp=" + repository + "\n");
}
if( log.isDebugEnabled() )
log.debug( "Using classpath: " + System.getProperty("java.class.path") + sep
+ classpath);
// Initializing sourcepath
Path srcPath = new Path(project);
srcPath.setLocation(options.getScratchDir());
info.append(" work dir=" + options.getScratchDir() + "\n");
// Initialize and set java extensions
String exts = System.getProperty("java.ext.dirs");
if (exts != null) {
Path extdirs = new Path(project);
extdirs.setPath(exts);
javac.setExtdirs(extdirs);
info.append(" extension dir=" + exts + "\n");
}
// Add endorsed directories if any are specified and we're forking
// See Bugzilla 31257
if(ctxt.getOptions().getFork()) {
String endorsed = System.getProperty("java.endorsed.dirs");
if(endorsed != null) {
Javac.ImplementationSpecificArgument endorsedArg =
javac.createCompilerArg();
endorsedArg.setLine("-J-Djava.endorsed.dirs=" +
quotePathList(endorsed));
info.append(" endorsed dir=" + quotePathList(endorsed) +
"\n");
} else {
info.append(" no endorsed dirs specified\n");
}
}
// Configure the compiler object
javac.setEncoding(javaEncoding);
javac.setClasspath(path);
javac.setDebug(ctxt.getOptions().getClassDebugInfo());
javac.setSrcdir(srcPath);
javac.setTempdir(options.getScratchDir());
javac.setOptimize(! ctxt.getOptions().getClassDebugInfo() );
javac.setFork(ctxt.getOptions().getFork());
info.append(" srcDir=" + srcPath + "\n" );
// Set the Java compiler to use
if (options.getCompiler() != null) {
javac.setCompiler(options.getCompiler());
info.append(" compiler=" + options.getCompiler() + "\n");
}
if (options.getCompilerTargetVM() != null) {
javac.setTarget(options.getCompilerTargetVM());
info.append(" compilerTargetVM=" + options.getCompilerTargetVM() + "\n");
}
if (options.getCompilerSourceVM() != null) {
javac.setSource(options.getCompilerSourceVM());
info.append(" compilerSourceVM=" + options.getCompilerSourceVM() + "\n");
}
// Build includes path
PatternSet.NameEntry includes = javac.createInclude();
includes.setName(ctxt.getJavaPath());
info.append(" include="+ ctxt.getJavaPath() + "\n" );
BuildException be = null;
try {
if (ctxt.getOptions().getFork()) {
javac.execute();
} else {
synchronized(javacLock) {
javac.execute();
}
}
} catch (BuildException e) {
be = e;
log.error(Localizer.getMessage("jsp.error.javac"), e);
log.error(Localizer.getMessage("jsp.error.javac.env") + info.toString());
}
errorReport.append(logger.getReport());
// Stop capturing the System.err output for this thread
String errorCapture = SystemLogHandler.unsetThread();
if (errorCapture != null) {
errorReport.append(System.getProperty("line.separator"));
errorReport.append(errorCapture);
}
if (!ctxt.keepGenerated()) {
File javaFile = new File(javaFileName);
javaFile.delete();
}
if (be != null) {
String errorReportString = errorReport.toString();
log.error(Localizer.getMessage("jsp.error.compilation", javaFileName, errorReportString));
JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors(
errorReportString, javaFileName, pageNodes);
if (javacErrors != null) {
errDispatcher.javacError(javacErrors);
} else {
errDispatcher.javacError(errorReportString, be);
}
}
if( log.isDebugEnabled() ) {
long t2 = System.currentTimeMillis();
log.debug("Compiled " + ctxt.getServletJavaFileName() + " "
+ (t2-t1) + "ms");
}
logger = null;
project = null;
if (ctxt.isPrototypeMode()) {
return;
}
// JSR45 Support
if (! options.isSmapSuppressed()) {
SmapUtil.installSmap(smap);
}
}
private String quotePathList(String list) {
StringBuffer result = new StringBuffer(list.length() + 10);
StringTokenizer st = new StringTokenizer(list, File.pathSeparator);
while (st.hasMoreTokens()) {
String token = st.nextToken();
if (token.indexOf(' ') == -1) {
result.append(token);
} else {
result.append('\"');
result.append(token);
result.append('\"');
}
if (st.hasMoreTokens()) {
result.append(File.pathSeparatorChar);
}
}
return result.toString();
}
protected static class SystemLogHandler extends PrintStream {
// ----------------------------------------------------------- Constructors
/**
* Construct the handler to capture the output of the given steam.
*/
public SystemLogHandler(PrintStream wrapped) {
super(wrapped);
this.wrapped = wrapped;
}
// ----------------------------------------------------- Instance Variables
/**
* Wrapped PrintStream.
*/
protected PrintStream wrapped = null;
/**
* Thread <-> PrintStream associations.
*/
protected static ThreadLocal streams = new ThreadLocal();
/**
* Thread <-> ByteArrayOutputStream associations.
*/
protected static ThreadLocal data = new ThreadLocal();
// --------------------------------------------------------- Public Methods
public PrintStream getWrapped() {
return wrapped;
}
/**
* Start capturing thread's output.
*/
public static void setThread() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
data.set(baos);
streams.set(new PrintStream(baos));
}
/**
* Stop capturing thread's output and return captured data as a String.
*/
public static String unsetThread() {
ByteArrayOutputStream baos =
(ByteArrayOutputStream) data.get();
if (baos == null) {
return null;
}
streams.set(null);
data.set(null);
return baos.toString();
}
// ------------------------------------------------------ Protected Methods
/**
* Find PrintStream to which the output must be written to.
*/
protected PrintStream findStream() {
PrintStream ps = (PrintStream) streams.get();
if (ps == null) {
ps = wrapped;
}
return ps;
}
// ---------------------------------------------------- PrintStream Methods
public void flush() {
findStream().flush();
}
public void close() {
findStream().close();
}
public boolean checkError() {
return findStream().checkError();
}
protected void setError() {
//findStream().setError();
}
public void write(int b) {
findStream().write(b);
}
public void write(byte[] b)
throws IOException {
findStream().write(b);
}
public void write(byte[] buf, int off, int len) {
findStream().write(buf, off, len);
}
public void print(boolean b) {
findStream().print(b);
}
public void print(char c) {
findStream().print(c);
}
public void print(int i) {
findStream().print(i);
}
public void print(long l) {
findStream().print(l);
}
public void print(float f) {
findStream().print(f);
}
public void print(double d) {
findStream().print(d);
}
public void print(char[] s) {
findStream().print(s);
}
public void print(String s) {
findStream().print(s);
}
public void print(Object obj) {
findStream().print(obj);
}
public void println() {
findStream().println();
}
public void println(boolean x) {
findStream().println(x);
}
public void println(char x) {
findStream().println(x);
}
public void println(int x) {
findStream().println(x);
}
public void println(long x) {
findStream().println(x);
}
public void println(float x) {
findStream().println(x);
}
public void println(double x) {
findStream().println(x);
}
public void println(char[] x) {
findStream().println(x);
}
public void println(String x) {
findStream().println(x);
}
public void println(Object x) {
findStream().println(x);
}
}
}
@@ -0,0 +1,75 @@
/*
* 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.jasper.compiler;
import java.util.HashMap;
import org.apache.jasper.JasperException;
/**
* Repository of {page, request, session, application}-scoped beans
*
* @author Mandar Raje
* @author Remy Maucherat
*/
public class BeanRepository {
protected HashMap<String, String> beanTypes;
protected ClassLoader loader;
protected ErrorDispatcher errDispatcher;
/**
* Constructor.
*/
public BeanRepository(ClassLoader loader, ErrorDispatcher err) {
this.loader = loader;
this.errDispatcher = err;
beanTypes = new HashMap<String, String>();
}
public void addBean(Node.UseBean n, String s, String type, String scope)
throws JasperException {
if (!(scope == null || scope.equals("page") || scope.equals("request")
|| scope.equals("session") || scope.equals("application"))) {
errDispatcher.jspError(n, "jsp.error.usebean.badScope");
}
beanTypes.put(s, type);
}
public Class getBeanType(String bean)
throws JasperException {
Class clazz = null;
try {
clazz = loader.loadClass(beanTypes.get(bean));
} catch (ClassNotFoundException ex) {
throw new JasperException (ex);
}
return clazz;
}
public boolean checkVariable(String bean) {
return beanTypes.containsKey(bean);
}
}
@@ -0,0 +1,204 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jasper.compiler;
import org.apache.jasper.JasperException;
/**
* Collect info about the page and nodes, and make them availabe through
* the PageInfo object.
*
* @author Kin-man Chung
* @author Mark Roth
*/
class Collector {
/**
* A visitor for collecting information on the page and the body of
* the custom tags.
*/
static class CollectVisitor extends Node.Visitor {
private boolean scriptingElementSeen = false;
private boolean usebeanSeen = false;
private boolean includeActionSeen = false;
private boolean paramActionSeen = false;
private boolean setPropertySeen = false;
private boolean hasScriptingVars = false;
public void visit(Node.ParamAction n) throws JasperException {
if (n.getValue().isExpression()) {
scriptingElementSeen = true;
}
paramActionSeen = true;
}
public void visit(Node.IncludeAction n) throws JasperException {
if (n.getPage().isExpression()) {
scriptingElementSeen = true;
}
includeActionSeen = true;
visitBody(n);
}
public void visit(Node.ForwardAction n) throws JasperException {
if (n.getPage().isExpression()) {
scriptingElementSeen = true;
}
visitBody(n);
}
public void visit(Node.SetProperty n) throws JasperException {
if (n.getValue() != null && n.getValue().isExpression()) {
scriptingElementSeen = true;
}
setPropertySeen = true;
}
public void visit(Node.UseBean n) throws JasperException {
if (n.getBeanName() != null && n.getBeanName().isExpression()) {
scriptingElementSeen = true;
}
usebeanSeen = true;
visitBody(n);
}
public void visit(Node.PlugIn n) throws JasperException {
if (n.getHeight() != null && n.getHeight().isExpression()) {
scriptingElementSeen = true;
}
if (n.getWidth() != null && n.getWidth().isExpression()) {
scriptingElementSeen = true;
}
visitBody(n);
}
public void visit(Node.CustomTag n) throws JasperException {
// Check to see what kinds of element we see as child elements
checkSeen( n.getChildInfo(), n );
}
/**
* Check all child nodes for various elements and update the given
* ChildInfo object accordingly. Visits body in the process.
*/
private void checkSeen( Node.ChildInfo ci, Node n )
throws JasperException
{
// save values collected so far
boolean scriptingElementSeenSave = scriptingElementSeen;
scriptingElementSeen = false;
boolean usebeanSeenSave = usebeanSeen;
usebeanSeen = false;
boolean includeActionSeenSave = includeActionSeen;
includeActionSeen = false;
boolean paramActionSeenSave = paramActionSeen;
paramActionSeen = false;
boolean setPropertySeenSave = setPropertySeen;
setPropertySeen = false;
boolean hasScriptingVarsSave = hasScriptingVars;
hasScriptingVars = false;
// Scan attribute list for expressions
if( n instanceof Node.CustomTag ) {
Node.CustomTag ct = (Node.CustomTag)n;
Node.JspAttribute[] attrs = ct.getJspAttributes();
for (int i = 0; attrs != null && i < attrs.length; i++) {
if (attrs[i].isExpression()) {
scriptingElementSeen = true;
break;
}
}
}
visitBody(n);
if( (n instanceof Node.CustomTag) && !hasScriptingVars) {
Node.CustomTag ct = (Node.CustomTag)n;
hasScriptingVars = ct.getVariableInfos().length > 0 ||
ct.getTagVariableInfos().length > 0;
}
// Record if the tag element and its body contains any scriptlet.
ci.setScriptless(! scriptingElementSeen);
ci.setHasUseBean(usebeanSeen);
ci.setHasIncludeAction(includeActionSeen);
ci.setHasParamAction(paramActionSeen);
ci.setHasSetProperty(setPropertySeen);
ci.setHasScriptingVars(hasScriptingVars);
// Propagate value of scriptingElementSeen up.
scriptingElementSeen = scriptingElementSeen || scriptingElementSeenSave;
usebeanSeen = usebeanSeen || usebeanSeenSave;
setPropertySeen = setPropertySeen || setPropertySeenSave;
includeActionSeen = includeActionSeen || includeActionSeenSave;
paramActionSeen = paramActionSeen || paramActionSeenSave;
hasScriptingVars = hasScriptingVars || hasScriptingVarsSave;
}
public void visit(Node.JspElement n) throws JasperException {
if (n.getNameAttribute().isExpression())
scriptingElementSeen = true;
Node.JspAttribute[] attrs = n.getJspAttributes();
for (int i = 0; i < attrs.length; i++) {
if (attrs[i].isExpression()) {
scriptingElementSeen = true;
break;
}
}
visitBody(n);
}
public void visit(Node.JspBody n) throws JasperException {
checkSeen( n.getChildInfo(), n );
}
public void visit(Node.NamedAttribute n) throws JasperException {
checkSeen( n.getChildInfo(), n );
}
public void visit(Node.Declaration n) throws JasperException {
scriptingElementSeen = true;
}
public void visit(Node.Expression n) throws JasperException {
scriptingElementSeen = true;
}
public void visit(Node.Scriptlet n) throws JasperException {
scriptingElementSeen = true;
}
public void updatePageInfo(PageInfo pageInfo) {
pageInfo.setScriptless(! scriptingElementSeen);
}
}
public static void collect(Compiler compiler, Node.Nodes page)
throws JasperException {
CollectVisitor collectVisitor = new CollectVisitor();
page.visit(collectVisitor);
collectVisitor.updatePageInfo(compiler.getPageInfo());
}
}
@@ -0,0 +1,551 @@
/*
* 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.jasper.compiler;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.List;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.Options;
import org.apache.jasper.servlet.JspServletWrapper;
/**
* Main JSP compiler class. This class uses Ant for compiling.
*
* @author Anil K. Vijendran
* @author Mandar Raje
* @author Pierre Delisle
* @author Kin-man Chung
* @author Remy Maucherat
* @author Mark Roth
*/
public abstract class Compiler {
protected org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
.getLog(Compiler.class);
// ----------------------------------------------------- Instance Variables
protected JspCompilationContext ctxt;
protected ErrorDispatcher errDispatcher;
protected PageInfo pageInfo;
protected JspServletWrapper jsw;
protected TagFileProcessor tfp;
protected Options options;
protected Node.Nodes pageNodes;
// ------------------------------------------------------------ Constructor
public void init(JspCompilationContext ctxt, JspServletWrapper jsw) {
this.jsw = jsw;
this.ctxt = ctxt;
this.options = ctxt.getOptions();
}
// --------------------------------------------------------- Public Methods
/**
* <p>
* Retrieves the parsed nodes of the JSP page, if they are available. May
* return null. Used in development mode for generating detailed error
* messages. http://issues.apache.org/bugzilla/show_bug.cgi?id=37062.
* </p>
*/
public Node.Nodes getPageNodes() {
return this.pageNodes;
}
/**
* Compile the jsp file into equivalent servlet in .java file
*
* @return a smap for the current JSP page, if one is generated, null
* otherwise
*/
protected String[] generateJava() throws Exception {
String[] smapStr = null;
long t1, t2, t3, t4;
t1 = t2 = t3 = t4 = 0;
if (log.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
// Setup page info area
pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(),
errDispatcher), ctxt.getJspFile());
JspConfig jspConfig = options.getJspConfig();
JspConfig.JspProperty jspProperty = jspConfig.findJspProperty(ctxt
.getJspFile());
/*
* If the current uri is matched by a pattern specified in a
* jsp-property-group in web.xml, initialize pageInfo with those
* properties.
*/
if (jspProperty.isELIgnored() != null) {
pageInfo.setELIgnored(JspUtil.booleanValue(jspProperty
.isELIgnored()));
}
if (jspProperty.isScriptingInvalid() != null) {
pageInfo.setScriptingInvalid(JspUtil.booleanValue(jspProperty
.isScriptingInvalid()));
}
if (jspProperty.getIncludePrelude() != null) {
pageInfo.setIncludePrelude(jspProperty.getIncludePrelude());
}
if (jspProperty.getIncludeCoda() != null) {
pageInfo.setIncludeCoda(jspProperty.getIncludeCoda());
}
if (jspProperty.isDeferedSyntaxAllowedAsLiteral() != null) {
pageInfo.setDeferredSyntaxAllowedAsLiteral(JspUtil.booleanValue(jspProperty
.isDeferedSyntaxAllowedAsLiteral()));
}
if (jspProperty.isTrimDirectiveWhitespaces() != null) {
pageInfo.setTrimDirectiveWhitespaces(JspUtil.booleanValue(jspProperty
.isTrimDirectiveWhitespaces()));
}
ctxt.checkOutputDir();
String javaFileName = ctxt.getServletJavaFileName();
ServletWriter writer = null;
try {
/*
* The setting of isELIgnored changes the behaviour of the parser
* in subtle ways. To add to the 'fun', isELIgnored can be set in
* any file that forms part of the translation unit so setting it
* in a file included towards the end of the translation unit can
* change how the parser should have behaved when parsing content
* up to the point where isELIgnored was set. Arghh!
* Previous attempts to hack around this have only provided partial
* solutions. We now use two passes to parse the translation unit.
* The first just parses the directives and the second parses the
* whole translation unit once we know how isELIgnored has been set.
* TODO There are some possible optimisations of this process.
*/
// Parse the file
ParserController parserCtl = new ParserController(ctxt, this);
// Pass 1 - the directives
Node.Nodes directives =
parserCtl.parseDirectives(ctxt.getJspFile());
Validator.validateDirectives(this, directives);
// Pass 2 - the whole translation unit
pageNodes = parserCtl.parse(ctxt.getJspFile());
if (ctxt.isPrototypeMode()) {
// generate prototype .java file for the tag file
writer = setupContextWriter(javaFileName);
Generator.generate(writer, this, pageNodes);
writer.close();
writer = null;
return null;
}
// Validate and process attributes - don't re-validate the
// directives we validated in pass 1
Validator.validateExDirectives(this, pageNodes);
if (log.isDebugEnabled()) {
t2 = System.currentTimeMillis();
}
// Collect page info
Collector.collect(this, pageNodes);
// Compile (if necessary) and load the tag files referenced in
// this compilation unit.
tfp = new TagFileProcessor();
tfp.loadTagFiles(this, pageNodes);
if (log.isDebugEnabled()) {
t3 = System.currentTimeMillis();
}
// Determine which custom tag needs to declare which scripting vars
ScriptingVariabler.set(pageNodes, errDispatcher);
// Optimizations by Tag Plugins
TagPluginManager tagPluginManager = options.getTagPluginManager();
tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);
// Optimization: concatenate contiguous template texts.
TextOptimizer.concatenate(this, pageNodes);
// Generate static function mapper codes.
ELFunctionMapper.map(this, pageNodes);
// generate servlet .java file
writer = setupContextWriter(javaFileName);
Generator.generate(writer, this, pageNodes);
writer.close();
writer = null;
// The writer is only used during the compile, dereference
// it in the JspCompilationContext when done to allow it
// to be GC'd and save memory.
ctxt.setWriter(null);
if (log.isDebugEnabled()) {
t4 = System.currentTimeMillis();
log.debug("Generated " + javaFileName + " total=" + (t4 - t1)
+ " generate=" + (t4 - t3) + " validate=" + (t2 - t1));
}
} catch (Exception e) {
if (writer != null) {
try {
writer.close();
writer = null;
} catch (Exception e1) {
// do nothing
}
}
// Remove the generated .java file
new File(javaFileName).delete();
throw e;
} finally {
if (writer != null) {
try {
writer.close();
} catch (Exception e2) {
// do nothing
}
}
}
// JSR45 Support
if (!options.isSmapSuppressed()) {
smapStr = SmapUtil.generateSmap(ctxt, pageNodes);
}
// If any proto type .java and .class files was generated,
// the prototype .java may have been replaced by the current
// compilation (if the tag file is self referencing), but the
// .class file need to be removed, to make sure that javac would
// generate .class again from the new .java file just generated.
tfp.removeProtoTypeFiles(ctxt.getClassFileName());
return smapStr;
}
private ServletWriter setupContextWriter(String javaFileName)
throws FileNotFoundException, JasperException {
ServletWriter writer;
// Setup the ServletWriter
String javaEncoding = ctxt.getOptions().getJavaEncoding();
OutputStreamWriter osw = null;
try {
osw = new OutputStreamWriter(
new FileOutputStream(javaFileName), javaEncoding);
} catch (UnsupportedEncodingException ex) {
errDispatcher.jspError("jsp.error.needAlternateJavaEncoding",
javaEncoding);
}
writer = new ServletWriter(new PrintWriter(osw));
ctxt.setWriter(writer);
return writer;
}
/**
* Compile the servlet from .java file to .class file
*/
protected abstract void generateClass(String[] smap)
throws FileNotFoundException, JasperException, Exception;
/**
* Compile the jsp file from the current engine context
*/
public void compile() throws FileNotFoundException, JasperException,
Exception {
compile(true);
}
/**
* Compile the jsp file from the current engine context. As an side- effect,
* tag files that are referenced by this page are also compiled.
*
* @param compileClass
* If true, generate both .java and .class file If false,
* generate only .java file
*/
public void compile(boolean compileClass) throws FileNotFoundException,
JasperException, Exception {
compile(compileClass, false);
}
/**
* Compile the jsp file from the current engine context. As an side- effect,
* tag files that are referenced by this page are also compiled.
*
* @param compileClass
* If true, generate both .java and .class file If false,
* generate only .java file
* @param jspcMode
* true if invoked from JspC, false otherwise
*/
public void compile(boolean compileClass, boolean jspcMode)
throws FileNotFoundException, JasperException, Exception {
if (errDispatcher == null) {
this.errDispatcher = new ErrorDispatcher(jspcMode);
}
try {
String[] smap = generateJava();
if (compileClass) {
generateClass(smap);
// Fix for bugzilla 41606
// Set JspServletWrapper.servletClassLastModifiedTime after successful compile
String targetFileName = ctxt.getClassFileName();
if (targetFileName != null) {
File targetFile = new File(targetFileName);
if (targetFile.exists() && jsw != null) {
jsw.setServletClassLastModifiedTime(targetFile.lastModified());
}
}
}
} finally {
if (tfp != null && ctxt.isPrototypeMode()) {
tfp.removeProtoTypeFiles(null);
}
// Make sure these object which are only used during the
// generation and compilation of the JSP page get
// dereferenced so that they can be GC'd and reduce the
// memory footprint.
tfp = null;
errDispatcher = null;
pageInfo = null;
// Only get rid of the pageNodes if in production.
// In development mode, they are used for detailed
// error messages.
// http://issues.apache.org/bugzilla/show_bug.cgi?id=37062
if (!this.options.getDevelopment()) {
pageNodes = null;
}
if (ctxt.getWriter() != null) {
ctxt.getWriter().close();
ctxt.setWriter(null);
}
}
}
/**
* This is a protected method intended to be overridden by subclasses of
* Compiler. This is used by the compile method to do all the compilation.
*/
public boolean isOutDated() {
return isOutDated(true);
}
/**
* Determine if a compilation is necessary by checking the time stamp of the
* JSP page with that of the corresponding .class or .java file. If the page
* has dependencies, the check is also extended to its dependeants, and so
* on. This method can by overidden by a subclasses of Compiler.
*
* @param checkClass
* If true, check against .class file, if false, check against
* .java file.
*/
public boolean isOutDated(boolean checkClass) {
String jsp = ctxt.getJspFile();
if (jsw != null
&& (ctxt.getOptions().getModificationTestInterval() > 0)) {
if (jsw.getLastModificationTest()
+ (ctxt.getOptions().getModificationTestInterval() * 1000) > System
.currentTimeMillis()) {
return false;
} else {
jsw.setLastModificationTest(System.currentTimeMillis());
}
}
long jspRealLastModified = 0;
try {
URL jspUrl = ctxt.getResource(jsp);
if (jspUrl == null) {
ctxt.incrementRemoved();
return false;
}
URLConnection uc = jspUrl.openConnection();
if (uc instanceof JarURLConnection) {
jspRealLastModified =
((JarURLConnection) uc).getJarEntry().getTime();
} else {
jspRealLastModified = uc.getLastModified();
}
uc.getInputStream().close();
} catch (Exception e) {
return true;
}
long targetLastModified = 0;
File targetFile;
if (checkClass) {
targetFile = new File(ctxt.getClassFileName());
} else {
targetFile = new File(ctxt.getServletJavaFileName());
}
if (!targetFile.exists()) {
return true;
}
targetLastModified = targetFile.lastModified();
if (checkClass && jsw != null) {
jsw.setServletClassLastModifiedTime(targetLastModified);
}
if (targetLastModified < jspRealLastModified) {
if (log.isDebugEnabled()) {
log.debug("Compiler: outdated: " + targetFile + " "
+ targetLastModified);
}
return true;
}
// determine if source dependent files (e.g. includes using include
// directives) have been changed.
if (jsw == null) {
return false;
}
List depends = jsw.getDependants();
if (depends == null) {
return false;
}
Iterator it = depends.iterator();
while (it.hasNext()) {
String include = (String) it.next();
try {
URL includeUrl = ctxt.getResource(include);
if (includeUrl == null) {
return true;
}
URLConnection iuc = includeUrl.openConnection();
long includeLastModified = 0;
if (iuc instanceof JarURLConnection) {
includeLastModified =
((JarURLConnection) iuc).getJarEntry().getTime();
} else {
includeLastModified = iuc.getLastModified();
}
iuc.getInputStream().close();
if (includeLastModified > targetLastModified) {
return true;
}
} catch (Exception e) {
return true;
}
}
return false;
}
/**
* Gets the error dispatcher.
*/
public ErrorDispatcher getErrorDispatcher() {
return errDispatcher;
}
/**
* Gets the info about the page under compilation
*/
public PageInfo getPageInfo() {
return pageInfo;
}
public JspCompilationContext getCompilationContext() {
return ctxt;
}
/**
* Remove generated files
*/
public void removeGeneratedFiles() {
try {
String classFileName = ctxt.getClassFileName();
if (classFileName != null) {
File classFile = new File(classFileName);
if (log.isDebugEnabled())
log.debug("Deleting " + classFile);
classFile.delete();
}
} catch (Exception e) {
// Remove as much as possible, ignore possible exceptions
}
try {
String javaFileName = ctxt.getServletJavaFileName();
if (javaFileName != null) {
File javaFile = new File(javaFileName);
if (log.isDebugEnabled())
log.debug("Deleting " + javaFile);
javaFile.delete();
}
} catch (Exception e) {
// Remove as much as possible, ignore possible exceptions
}
}
public void removeGeneratedClassFiles() {
try {
String classFileName = ctxt.getClassFileName();
if (classFileName != null) {
File classFile = new File(classFileName);
if (log.isDebugEnabled())
log.debug("Deleting " + classFile);
classFile.delete();
}
} catch (Exception e) {
// Remove as much as possible, ignore possible exceptions
}
}
}
@@ -0,0 +1,109 @@
/*
* 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.jasper.compiler;
import org.apache.jasper.JasperException;
/**
* Default implementation of ErrorHandler interface.
*
* @author Jan Luehe
*/
class DefaultErrorHandler implements ErrorHandler {
/*
* Processes the given JSP parse error.
*
* @param fname Name of the JSP file in which the parse error occurred
* @param line Parse error line number
* @param column Parse error column number
* @param errMsg Parse error message
* @param exception Parse exception
*/
public void jspError(String fname, int line, int column, String errMsg,
Exception ex) throws JasperException {
throw new JasperException(fname + "(" + line + "," + column + ")"
+ " " + errMsg, ex);
}
/*
* Processes the given JSP parse error.
*
* @param errMsg Parse error message
* @param exception Parse exception
*/
public void jspError(String errMsg, Exception ex) throws JasperException {
throw new JasperException(errMsg, ex);
}
/*
* Processes the given javac compilation errors.
*
* @param details Array of JavacErrorDetail instances corresponding to the
* compilation errors
*/
public void javacError(JavacErrorDetail[] details) throws JasperException {
if (details == null) {
return;
}
Object[] args = null;
StringBuffer buf = new StringBuffer();
for (int i=0; i < details.length; i++) {
if (details[i].getJspBeginLineNumber() >= 0) {
args = new Object[] {
new Integer(details[i].getJspBeginLineNumber()),
details[i].getJspFileName() };
buf.append("\n\n");
buf.append(Localizer.getMessage("jsp.error.single.line.number",
args));
buf.append("\n");
buf.append(details[i].getErrorMessage());
buf.append("\n");
buf.append(details[i].getJspExtract());
} else {
args = new Object[] {
new Integer(details[i].getJavaLineNumber()) };
buf.append("\n\n");
buf.append(Localizer.getMessage("jsp.error.java.line.number",
args));
buf.append("\n");
buf.append(details[i].getErrorMessage());
}
}
buf.append("\n\nStacktrace:");
throw new JasperException(
Localizer.getMessage("jsp.error.unable.compile") + ": " + buf);
}
/**
* Processes the given javac error report and exception.
*
* @param errorReport Compilation error report
* @param exception Compilation exception
*/
public void javacError(String errorReport, Exception exception)
throws JasperException {
throw new JasperException(
Localizer.getMessage("jsp.error.unable.compile"), exception);
}
}
@@ -0,0 +1,207 @@
/*
* 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.jasper.compiler;
import org.xml.sax.Attributes;
import org.apache.jasper.JasperException;
class Dumper {
static class DumpVisitor extends Node.Visitor {
private int indent = 0;
private String getAttributes(Attributes attrs) {
if (attrs == null)
return "";
StringBuffer buf = new StringBuffer();
for (int i=0; i < attrs.getLength(); i++) {
buf.append(" " + attrs.getQName(i) + "=\""
+ attrs.getValue(i) + "\"");
}
return buf.toString();
}
private void printString(String str) {
printIndent();
System.out.print(str);
}
private void printString(String prefix, char[] chars, String suffix) {
String str = null;
if (chars != null) {
str = new String(chars);
}
printString(prefix, str, suffix);
}
private void printString(String prefix, String str, String suffix) {
printIndent();
if (str != null) {
System.out.print(prefix + str + suffix);
} else {
System.out.print(prefix + suffix);
}
}
private void printAttributes(String prefix, Attributes attrs,
String suffix) {
printString(prefix, getAttributes(attrs), suffix);
}
private void dumpBody(Node n) throws JasperException {
Node.Nodes page = n.getBody();
if (page != null) {
// indent++;
page.visit(this);
// indent--;
}
}
public void visit(Node.PageDirective n) throws JasperException {
printAttributes("<%@ page", n.getAttributes(), "%>");
}
public void visit(Node.TaglibDirective n) throws JasperException {
printAttributes("<%@ taglib", n.getAttributes(), "%>");
}
public void visit(Node.IncludeDirective n) throws JasperException {
printAttributes("<%@ include", n.getAttributes(), "%>");
dumpBody(n);
}
public void visit(Node.Comment n) throws JasperException {
printString("<%--", n.getText(), "--%>");
}
public void visit(Node.Declaration n) throws JasperException {
printString("<%!", n.getText(), "%>");
}
public void visit(Node.Expression n) throws JasperException {
printString("<%=", n.getText(), "%>");
}
public void visit(Node.Scriptlet n) throws JasperException {
printString("<%", n.getText(), "%>");
}
public void visit(Node.IncludeAction n) throws JasperException {
printAttributes("<jsp:include", n.getAttributes(), ">");
dumpBody(n);
printString("</jsp:include>");
}
public void visit(Node.ForwardAction n) throws JasperException {
printAttributes("<jsp:forward", n.getAttributes(), ">");
dumpBody(n);
printString("</jsp:forward>");
}
public void visit(Node.GetProperty n) throws JasperException {
printAttributes("<jsp:getProperty", n.getAttributes(), "/>");
}
public void visit(Node.SetProperty n) throws JasperException {
printAttributes("<jsp:setProperty", n.getAttributes(), ">");
dumpBody(n);
printString("</jsp:setProperty>");
}
public void visit(Node.UseBean n) throws JasperException {
printAttributes("<jsp:useBean", n.getAttributes(), ">");
dumpBody(n);
printString("</jsp:useBean>");
}
public void visit(Node.PlugIn n) throws JasperException {
printAttributes("<jsp:plugin", n.getAttributes(), ">");
dumpBody(n);
printString("</jsp:plugin>");
}
public void visit(Node.ParamsAction n) throws JasperException {
printAttributes("<jsp:params", n.getAttributes(), ">");
dumpBody(n);
printString("</jsp:params>");
}
public void visit(Node.ParamAction n) throws JasperException {
printAttributes("<jsp:param", n.getAttributes(), ">");
dumpBody(n);
printString("</jsp:param>");
}
public void visit(Node.NamedAttribute n) throws JasperException {
printAttributes("<jsp:attribute", n.getAttributes(), ">");
dumpBody(n);
printString("</jsp:attribute>");
}
public void visit(Node.JspBody n) throws JasperException {
printAttributes("<jsp:body", n.getAttributes(), ">");
dumpBody(n);
printString("</jsp:body>");
}
public void visit(Node.ELExpression n) throws JasperException {
printString( "${" + new String( n.getText() ) + "}" );
}
public void visit(Node.CustomTag n) throws JasperException {
printAttributes("<" + n.getQName(), n.getAttributes(), ">");
dumpBody(n);
printString("</" + n.getQName() + ">");
}
public void visit(Node.UninterpretedTag n) throws JasperException {
String tag = n.getQName();
printAttributes("<"+tag, n.getAttributes(), ">");
dumpBody(n);
printString("</" + tag + ">");
}
public void visit(Node.TemplateText n) throws JasperException {
printString(new String(n.getText()));
}
private void printIndent() {
for (int i=0; i < indent; i++) {
System.out.print(" ");
}
}
}
public static void dump(Node n) {
try {
n.accept(new DumpVisitor());
} catch (JasperException e) {
e.printStackTrace();
}
}
public static void dump(Node.Nodes page) {
try {
page.visit(new DumpVisitor());
} catch (JasperException e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,281 @@
/*
* 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.jasper.compiler;
import java.util.*;
import javax.servlet.jsp.tagext.FunctionInfo;
import org.apache.jasper.JasperException;
/**
* This class generates functions mappers for the EL expressions in the page.
* Instead of a global mapper, a mapper is used for ecah call to EL
* evaluator, thus avoiding the prefix overlapping and redefinition
* issues.
*
* @author Kin-man Chung
*/
public class ELFunctionMapper {
private int currFunc = 0;
StringBuffer ds; // Contains codes to initialize the functions mappers.
StringBuffer ss; // Contains declarations of the functions mappers.
/**
* Creates the functions mappers for all EL expressions in the JSP page.
*
* @param compiler Current compiler, mainly for accessing error dispatcher.
* @param page The current compilation unit.
*/
public static void map(Compiler compiler, Node.Nodes page)
throws JasperException {
ELFunctionMapper map = new ELFunctionMapper();
map.ds = new StringBuffer();
map.ss = new StringBuffer();
page.visit(map.new ELFunctionVisitor());
// Append the declarations to the root node
String ds = map.ds.toString();
if (ds.length() > 0) {
Node root = page.getRoot();
new Node.Declaration(map.ss.toString(), null, root);
new Node.Declaration("static {\n" + ds + "}\n", null, root);
}
}
/**
* A visitor for the page. The places where EL is allowed are scanned
* for functions, and if found functions mappers are created.
*/
class ELFunctionVisitor extends Node.Visitor {
/**
* Use a global name map to facilitate reuse of function maps.
* The key used is prefix:function:uri.
*/
private HashMap<String, String> gMap = new HashMap<String, String>();
public void visit(Node.ParamAction n) throws JasperException {
doMap(n.getValue());
visitBody(n);
}
public void visit(Node.IncludeAction n) throws JasperException {
doMap(n.getPage());
visitBody(n);
}
public void visit(Node.ForwardAction n) throws JasperException {
doMap(n.getPage());
visitBody(n);
}
public void visit(Node.SetProperty n) throws JasperException {
doMap(n.getValue());
visitBody(n);
}
public void visit(Node.UseBean n) throws JasperException {
doMap(n.getBeanName());
visitBody(n);
}
public void visit(Node.PlugIn n) throws JasperException {
doMap(n.getHeight());
doMap(n.getWidth());
visitBody(n);
}
public void visit(Node.JspElement n) throws JasperException {
Node.JspAttribute[] attrs = n.getJspAttributes();
for (int i = 0; attrs != null && i < attrs.length; i++) {
doMap(attrs[i]);
}
doMap(n.getNameAttribute());
visitBody(n);
}
public void visit(Node.UninterpretedTag n) throws JasperException {
Node.JspAttribute[] attrs = n.getJspAttributes();
for (int i = 0; attrs != null && i < attrs.length; i++) {
doMap(attrs[i]);
}
visitBody(n);
}
public void visit(Node.CustomTag n) throws JasperException {
Node.JspAttribute[] attrs = n.getJspAttributes();
for (int i = 0; attrs != null && i < attrs.length; i++) {
doMap(attrs[i]);
}
visitBody(n);
}
public void visit(Node.ELExpression n) throws JasperException {
doMap(n.getEL());
}
private void doMap(Node.JspAttribute attr)
throws JasperException {
if (attr != null) {
doMap(attr.getEL());
}
}
/**
* Creates function mappers, if needed, from ELNodes
*/
private void doMap(ELNode.Nodes el)
throws JasperException {
// Only care about functions in ELNode's
class Fvisitor extends ELNode.Visitor {
ArrayList<ELNode.Function> funcs =
new ArrayList<ELNode.Function>();
HashMap<String, String> keyMap = new HashMap<String, String>();
public void visit(ELNode.Function n) throws JasperException {
String key = n.getPrefix() + ":" + n.getName();
if (! keyMap.containsKey(key)) {
keyMap.put(key,"");
funcs.add(n);
}
}
}
if (el == null) {
return;
}
// First locate all unique functions in this EL
Fvisitor fv = new Fvisitor();
el.visit(fv);
ArrayList functions = fv.funcs;
if (functions.size() == 0) {
return;
}
// Reuse a previous map if possible
String decName = matchMap(functions);
if (decName != null) {
el.setMapName(decName);
return;
}
// Generate declaration for the map statically
decName = getMapName();
ss.append("static private org.apache.jasper.runtime.ProtectedFunctionMapper " + decName + ";\n");
ds.append(" " + decName + "= ");
ds.append("org.apache.jasper.runtime.ProtectedFunctionMapper");
// Special case if there is only one function in the map
String funcMethod = null;
if (functions.size() == 1) {
funcMethod = ".getMapForFunction";
} else {
ds.append(".getInstance();\n");
funcMethod = " " + decName + ".mapFunction";
}
// Setup arguments for either getMapForFunction or mapFunction
for (int i = 0; i < functions.size(); i++) {
ELNode.Function f = (ELNode.Function)functions.get(i);
FunctionInfo funcInfo = f.getFunctionInfo();
String key = f.getPrefix()+ ":" + f.getName();
ds.append(funcMethod + "(\"" + key + "\", " +
funcInfo.getFunctionClass() + ".class, " +
'\"' + f.getMethodName() + "\", " +
"new Class[] {");
String params[] = f.getParameters();
for (int k = 0; k < params.length; k++) {
if (k != 0) {
ds.append(", ");
}
int iArray = params[k].indexOf('[');
if (iArray < 0) {
ds.append(params[k] + ".class");
}
else {
String baseType = params[k].substring(0, iArray);
ds.append("java.lang.reflect.Array.newInstance(");
ds.append(baseType);
ds.append(".class,");
// Count the number of array dimension
int aCount = 0;
for (int jj = iArray; jj < params[k].length(); jj++ ) {
if (params[k].charAt(jj) == '[') {
aCount++;
}
}
if (aCount == 1) {
ds.append("0).getClass()");
} else {
ds.append("new int[" + aCount + "]).getClass()");
}
}
}
ds.append("});\n");
// Put the current name in the global function map
gMap.put(f.getPrefix() + ':' + f.getName() + ':' + f.getUri(),
decName);
}
el.setMapName(decName);
}
/**
* Find the name of the function mapper for an EL. Reuse a
* previously generated one if possible.
* @param functions An ArrayList of ELNode.Function instances that
* represents the functions in an EL
* @return A previous generated function mapper name that can be used
* by this EL; null if none found.
*/
private String matchMap(ArrayList functions) {
String mapName = null;
for (int i = 0; i < functions.size(); i++) {
ELNode.Function f = (ELNode.Function)functions.get(i);
String temName = (String) gMap.get(f.getPrefix() + ':' +
f.getName() + ':' + f.getUri());
if (temName == null) {
return null;
}
if (mapName == null) {
mapName = temName;
} else if (!temName.equals(mapName)) {
// If not all in the previous match, then no match.
return null;
}
}
return mapName;
}
/*
* @return An unique name for a function mapper.
*/
private String getMapName() {
return "_jspx_fnmap_" + currFunc++;
}
}
}
@@ -0,0 +1,255 @@
/*
* 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.jasper.compiler;
import java.util.*;
import javax.servlet.jsp.tagext.FunctionInfo;
import org.apache.jasper.JasperException;
/**
* This class defines internal representation for an EL Expression
*
* It currently only defines functions. It can be expanded to define
* all the components of an EL expression, if need to.
*
* @author Kin-man Chung
*/
abstract class ELNode {
abstract public void accept(Visitor v) throws JasperException;
/**
* Child classes
*/
/**
* Represents an EL expression: anything in ${ and }.
*/
public static class Root extends ELNode {
private ELNode.Nodes expr;
private char type;
Root(ELNode.Nodes expr, char type) {
this.expr = expr;
this.type = type;
}
public void accept(Visitor v) throws JasperException {
v.visit(this);
}
public ELNode.Nodes getExpression() {
return expr;
}
public char getType() {
return type;
}
}
/**
* Represents text outside of EL expression.
*/
public static class Text extends ELNode {
private String text;
Text(String text) {
this.text = text;
}
public void accept(Visitor v) throws JasperException {
v.visit(this);
}
public String getText() {
return text;
}
}
/**
* Represents anything in EL expression, other than functions, including
* function arguments etc
*/
public static class ELText extends ELNode {
private String text;
ELText(String text) {
this.text = text;
}
public void accept(Visitor v) throws JasperException {
v.visit(this);
}
public String getText() {
return text;
}
}
/**
* Represents a function
* Currently only include the prefix and function name, but not its
* arguments.
*/
public static class Function extends ELNode {
private String prefix;
private String name;
private String uri;
private FunctionInfo functionInfo;
private String methodName;
private String[] parameters;
Function(String prefix, String name) {
this.prefix = prefix;
this.name = name;
}
public void accept(Visitor v) throws JasperException {
v.visit(this);
}
public String getPrefix() {
return prefix;
}
public String getName() {
return name;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getUri() {
return uri;
}
public void setFunctionInfo(FunctionInfo f) {
this.functionInfo = f;
}
public FunctionInfo getFunctionInfo() {
return functionInfo;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getMethodName() {
return methodName;
}
public void setParameters(String[] parameters) {
this.parameters = parameters;
}
public String[] getParameters() {
return parameters;
}
}
/**
* An ordered list of ELNode.
*/
public static class Nodes {
/* Name used for creating a map for the functions in this
EL expression, for communication to Generator.
*/
String mapName = null; // The function map associated this EL
private List<ELNode> list;
public Nodes() {
list = new ArrayList<ELNode>();
}
public void add(ELNode en) {
list.add(en);
}
/**
* Visit the nodes in the list with the supplied visitor
* @param v The visitor used
*/
public void visit(Visitor v) throws JasperException {
Iterator<ELNode> iter = list.iterator();
while (iter.hasNext()) {
ELNode n = iter.next();
n.accept(v);
}
}
public Iterator<ELNode> iterator() {
return list.iterator();
}
public boolean isEmpty() {
return list.size() == 0;
}
/**
* @return true if the expression contains a ${...}
*/
public boolean containsEL() {
Iterator<ELNode> iter = list.iterator();
while (iter.hasNext()) {
ELNode n = iter.next();
if (n instanceof Root) {
return true;
}
}
return false;
}
public void setMapName(String name) {
this.mapName = name;
}
public String getMapName() {
return mapName;
}
}
/*
* A visitor class for traversing ELNodes
*/
public static class Visitor {
public void visit(Root n) throws JasperException {
n.getExpression().visit(this);
}
public void visit(Function n) throws JasperException {
}
public void visit(Text n) throws JasperException {
}
public void visit(ELText n) throws JasperException {
}
}
}
@@ -0,0 +1,382 @@
/*
* 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.jasper.compiler;
/**
* This class implements a parser for EL expressions.
*
* It takes strings of the form xxx${..}yyy${..}zzz etc, and turn it into a
* ELNode.Nodes.
*
* Currently, it only handles text outside ${..} and functions in ${ ..}.
*
* @author Kin-man Chung
*/
public class ELParser {
private Token curToken; // current token
private ELNode.Nodes expr;
private ELNode.Nodes ELexpr;
private int index; // Current index of the expression
private String expression; // The EL expression
private char type;
private boolean escapeBS; // is '\' an escape char in text outside EL?
private static final String reservedWords[] = { "and", "div", "empty",
"eq", "false", "ge", "gt", "instanceof", "le", "lt", "mod", "ne",
"not", "null", "or", "true" };
public ELParser(String expression) {
index = 0;
this.expression = expression;
expr = new ELNode.Nodes();
}
/**
* Parse an EL expression
*
* @param expression
* The input expression string of the form Char* ('${' Char*
* '}')* Char*
* @return Parsed EL expression in ELNode.Nodes
*/
public static ELNode.Nodes parse(String expression) {
ELParser parser = new ELParser(expression);
while (parser.hasNextChar()) {
String text = parser.skipUntilEL();
if (text.length() > 0) {
parser.expr.add(new ELNode.Text(text));
}
ELNode.Nodes elexpr = parser.parseEL();
if (!elexpr.isEmpty()) {
parser.expr.add(new ELNode.Root(elexpr, parser.type));
}
}
return parser.expr;
}
/**
* Parse an EL expression string '${...}'
*
* @return An ELNode.Nodes representing the EL expression TODO: Currently
* only parsed into functions and text strings. This should be
* rewritten for a full parser.
*/
private ELNode.Nodes parseEL() {
StringBuffer buf = new StringBuffer();
ELexpr = new ELNode.Nodes();
while (hasNext()) {
curToken = nextToken();
if (curToken instanceof Char) {
if (curToken.toChar() == '}') {
break;
}
buf.append(curToken.toChar());
} else {
// Output whatever is in buffer
if (buf.length() > 0) {
ELexpr.add(new ELNode.ELText(buf.toString()));
}
if (!parseFunction()) {
ELexpr.add(new ELNode.ELText(curToken.toString()));
}
}
}
if (buf.length() > 0) {
ELexpr.add(new ELNode.ELText(buf.toString()));
}
return ELexpr;
}
/**
* Parse for a function FunctionInvokation ::= (identifier ':')? identifier
* '(' (Expression (,Expression)*)? ')' Note: currently we don't parse
* arguments
*/
private boolean parseFunction() {
if (!(curToken instanceof Id) || isELReserved(curToken.toString())) {
return false;
}
String s1 = null; // Function prefix
String s2 = curToken.toString(); // Function name
int mark = getIndex();
if (hasNext()) {
Token t = nextToken();
if (t.toChar() == ':') {
if (hasNext()) {
Token t2 = nextToken();
if (t2 instanceof Id) {
s1 = s2;
s2 = t2.toString();
if (hasNext()) {
t = nextToken();
}
}
}
}
if (t.toChar() == '(') {
ELexpr.add(new ELNode.Function(s1, s2));
return true;
}
}
setIndex(mark);
return false;
}
/**
* Test if an id is a reserved word in EL
*/
private boolean isELReserved(String id) {
int i = 0;
int j = reservedWords.length;
while (i < j) {
int k = (i + j) / 2;
int result = reservedWords[k].compareTo(id);
if (result == 0) {
return true;
}
if (result < 0) {
i = k + 1;
} else {
j = k;
}
}
return false;
}
/**
* Skip until an EL expression ('${' || '#{') is reached, allowing escape
* sequences '\\' and '\$' and '\#'.
*
* @return The text string up to the EL expression
*/
private String skipUntilEL() {
char prev = 0;
StringBuffer buf = new StringBuffer();
while (hasNextChar()) {
char ch = nextChar();
if (prev == '\\') {
prev = 0;
if (ch == '\\') {
buf.append('\\');
if (!escapeBS)
prev = '\\';
} else if (ch == '$' || ch == '#') {
buf.append(ch);
}
// else error!
} else if (prev == '$' || prev == '#') {
if (ch == '{') {
this.type = prev;
prev = 0;
break;
}
buf.append(prev);
prev = 0;
}
if (ch == '\\' || ch == '$' || ch == '#') {
prev = ch;
} else {
buf.append(ch);
}
}
if (prev != 0) {
buf.append(prev);
}
return buf.toString();
}
/*
* @return true if there is something left in EL expression buffer other
* than white spaces.
*/
private boolean hasNext() {
skipSpaces();
return hasNextChar();
}
/*
* @return The next token in the EL expression buffer.
*/
private Token nextToken() {
skipSpaces();
if (hasNextChar()) {
char ch = nextChar();
if (Character.isJavaIdentifierStart(ch)) {
StringBuffer buf = new StringBuffer();
buf.append(ch);
while ((ch = peekChar()) != -1
&& Character.isJavaIdentifierPart(ch)) {
buf.append(ch);
nextChar();
}
return new Id(buf.toString());
}
if (ch == '\'' || ch == '"') {
return parseQuotedChars(ch);
} else {
// For now...
return new Char(ch);
}
}
return null;
}
/*
* Parse a string in single or double quotes, allowing for escape sequences
* '\\', and ('\"', or "\'")
*/
private Token parseQuotedChars(char quote) {
StringBuffer buf = new StringBuffer();
buf.append(quote);
while (hasNextChar()) {
char ch = nextChar();
if (ch == '\\') {
ch = nextChar();
if (ch == '\\' || ch == quote) {
buf.append(ch);
}
// else error!
} else if (ch == quote) {
buf.append(ch);
break;
} else {
buf.append(ch);
}
}
return new QuotedString(buf.toString());
}
/*
* A collection of low level parse methods dealing with character in the EL
* expression buffer.
*/
private void skipSpaces() {
while (hasNextChar()) {
if (expression.charAt(index) > ' ')
break;
index++;
}
}
private boolean hasNextChar() {
return index < expression.length();
}
private char nextChar() {
if (index >= expression.length()) {
return (char) -1;
}
return expression.charAt(index++);
}
private char peekChar() {
if (index >= expression.length()) {
return (char) -1;
}
return expression.charAt(index);
}
private int getIndex() {
return index;
}
private void setIndex(int i) {
index = i;
}
/*
* Represents a token in EL expression string
*/
private static class Token {
char toChar() {
return 0;
}
public String toString() {
return "";
}
}
/*
* Represents an ID token in EL
*/
private static class Id extends Token {
String id;
Id(String id) {
this.id = id;
}
public String toString() {
return id;
}
}
/*
* Represents a character token in EL
*/
private static class Char extends Token {
private char ch;
Char(char ch) {
this.ch = ch;
}
char toChar() {
return ch;
}
public String toString() {
return (new Character(ch)).toString();
}
}
/*
* Represents a quoted (single or double) string token in EL
*/
private static class QuotedString extends Token {
private String value;
QuotedString(String v) {
this.value = v;
}
public String toString() {
return value;
}
}
public char getType() {
return type;
}
}
@@ -0,0 +1,615 @@
/*
* 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.jasper.compiler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.util.ArrayList;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.xml.sax.SAXException;
/**
* Class responsible for dispatching JSP parse and javac compilation errors
* to the configured error handler.
*
* This class is also responsible for localizing any error codes before they
* are passed on to the configured error handler.
*
* In the case of a Java compilation error, the compiler error message is
* parsed into an array of JavacErrorDetail instances, which is passed on to
* the configured error handler.
*
* @author Jan Luehe
* @author Kin-man Chung
*/
public class ErrorDispatcher {
// Custom error handler
private ErrorHandler errHandler;
// Indicates whether the compilation was initiated by JspServlet or JspC
private boolean jspcMode = false;
/*
* Constructor.
*
* @param jspcMode true if compilation has been initiated by JspC, false
* otherwise
*/
public ErrorDispatcher(boolean jspcMode) {
// XXX check web.xml for custom error handler
errHandler = new DefaultErrorHandler();
this.jspcMode = jspcMode;
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param errCode Error code
*/
public void jspError(String errCode) throws JasperException {
dispatch(null, errCode, null, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param where Error location
* @param errCode Error code
*/
public void jspError(Mark where, String errCode) throws JasperException {
dispatch(where, errCode, null, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param n Node that caused the error
* @param errCode Error code
*/
public void jspError(Node n, String errCode) throws JasperException {
dispatch(n.getStart(), errCode, null, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param errCode Error code
* @param arg Argument for parametric replacement
*/
public void jspError(String errCode, String arg) throws JasperException {
dispatch(null, errCode, new Object[] {arg}, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param where Error location
* @param errCode Error code
* @param arg Argument for parametric replacement
*/
public void jspError(Mark where, String errCode, String arg)
throws JasperException {
dispatch(where, errCode, new Object[] {arg}, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param n Node that caused the error
* @param errCode Error code
* @param arg Argument for parametric replacement
*/
public void jspError(Node n, String errCode, String arg)
throws JasperException {
dispatch(n.getStart(), errCode, new Object[] {arg}, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param errCode Error code
* @param arg1 First argument for parametric replacement
* @param arg2 Second argument for parametric replacement
*/
public void jspError(String errCode, String arg1, String arg2)
throws JasperException {
dispatch(null, errCode, new Object[] {arg1, arg2}, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param errCode Error code
* @param arg1 First argument for parametric replacement
* @param arg2 Second argument for parametric replacement
* @param arg3 Third argument for parametric replacement
*/
public void jspError(String errCode, String arg1, String arg2, String arg3)
throws JasperException {
dispatch(null, errCode, new Object[] {arg1, arg2, arg3}, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param where Error location
* @param errCode Error code
* @param arg1 First argument for parametric replacement
* @param arg2 Second argument for parametric replacement
*/
public void jspError(Mark where, String errCode, String arg1, String arg2)
throws JasperException {
dispatch(where, errCode, new Object[] {arg1, arg2}, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param where Error location
* @param errCode Error code
* @param arg1 First argument for parametric replacement
* @param arg2 Second argument for parametric replacement
* @param arg3 Third argument for parametric replacement
*/
public void jspError(Mark where, String errCode, String arg1, String arg2,
String arg3)
throws JasperException {
dispatch(where, errCode, new Object[] {arg1, arg2, arg3}, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param n Node that caused the error
* @param errCode Error code
* @param arg1 First argument for parametric replacement
* @param arg2 Second argument for parametric replacement
*/
public void jspError(Node n, String errCode, String arg1, String arg2)
throws JasperException {
dispatch(n.getStart(), errCode, new Object[] {arg1, arg2}, null);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param n Node that caused the error
* @param errCode Error code
* @param arg1 First argument for parametric replacement
* @param arg2 Second argument for parametric replacement
* @param arg3 Third argument for parametric replacement
*/
public void jspError(Node n, String errCode, String arg1, String arg2,
String arg3)
throws JasperException {
dispatch(n.getStart(), errCode, new Object[] {arg1, arg2, arg3}, null);
}
/*
* Dispatches the given parsing exception to the configured error handler.
*
* @param e Parsing exception
*/
public void jspError(Exception e) throws JasperException {
dispatch(null, null, null, e);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param errCode Error code
* @param arg Argument for parametric replacement
* @param e Parsing exception
*/
public void jspError(String errCode, String arg, Exception e)
throws JasperException {
dispatch(null, errCode, new Object[] {arg}, e);
}
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param n Node that caused the error
* @param errCode Error code
* @param arg Argument for parametric replacement
* @param e Parsing exception
*/
public void jspError(Node n, String errCode, String arg, Exception e)
throws JasperException {
dispatch(n.getStart(), errCode, new Object[] {arg}, e);
}
/**
* Parses the given error message into an array of javac compilation error
* messages (one per javac compilation error line number).
*
* @param errMsg Error message
* @param fname Name of Java source file whose compilation failed
* @param page Node representation of JSP page from which the Java source
* file was generated
*
* @return Array of javac compilation errors, or null if the given error
* message does not contain any compilation error line numbers
*/
public static JavacErrorDetail[] parseJavacErrors(String errMsg,
String fname,
Node.Nodes page)
throws JasperException, IOException {
return parseJavacMessage(errMsg, fname, page);
}
/*
* Dispatches the given javac compilation errors to the configured error
* handler.
*
* @param javacErrors Array of javac compilation errors
*/
public void javacError(JavacErrorDetail[] javacErrors)
throws JasperException {
errHandler.javacError(javacErrors);
}
/*
* Dispatches the given compilation error report and exception to the
* configured error handler.
*
* @param errorReport Compilation error report
* @param e Compilation exception
*/
public void javacError(String errorReport, Exception e)
throws JasperException {
errHandler.javacError(errorReport, e);
}
//*********************************************************************
// Private utility methods
/*
* Dispatches the given JSP parse error to the configured error handler.
*
* The given error code is localized. If it is not found in the
* resource bundle for localized error messages, it is used as the error
* message.
*
* @param where Error location
* @param errCode Error code
* @param args Arguments for parametric replacement
* @param e Parsing exception
*/
private void dispatch(Mark where, String errCode, Object[] args,
Exception e) throws JasperException {
String file = null;
String errMsg = null;
int line = -1;
int column = -1;
boolean hasLocation = false;
// Localize
if (errCode != null) {
errMsg = Localizer.getMessage(errCode, args);
} else if (e != null) {
// give a hint about what's wrong
errMsg = e.getMessage();
}
// Get error location
if (where != null) {
if (jspcMode) {
// Get the full URL of the resource that caused the error
try {
file = where.getURL().toString();
} catch (MalformedURLException me) {
// Fallback to using context-relative path
file = where.getFile();
}
} else {
// Get the context-relative resource path, so as to not
// disclose any local filesystem details
file = where.getFile();
}
line = where.getLineNumber();
column = where.getColumnNumber();
hasLocation = true;
}
// Get nested exception
Exception nestedEx = e;
if ((e instanceof SAXException)
&& (((SAXException) e).getException() != null)) {
nestedEx = ((SAXException) e).getException();
}
if (hasLocation) {
errHandler.jspError(file, line, column, errMsg, nestedEx);
} else {
errHandler.jspError(errMsg, nestedEx);
}
}
/*
* Parses the given Java compilation error message, which may contain one
* or more compilation errors, into an array of JavacErrorDetail instances.
*
* Each JavacErrorDetail instance contains the information about a single
* compilation error.
*
* @param errMsg Compilation error message that was generated by the
* javac compiler
* @param fname Name of Java source file whose compilation failed
* @param page Node representation of JSP page from which the Java source
* file was generated
*
* @return Array of JavacErrorDetail instances corresponding to the
* compilation errors
*/
private static JavacErrorDetail[] parseJavacMessage(
String errMsg, String fname, Node.Nodes page)
throws IOException, JasperException {
ArrayList<JavacErrorDetail> errors = new ArrayList<JavacErrorDetail>();
StringBuffer errMsgBuf = null;
int lineNum = -1;
JavacErrorDetail javacError = null;
BufferedReader reader = new BufferedReader(new StringReader(errMsg));
/*
* Parse compilation errors. Each compilation error consists of a file
* path and error line number, followed by a number of lines describing
* the error.
*/
String line = null;
while ((line = reader.readLine()) != null) {
/*
* Error line number is delimited by set of colons.
* Ignore colon following drive letter on Windows (fromIndex = 2).
* XXX Handle deprecation warnings that don't have line info
*/
int beginColon = line.indexOf(':', 2);
int endColon = line.indexOf(':', beginColon + 1);
if ((beginColon >= 0) && (endColon >= 0)) {
if (javacError != null) {
// add previous error to error vector
errors.add(javacError);
}
String lineNumStr = line.substring(beginColon + 1, endColon);
try {
lineNum = Integer.parseInt(lineNumStr);
} catch (NumberFormatException e) {
lineNum = -1;
}
errMsgBuf = new StringBuffer();
javacError = createJavacError(fname, page, errMsgBuf, lineNum);
}
// Ignore messages preceding first error
if (errMsgBuf != null) {
errMsgBuf.append(line);
errMsgBuf.append("\n");
}
}
// Add last error to error vector
if (javacError != null) {
errors.add(javacError);
}
reader.close();
JavacErrorDetail[] errDetails = null;
if (errors.size() > 0) {
errDetails = new JavacErrorDetail[errors.size()];
errors.toArray(errDetails);
}
return errDetails;
}
/**
* @param fname
* @param page
* @param errMsgBuf
* @param lineNum
* @return JavacErrorDetail The error details
* @throws JasperException
*/
public static JavacErrorDetail createJavacError(String fname,
Node.Nodes page, StringBuffer errMsgBuf, int lineNum)
throws JasperException {
return createJavacError(fname, page, errMsgBuf, lineNum, null);
}
/**
* @param fname
* @param page
* @param errMsgBuf
* @param lineNum
* @param ctxt
* @return JavacErrorDetail The error details
* @throws JasperException
*/
public static JavacErrorDetail createJavacError(String fname,
Node.Nodes page, StringBuffer errMsgBuf, int lineNum,
JspCompilationContext ctxt) throws JasperException {
JavacErrorDetail javacError;
// Attempt to map javac error line number to line in JSP page
ErrorVisitor errVisitor = new ErrorVisitor(lineNum);
page.visit(errVisitor);
Node errNode = errVisitor.getJspSourceNode();
if ((errNode != null) && (errNode.getStart() != null)) {
// If this is a scriplet node then there is a one to one mapping
// between JSP lines and Java lines
if (errVisitor.getJspSourceNode() instanceof Node.Scriptlet) {
javacError = new JavacErrorDetail(
fname,
lineNum,
errNode.getStart().getFile(),
errNode.getStart().getLineNumber() + lineNum -
errVisitor.getJspSourceNode().getBeginJavaLine(),
errMsgBuf,
ctxt);
} else {
javacError = new JavacErrorDetail(
fname,
lineNum,
errNode.getStart().getFile(),
errNode.getStart().getLineNumber(),
errMsgBuf,
ctxt);
}
} else {
/*
* javac error line number cannot be mapped to JSP page
* line number. For example, this is the case if a
* scriptlet is missing a closing brace, which causes
* havoc with the try-catch-finally block that the code
* generator places around all generated code: As a result
* of this, the javac error line numbers will be outside
* the range of begin and end java line numbers that were
* generated for the scriptlet, and therefore cannot be
* mapped to the start line number of the scriptlet in the
* JSP page.
* Include just the javac error info in the error detail.
*/
javacError = new JavacErrorDetail(
fname,
lineNum,
errMsgBuf);
}
return javacError;
}
/*
* Visitor responsible for mapping a line number in the generated servlet
* source code to the corresponding JSP node.
*/
static class ErrorVisitor extends Node.Visitor {
// Java source line number to be mapped
private int lineNum;
/*
* JSP node whose Java source code range in the generated servlet
* contains the Java source line number to be mapped
*/
Node found;
/*
* Constructor.
*
* @param lineNum Source line number in the generated servlet code
*/
public ErrorVisitor(int lineNum) {
this.lineNum = lineNum;
}
public void doVisit(Node n) throws JasperException {
if ((lineNum >= n.getBeginJavaLine())
&& (lineNum < n.getEndJavaLine())) {
found = n;
}
}
/*
* Gets the JSP node to which the source line number in the generated
* servlet code was mapped.
*
* @return JSP node to which the source line number in the generated
* servlet code was mapped
*/
public Node getJspSourceNode() {
return found;
}
}
}
@@ -0,0 +1,73 @@
/*
* 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.jasper.compiler;
import org.apache.jasper.JasperException;
/**
* Interface for handling JSP parse and javac compilation errors.
*
* An implementation of this interface may be registered with the
* ErrorDispatcher by setting the XXX initialization parameter in the JSP
* page compiler and execution servlet in Catalina's web.xml file to the
* implementation's fully qualified class name.
*
* @author Jan Luehe
* @author Kin-man Chung
*/
public interface ErrorHandler {
/**
* Processes the given JSP parse error.
*
* @param fname Name of the JSP file in which the parse error occurred
* @param line Parse error line number
* @param column Parse error column number
* @param msg Parse error message
* @param exception Parse exception
*/
public void jspError(String fname, int line, int column, String msg,
Exception exception) throws JasperException;
/**
* Processes the given JSP parse error.
*
* @param msg Parse error message
* @param exception Parse exception
*/
public void jspError(String msg, Exception exception)
throws JasperException;
/**
* Processes the given javac compilation errors.
*
* @param details Array of JavacErrorDetail instances corresponding to the
* compilation errors
*/
public void javacError(JavacErrorDetail[] details)
throws JasperException;
/**
* Processes the given javac error report and exception.
*
* @param errorReport Compilation error report
* @param exception Compilation exception
*/
public void javacError(String errorReport, Exception exception)
throws JasperException;
}
@@ -0,0 +1,218 @@
/*
* 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.jasper.compiler;
import java.io.InputStream;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
import javax.servlet.jsp.tagext.FunctionInfo;
import javax.servlet.jsp.tagext.TagFileInfo;
import javax.servlet.jsp.tagext.TagInfo;
import javax.servlet.jsp.tagext.TagLibraryInfo;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.xmlparser.ParserUtils;
import org.apache.jasper.xmlparser.TreeNode;
/**
* Class responsible for generating an implicit tag library containing tag
* handlers corresponding to the tag files in "/WEB-INF/tags/" or a
* subdirectory of it.
*
* @author Jan Luehe
*/
class ImplicitTagLibraryInfo extends TagLibraryInfo {
private static final String WEB_INF_TAGS = "/WEB-INF/tags";
private static final String TAG_FILE_SUFFIX = ".tag";
private static final String TAGX_FILE_SUFFIX = ".tagx";
private static final String TAGS_SHORTNAME = "tags";
private static final String TLIB_VERSION = "1.0";
private static final String JSP_VERSION = "2.0";
private static final String IMPLICIT_TLD = "implicit.tld";
// Maps tag names to tag file paths
private Hashtable tagFileMap;
private ParserController pc;
private PageInfo pi;
private Vector vec;
/**
* Constructor.
*/
public ImplicitTagLibraryInfo(JspCompilationContext ctxt,
ParserController pc,
PageInfo pi,
String prefix,
String tagdir,
ErrorDispatcher err) throws JasperException {
super(prefix, null);
this.pc = pc;
this.pi = pi;
this.tagFileMap = new Hashtable();
this.vec = new Vector();
// Implicit tag libraries have no functions:
this.functions = new FunctionInfo[0];
tlibversion = TLIB_VERSION;
jspversion = JSP_VERSION;
if (!tagdir.startsWith(WEB_INF_TAGS)) {
err.jspError("jsp.error.invalid.tagdir", tagdir);
}
// Determine the value of the <short-name> subelement of the
// "imaginary" <taglib> element
if (tagdir.equals(WEB_INF_TAGS)
|| tagdir.equals( WEB_INF_TAGS + "/")) {
shortname = TAGS_SHORTNAME;
} else {
shortname = tagdir.substring(WEB_INF_TAGS.length());
shortname = shortname.replace('/', '-');
}
// Populate mapping of tag names to tag file paths
Set dirList = ctxt.getResourcePaths(tagdir);
if (dirList != null) {
Iterator it = dirList.iterator();
while (it.hasNext()) {
String path = (String) it.next();
if (path.endsWith(TAG_FILE_SUFFIX)
|| path.endsWith(TAGX_FILE_SUFFIX)) {
/*
* Use the filename of the tag file, without the .tag or
* .tagx extension, respectively, as the <name> subelement
* of the "imaginary" <tag-file> element
*/
String suffix = path.endsWith(TAG_FILE_SUFFIX) ?
TAG_FILE_SUFFIX : TAGX_FILE_SUFFIX;
String tagName = path.substring(path.lastIndexOf("/") + 1);
tagName = tagName.substring(0,
tagName.lastIndexOf(suffix));
tagFileMap.put(tagName, path);
} else if (path.endsWith(IMPLICIT_TLD)) {
InputStream in = null;
try {
in = ctxt.getResourceAsStream(path);
if (in != null) {
// Add implicit TLD to dependency list
if (pi != null) {
pi.addDependant(path);
}
ParserUtils pu = new ParserUtils();
TreeNode tld = pu.parseXMLDocument(uri, in);
if (tld.findAttribute("version") != null) {
this.jspversion = tld.findAttribute("version");
}
// Process each child element of our <taglib> element
Iterator list = tld.findChildren();
while (list.hasNext()) {
TreeNode element = (TreeNode) list.next();
String tname = element.getName();
if ("tlibversion".equals(tname) // JSP 1.1
|| "tlib-version".equals(tname)) { // JSP 1.2
this.tlibversion = element.getBody();
} else if ("jspversion".equals(tname)
|| "jsp-version".equals(tname)) {
this.jspversion = element.getBody();
} else if ("shortname".equals(tname) || "short-name".equals(tname)) {
// Ignore
} else {
// All other elements are invalid
err.jspError("jsp.error.invalid.implicit", path);
}
}
try {
double version = Double.parseDouble(this.jspversion);
if (version < 2.0) {
err.jspError("jsp.error.invalid.implicit.version", path);
}
} catch (NumberFormatException e) {
err.jspError("jsp.error.invalid.implicit.version", path);
}
}
} finally {
if (in != null) {
try {
in.close();
} catch (Throwable t) {
}
}
}
}
}
}
}
/**
* Checks to see if the given tag name maps to a tag file path,
* and if so, parses the corresponding tag file.
*
* @return The TagFileInfo corresponding to the given tag name, or null if
* the given tag name is not implemented as a tag file
*/
public TagFileInfo getTagFile(String shortName) {
TagFileInfo tagFile = super.getTagFile(shortName);
if (tagFile == null) {
String path = (String) tagFileMap.get(shortName);
if (path == null) {
return null;
}
TagInfo tagInfo = null;
try {
tagInfo = TagFileProcessor.parseTagFileDirectives(pc,
shortName,
path,
pc.getJspCompilationContext().getTagFileJarUrl(path),
this);
} catch (JasperException je) {
throw new RuntimeException(je.toString(), je);
}
tagFile = new TagFileInfo(shortName, path, tagInfo);
vec.addElement(tagFile);
this.tagFiles = new TagFileInfo[vec.size()];
vec.copyInto(this.tagFiles);
}
return tagFile;
}
public TagLibraryInfo[] getTagLibraryInfos() {
Collection coll = pi.getTaglibs();
return (TagLibraryInfo[]) coll.toArray(new TagLibraryInfo[0]);
}
}
@@ -0,0 +1,460 @@
/*
* 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.jasper.compiler;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.jasper.JasperException;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
/**
* JDT class compiler. This compiler will load source dependencies from the
* context classloader, reducing dramatically disk access during
* the compilation process.
*
* @author Cocoon2
* @author Remy Maucherat
*/
public class JDTCompiler extends org.apache.jasper.compiler.Compiler {
/**
* Compile the servlet from .java file to .class file
*/
protected void generateClass(String[] smap)
throws FileNotFoundException, JasperException, Exception {
long t1 = 0;
if (log.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
final String sourceFile = ctxt.getServletJavaFileName();
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
String packageName = ctxt.getServletPackageName();
final String targetClassName =
((packageName.length() != 0) ? (packageName + ".") : "")
+ ctxt.getServletClassName();
final ClassLoader classLoader = ctxt.getJspLoader();
String[] fileNames = new String[] {sourceFile};
String[] classNames = new String[] {targetClassName};
final ArrayList problemList = new ArrayList();
class CompilationUnit implements ICompilationUnit {
String className;
String sourceFile;
CompilationUnit(String sourceFile, String className) {
this.className = className;
this.sourceFile = sourceFile;
}
public char[] getFileName() {
return sourceFile.toCharArray();
}
public char[] getContents() {
char[] result = null;
FileInputStream is = null;
try {
is = new FileInputStream(sourceFile);
Reader reader =
new BufferedReader(new InputStreamReader(is, ctxt.getOptions().getJavaEncoding()));
if (reader != null) {
char[] chars = new char[8192];
StringBuffer buf = new StringBuffer();
int count;
while ((count = reader.read(chars, 0,
chars.length)) > 0) {
buf.append(chars, 0, count);
}
result = new char[buf.length()];
buf.getChars(0, result.length, result, 0);
}
} catch (IOException e) {
log.error("Compilation error", e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException exc) {
// Ignore
}
}
}
return result;
}
public char[] getMainTypeName() {
int dot = className.lastIndexOf('.');
if (dot > 0) {
return className.substring(dot + 1).toCharArray();
}
return className.toCharArray();
}
public char[][] getPackageName() {
StringTokenizer izer =
new StringTokenizer(className, ".");
char[][] result = new char[izer.countTokens()-1][];
for (int i = 0; i < result.length; i++) {
String tok = izer.nextToken();
result[i] = tok.toCharArray();
}
return result;
}
}
final INameEnvironment env = new INameEnvironment() {
public NameEnvironmentAnswer
findType(char[][] compoundTypeName) {
String result = "";
String sep = "";
for (int i = 0; i < compoundTypeName.length; i++) {
result += sep;
result += new String(compoundTypeName[i]);
sep = ".";
}
return findType(result);
}
public NameEnvironmentAnswer
findType(char[] typeName,
char[][] packageName) {
String result = "";
String sep = "";
for (int i = 0; i < packageName.length; i++) {
result += sep;
result += new String(packageName[i]);
sep = ".";
}
result += sep;
result += new String(typeName);
return findType(result);
}
private NameEnvironmentAnswer findType(String className) {
InputStream is = null;
try {
if (className.equals(targetClassName)) {
ICompilationUnit compilationUnit =
new CompilationUnit(sourceFile, className);
return
new NameEnvironmentAnswer(compilationUnit, null);
}
String resourceName =
className.replace('.', '/') + ".class";
is = classLoader.getResourceAsStream(resourceName);
if (is != null) {
byte[] classBytes;
byte[] buf = new byte[8192];
ByteArrayOutputStream baos =
new ByteArrayOutputStream(buf.length);
int count;
while ((count = is.read(buf, 0, buf.length)) > 0) {
baos.write(buf, 0, count);
}
baos.flush();
classBytes = baos.toByteArray();
char[] fileName = className.toCharArray();
ClassFileReader classFileReader =
new ClassFileReader(classBytes, fileName,
true);
return
new NameEnvironmentAnswer(classFileReader, null);
}
} catch (IOException exc) {
log.error("Compilation error", exc);
} catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) {
log.error("Compilation error", exc);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException exc) {
// Ignore
}
}
}
return null;
}
private boolean isPackage(String result) {
if (result.equals(targetClassName)) {
return false;
}
String resourceName = result.replace('.', '/') + ".class";
InputStream is =
classLoader.getResourceAsStream(resourceName);
return is == null;
}
public boolean isPackage(char[][] parentPackageName,
char[] packageName) {
String result = "";
String sep = "";
if (parentPackageName != null) {
for (int i = 0; i < parentPackageName.length; i++) {
result += sep;
String str = new String(parentPackageName[i]);
result += str;
sep = ".";
}
}
String str = new String(packageName);
if (Character.isUpperCase(str.charAt(0))) {
if (!isPackage(result)) {
return false;
}
}
result += sep;
result += str;
return isPackage(result);
}
public void cleanup() {
}
};
final IErrorHandlingPolicy policy =
DefaultErrorHandlingPolicies.proceedWithAllProblems();
final Map settings = new HashMap();
settings.put(CompilerOptions.OPTION_LineNumberAttribute,
CompilerOptions.GENERATE);
settings.put(CompilerOptions.OPTION_SourceFileAttribute,
CompilerOptions.GENERATE);
settings.put(CompilerOptions.OPTION_ReportDeprecation,
CompilerOptions.IGNORE);
if (ctxt.getOptions().getJavaEncoding() != null) {
settings.put(CompilerOptions.OPTION_Encoding,
ctxt.getOptions().getJavaEncoding());
}
if (ctxt.getOptions().getClassDebugInfo()) {
settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
CompilerOptions.GENERATE);
}
// Source JVM
if(ctxt.getOptions().getCompilerSourceVM() != null) {
String opt = ctxt.getOptions().getCompilerSourceVM();
if(opt.equals("1.1")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_1);
} else if(opt.equals("1.2")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_2);
} else if(opt.equals("1.3")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_3);
} else if(opt.equals("1.4")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_4);
} else if(opt.equals("1.5")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_5);
} else if(opt.equals("1.6")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_6);
} else if(opt.equals("1.7")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_7);
} else {
log.warn("Unknown source VM " + opt + " ignored.");
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_5);
}
} else {
// Default to 1.5
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_5);
}
// Target JVM
if(ctxt.getOptions().getCompilerTargetVM() != null) {
String opt = ctxt.getOptions().getCompilerTargetVM();
if(opt.equals("1.1")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_1);
} else if(opt.equals("1.2")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_2);
} else if(opt.equals("1.3")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_3);
} else if(opt.equals("1.4")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_4);
} else if(opt.equals("1.5")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_5);
settings.put(CompilerOptions.OPTION_Compliance,
CompilerOptions.VERSION_1_5);
} else if(opt.equals("1.6")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_6);
settings.put(CompilerOptions.OPTION_Compliance,
CompilerOptions.VERSION_1_6);
} else if(opt.equals("1.7")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_7);
settings.put(CompilerOptions.OPTION_Compliance,
CompilerOptions.VERSION_1_7);
} else {
log.warn("Unknown target VM " + opt + " ignored.");
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_5);
}
} else {
// Default to 1.5
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_5);
settings.put(CompilerOptions.OPTION_Compliance,
CompilerOptions.VERSION_1_5);
}
final IProblemFactory problemFactory =
new DefaultProblemFactory(Locale.getDefault());
final ICompilerRequestor requestor = new ICompilerRequestor() {
public void acceptResult(CompilationResult result) {
try {
if (result.hasProblems()) {
IProblem[] problems = result.getProblems();
for (int i = 0; i < problems.length; i++) {
IProblem problem = problems[i];
if (problem.isError()) {
String name =
new String(problems[i].getOriginatingFileName());
try {
problemList.add(ErrorDispatcher.createJavacError
(name, pageNodes, new StringBuffer(problem.getMessage()),
problem.getSourceLineNumber(), ctxt));
} catch (JasperException e) {
log.error("Error visiting node", e);
}
}
}
}
if (problemList.isEmpty()) {
ClassFile[] classFiles = result.getClassFiles();
for (int i = 0; i < classFiles.length; i++) {
ClassFile classFile = classFiles[i];
char[][] compoundName =
classFile.getCompoundName();
String className = "";
String sep = "";
for (int j = 0;
j < compoundName.length; j++) {
className += sep;
className += new String(compoundName[j]);
sep = ".";
}
byte[] bytes = classFile.getBytes();
String outFile = outputDir + "/" +
className.replace('.', '/') + ".class";
FileOutputStream fout =
new FileOutputStream(outFile);
BufferedOutputStream bos =
new BufferedOutputStream(fout);
bos.write(bytes);
bos.close();
}
}
} catch (IOException exc) {
log.error("Compilation error", exc);
}
}
};
ICompilationUnit[] compilationUnits =
new ICompilationUnit[classNames.length];
for (int i = 0; i < compilationUnits.length; i++) {
String className = classNames[i];
compilationUnits[i] = new CompilationUnit(fileNames[i], className);
}
Compiler compiler = new Compiler(env,
policy,
settings,
requestor,
problemFactory,
true);
compiler.compile(compilationUnits);
if (!ctxt.keepGenerated()) {
File javaFile = new File(ctxt.getServletJavaFileName());
javaFile.delete();
}
if (!problemList.isEmpty()) {
JavacErrorDetail[] jeds =
(JavacErrorDetail[]) problemList.toArray(new JavacErrorDetail[0]);
errDispatcher.javacError(jeds);
}
if( log.isDebugEnabled() ) {
long t2=System.currentTimeMillis();
log.debug("Compiled " + ctxt.getServletJavaFileName() + " "
+ (t2-t1) + "ms");
}
if (ctxt.isPrototypeMode()) {
return;
}
// JSR45 Support
if (! options.isSmapSuppressed()) {
SmapUtil.installSmap(smap);
}
}
}
@@ -0,0 +1,58 @@
/*
* 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.jasper.compiler;
import javax.servlet.jsp.tagext.*;
/**
* TagInfo extension used by tag handlers that are implemented via tag files.
* This class provides access to the name of the Map used to store the
* dynamic attribute names and values passed to the custom action invocation.
* This information is used by the code generator.
*/
class JasperTagInfo extends TagInfo {
private String dynamicAttrsMapName;
public JasperTagInfo(String tagName,
String tagClassName,
String bodyContent,
String infoString,
TagLibraryInfo taglib,
TagExtraInfo tagExtraInfo,
TagAttributeInfo[] attributeInfo,
String displayName,
String smallIcon,
String largeIcon,
TagVariableInfo[] tvi,
String mapName) {
super(tagName, tagClassName, bodyContent, infoString, taglib,
tagExtraInfo, attributeInfo, displayName, smallIcon, largeIcon,
tvi);
this.dynamicAttrsMapName = mapName;
}
public String getDynamicAttributesMapName() {
return dynamicAttrsMapName;
}
public boolean hasDynamicAttributes() {
return dynamicAttrsMapName != null;
}
}
@@ -0,0 +1,232 @@
/*
* 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.jasper.compiler;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.apache.jasper.JspCompilationContext;
/**
* Class providing details about a javac compilation error.
*
* @author Jan Luehe
* @author Kin-man Chung
*/
public class JavacErrorDetail {
private String javaFileName;
private int javaLineNum;
private String jspFileName;
private int jspBeginLineNum;
private StringBuffer errMsg;
private String jspExtract = null;
/**
* Constructor.
*
* @param javaFileName The name of the Java file in which the
* compilation error occurred
* @param javaLineNum The compilation error line number
* @param errMsg The compilation error message
*/
public JavacErrorDetail(String javaFileName,
int javaLineNum,
StringBuffer errMsg) {
this.javaFileName = javaFileName;
this.javaLineNum = javaLineNum;
this.errMsg = errMsg;
this.jspBeginLineNum = -1;
}
/**
* Constructor.
*
* @param javaFileName The name of the Java file in which the
* compilation error occurred
* @param javaLineNum The compilation error line number
* @param jspFileName The name of the JSP file from which the Java source
* file was generated
* @param jspBeginLineNum The start line number of the JSP element
* responsible for the compilation error
* @param errMsg The compilation error message
*/
public JavacErrorDetail(String javaFileName,
int javaLineNum,
String jspFileName,
int jspBeginLineNum,
StringBuffer errMsg) {
this(javaFileName, javaLineNum, jspFileName, jspBeginLineNum, errMsg,
null);
}
public JavacErrorDetail(String javaFileName,
int javaLineNum,
String jspFileName,
int jspBeginLineNum,
StringBuffer errMsg,
JspCompilationContext ctxt) {
this(javaFileName, javaLineNum, errMsg);
this.jspFileName = jspFileName;
this.jspBeginLineNum = jspBeginLineNum;
if (jspBeginLineNum > 0 && ctxt != null) {
InputStream is = null;
FileInputStream fis = null;
try {
// Read both files in, so we can inspect them
is = ctxt.getResourceAsStream(jspFileName);
String[] jspLines = readFile(is);
fis = new FileInputStream(ctxt.getServletJavaFileName());
String[] javaLines = readFile(fis);
// If the line contains the opening of a multi-line scriptlet
// block, then the JSP line number we got back is probably
// faulty. Scan forward to match the java line...
if (jspLines[jspBeginLineNum-1].lastIndexOf("<%") >
jspLines[jspBeginLineNum-1].lastIndexOf("%>")) {
String javaLine = javaLines[javaLineNum-1].trim();
for (int i=jspBeginLineNum-1; i<jspLines.length; i++) {
if (jspLines[i].indexOf(javaLine) != -1) {
// Update jsp line number
this.jspBeginLineNum = i+1;
break;
}
}
}
// copy out a fragment of JSP to display to the user
StringBuffer fragment = new StringBuffer(1024);
int startIndex = Math.max(0, this.jspBeginLineNum-1-3);
int endIndex = Math.min(
jspLines.length-1, this.jspBeginLineNum-1+3);
for (int i=startIndex;i<=endIndex; ++i) {
fragment.append(i+1);
fragment.append(": ");
fragment.append(jspLines[i]);
fragment.append("\n");
}
jspExtract = fragment.toString();
} catch (IOException ioe) {
// Can't read files - ignore
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ioe) {
// Ignore
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException ioe) {
// Ignore
}
}
}
}
}
/**
* Gets the name of the Java source file in which the compilation error
* occurred.
*
* @return Java source file name
*/
public String getJavaFileName() {
return this.javaFileName;
}
/**
* Gets the compilation error line number.
*
* @return Compilation error line number
*/
public int getJavaLineNumber() {
return this.javaLineNum;
}
/**
* Gets the name of the JSP file from which the Java source file was
* generated.
*
* @return JSP file from which the Java source file was generated.
*/
public String getJspFileName() {
return this.jspFileName;
}
/**
* Gets the start line number (in the JSP file) of the JSP element
* responsible for the compilation error.
*
* @return Start line number of the JSP element responsible for the
* compilation error
*/
public int getJspBeginLineNumber() {
return this.jspBeginLineNum;
}
/**
* Gets the compilation error message.
*
* @return Compilation error message
*/
public String getErrorMessage() {
return this.errMsg.toString();
}
/**
* Gets the extract of the JSP that corresponds to this message.
*
* @return Extract of JSP where error occurred
*/
public String getJspExtract() {
return this.jspExtract;
}
/**
* Reads a text file from an input stream into a String[]. Used to read in
* the JSP and generated Java file when generating error messages.
*/
private String[] readFile(InputStream s) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(s));
List lines = new ArrayList();
String line;
while ( (line = reader.readLine()) != null ) {
lines.add(line);
}
return (String[]) lines.toArray( new String[lines.size()] );
}
}
@@ -0,0 +1,531 @@
/*
* 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.jasper.compiler;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Vector;
import java.net.URL;
import javax.servlet.ServletContext;
import org.apache.jasper.JasperException;
import org.apache.jasper.xmlparser.ParserUtils;
import org.apache.jasper.xmlparser.TreeNode;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.xml.sax.InputSource;
/**
* Handles the jsp-config element in WEB_INF/web.xml. This is used
* for specifying the JSP configuration information on a JSP page
*
* @author Kin-man Chung
* @author Remy Maucherat
*/
public class JspConfig {
private static final String WEB_XML = "/WEB-INF/web.xml";
// Logger
private Log log = LogFactory.getLog(JspConfig.class);
private Vector jspProperties = null;
private ServletContext ctxt;
private boolean initialized = false;
private String defaultIsXml = null; // unspecified
private String defaultIsELIgnored = null; // unspecified
private String defaultIsScriptingInvalid = null;
private String defaultDeferedSyntaxAllowedAsLiteral = null;
private String defaultTrimDirectiveWhitespaces = null;
private JspProperty defaultJspProperty;
public JspConfig(ServletContext ctxt) {
this.ctxt = ctxt;
}
private double getVersion(TreeNode webApp) {
String v = webApp.findAttribute("version");
if (v != null) {
try {
return Double.parseDouble(v);
} catch (NumberFormatException e) {
}
}
return 2.3;
}
private void processWebDotXml(ServletContext ctxt) throws JasperException {
InputStream is = null;
try {
URL uri = ctxt.getResource(WEB_XML);
if (uri == null) {
// no web.xml
return;
}
is = uri.openStream();
InputSource ip = new InputSource(is);
ip.setSystemId(uri.toExternalForm());
ParserUtils pu = new ParserUtils();
TreeNode webApp = pu.parseXMLDocument(WEB_XML, ip);
if (webApp == null
|| getVersion(webApp) < 2.4) {
defaultIsELIgnored = "true";
return;
}
TreeNode jspConfig = webApp.findChild("jsp-config");
if (jspConfig == null) {
return;
}
jspProperties = new Vector();
Iterator jspPropertyList = jspConfig.findChildren("jsp-property-group");
while (jspPropertyList.hasNext()) {
TreeNode element = (TreeNode) jspPropertyList.next();
Iterator list = element.findChildren();
Vector urlPatterns = new Vector();
String pageEncoding = null;
String scriptingInvalid = null;
String elIgnored = null;
String isXml = null;
Vector includePrelude = new Vector();
Vector includeCoda = new Vector();
String deferredSyntaxAllowedAsLiteral = null;
String trimDirectiveWhitespaces = null;
while (list.hasNext()) {
element = (TreeNode) list.next();
String tname = element.getName();
if ("url-pattern".equals(tname))
urlPatterns.addElement( element.getBody() );
else if ("page-encoding".equals(tname))
pageEncoding = element.getBody();
else if ("is-xml".equals(tname))
isXml = element.getBody();
else if ("el-ignored".equals(tname))
elIgnored = element.getBody();
else if ("scripting-invalid".equals(tname))
scriptingInvalid = element.getBody();
else if ("include-prelude".equals(tname))
includePrelude.addElement(element.getBody());
else if ("include-coda".equals(tname))
includeCoda.addElement(element.getBody());
else if ("deferred-syntax-allowed-as-literal".equals(tname))
deferredSyntaxAllowedAsLiteral = element.getBody();
else if ("trim-directive-whitespaces".equals(tname))
trimDirectiveWhitespaces = element.getBody();
}
if (urlPatterns.size() == 0) {
continue;
}
// Add one JspPropertyGroup for each URL Pattern. This makes
// the matching logic easier.
for( int p = 0; p < urlPatterns.size(); p++ ) {
String urlPattern = (String)urlPatterns.elementAt( p );
String path = null;
String extension = null;
if (urlPattern.indexOf('*') < 0) {
// Exact match
path = urlPattern;
} else {
int i = urlPattern.lastIndexOf('/');
String file;
if (i >= 0) {
path = urlPattern.substring(0,i+1);
file = urlPattern.substring(i+1);
} else {
file = urlPattern;
}
// pattern must be "*", or of the form "*.jsp"
if (file.equals("*")) {
extension = "*";
} else if (file.startsWith("*.")) {
extension = file.substring(file.indexOf('.')+1);
}
// The url patterns are reconstructed as the follwoing:
// path != null, extension == null: / or /foo/bar.ext
// path == null, extension != null: *.ext
// path != null, extension == "*": /foo/*
boolean isStar = "*".equals(extension);
if ((path == null && (extension == null || isStar))
|| (path != null && !isStar)) {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.warning.bad.urlpattern.propertygroup",
urlPattern));
}
continue;
}
}
JspProperty property = new JspProperty(isXml,
elIgnored,
scriptingInvalid,
pageEncoding,
includePrelude,
includeCoda,
deferredSyntaxAllowedAsLiteral,
trimDirectiveWhitespaces);
JspPropertyGroup propertyGroup =
new JspPropertyGroup(path, extension, property);
jspProperties.addElement(propertyGroup);
}
}
} catch (Exception ex) {
throw new JasperException(ex);
} finally {
if (is != null) {
try {
is.close();
} catch (Throwable t) {}
}
}
}
private void init() throws JasperException {
if (!initialized) {
processWebDotXml(ctxt);
defaultJspProperty = new JspProperty(defaultIsXml,
defaultIsELIgnored,
defaultIsScriptingInvalid,
null, null, null, defaultDeferedSyntaxAllowedAsLiteral,
defaultTrimDirectiveWhitespaces);
initialized = true;
}
}
/**
* Select the property group that has more restrictive url-pattern.
* In case of tie, select the first.
*/
private JspPropertyGroup selectProperty(JspPropertyGroup prev,
JspPropertyGroup curr) {
if (prev == null) {
return curr;
}
if (prev.getExtension() == null) {
// exact match
return prev;
}
if (curr.getExtension() == null) {
// exact match
return curr;
}
String prevPath = prev.getPath();
String currPath = curr.getPath();
if (prevPath == null && currPath == null) {
// Both specifies a *.ext, keep the first one
return prev;
}
if (prevPath == null && currPath != null) {
return curr;
}
if (prevPath != null && currPath == null) {
return prev;
}
if (prevPath.length() >= currPath.length()) {
return prev;
}
return curr;
}
/**
* Find a property that best matches the supplied resource.
* @param uri the resource supplied.
* @return a JspProperty indicating the best match, or some default.
*/
public JspProperty findJspProperty(String uri) throws JasperException {
init();
// JSP Configuration settings do not apply to tag files
if (jspProperties == null || uri.endsWith(".tag")
|| uri.endsWith(".tagx")) {
return defaultJspProperty;
}
String uriPath = null;
int index = uri.lastIndexOf('/');
if (index >=0 ) {
uriPath = uri.substring(0, index+1);
}
String uriExtension = null;
index = uri.lastIndexOf('.');
if (index >=0) {
uriExtension = uri.substring(index+1);
}
Vector includePreludes = new Vector();
Vector includeCodas = new Vector();
JspPropertyGroup isXmlMatch = null;
JspPropertyGroup elIgnoredMatch = null;
JspPropertyGroup scriptingInvalidMatch = null;
JspPropertyGroup pageEncodingMatch = null;
JspPropertyGroup deferedSyntaxAllowedAsLiteralMatch = null;
JspPropertyGroup trimDirectiveWhitespacesMatch = null;
Iterator iter = jspProperties.iterator();
while (iter.hasNext()) {
JspPropertyGroup jpg = (JspPropertyGroup) iter.next();
JspProperty jp = jpg.getJspProperty();
// (arrays will be the same length)
String extension = jpg.getExtension();
String path = jpg.getPath();
if (extension == null) {
// exact match pattern: /a/foo.jsp
if (!uri.equals(path)) {
// not matched;
continue;
}
} else {
// Matching patterns *.ext or /p/*
if (path != null && uriPath != null &&
! uriPath.startsWith(path)) {
// not matched
continue;
}
if (!extension.equals("*") &&
!extension.equals(uriExtension)) {
// not matched
continue;
}
}
// We have a match
// Add include-preludes and include-codas
if (jp.getIncludePrelude() != null) {
includePreludes.addAll(jp.getIncludePrelude());
}
if (jp.getIncludeCoda() != null) {
includeCodas.addAll(jp.getIncludeCoda());
}
// If there is a previous match for the same property, remember
// the one that is more restrictive.
if (jp.isXml() != null) {
isXmlMatch = selectProperty(isXmlMatch, jpg);
}
if (jp.isELIgnored() != null) {
elIgnoredMatch = selectProperty(elIgnoredMatch, jpg);
}
if (jp.isScriptingInvalid() != null) {
scriptingInvalidMatch =
selectProperty(scriptingInvalidMatch, jpg);
}
if (jp.getPageEncoding() != null) {
pageEncodingMatch = selectProperty(pageEncodingMatch, jpg);
}
if (jp.isDeferedSyntaxAllowedAsLiteral() != null) {
deferedSyntaxAllowedAsLiteralMatch =
selectProperty(deferedSyntaxAllowedAsLiteralMatch, jpg);
}
if (jp.isTrimDirectiveWhitespaces() != null) {
trimDirectiveWhitespacesMatch =
selectProperty(trimDirectiveWhitespacesMatch, jpg);
}
}
String isXml = defaultIsXml;
String isELIgnored = defaultIsELIgnored;
String isScriptingInvalid = defaultIsScriptingInvalid;
String pageEncoding = null;
String isDeferedSyntaxAllowedAsLiteral = defaultDeferedSyntaxAllowedAsLiteral;
String isTrimDirectiveWhitespaces = defaultTrimDirectiveWhitespaces;
if (isXmlMatch != null) {
isXml = isXmlMatch.getJspProperty().isXml();
}
if (elIgnoredMatch != null) {
isELIgnored = elIgnoredMatch.getJspProperty().isELIgnored();
}
if (scriptingInvalidMatch != null) {
isScriptingInvalid =
scriptingInvalidMatch.getJspProperty().isScriptingInvalid();
}
if (pageEncodingMatch != null) {
pageEncoding = pageEncodingMatch.getJspProperty().getPageEncoding();
}
if (deferedSyntaxAllowedAsLiteralMatch != null) {
isDeferedSyntaxAllowedAsLiteral =
deferedSyntaxAllowedAsLiteralMatch.getJspProperty().isDeferedSyntaxAllowedAsLiteral();
}
if (trimDirectiveWhitespacesMatch != null) {
isTrimDirectiveWhitespaces =
trimDirectiveWhitespacesMatch.getJspProperty().isTrimDirectiveWhitespaces();
}
return new JspProperty(isXml, isELIgnored, isScriptingInvalid,
pageEncoding, includePreludes, includeCodas,
isDeferedSyntaxAllowedAsLiteral, isTrimDirectiveWhitespaces);
}
/**
* To find out if an uri matches an url pattern in jsp config. If so,
* then the uri is a JSP page. This is used primarily for jspc.
*/
public boolean isJspPage(String uri) throws JasperException {
init();
if (jspProperties == null) {
return false;
}
String uriPath = null;
int index = uri.lastIndexOf('/');
if (index >=0 ) {
uriPath = uri.substring(0, index+1);
}
String uriExtension = null;
index = uri.lastIndexOf('.');
if (index >=0) {
uriExtension = uri.substring(index+1);
}
Iterator iter = jspProperties.iterator();
while (iter.hasNext()) {
JspPropertyGroup jpg = (JspPropertyGroup) iter.next();
JspProperty jp = jpg.getJspProperty();
String extension = jpg.getExtension();
String path = jpg.getPath();
if (extension == null) {
if (uri.equals(path)) {
// There is an exact match
return true;
}
} else {
if ((path == null || path.equals(uriPath)) &&
(extension.equals("*") || extension.equals(uriExtension))) {
// Matches *, *.ext, /p/*, or /p/*.ext
return true;
}
}
}
return false;
}
static class JspPropertyGroup {
private String path;
private String extension;
private JspProperty jspProperty;
JspPropertyGroup(String path, String extension,
JspProperty jspProperty) {
this.path = path;
this.extension = extension;
this.jspProperty = jspProperty;
}
public String getPath() {
return path;
}
public String getExtension() {
return extension;
}
public JspProperty getJspProperty() {
return jspProperty;
}
}
static public class JspProperty {
private String isXml;
private String elIgnored;
private String scriptingInvalid;
private String pageEncoding;
private Vector includePrelude;
private Vector includeCoda;
private String deferedSyntaxAllowedAsLiteral;
private String trimDirectiveWhitespaces;
public JspProperty(String isXml, String elIgnored,
String scriptingInvalid, String pageEncoding,
Vector includePrelude, Vector includeCoda,
String deferedSyntaxAllowedAsLiteral,
String trimDirectiveWhitespaces) {
this.isXml = isXml;
this.elIgnored = elIgnored;
this.scriptingInvalid = scriptingInvalid;
this.pageEncoding = pageEncoding;
this.includePrelude = includePrelude;
this.includeCoda = includeCoda;
this.deferedSyntaxAllowedAsLiteral = deferedSyntaxAllowedAsLiteral;
this.trimDirectiveWhitespaces = trimDirectiveWhitespaces;
}
public String isXml() {
return isXml;
}
public String isELIgnored() {
return elIgnored;
}
public String isScriptingInvalid() {
return scriptingInvalid;
}
public String getPageEncoding() {
return pageEncoding;
}
public Vector getIncludePrelude() {
return includePrelude;
}
public Vector getIncludeCoda() {
return includeCoda;
}
public String isDeferedSyntaxAllowedAsLiteral() {
return deferedSyntaxAllowedAsLiteral;
}
public String isTrimDirectiveWhitespaces() {
return trimDirectiveWhitespaces;
}
}
}
@@ -0,0 +1,657 @@
/*
* 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.jasper.compiler;
import java.io.CharArrayWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Vector;
import java.util.jar.JarFile;
import java.net.URL;
import java.net.MalformedURLException;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* JspReader is an input buffer for the JSP parser. It should allow
* unlimited lookahead and pushback. It also has a bunch of parsing
* utility methods for understanding htmlesque thingies.
*
* @author Anil K. Vijendran
* @author Anselm Baird-Smith
* @author Harish Prabandham
* @author Rajiv Mordani
* @author Mandar Raje
* @author Danno Ferrin
* @author Kin-man Chung
* @author Shawn Bayern
* @author Mark Roth
*/
class JspReader {
/**
* Logger.
*/
private Log log = LogFactory.getLog(JspReader.class);
/**
* The current spot in the file.
*/
private Mark current;
/**
* What is this?
*/
private String master;
/**
* The list of source files.
*/
private List sourceFiles;
/**
* The current file ID (-1 indicates an error or no file).
*/
private int currFileId;
/**
* Seems redundant.
*/
private int size;
/**
* The compilation context.
*/
private JspCompilationContext context;
/**
* The Jasper error dispatcher.
*/
private ErrorDispatcher err;
/**
* Set to true when using the JspReader on a single file where we read up
* to the end and reset to the beginning many times.
* (as in ParserController.figureOutJspDocument()).
*/
private boolean singleFile;
/**
* Constructor.
*
* @param ctxt The compilation context
* @param fname The file name
* @param encoding The file encoding
* @param jarFile ?
* @param err The error dispatcher
* @throws JasperException If a Jasper-internal error occurs
* @throws FileNotFoundException If the JSP file is not found (or is unreadable)
* @throws IOException If an IO-level error occurs, e.g. reading the file
*/
public JspReader(JspCompilationContext ctxt,
String fname,
String encoding,
JarFile jarFile,
ErrorDispatcher err)
throws JasperException, FileNotFoundException, IOException {
this(ctxt, fname, encoding,
JspUtil.getReader(fname, encoding, jarFile, ctxt, err),
err);
}
/**
* Constructor: same as above constructor but with initialized reader
* to the file given.
*/
public JspReader(JspCompilationContext ctxt,
String fname,
String encoding,
InputStreamReader reader,
ErrorDispatcher err)
throws JasperException, FileNotFoundException {
this.context = ctxt;
this.err = err;
sourceFiles = new Vector();
currFileId = 0;
size = 0;
singleFile = false;
pushFile(fname, encoding, reader);
}
/**
* @return JSP compilation context with which this JspReader is
* associated
*/
JspCompilationContext getJspCompilationContext() {
return context;
}
/**
* Returns the file at the given position in the list.
*
* @param fileid The file position in the list
* @return The file at that position, if found, null otherwise
*/
String getFile(final int fileid) {
return (String) sourceFiles.get(fileid);
}
/**
* Checks if the current file has more input.
*
* @return True if more reading is possible
* @throws JasperException if an error occurs
*/
boolean hasMoreInput() throws JasperException {
if (current.cursor >= current.stream.length) {
if (singleFile) return false;
while (popFile()) {
if (current.cursor < current.stream.length) return true;
}
return false;
}
return true;
}
int nextChar() throws JasperException {
if (!hasMoreInput())
return -1;
int ch = current.stream[current.cursor];
current.cursor++;
if (ch == '\n') {
current.line++;
current.col = 0;
} else {
current.col++;
}
return ch;
}
/**
* Back up the current cursor by one char, assumes current.cursor > 0,
* and that the char to be pushed back is not '\n'.
*/
void pushChar() {
current.cursor--;
current.col--;
}
String getText(Mark start, Mark stop) throws JasperException {
Mark oldstart = mark();
reset(start);
CharArrayWriter caw = new CharArrayWriter();
while (!stop.equals(mark()))
caw.write(nextChar());
caw.close();
reset(oldstart);
return caw.toString();
}
int peekChar() throws JasperException {
if (!hasMoreInput())
return -1;
return current.stream[current.cursor];
}
Mark mark() {
return new Mark(current);
}
void reset(Mark mark) {
current = new Mark(mark);
}
boolean matchesIgnoreCase(String string) throws JasperException {
Mark mark = mark();
int ch = 0;
int i = 0;
do {
ch = nextChar();
if (Character.toLowerCase((char) ch) != string.charAt(i++)) {
reset(mark);
return false;
}
} while (i < string.length());
reset(mark);
return true;
}
/**
* search the stream for a match to a string
* @param string The string to match
* @return <strong>true</strong> is one is found, the current position
* in stream is positioned after the search string, <strong>
* false</strong> otherwise, position in stream unchanged.
*/
boolean matches(String string) throws JasperException {
Mark mark = mark();
int ch = 0;
int i = 0;
do {
ch = nextChar();
if (((char) ch) != string.charAt(i++)) {
reset(mark);
return false;
}
} while (i < string.length());
return true;
}
boolean matchesETag(String tagName) throws JasperException {
Mark mark = mark();
if (!matches("</" + tagName))
return false;
skipSpaces();
if (nextChar() == '>')
return true;
reset(mark);
return false;
}
boolean matchesETagWithoutLessThan(String tagName)
throws JasperException
{
Mark mark = mark();
if (!matches("/" + tagName))
return false;
skipSpaces();
if (nextChar() == '>')
return true;
reset(mark);
return false;
}
/**
* Looks ahead to see if there are optional spaces followed by
* the given String. If so, true is returned and those spaces and
* characters are skipped. If not, false is returned and the
* position is restored to where we were before.
*/
boolean matchesOptionalSpacesFollowedBy( String s )
throws JasperException
{
Mark mark = mark();
skipSpaces();
boolean result = matches( s );
if( !result ) {
reset( mark );
}
return result;
}
int skipSpaces() throws JasperException {
int i = 0;
while (hasMoreInput() && isSpace()) {
i++;
nextChar();
}
return i;
}
/**
* Skip until the given string is matched in the stream.
* When returned, the context is positioned past the end of the match.
*
* @param s The String to match.
* @return A non-null <code>Mark</code> instance (positioned immediately
* before the search string) if found, <strong>null</strong>
* otherwise.
*/
Mark skipUntil(String limit) throws JasperException {
Mark ret = null;
int limlen = limit.length();
int ch;
skip:
for (ret = mark(), ch = nextChar() ; ch != -1 ;
ret = mark(), ch = nextChar()) {
if (ch == limit.charAt(0)) {
Mark restart = mark();
for (int i = 1 ; i < limlen ; i++) {
if (peekChar() == limit.charAt(i))
nextChar();
else {
reset(restart);
continue skip;
}
}
return ret;
}
}
return null;
}
/**
* Skip until the given string is matched in the stream, but ignoring
* chars initially escaped by a '\'.
* When returned, the context is positioned past the end of the match.
*
* @param s The String to match.
* @return A non-null <code>Mark</code> instance (positioned immediately
* before the search string) if found, <strong>null</strong>
* otherwise.
*/
Mark skipUntilIgnoreEsc(String limit) throws JasperException {
Mark ret = null;
int limlen = limit.length();
int ch;
int prev = 'x'; // Doesn't matter
skip:
for (ret = mark(), ch = nextChar() ; ch != -1 ;
ret = mark(), prev = ch, ch = nextChar()) {
if (ch == '\\' && prev == '\\') {
ch = 0; // Double \ is not an escape char anymore
}
else if (ch == limit.charAt(0) && prev != '\\') {
for (int i = 1 ; i < limlen ; i++) {
if (peekChar() == limit.charAt(i))
nextChar();
else
continue skip;
}
return ret;
}
}
return null;
}
/**
* Skip until the given end tag is matched in the stream.
* When returned, the context is positioned past the end of the tag.
*
* @param tag The name of the tag whose ETag (</tag>) to match.
* @return A non-null <code>Mark</code> instance (positioned immediately
* before the ETag) if found, <strong>null</strong> otherwise.
*/
Mark skipUntilETag(String tag) throws JasperException {
Mark ret = skipUntil("</" + tag);
if (ret != null) {
skipSpaces();
if (nextChar() != '>')
ret = null;
}
return ret;
}
final boolean isSpace() throws JasperException {
// Note: If this logic changes, also update Node.TemplateText.rtrim()
return peekChar() <= ' ';
}
/**
* Parse a space delimited token.
* If quoted the token will consume all characters up to a matching quote,
* otherwise, it consumes up to the first delimiter character.
*
* @param quoted If <strong>true</strong> accept quoted strings.
*/
String parseToken(boolean quoted) throws JasperException {
StringBuffer stringBuffer = new StringBuffer();
skipSpaces();
stringBuffer.setLength(0);
if (!hasMoreInput()) {
return "";
}
int ch = peekChar();
if (quoted) {
if (ch == '"' || ch == '\'') {
char endQuote = ch == '"' ? '"' : '\'';
// Consume the open quote:
ch = nextChar();
for (ch = nextChar(); ch != -1 && ch != endQuote;
ch = nextChar()) {
if (ch == '\\')
ch = nextChar();
stringBuffer.append((char) ch);
}
// Check end of quote, skip closing quote:
if (ch == -1) {
err.jspError(mark(), "jsp.error.quotes.unterminated");
}
} else {
err.jspError(mark(), "jsp.error.attr.quoted");
}
} else {
if (!isDelimiter()) {
// Read value until delimiter is found:
do {
ch = nextChar();
// Take care of the quoting here.
if (ch == '\\') {
if (peekChar() == '"' || peekChar() == '\'' ||
peekChar() == '>' || peekChar() == '%')
ch = nextChar();
}
stringBuffer.append((char) ch);
} while (!isDelimiter());
}
}
return stringBuffer.toString();
}
void setSingleFile(boolean val) {
singleFile = val;
}
/**
* Gets the URL for the given path name.
*
* @param path Path name
*
* @return URL for the given path name.
*
* @exception MalformedURLException if the path name is not given in
* the correct form
*/
URL getResource(String path) throws MalformedURLException {
return context.getResource(path);
}
/**
* Parse utils - Is current character a token delimiter ?
* Delimiters are currently defined to be =, &gt;, &lt;, ", and ' or any
* any space character as defined by <code>isSpace</code>.
*
* @return A boolean.
*/
private boolean isDelimiter() throws JasperException {
if (! isSpace()) {
int ch = peekChar();
// Look for a single-char work delimiter:
if (ch == '=' || ch == '>' || ch == '"' || ch == '\''
|| ch == '/') {
return true;
}
// Look for an end-of-comment or end-of-tag:
if (ch == '-') {
Mark mark = mark();
if (((ch = nextChar()) == '>')
|| ((ch == '-') && (nextChar() == '>'))) {
reset(mark);
return true;
} else {
reset(mark);
return false;
}
}
return false;
} else {
return true;
}
}
/**
* Register a new source file.
* This method is used to implement file inclusion. Each included file
* gets a unique identifier (which is the index in the array of source
* files).
*
* @return The index of the now registered file.
*/
private int registerSourceFile(final String file) {
if (sourceFiles.contains(file)) {
return -1;
}
sourceFiles.add(file);
this.size++;
return sourceFiles.size() - 1;
}
/**
* Unregister the source file.
* This method is used to implement file inclusion. Each included file
* gets a uniq identifier (which is the index in the array of source
* files).
*
* @return The index of the now registered file.
*/
private int unregisterSourceFile(final String file) {
if (!sourceFiles.contains(file)) {
return -1;
}
sourceFiles.remove(file);
this.size--;
return sourceFiles.size() - 1;
}
/**
* Push a file (and its associated Stream) on the file stack. THe
* current position in the current file is remembered.
*/
private void pushFile(String file, String encoding,
InputStreamReader reader)
throws JasperException, FileNotFoundException {
// Register the file
String longName = file;
int fileid = registerSourceFile(longName);
if (fileid == -1) {
// Bugzilla 37407: http://issues.apache.org/bugzilla/show_bug.cgi?id=37407
if(reader != null) {
try {
reader.close();
} catch (Exception any) {
if(log.isDebugEnabled()) {
log.debug("Exception closing reader: ", any);
}
}
}
err.jspError("jsp.error.file.already.registered", file);
}
currFileId = fileid;
try {
CharArrayWriter caw = new CharArrayWriter();
char buf[] = new char[1024];
for (int i = 0 ; (i = reader.read(buf)) != -1 ;)
caw.write(buf, 0, i);
caw.close();
if (current == null) {
current = new Mark(this, caw.toCharArray(), fileid,
getFile(fileid), master, encoding);
} else {
current.pushStream(caw.toCharArray(), fileid, getFile(fileid),
longName, encoding);
}
} catch (Throwable ex) {
log.error("Exception parsing file ", ex);
// Pop state being constructed:
popFile();
err.jspError("jsp.error.file.cannot.read", file);
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception any) {
if(log.isDebugEnabled()) {
log.debug("Exception closing reader: ", any);
}
}
}
}
}
/**
* Pop a file from the file stack. The field "current" is retored
* to the value to point to the previous files, if any, and is set
* to null otherwise.
* @return true is there is a previous file on the stack.
* false otherwise.
*/
private boolean popFile() throws JasperException {
// Is stack created ? (will happen if the Jsp file we're looking at is
// missing.
if (current == null || currFileId < 0) {
return false;
}
// Restore parser state:
String fName = getFile(currFileId);
currFileId = unregisterSourceFile(fName);
if (currFileId < -1) {
err.jspError("jsp.error.file.not.registered", fName);
}
Mark previous = current.popStream();
if (previous != null) {
master = current.baseDir;
current = previous;
return true;
}
// Note that although the current file is undefined here, "current"
// is not set to null just for convience, for it maybe used to
// set the current (undefined) position.
return false;
}
}
@@ -0,0 +1,446 @@
/*
* 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.jasper.compiler;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilePermission;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.Policy;
import java.security.cert.Certificate;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspFactory;
import org.apache.jasper.Constants;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.Options;
import org.apache.jasper.runtime.JspFactoryImpl;
import org.apache.jasper.security.SecurityClassLoad;
import org.apache.jasper.servlet.JspServletWrapper;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* Class for tracking JSP compile time file dependencies when the
* &060;%@include file="..."%&062; directive is used.
*
* A background thread periodically checks the files a JSP page
* is dependent upon. If a dpendent file changes the JSP page
* which included it is recompiled.
*
* Only used if a web application context is a directory.
*
* @author Glenn L. Nielsen
* @version $Revision: 505593 $
*/
public final class JspRuntimeContext {
// Logger
private Log log = LogFactory.getLog(JspRuntimeContext.class);
/*
* Counts how many times the webapp's JSPs have been reloaded.
*/
private int jspReloadCount;
/**
* Preload classes required at runtime by a JSP servlet so that
* we don't get a defineClassInPackage security exception.
*/
static {
JspFactoryImpl factory = new JspFactoryImpl();
SecurityClassLoad.securityClassLoad(factory.getClass().getClassLoader());
if( System.getSecurityManager() != null ) {
String basePackage = "org.apache.jasper.";
try {
factory.getClass().getClassLoader().loadClass( basePackage +
"runtime.JspFactoryImpl$PrivilegedGetPageContext");
factory.getClass().getClassLoader().loadClass( basePackage +
"runtime.JspFactoryImpl$PrivilegedReleasePageContext");
factory.getClass().getClassLoader().loadClass( basePackage +
"runtime.JspRuntimeLibrary");
factory.getClass().getClassLoader().loadClass( basePackage +
"runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper");
factory.getClass().getClassLoader().loadClass( basePackage +
"runtime.ServletResponseWrapperInclude");
factory.getClass().getClassLoader().loadClass( basePackage +
"servlet.JspServletWrapper");
} catch (ClassNotFoundException ex) {
throw new IllegalStateException(ex);
}
}
JspFactory.setDefaultFactory(factory);
}
// ----------------------------------------------------------- Constructors
/**
* Create a JspRuntimeContext for a web application context.
*
* Loads in any previously generated dependencies from file.
*
* @param context ServletContext for web application
*/
public JspRuntimeContext(ServletContext context, Options options) {
this.context = context;
this.options = options;
// Get the parent class loader
parentClassLoader =
(URLClassLoader) Thread.currentThread().getContextClassLoader();
if (parentClassLoader == null) {
parentClassLoader =
(URLClassLoader)this.getClass().getClassLoader();
}
if (log.isDebugEnabled()) {
if (parentClassLoader != null) {
log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is",
parentClassLoader.toString()));
} else {
log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is",
"<none>"));
}
}
initClassPath();
if (context instanceof org.apache.jasper.servlet.JspCServletContext) {
return;
}
if (Constants.IS_SECURITY_ENABLED) {
initSecurity();
}
// If this web application context is running from a
// directory, start the background compilation thread
String appBase = context.getRealPath("/");
if (!options.getDevelopment()
&& appBase != null
&& options.getCheckInterval() > 0) {
lastCheck = System.currentTimeMillis();
}
}
// ----------------------------------------------------- Instance Variables
/**
* This web applications ServletContext
*/
private ServletContext context;
private Options options;
private URLClassLoader parentClassLoader;
private PermissionCollection permissionCollection;
private CodeSource codeSource;
private String classpath;
private long lastCheck = -1L;
/**
* Maps JSP pages to their JspServletWrapper's
*/
private Map<String, JspServletWrapper> jsps = new ConcurrentHashMap<String, JspServletWrapper>();
// ------------------------------------------------------ Public Methods
/**
* Add a new JspServletWrapper.
*
* @param jspUri JSP URI
* @param jsw Servlet wrapper for JSP
*/
public void addWrapper(String jspUri, JspServletWrapper jsw) {
jsps.put(jspUri, jsw);
}
/**
* Get an already existing JspServletWrapper.
*
* @param jspUri JSP URI
* @return JspServletWrapper for JSP
*/
public JspServletWrapper getWrapper(String jspUri) {
return jsps.get(jspUri);
}
/**
* Remove a JspServletWrapper.
*
* @param jspUri JSP URI of JspServletWrapper to remove
*/
public void removeWrapper(String jspUri) {
jsps.remove(jspUri);
}
/**
* Returns the number of JSPs for which JspServletWrappers exist, i.e.,
* the number of JSPs that have been loaded into the webapp.
*
* @return The number of JSPs that have been loaded into the webapp
*/
public int getJspCount() {
return jsps.size();
}
/**
* Get the SecurityManager Policy CodeSource for this web
* applicaiton context.
*
* @return CodeSource for JSP
*/
public CodeSource getCodeSource() {
return codeSource;
}
/**
* Get the parent URLClassLoader.
*
* @return URLClassLoader parent
*/
public URLClassLoader getParentClassLoader() {
return parentClassLoader;
}
/**
* Get the SecurityManager PermissionCollection for this
* web application context.
*
* @return PermissionCollection permissions
*/
public PermissionCollection getPermissionCollection() {
return permissionCollection;
}
/**
* Process a "destory" event for this web application context.
*/
public void destroy() {
Iterator servlets = jsps.values().iterator();
while (servlets.hasNext()) {
((JspServletWrapper) servlets.next()).destroy();
}
}
/**
* Increments the JSP reload counter.
*/
public synchronized void incrementJspReloadCount() {
jspReloadCount++;
}
/**
* Resets the JSP reload counter.
*
* @param count Value to which to reset the JSP reload counter
*/
public synchronized void setJspReloadCount(int count) {
this.jspReloadCount = count;
}
/**
* Gets the current value of the JSP reload counter.
*
* @return The current value of the JSP reload counter
*/
public int getJspReloadCount() {
return jspReloadCount;
}
/**
* Method used by background thread to check the JSP dependencies
* registered with this class for JSP's.
*/
public void checkCompile() {
if (lastCheck < 0) {
// Checking was disabled
return;
}
long now = System.currentTimeMillis();
if (now > (lastCheck + (options.getCheckInterval() * 1000L))) {
lastCheck = now;
} else {
return;
}
Object [] wrappers = jsps.values().toArray();
for (int i = 0; i < wrappers.length; i++ ) {
JspServletWrapper jsw = (JspServletWrapper)wrappers[i];
JspCompilationContext ctxt = jsw.getJspEngineContext();
// JspServletWrapper also synchronizes on this when
// it detects it has to do a reload
synchronized(jsw) {
try {
ctxt.compile();
} catch (FileNotFoundException ex) {
ctxt.incrementRemoved();
} catch (Throwable t) {
jsw.getServletContext().log("Background compile failed",
t);
}
}
}
}
/**
* The classpath that is passed off to the Java compiler.
*/
public String getClassPath() {
return classpath;
}
// -------------------------------------------------------- Private Methods
/**
* Method used to initialize classpath for compiles.
*/
private void initClassPath() {
URL [] urls = parentClassLoader.getURLs();
StringBuffer cpath = new StringBuffer();
String sep = System.getProperty("path.separator");
for(int i = 0; i < urls.length; i++) {
// Tomcat 4 can use URL's other than file URL's,
// a protocol other than file: will generate a
// bad file system path, so only add file:
// protocol URL's to the classpath.
if( urls[i].getProtocol().equals("file") ) {
cpath.append((String)urls[i].getFile()+sep);
}
}
cpath.append(options.getScratchDir() + sep);
String cp = (String) context.getAttribute(Constants.SERVLET_CLASSPATH);
if (cp == null || cp.equals("")) {
cp = options.getClassPath();
}
classpath = cpath.toString() + cp;
if(log.isDebugEnabled()) {
log.debug("Compilation classpath initialized: " + getClassPath());
}
}
/**
* Method used to initialize SecurityManager data.
*/
private void initSecurity() {
// Setup the PermissionCollection for this web app context
// based on the permissions configured for the root of the
// web app context directory, then add a file read permission
// for that directory.
Policy policy = Policy.getPolicy();
if( policy != null ) {
try {
// Get the permissions for the web app context
String docBase = context.getRealPath("/");
if( docBase == null ) {
docBase = options.getScratchDir().toString();
}
String codeBase = docBase;
if (!codeBase.endsWith(File.separator)){
codeBase = codeBase + File.separator;
}
File contextDir = new File(codeBase);
URL url = contextDir.getCanonicalFile().toURL();
codeSource = new CodeSource(url,(Certificate[])null);
permissionCollection = policy.getPermissions(codeSource);
// Create a file read permission for web app context directory
if (!docBase.endsWith(File.separator)){
permissionCollection.add
(new FilePermission(docBase,"read"));
docBase = docBase + File.separator;
} else {
permissionCollection.add
(new FilePermission
(docBase.substring(0,docBase.length() - 1),"read"));
}
docBase = docBase + "-";
permissionCollection.add(new FilePermission(docBase,"read"));
// Create a file read permission for web app tempdir (work)
// directory
String workDir = options.getScratchDir().toString();
if (!workDir.endsWith(File.separator)){
permissionCollection.add
(new FilePermission(workDir,"read"));
workDir = workDir + File.separator;
}
workDir = workDir + "-";
permissionCollection.add(new FilePermission(workDir,"read"));
// Allow the JSP to access org.apache.jasper.runtime.HttpJspBase
permissionCollection.add( new RuntimePermission(
"accessClassInPackage.org.apache.jasper.runtime") );
if (parentClassLoader instanceof URLClassLoader) {
URL [] urls = parentClassLoader.getURLs();
String jarUrl = null;
String jndiUrl = null;
for (int i=0; i<urls.length; i++) {
if (jndiUrl == null
&& urls[i].toString().startsWith("jndi:") ) {
jndiUrl = urls[i].toString() + "-";
}
if (jarUrl == null
&& urls[i].toString().startsWith("jar:jndi:")
) {
jarUrl = urls[i].toString();
jarUrl = jarUrl.substring(0,jarUrl.length() - 2);
jarUrl = jarUrl.substring(0,
jarUrl.lastIndexOf('/')) + "/-";
}
}
if (jarUrl != null) {
permissionCollection.add(
new FilePermission(jarUrl,"read"));
permissionCollection.add(
new FilePermission(jarUrl.substring(4),"read"));
}
if (jndiUrl != null)
permissionCollection.add(
new FilePermission(jndiUrl,"read") );
}
} catch(Exception e) {
context.log("Security Init for context failed",e);
}
}
}
}
@@ -0,0 +1,160 @@
/*
* 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.jasper.compiler;
import java.text.MessageFormat;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* Class responsible for converting error codes to corresponding localized
* error messages.
*
* @author Jan Luehe
*/
public class Localizer {
private static ResourceBundle bundle = null;
static {
try {
bundle = ResourceBundle.getBundle(
"org.apache.jasper.resources.LocalStrings");
} catch (Throwable t) {
t.printStackTrace();
}
}
/*
* Returns the localized error message corresponding to the given error
* code.
*
* If the given error code is not defined in the resource bundle for
* localized error messages, it is used as the error message.
*
* @param errCode Error code to localize
*
* @return Localized error message
*/
public static String getMessage(String errCode) {
String errMsg = errCode;
try {
errMsg = bundle.getString(errCode);
} catch (MissingResourceException e) {
}
return errMsg;
}
/*
* Returns the localized error message corresponding to the given error
* code.
*
* If the given error code is not defined in the resource bundle for
* localized error messages, it is used as the error message.
*
* @param errCode Error code to localize
* @param arg Argument for parametric replacement
*
* @return Localized error message
*/
public static String getMessage(String errCode, String arg) {
return getMessage(errCode, new Object[] {arg});
}
/*
* Returns the localized error message corresponding to the given error
* code.
*
* If the given error code is not defined in the resource bundle for
* localized error messages, it is used as the error message.
*
* @param errCode Error code to localize
* @param arg1 First argument for parametric replacement
* @param arg2 Second argument for parametric replacement
*
* @return Localized error message
*/
public static String getMessage(String errCode, String arg1, String arg2) {
return getMessage(errCode, new Object[] {arg1, arg2});
}
/*
* Returns the localized error message corresponding to the given error
* code.
*
* If the given error code is not defined in the resource bundle for
* localized error messages, it is used as the error message.
*
* @param errCode Error code to localize
* @param arg1 First argument for parametric replacement
* @param arg2 Second argument for parametric replacement
* @param arg3 Third argument for parametric replacement
*
* @return Localized error message
*/
public static String getMessage(String errCode, String arg1, String arg2,
String arg3) {
return getMessage(errCode, new Object[] {arg1, arg2, arg3});
}
/*
* Returns the localized error message corresponding to the given error
* code.
*
* If the given error code is not defined in the resource bundle for
* localized error messages, it is used as the error message.
*
* @param errCode Error code to localize
* @param arg1 First argument for parametric replacement
* @param arg2 Second argument for parametric replacement
* @param arg3 Third argument for parametric replacement
* @param arg4 Fourth argument for parametric replacement
*
* @return Localized error message
*/
public static String getMessage(String errCode, String arg1, String arg2,
String arg3, String arg4) {
return getMessage(errCode, new Object[] {arg1, arg2, arg3, arg4});
}
/*
* Returns the localized error message corresponding to the given error
* code.
*
* If the given error code is not defined in the resource bundle for
* localized error messages, it is used as the error message.
*
* @param errCode Error code to localize
* @param args Arguments for parametric replacement
*
* @return Localized error message
*/
public static String getMessage(String errCode, Object[] args) {
String errMsg = errCode;
try {
errMsg = bundle.getString(errCode);
if (args != null) {
MessageFormat formatter = new MessageFormat(errMsg);
errMsg = formatter.format(args);
}
} catch (MissingResourceException e) {
}
return errMsg;
}
}
@@ -0,0 +1,282 @@
/*
* 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.jasper.compiler;
import java.util.Stack;
import java.net.URL;
import java.net.MalformedURLException;
import org.apache.jasper.JspCompilationContext;
/**
* Mark represents a point in the JSP input.
*
* @author Anil K. Vijendran
*/
final class Mark {
// position within current stream
int cursor, line, col;
// directory of file for current stream
String baseDir;
// current stream
char[] stream = null;
// fileid of current stream
private int fileId;
// name of the current file
private String fileName;
/*
* stack of stream and stream state of streams that have included
* current stream
*/
private Stack includeStack = null;
// encoding of current file
private String encoding = null;
// reader that owns this mark (so we can look up fileid's)
private JspReader reader;
private JspCompilationContext ctxt;
/**
* Constructor
*
* @param reader JspReader this mark belongs to
* @param inStream current stream for this mark
* @param fileId id of requested jsp file
* @param name JSP file name
* @param inBaseDir base directory of requested jsp file
* @param inEncoding encoding of current file
*/
Mark(JspReader reader, char[] inStream, int fileId, String name,
String inBaseDir, String inEncoding) {
this.reader = reader;
this.ctxt = reader.getJspCompilationContext();
this.stream = inStream;
this.cursor = 0;
this.line = 1;
this.col = 1;
this.fileId = fileId;
this.fileName = name;
this.baseDir = inBaseDir;
this.encoding = inEncoding;
this.includeStack = new Stack();
}
/**
* Constructor
*/
Mark(Mark other) {
this.reader = other.reader;
this.ctxt = other.reader.getJspCompilationContext();
this.stream = other.stream;
this.fileId = other.fileId;
this.fileName = other.fileName;
this.cursor = other.cursor;
this.line = other.line;
this.col = other.col;
this.baseDir = other.baseDir;
this.encoding = other.encoding;
// clone includeStack without cloning contents
includeStack = new Stack();
for ( int i=0; i < other.includeStack.size(); i++ ) {
includeStack.addElement( other.includeStack.elementAt(i) );
}
}
/**
* Constructor
*/
Mark(JspCompilationContext ctxt, String filename, int line, int col) {
this.reader = null;
this.ctxt = ctxt;
this.stream = null;
this.cursor = 0;
this.line = line;
this.col = col;
this.fileId = -1;
this.fileName = filename;
this.baseDir = "le-basedir";
this.encoding = "le-endocing";
this.includeStack = null;
}
/**
* Sets this mark's state to a new stream.
* It will store the current stream in it's includeStack.
*
* @param inStream new stream for mark
* @param inFileId id of new file from which stream comes from
* @param inBaseDir directory of file
* @param inEncoding encoding of new file
*/
public void pushStream(char[] inStream, int inFileId, String name,
String inBaseDir, String inEncoding)
{
// store current state in stack
includeStack.push(new IncludeState(cursor, line, col, fileId,
fileName, baseDir,
encoding, stream) );
// set new variables
cursor = 0;
line = 1;
col = 1;
fileId = inFileId;
fileName = name;
baseDir = inBaseDir;
encoding = inEncoding;
stream = inStream;
}
/**
* Restores this mark's state to a previously stored stream.
* @return The previous Mark instance when the stream was pushed, or null
* if there is no previous stream
*/
public Mark popStream() {
// make sure we have something to pop
if ( includeStack.size() <= 0 ) {
return null;
}
// get previous state in stack
IncludeState state = (IncludeState) includeStack.pop( );
// set new variables
cursor = state.cursor;
line = state.line;
col = state.col;
fileId = state.fileId;
fileName = state.fileName;
baseDir = state.baseDir;
stream = state.stream;
return this;
}
// -------------------- Locator interface --------------------
public int getLineNumber() {
return line;
}
public int getColumnNumber() {
return col;
}
public String getSystemId() {
return getFile();
}
public String getPublicId() {
return null;
}
public String toString() {
return getFile()+"("+line+","+col+")";
}
public String getFile() {
return this.fileName;
}
/**
* Gets the URL of the resource with which this Mark is associated
*
* @return URL of the resource with which this Mark is associated
*
* @exception MalformedURLException if the resource pathname is incorrect
*/
public URL getURL() throws MalformedURLException {
return ctxt.getResource(getFile());
}
public String toShortString() {
return "("+line+","+col+")";
}
public boolean equals(Object other) {
if (other instanceof Mark) {
Mark m = (Mark) other;
return this.reader == m.reader && this.fileId == m.fileId
&& this.cursor == m.cursor && this.line == m.line
&& this.col == m.col;
}
return false;
}
/**
* @return true if this Mark is greather than the <code>other</code>
* Mark, false otherwise.
*/
public boolean isGreater(Mark other) {
boolean greater = false;
if (this.line > other.line) {
greater = true;
} else if (this.line == other.line && this.col > other.col) {
greater = true;
}
return greater;
}
/**
* Keep track of parser before parsing an included file.
* This class keeps track of the parser before we switch to parsing an
* included file. In other words, it's the parser's continuation to be
* reinstalled after the included file parsing is done.
*/
class IncludeState {
int cursor, line, col;
int fileId;
String fileName;
String baseDir;
String encoding;
char[] stream = null;
IncludeState(int inCursor, int inLine, int inCol, int inFileId,
String name, String inBaseDir, String inEncoding,
char[] inStream) {
cursor = inCursor;
line = inLine;
col = inCol;
fileId = inFileId;
fileName = name;
baseDir = inBaseDir;
encoding = inEncoding;
stream = inStream;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,711 @@
/*
* 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.jasper.compiler;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.CharArrayWriter;
import java.io.UnsupportedEncodingException;
import java.util.ListIterator;
import javax.servlet.jsp.tagext.PageData;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl;
import org.apache.jasper.JasperException;
/**
* An implementation of <tt>javax.servlet.jsp.tagext.PageData</tt> which
* builds the XML view of a given page.
*
* The XML view is built in two passes:
*
* During the first pass, the FirstPassVisitor collects the attributes of the
* top-level jsp:root and those of the jsp:root elements of any included
* pages, and adds them to the jsp:root element of the XML view.
* In addition, any taglib directives are converted into xmlns: attributes and
* added to the jsp:root element of the XML view.
* This pass ignores any nodes other than JspRoot and TaglibDirective.
*
* During the second pass, the SecondPassVisitor produces the XML view, using
* the combined jsp:root attributes determined in the first pass and any
* remaining pages nodes (this pass ignores any JspRoot and TaglibDirective
* nodes).
*
* @author Jan Luehe
*/
class PageDataImpl extends PageData implements TagConstants {
private static final String JSP_VERSION = "2.0";
private static final String CDATA_START_SECTION = "<![CDATA[\n";
private static final String CDATA_END_SECTION = "]]>\n";
// string buffer used to build XML view
private StringBuffer buf;
/**
* Constructor.
*
* @param page the page nodes from which to generate the XML view
*/
public PageDataImpl(Node.Nodes page, Compiler compiler)
throws JasperException {
// First pass
FirstPassVisitor firstPass = new FirstPassVisitor(page.getRoot(),
compiler.getPageInfo());
page.visit(firstPass);
// Second pass
buf = new StringBuffer();
SecondPassVisitor secondPass
= new SecondPassVisitor(page.getRoot(), buf, compiler,
firstPass.getJspIdPrefix());
page.visit(secondPass);
}
/**
* Returns the input stream of the XML view.
*
* @return the input stream of the XML view
*/
public InputStream getInputStream() {
// Turn StringBuffer into InputStream
try {
return new ByteArrayInputStream(buf.toString().getBytes("UTF-8"));
} catch (UnsupportedEncodingException uee) {
// should never happen
throw new RuntimeException(uee.toString());
}
}
/*
* First-pass Visitor for JspRoot nodes (representing jsp:root elements)
* and TablibDirective nodes, ignoring any other nodes.
*
* The purpose of this Visitor is to collect the attributes of the
* top-level jsp:root and those of the jsp:root elements of any included
* pages, and add them to the jsp:root element of the XML view.
* In addition, this Visitor converts any taglib directives into xmlns:
* attributes and adds them to the jsp:root element of the XML view.
*/
static class FirstPassVisitor
extends Node.Visitor implements TagConstants {
private Node.Root root;
private AttributesImpl rootAttrs;
private PageInfo pageInfo;
// Prefix for the 'id' attribute
private String jspIdPrefix;
/*
* Constructor
*/
public FirstPassVisitor(Node.Root root, PageInfo pageInfo) {
this.root = root;
this.pageInfo = pageInfo;
this.rootAttrs = new AttributesImpl();
this.rootAttrs.addAttribute("", "", "version", "CDATA",
JSP_VERSION);
this.jspIdPrefix = "jsp";
}
public void visit(Node.Root n) throws JasperException {
visitBody(n);
if (n == root) {
/*
* Top-level page.
*
* Add
* xmlns:jsp="http://java.sun.com/JSP/Page"
* attribute only if not already present.
*/
if (!JSP_URI.equals(rootAttrs.getValue("xmlns:jsp"))) {
rootAttrs.addAttribute("", "", "xmlns:jsp", "CDATA",
JSP_URI);
}
if (pageInfo.isJspPrefixHijacked()) {
/*
* 'jsp' prefix has been hijacked, that is, bound to a
* namespace other than the JSP namespace. This means that
* when adding an 'id' attribute to each element, we can't
* use the 'jsp' prefix. Therefore, create a new prefix
* (one that is unique across the translation unit) for use
* by the 'id' attribute, and bind it to the JSP namespace
*/
jspIdPrefix += "jsp";
while (pageInfo.containsPrefix(jspIdPrefix)) {
jspIdPrefix += "jsp";
}
rootAttrs.addAttribute("", "", "xmlns:" + jspIdPrefix,
"CDATA", JSP_URI);
}
root.setAttributes(rootAttrs);
}
}
public void visit(Node.JspRoot n) throws JasperException {
addAttributes(n.getTaglibAttributes());
addAttributes(n.getNonTaglibXmlnsAttributes());
addAttributes(n.getAttributes());
visitBody(n);
}
/*
* Converts taglib directive into "xmlns:..." attribute of jsp:root
* element.
*/
public void visit(Node.TaglibDirective n) throws JasperException {
Attributes attrs = n.getAttributes();
if (attrs != null) {
String qName = "xmlns:" + attrs.getValue("prefix");
/*
* According to javadocs of org.xml.sax.helpers.AttributesImpl,
* the addAttribute method does not check to see if the
* specified attribute is already contained in the list: This
* is the application's responsibility!
*/
if (rootAttrs.getIndex(qName) == -1) {
String location = attrs.getValue("uri");
if (location != null) {
if (location.startsWith("/")) {
location = URN_JSPTLD + location;
}
rootAttrs.addAttribute("", "", qName, "CDATA",
location);
} else {
location = attrs.getValue("tagdir");
rootAttrs.addAttribute("", "", qName, "CDATA",
URN_JSPTAGDIR + location);
}
}
}
}
public String getJspIdPrefix() {
return jspIdPrefix;
}
private void addAttributes(Attributes attrs) {
if (attrs != null) {
int len = attrs.getLength();
for (int i=0; i<len; i++) {
String qName = attrs.getQName(i);
if ("version".equals(qName)) {
continue;
}
// Bugzilla 35252: http://issues.apache.org/bugzilla/show_bug.cgi?id=35252
if(rootAttrs.getIndex(qName) == -1) {
rootAttrs.addAttribute(attrs.getURI(i),
attrs.getLocalName(i),
qName,
attrs.getType(i),
attrs.getValue(i));
}
}
}
}
}
/*
* Second-pass Visitor responsible for producing XML view and assigning
* each element a unique jsp:id attribute.
*/
static class SecondPassVisitor extends Node.Visitor
implements TagConstants {
private Node.Root root;
private StringBuffer buf;
private Compiler compiler;
private String jspIdPrefix;
private boolean resetDefaultNS = false;
// Current value of jsp:id attribute
private int jspId;
/*
* Constructor
*/
public SecondPassVisitor(Node.Root root, StringBuffer buf,
Compiler compiler, String jspIdPrefix) {
this.root = root;
this.buf = buf;
this.compiler = compiler;
this.jspIdPrefix = jspIdPrefix;
}
/*
* Visits root node.
*/
public void visit(Node.Root n) throws JasperException {
if (n == this.root) {
// top-level page
appendXmlProlog();
appendTag(n);
} else {
boolean resetDefaultNSSave = resetDefaultNS;
if (n.isXmlSyntax()) {
resetDefaultNS = true;
}
visitBody(n);
resetDefaultNS = resetDefaultNSSave;
}
}
/*
* Visits jsp:root element of JSP page in XML syntax.
*
* Any nested jsp:root elements (from pages included via an
* include directive) are ignored.
*/
public void visit(Node.JspRoot n) throws JasperException {
visitBody(n);
}
public void visit(Node.PageDirective n) throws JasperException {
appendPageDirective(n);
}
public void visit(Node.IncludeDirective n) throws JasperException {
// expand in place
visitBody(n);
}
public void visit(Node.Comment n) throws JasperException {
// Comments are ignored in XML view
}
public void visit(Node.Declaration n) throws JasperException {
appendTag(n);
}
public void visit(Node.Expression n) throws JasperException {
appendTag(n);
}
public void visit(Node.Scriptlet n) throws JasperException {
appendTag(n);
}
public void visit(Node.JspElement n) throws JasperException {
appendTag(n);
}
public void visit(Node.ELExpression n) throws JasperException {
if (!n.getRoot().isXmlSyntax()) {
buf.append("<").append(JSP_TEXT_ACTION);
buf.append(" ");
buf.append(jspIdPrefix);
buf.append(":id=\"");
buf.append(jspId++).append("\">");
}
buf.append("${");
buf.append(JspUtil.escapeXml(n.getText()));
buf.append("}");
if (!n.getRoot().isXmlSyntax()) {
buf.append(JSP_TEXT_ACTION_END);
}
buf.append("\n");
}
public void visit(Node.IncludeAction n) throws JasperException {
appendTag(n);
}
public void visit(Node.ForwardAction n) throws JasperException {
appendTag(n);
}
public void visit(Node.GetProperty n) throws JasperException {
appendTag(n);
}
public void visit(Node.SetProperty n) throws JasperException {
appendTag(n);
}
public void visit(Node.ParamAction n) throws JasperException {
appendTag(n);
}
public void visit(Node.ParamsAction n) throws JasperException {
appendTag(n);
}
public void visit(Node.FallBackAction n) throws JasperException {
appendTag(n);
}
public void visit(Node.UseBean n) throws JasperException {
appendTag(n);
}
public void visit(Node.PlugIn n) throws JasperException {
appendTag(n);
}
public void visit(Node.NamedAttribute n) throws JasperException {
appendTag(n);
}
public void visit(Node.JspBody n) throws JasperException {
appendTag(n);
}
public void visit(Node.CustomTag n) throws JasperException {
boolean resetDefaultNSSave = resetDefaultNS;
appendTag(n, resetDefaultNS);
resetDefaultNS = resetDefaultNSSave;
}
public void visit(Node.UninterpretedTag n) throws JasperException {
boolean resetDefaultNSSave = resetDefaultNS;
appendTag(n, resetDefaultNS);
resetDefaultNS = resetDefaultNSSave;
}
public void visit(Node.JspText n) throws JasperException {
appendTag(n);
}
public void visit(Node.DoBodyAction n) throws JasperException {
appendTag(n);
}
public void visit(Node.InvokeAction n) throws JasperException {
appendTag(n);
}
public void visit(Node.TagDirective n) throws JasperException {
appendTagDirective(n);
}
public void visit(Node.AttributeDirective n) throws JasperException {
appendTag(n);
}
public void visit(Node.VariableDirective n) throws JasperException {
appendTag(n);
}
public void visit(Node.TemplateText n) throws JasperException {
/*
* If the template text came from a JSP page written in JSP syntax,
* create a jsp:text element for it (JSP 5.3.2).
*/
appendText(n.getText(), !n.getRoot().isXmlSyntax());
}
/*
* Appends the given tag, including its body, to the XML view.
*/
private void appendTag(Node n) throws JasperException {
appendTag(n, false);
}
/*
* Appends the given tag, including its body, to the XML view,
* and optionally reset default namespace to "", if none specified.
*/
private void appendTag(Node n, boolean addDefaultNS)
throws JasperException {
Node.Nodes body = n.getBody();
String text = n.getText();
buf.append("<").append(n.getQName());
buf.append("\n");
printAttributes(n, addDefaultNS);
buf.append(" ").append(jspIdPrefix).append(":id").append("=\"");
buf.append(jspId++).append("\"\n");
if (ROOT_ACTION.equals(n.getLocalName()) || body != null
|| text != null) {
buf.append(">\n");
if (ROOT_ACTION.equals(n.getLocalName())) {
if (compiler.getCompilationContext().isTagFile()) {
appendTagDirective();
} else {
appendPageDirective();
}
}
if (body != null) {
body.visit(this);
} else {
appendText(text, false);
}
buf.append("</" + n.getQName() + ">\n");
} else {
buf.append("/>\n");
}
}
/*
* Appends the page directive with the given attributes to the XML
* view.
*
* Since the import attribute of the page directive is the only page
* attribute that is allowed to appear multiple times within the same
* document, and since XML allows only single-value attributes,
* the values of multiple import attributes must be combined into one,
* separated by comma.
*
* If the given page directive contains just 'contentType' and/or
* 'pageEncoding' attributes, we ignore it, as we've already appended
* a page directive containing just these two attributes.
*/
private void appendPageDirective(Node.PageDirective n) {
boolean append = false;
Attributes attrs = n.getAttributes();
int len = (attrs == null) ? 0 : attrs.getLength();
for (int i=0; i<len; i++) {
String attrName = attrs.getQName(i);
if (!"pageEncoding".equals(attrName)
&& !"contentType".equals(attrName)) {
append = true;
break;
}
}
if (!append) {
return;
}
buf.append("<").append(n.getQName());
buf.append("\n");
// append jsp:id
buf.append(" ").append(jspIdPrefix).append(":id").append("=\"");
buf.append(jspId++).append("\"\n");
// append remaining attributes
for (int i=0; i<len; i++) {
String attrName = attrs.getQName(i);
if ("import".equals(attrName) || "contentType".equals(attrName)
|| "pageEncoding".equals(attrName)) {
/*
* Page directive's 'import' attribute is considered
* further down, and its 'pageEncoding' and 'contentType'
* attributes are ignored, since we've already appended
* a new page directive containing just these two
* attributes
*/
continue;
}
String value = attrs.getValue(i);
buf.append(" ").append(attrName).append("=\"");
buf.append(JspUtil.getExprInXml(value)).append("\"\n");
}
if (n.getImports().size() > 0) {
// Concatenate names of imported classes/packages
boolean first = true;
ListIterator iter = n.getImports().listIterator();
while (iter.hasNext()) {
if (first) {
first = false;
buf.append(" import=\"");
} else {
buf.append(",");
}
buf.append(JspUtil.getExprInXml((String) iter.next()));
}
buf.append("\"\n");
}
buf.append("/>\n");
}
/*
* Appends a page directive with 'pageEncoding' and 'contentType'
* attributes.
*
* The value of the 'pageEncoding' attribute is hard-coded
* to UTF-8, whereas the value of the 'contentType' attribute, which
* is identical to what the container will pass to
* ServletResponse.setContentType(), is derived from the pageInfo.
*/
private void appendPageDirective() {
buf.append("<").append(JSP_PAGE_DIRECTIVE_ACTION);
buf.append("\n");
// append jsp:id
buf.append(" ").append(jspIdPrefix).append(":id").append("=\"");
buf.append(jspId++).append("\"\n");
buf.append(" ").append("pageEncoding").append("=\"UTF-8\"\n");
buf.append(" ").append("contentType").append("=\"");
buf.append(compiler.getPageInfo().getContentType()).append("\"\n");
buf.append("/>\n");
}
/*
* Appends the tag directive with the given attributes to the XML
* view.
*
* If the given tag directive contains just a 'pageEncoding'
* attributes, we ignore it, as we've already appended
* a tag directive containing just this attributes.
*/
private void appendTagDirective(Node.TagDirective n)
throws JasperException {
boolean append = false;
Attributes attrs = n.getAttributes();
int len = (attrs == null) ? 0 : attrs.getLength();
for (int i=0; i<len; i++) {
String attrName = attrs.getQName(i);
if (!"pageEncoding".equals(attrName)) {
append = true;
break;
}
}
if (!append) {
return;
}
appendTag(n);
}
/*
* Appends a tag directive containing a single 'pageEncoding'
* attribute whose value is hard-coded to UTF-8.
*/
private void appendTagDirective() {
buf.append("<").append(JSP_TAG_DIRECTIVE_ACTION);
buf.append("\n");
// append jsp:id
buf.append(" ").append(jspIdPrefix).append(":id").append("=\"");
buf.append(jspId++).append("\"\n");
buf.append(" ").append("pageEncoding").append("=\"UTF-8\"\n");
buf.append("/>\n");
}
private void appendText(String text, boolean createJspTextElement) {
if (createJspTextElement) {
buf.append("<").append(JSP_TEXT_ACTION);
buf.append("\n");
// append jsp:id
buf.append(" ").append(jspIdPrefix).append(":id").append("=\"");
buf.append(jspId++).append("\"\n");
buf.append(">\n");
appendCDATA(text);
buf.append(JSP_TEXT_ACTION_END);
buf.append("\n");
} else {
appendCDATA(text);
}
}
/*
* Appends the given text as a CDATA section to the XML view, unless
* the text has already been marked as CDATA.
*/
private void appendCDATA(String text) {
buf.append(CDATA_START_SECTION);
buf.append(escapeCDATA(text));
buf.append(CDATA_END_SECTION);
}
/*
* Escapes any occurrences of "]]>" (by replacing them with "]]&gt;")
* within the given text, so it can be included in a CDATA section.
*/
private String escapeCDATA(String text) {
if( text==null ) return "";
int len = text.length();
CharArrayWriter result = new CharArrayWriter(len);
for (int i=0; i<len; i++) {
if (((i+2) < len)
&& (text.charAt(i) == ']')
&& (text.charAt(i+1) == ']')
&& (text.charAt(i+2) == '>')) {
// match found
result.write(']');
result.write(']');
result.write('&');
result.write('g');
result.write('t');
result.write(';');
i += 2;
} else {
result.write(text.charAt(i));
}
}
return result.toString();
}
/*
* Appends the attributes of the given Node to the XML view.
*/
private void printAttributes(Node n, boolean addDefaultNS) {
/*
* Append "xmlns" attributes that represent tag libraries
*/
Attributes attrs = n.getTaglibAttributes();
int len = (attrs == null) ? 0 : attrs.getLength();
for (int i=0; i<len; i++) {
String name = attrs.getQName(i);
String value = attrs.getValue(i);
buf.append(" ").append(name).append("=\"").append(value).append("\"\n");
}
/*
* Append "xmlns" attributes that do not represent tag libraries
*/
attrs = n.getNonTaglibXmlnsAttributes();
len = (attrs == null) ? 0 : attrs.getLength();
boolean defaultNSSeen = false;
for (int i=0; i<len; i++) {
String name = attrs.getQName(i);
String value = attrs.getValue(i);
buf.append(" ").append(name).append("=\"").append(value).append("\"\n");
defaultNSSeen |= "xmlns".equals(name);
}
if (addDefaultNS && !defaultNSSeen) {
buf.append(" xmlns=\"\"\n");
}
resetDefaultNS = false;
/*
* Append all other attributes
*/
attrs = n.getAttributes();
len = (attrs == null) ? 0 : attrs.getLength();
for (int i=0; i<len; i++) {
String name = attrs.getQName(i);
String value = attrs.getValue(i);
buf.append(" ").append(name).append("=\"");
buf.append(JspUtil.getExprInXml(value)).append("\"\n");
}
}
/*
* Appends XML prolog with encoding declaration.
*/
private void appendXmlProlog() {
buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
}
}
}
@@ -0,0 +1,711 @@
/*
* 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.jasper.compiler;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import org.apache.el.ExpressionFactoryImpl;
import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
import javax.el.ExpressionFactory;
import javax.servlet.jsp.tagext.TagLibraryInfo;
/**
* A repository for various info about the translation unit under compilation.
*
* @author Kin-man Chung
*/
class PageInfo {
private Vector imports;
private Vector dependants;
private BeanRepository beanRepository;
private HashMap taglibsMap;
private HashMap jspPrefixMapper;
private HashMap xmlPrefixMapper;
private HashMap nonCustomTagPrefixMap;
private String jspFile;
private String defaultLanguage = "java";
private String language;
private String defaultExtends = Constants.JSP_SERVLET_BASE;
private String xtends;
private String contentType = null;
private String session;
private boolean isSession = true;
private String bufferValue;
private int buffer = 8*1024; // XXX confirm
private String autoFlush;
private boolean isAutoFlush = true;
private String isThreadSafeValue;
private boolean isThreadSafe = true;
private String isErrorPageValue;
private boolean isErrorPage = false;
private String errorPage = null;
private String info;
private boolean scriptless = false;
private boolean scriptingInvalid = false;
private String isELIgnoredValue;
private boolean isELIgnored = false;
// JSP 2.1
private String deferredSyntaxAllowedAsLiteralValue;
private boolean deferredSyntaxAllowedAsLiteral = false;
private ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
private String trimDirectiveWhitespacesValue;
private boolean trimDirectiveWhitespaces = false;
private String omitXmlDecl = null;
private String doctypeName = null;
private String doctypePublic = null;
private String doctypeSystem = null;
private boolean isJspPrefixHijacked;
// Set of all element and attribute prefixes used in this translation unit
private HashSet prefixes;
private boolean hasJspRoot = false;
private Vector includePrelude;
private Vector includeCoda;
private Vector pluginDcls; // Id's for tagplugin declarations
PageInfo(BeanRepository beanRepository, String jspFile) {
this.jspFile = jspFile;
this.beanRepository = beanRepository;
this.taglibsMap = new HashMap();
this.jspPrefixMapper = new HashMap();
this.xmlPrefixMapper = new HashMap();
this.nonCustomTagPrefixMap = new HashMap();
this.imports = new Vector();
this.dependants = new Vector();
this.includePrelude = new Vector();
this.includeCoda = new Vector();
this.pluginDcls = new Vector();
this.prefixes = new HashSet();
// Enter standard imports
for(int i = 0; i < Constants.STANDARD_IMPORTS.length; i++)
imports.add(Constants.STANDARD_IMPORTS[i]);
}
/**
* Check if the plugin ID has been previously declared. Make a not
* that this Id is now declared.
* @return true if Id has been declared.
*/
public boolean isPluginDeclared(String id) {
if (pluginDcls.contains(id))
return true;
pluginDcls.add(id);
return false;
}
public void addImports(List imports) {
this.imports.addAll(imports);
}
public void addImport(String imp) {
this.imports.add(imp);
}
public List getImports() {
return imports;
}
public String getJspFile() {
return jspFile;
}
public void addDependant(String d) {
if (!dependants.contains(d) && !jspFile.equals(d))
dependants.add(d);
}
public List getDependants() {
return dependants;
}
public BeanRepository getBeanRepository() {
return beanRepository;
}
public void setScriptless(boolean s) {
scriptless = s;
}
public boolean isScriptless() {
return scriptless;
}
public void setScriptingInvalid(boolean s) {
scriptingInvalid = s;
}
public boolean isScriptingInvalid() {
return scriptingInvalid;
}
public List getIncludePrelude() {
return includePrelude;
}
public void setIncludePrelude(Vector prelude) {
includePrelude = prelude;
}
public List getIncludeCoda() {
return includeCoda;
}
public void setIncludeCoda(Vector coda) {
includeCoda = coda;
}
public void setHasJspRoot(boolean s) {
hasJspRoot = s;
}
public boolean hasJspRoot() {
return hasJspRoot;
}
public String getOmitXmlDecl() {
return omitXmlDecl;
}
public void setOmitXmlDecl(String omit) {
omitXmlDecl = omit;
}
public String getDoctypeName() {
return doctypeName;
}
public void setDoctypeName(String doctypeName) {
this.doctypeName = doctypeName;
}
public String getDoctypeSystem() {
return doctypeSystem;
}
public void setDoctypeSystem(String doctypeSystem) {
this.doctypeSystem = doctypeSystem;
}
public String getDoctypePublic() {
return doctypePublic;
}
public void setDoctypePublic(String doctypePublic) {
this.doctypePublic = doctypePublic;
}
/* Tag library and XML namespace management methods */
public void setIsJspPrefixHijacked(boolean isHijacked) {
isJspPrefixHijacked = isHijacked;
}
public boolean isJspPrefixHijacked() {
return isJspPrefixHijacked;
}
/*
* Adds the given prefix to the set of prefixes of this translation unit.
*
* @param prefix The prefix to add
*/
public void addPrefix(String prefix) {
prefixes.add(prefix);
}
/*
* Checks to see if this translation unit contains the given prefix.
*
* @param prefix The prefix to check
*
* @return true if this translation unit contains the given prefix, false
* otherwise
*/
public boolean containsPrefix(String prefix) {
return prefixes.contains(prefix);
}
/*
* Maps the given URI to the given tag library.
*
* @param uri The URI to map
* @param info The tag library to be associated with the given URI
*/
public void addTaglib(String uri, TagLibraryInfo info) {
taglibsMap.put(uri, info);
}
/*
* Gets the tag library corresponding to the given URI.
*
* @return Tag library corresponding to the given URI
*/
public TagLibraryInfo getTaglib(String uri) {
return (TagLibraryInfo) taglibsMap.get(uri);
}
/*
* Gets the collection of tag libraries that are associated with a URI
*
* @return Collection of tag libraries that are associated with a URI
*/
public Collection getTaglibs() {
return taglibsMap.values();
}
/*
* Checks to see if the given URI is mapped to a tag library.
*
* @param uri The URI to map
*
* @return true if the given URI is mapped to a tag library, false
* otherwise
*/
public boolean hasTaglib(String uri) {
return taglibsMap.containsKey(uri);
}
/*
* Maps the given prefix to the given URI.
*
* @param prefix The prefix to map
* @param uri The URI to be associated with the given prefix
*/
public void addPrefixMapping(String prefix, String uri) {
jspPrefixMapper.put(prefix, uri);
}
/*
* Pushes the given URI onto the stack of URIs to which the given prefix
* is mapped.
*
* @param prefix The prefix whose stack of URIs is to be pushed
* @param uri The URI to be pushed onto the stack
*/
public void pushPrefixMapping(String prefix, String uri) {
LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix);
if (stack == null) {
stack = new LinkedList();
xmlPrefixMapper.put(prefix, stack);
}
stack.addFirst(uri);
}
/*
* Removes the URI at the top of the stack of URIs to which the given
* prefix is mapped.
*
* @param prefix The prefix whose stack of URIs is to be popped
*/
public void popPrefixMapping(String prefix) {
LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix);
if (stack == null || stack.size() == 0) {
// XXX throw new Exception("XXX");
}
stack.removeFirst();
}
/*
* Returns the URI to which the given prefix maps.
*
* @param prefix The prefix whose URI is sought
*
* @return The URI to which the given prefix maps
*/
public String getURI(String prefix) {
String uri = null;
LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix);
if (stack == null || stack.size() == 0) {
uri = (String) jspPrefixMapper.get(prefix);
} else {
uri = (String) stack.getFirst();
}
return uri;
}
/* Page/Tag directive attributes */
/*
* language
*/
public void setLanguage(String value, Node n, ErrorDispatcher err,
boolean pagedir)
throws JasperException {
if (!"java".equalsIgnoreCase(value)) {
if (pagedir)
err.jspError(n, "jsp.error.page.language.nonjava");
else
err.jspError(n, "jsp.error.tag.language.nonjava");
}
language = value;
}
public String getLanguage(boolean useDefault) {
return (language == null && useDefault ? defaultLanguage : language);
}
public String getLanguage() {
return getLanguage(true);
}
/*
* extends
*/
public void setExtends(String value, Node.PageDirective n) {
xtends = value;
/*
* If page superclass is top level class (i.e. not in a package)
* explicitly import it. If this is not done, the compiler will assume
* the extended class is in the same pkg as the generated servlet.
*/
if (value.indexOf('.') < 0)
n.addImport(value);
}
/**
* Gets the value of the 'extends' page directive attribute.
*
* @param useDefault TRUE if the default
* (org.apache.jasper.runtime.HttpJspBase) should be returned if this
* attribute has not been set, FALSE otherwise
*
* @return The value of the 'extends' page directive attribute, or the
* default (org.apache.jasper.runtime.HttpJspBase) if this attribute has
* not been set and useDefault is TRUE
*/
public String getExtends(boolean useDefault) {
return (xtends == null && useDefault ? defaultExtends : xtends);
}
/**
* Gets the value of the 'extends' page directive attribute.
*
* @return The value of the 'extends' page directive attribute, or the
* default (org.apache.jasper.runtime.HttpJspBase) if this attribute has
* not been set
*/
public String getExtends() {
return getExtends(true);
}
/*
* contentType
*/
public void setContentType(String value) {
contentType = value;
}
public String getContentType() {
return contentType;
}
/*
* buffer
*/
public void setBufferValue(String value, Node n, ErrorDispatcher err)
throws JasperException {
if ("none".equalsIgnoreCase(value))
buffer = 0;
else {
if (value == null || !value.endsWith("kb"))
err.jspError(n, "jsp.error.page.invalid.buffer");
try {
Integer k = new Integer(value.substring(0, value.length()-2));
buffer = k.intValue() * 1024;
} catch (NumberFormatException e) {
err.jspError(n, "jsp.error.page.invalid.buffer");
}
}
bufferValue = value;
}
public String getBufferValue() {
return bufferValue;
}
public int getBuffer() {
return buffer;
}
/*
* session
*/
public void setSession(String value, Node n, ErrorDispatcher err)
throws JasperException {
if ("true".equalsIgnoreCase(value))
isSession = true;
else if ("false".equalsIgnoreCase(value))
isSession = false;
else
err.jspError(n, "jsp.error.page.invalid.session");
session = value;
}
public String getSession() {
return session;
}
public boolean isSession() {
return isSession;
}
/*
* autoFlush
*/
public void setAutoFlush(String value, Node n, ErrorDispatcher err)
throws JasperException {
if ("true".equalsIgnoreCase(value))
isAutoFlush = true;
else if ("false".equalsIgnoreCase(value))
isAutoFlush = false;
else
err.jspError(n, "jsp.error.autoFlush.invalid");
autoFlush = value;
}
public String getAutoFlush() {
return autoFlush;
}
public boolean isAutoFlush() {
return isAutoFlush;
}
/*
* isThreadSafe
*/
public void setIsThreadSafe(String value, Node n, ErrorDispatcher err)
throws JasperException {
if ("true".equalsIgnoreCase(value))
isThreadSafe = true;
else if ("false".equalsIgnoreCase(value))
isThreadSafe = false;
else
err.jspError(n, "jsp.error.page.invalid.isthreadsafe");
isThreadSafeValue = value;
}
public String getIsThreadSafe() {
return isThreadSafeValue;
}
public boolean isThreadSafe() {
return isThreadSafe;
}
/*
* info
*/
public void setInfo(String value) {
info = value;
}
public String getInfo() {
return info;
}
/*
* errorPage
*/
public void setErrorPage(String value) {
errorPage = value;
}
public String getErrorPage() {
return errorPage;
}
/*
* isErrorPage
*/
public void setIsErrorPage(String value, Node n, ErrorDispatcher err)
throws JasperException {
if ("true".equalsIgnoreCase(value))
isErrorPage = true;
else if ("false".equalsIgnoreCase(value))
isErrorPage = false;
else
err.jspError(n, "jsp.error.page.invalid.iserrorpage");
isErrorPageValue = value;
}
public String getIsErrorPage() {
return isErrorPageValue;
}
public boolean isErrorPage() {
return isErrorPage;
}
/*
* isELIgnored
*/
public void setIsELIgnored(String value, Node n, ErrorDispatcher err,
boolean pagedir)
throws JasperException {
if ("true".equalsIgnoreCase(value))
isELIgnored = true;
else if ("false".equalsIgnoreCase(value))
isELIgnored = false;
else {
if (pagedir)
err.jspError(n, "jsp.error.page.invalid.iselignored");
else
err.jspError(n, "jsp.error.tag.invalid.iselignored");
}
isELIgnoredValue = value;
}
/*
* deferredSyntaxAllowedAsLiteral
*/
public void setDeferredSyntaxAllowedAsLiteral(String value, Node n, ErrorDispatcher err,
boolean pagedir)
throws JasperException {
if ("true".equalsIgnoreCase(value))
deferredSyntaxAllowedAsLiteral = true;
else if ("false".equalsIgnoreCase(value))
deferredSyntaxAllowedAsLiteral = false;
else {
if (pagedir)
err.jspError(n, "jsp.error.page.invalid.deferredsyntaxallowedasliteral");
else
err.jspError(n, "jsp.error.tag.invalid.deferredsyntaxallowedasliteral");
}
deferredSyntaxAllowedAsLiteralValue = value;
}
/*
* trimDirectiveWhitespaces
*/
public void setTrimDirectiveWhitespaces(String value, Node n, ErrorDispatcher err,
boolean pagedir)
throws JasperException {
if ("true".equalsIgnoreCase(value))
trimDirectiveWhitespaces = true;
else if ("false".equalsIgnoreCase(value))
trimDirectiveWhitespaces = false;
else {
if (pagedir)
err.jspError(n, "jsp.error.page.invalid.trimdirectivewhitespaces");
else
err.jspError(n, "jsp.error.tag.invalid.trimdirectivewhitespaces");
}
trimDirectiveWhitespacesValue = value;
}
public void setELIgnored(boolean s) {
isELIgnored = s;
}
public String getIsELIgnored() {
return isELIgnoredValue;
}
public boolean isELIgnored() {
return isELIgnored;
}
public void putNonCustomTagPrefix(String prefix, Mark where) {
nonCustomTagPrefixMap.put(prefix, where);
}
public Mark getNonCustomTagPrefix(String prefix) {
return (Mark) nonCustomTagPrefixMap.get(prefix);
}
public String getDeferredSyntaxAllowedAsLiteral() {
return deferredSyntaxAllowedAsLiteralValue;
}
public boolean isDeferredSyntaxAllowedAsLiteral() {
return deferredSyntaxAllowedAsLiteral;
}
public void setDeferredSyntaxAllowedAsLiteral(boolean isELDeferred) {
this.deferredSyntaxAllowedAsLiteral = isELDeferred;
}
public ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
public String getTrimDirectiveWhitespaces() {
return trimDirectiveWhitespacesValue;
}
public boolean isTrimDirectiveWhitespaces() {
return trimDirectiveWhitespaces;
}
public void setTrimDirectiveWhitespaces(boolean trimDirectiveWhitespaces) {
this.trimDirectiveWhitespaces = trimDirectiveWhitespaces;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,638 @@
/*
* 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.jasper.compiler;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Stack;
import java.util.jar.JarFile;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.xmlparser.XMLEncodingDetector;
import org.xml.sax.Attributes;
/**
* Controller for the parsing of a JSP page.
* <p>
* The same ParserController instance is used for a JSP page and any JSP
* segments included by it (via an include directive), where each segment may
* be provided in standard or XML syntax. This class selects and invokes the
* appropriate parser for the JSP page and its included segments.
*
* @author Pierre Delisle
* @author Jan Luehe
*/
class ParserController implements TagConstants {
private static final String CHARSET = "charset=";
private JspCompilationContext ctxt;
private Compiler compiler;
private ErrorDispatcher err;
/*
* Indicates the syntax (XML or standard) of the file being processed
*/
private boolean isXml;
/*
* A stack to keep track of the 'current base directory'
* for include directives that refer to relative paths.
*/
private Stack baseDirStack = new Stack();
private boolean isEncodingSpecifiedInProlog;
private boolean isBomPresent;
private int skip;
private String sourceEnc;
private boolean isDefaultPageEncoding;
private boolean isTagFile;
private boolean directiveOnly;
/*
* Constructor
*/
public ParserController(JspCompilationContext ctxt, Compiler compiler) {
this.ctxt = ctxt;
this.compiler = compiler;
this.err = compiler.getErrorDispatcher();
}
public JspCompilationContext getJspCompilationContext () {
return ctxt;
}
public Compiler getCompiler () {
return compiler;
}
/**
* Parses a JSP page or tag file. This is invoked by the compiler.
*
* @param inFileName The path to the JSP page or tag file to be parsed.
*/
public Node.Nodes parse(String inFileName)
throws FileNotFoundException, JasperException, IOException {
// If we're parsing a packaged tag file or a resource included by it
// (using an include directive), ctxt.getTagFileJar() returns the
// JAR file from which to read the tag file or included resource,
// respectively.
isTagFile = ctxt.isTagFile();
directiveOnly = false;
return doParse(inFileName, null, ctxt.getTagFileJarUrl());
}
/**
* Parses the directives of a JSP page or tag file. This is invoked by the
* compiler.
*
* @param inFileName The path to the JSP page or tag file to be parsed.
*/
public Node.Nodes parseDirectives(String inFileName)
throws FileNotFoundException, JasperException, IOException {
// If we're parsing a packaged tag file or a resource included by it
// (using an include directive), ctxt.getTagFileJar() returns the
// JAR file from which to read the tag file or included resource,
// respectively.
isTagFile = ctxt.isTagFile();
directiveOnly = true;
return doParse(inFileName, null, ctxt.getTagFileJarUrl());
}
/**
* Processes an include directive with the given path.
*
* @param inFileName The path to the resource to be included.
* @param parent The parent node of the include directive.
* @param jarFile The JAR file from which to read the included resource,
* or null of the included resource is to be read from the filesystem
*/
public Node.Nodes parse(String inFileName, Node parent,
URL jarFileUrl)
throws FileNotFoundException, JasperException, IOException {
// For files that are statically included, isTagfile and directiveOnly
// remain unchanged.
return doParse(inFileName, parent, jarFileUrl);
}
/**
* Extracts tag file directive information from the tag file with the
* given name.
*
* This is invoked by the compiler
*
* @param inFileName The name of the tag file to be parsed.
* @deprecated Use {@link #parseTagFileDirectives(String, URL)}
* See https://issues.apache.org/bugzilla/show_bug.cgi?id=46471
*/
public Node.Nodes parseTagFileDirectives(String inFileName)
throws FileNotFoundException, JasperException, IOException {
return parseTagFileDirectives(
inFileName, ctxt.getTagFileJarUrl(inFileName));
}
/**
* Extracts tag file directive information from the given tag file.
*
* This is invoked by the compiler
*
* @param inFileName The name of the tag file to be parsed.
* @param tagFileJarUrl The location of the tag file.
*/
public Node.Nodes parseTagFileDirectives(String inFileName,
URL tagFileJarUrl)
throws FileNotFoundException, JasperException, IOException {
boolean isTagFileSave = isTagFile;
boolean directiveOnlySave = directiveOnly;
isTagFile = true;
directiveOnly = true;
Node.Nodes page = doParse(inFileName, null, tagFileJarUrl);
directiveOnly = directiveOnlySave;
isTagFile = isTagFileSave;
return page;
}
/**
* Parses the JSP page or tag file with the given path name.
*
* @param inFileName The name of the JSP page or tag file to be parsed.
* @param parent The parent node (non-null when processing an include
* directive)
* @param isTagFile true if file to be parsed is tag file, and false if it
* is a regular JSP page
* @param directivesOnly true if the file to be parsed is a tag file and
* we are only interested in the directives needed for constructing a
* TagFileInfo.
* @param jarFile The JAR file from which to read the JSP page or tag file,
* or null if the JSP page or tag file is to be read from the filesystem
*/
private Node.Nodes doParse(String inFileName,
Node parent,
URL jarFileUrl)
throws FileNotFoundException, JasperException, IOException {
Node.Nodes parsedPage = null;
isEncodingSpecifiedInProlog = false;
isBomPresent = false;
isDefaultPageEncoding = false;
JarFile jarFile = getJarFile(jarFileUrl);
String absFileName = resolveFileName(inFileName);
String jspConfigPageEnc = getJspConfigPageEncoding(absFileName);
// Figure out what type of JSP document and encoding type we are
// dealing with
determineSyntaxAndEncoding(absFileName, jarFile, jspConfigPageEnc);
if (parent != null) {
// Included resource, add to dependent list
if (jarFile == null) {
compiler.getPageInfo().addDependant(absFileName);
} else {
compiler.getPageInfo().addDependant(
jarFileUrl.toExternalForm() + absFileName.substring(1));
}
}
if ((isXml && isEncodingSpecifiedInProlog) || isBomPresent) {
/*
* Make sure the encoding explicitly specified in the XML
* prolog (if any) matches that in the JSP config element
* (if any), treating "UTF-16", "UTF-16BE", and "UTF-16LE" as
* identical.
*/
if (jspConfigPageEnc != null && !jspConfigPageEnc.equals(sourceEnc)
&& (!jspConfigPageEnc.startsWith("UTF-16")
|| !sourceEnc.startsWith("UTF-16"))) {
err.jspError("jsp.error.prolog_config_encoding_mismatch",
sourceEnc, jspConfigPageEnc);
}
}
// Dispatch to the appropriate parser
if (isXml) {
// JSP document (XML syntax)
// InputStream for jspx page is created and properly closed in
// JspDocumentParser.
parsedPage = JspDocumentParser.parse(this, absFileName,
jarFile, parent,
isTagFile, directiveOnly,
sourceEnc,
jspConfigPageEnc,
isEncodingSpecifiedInProlog,
isBomPresent);
} else {
// Standard syntax
InputStreamReader inStreamReader = null;
try {
inStreamReader = JspUtil.getReader(absFileName, sourceEnc,
jarFile, ctxt, err, skip);
JspReader jspReader = new JspReader(ctxt, absFileName,
sourceEnc, inStreamReader,
err);
parsedPage = Parser.parse(this, jspReader, parent, isTagFile,
directiveOnly, jarFileUrl,
sourceEnc, jspConfigPageEnc,
isDefaultPageEncoding, isBomPresent);
} finally {
if (inStreamReader != null) {
try {
inStreamReader.close();
} catch (Exception any) {
}
}
}
}
if (jarFile != null) {
try {
jarFile.close();
} catch (Throwable t) {}
}
baseDirStack.pop();
return parsedPage;
}
/*
* Checks to see if the given URI is matched by a URL pattern specified in
* a jsp-property-group in web.xml, and if so, returns the value of the
* <page-encoding> element.
*
* @param absFileName The URI to match
*
* @return The value of the <page-encoding> attribute of the
* jsp-property-group with matching URL pattern
*/
private String getJspConfigPageEncoding(String absFileName)
throws JasperException {
JspConfig jspConfig = ctxt.getOptions().getJspConfig();
JspConfig.JspProperty jspProperty
= jspConfig.findJspProperty(absFileName);
return jspProperty.getPageEncoding();
}
/**
* Determines the syntax (standard or XML) and page encoding properties
* for the given file, and stores them in the 'isXml' and 'sourceEnc'
* instance variables, respectively.
*/
private void determineSyntaxAndEncoding(String absFileName,
JarFile jarFile,
String jspConfigPageEnc)
throws JasperException, IOException {
isXml = false;
/*
* 'true' if the syntax (XML or standard) of the file is given
* from external information: either via a JSP configuration element,
* the ".jspx" suffix, or the enclosing file (for included resources)
*/
boolean isExternal = false;
/*
* Indicates whether we need to revert from temporary usage of
* "ISO-8859-1" back to "UTF-8"
*/
boolean revert = false;
JspConfig jspConfig = ctxt.getOptions().getJspConfig();
JspConfig.JspProperty jspProperty = jspConfig.findJspProperty(
absFileName);
if (jspProperty.isXml() != null) {
// If <is-xml> is specified in a <jsp-property-group>, it is used.
isXml = JspUtil.booleanValue(jspProperty.isXml());
isExternal = true;
} else if (absFileName.endsWith(".jspx")
|| absFileName.endsWith(".tagx")) {
isXml = true;
isExternal = true;
}
if (isExternal && !isXml) {
// JSP (standard) syntax. Use encoding specified in jsp-config
// if provided.
sourceEnc = jspConfigPageEnc;
if (sourceEnc != null) {
return;
}
// We don't know the encoding, so use BOM to determine it
sourceEnc = "ISO-8859-1";
} else {
// XML syntax or unknown, (auto)detect encoding ...
Object[] ret = XMLEncodingDetector.getEncoding(absFileName,
jarFile, ctxt, err);
sourceEnc = (String) ret[0];
if (((Boolean) ret[1]).booleanValue()) {
isEncodingSpecifiedInProlog = true;
}
if (((Boolean) ret[2]).booleanValue()) {
isBomPresent = true;
}
skip = ((Integer) ret[3]).intValue();
if (!isXml && sourceEnc.equals("UTF-8")) {
/*
* We don't know if we're dealing with XML or standard syntax.
* Therefore, we need to check to see if the page contains
* a <jsp:root> element.
*
* We need to be careful, because the page may be encoded in
* ISO-8859-1 (or something entirely different), and may
* contain byte sequences that will cause a UTF-8 converter to
* throw exceptions.
*
* It is safe to use a source encoding of ISO-8859-1 in this
* case, as there are no invalid byte sequences in ISO-8859-1,
* and the byte/character sequences we're looking for (i.e.,
* <jsp:root>) are identical in either encoding (both UTF-8
* and ISO-8859-1 are extensions of ASCII).
*/
sourceEnc = "ISO-8859-1";
revert = true;
}
}
if (isXml) {
// (This implies 'isExternal' is TRUE.)
// We know we're dealing with a JSP document (via JSP config or
// ".jspx" suffix), so we're done.
return;
}
/*
* At this point, 'isExternal' or 'isXml' is FALSE.
* Search for jsp:root action, in order to determine if we're dealing
* with XML or standard syntax (unless we already know what we're
* dealing with, i.e., when 'isExternal' is TRUE and 'isXml' is FALSE).
* No check for XML prolog, since nothing prevents a page from
* outputting XML and still using JSP syntax (in this case, the
* XML prolog is treated as template text).
*/
JspReader jspReader = null;
try {
jspReader = new JspReader(ctxt, absFileName, sourceEnc, jarFile,
err);
} catch (FileNotFoundException ex) {
throw new JasperException(ex);
}
jspReader.setSingleFile(true);
Mark startMark = jspReader.mark();
if (!isExternal) {
jspReader.reset(startMark);
if (hasJspRoot(jspReader)) {
if (revert) {
sourceEnc = "UTF-8";
}
isXml = true;
return;
} else {
if (revert && isBomPresent) {
sourceEnc = "UTF-8";
}
isXml = false;
}
}
/*
* At this point, we know we're dealing with JSP syntax.
* If an XML prolog is provided, it's treated as template text.
* Determine the page encoding from the page directive, unless it's
* specified via JSP config.
*/
if (!isBomPresent) {
sourceEnc = jspConfigPageEnc;
if (sourceEnc == null) {
sourceEnc = getPageEncodingForJspSyntax(jspReader, startMark);
if (sourceEnc == null) {
// Default to "ISO-8859-1" per JSP spec
sourceEnc = "ISO-8859-1";
isDefaultPageEncoding = true;
}
}
}
}
/*
* Determines page source encoding for page or tag file in JSP syntax,
* by reading (in this order) the value of the 'pageEncoding' page
* directive attribute, or the charset value of the 'contentType' page
* directive attribute.
*
* @return The page encoding, or null if not found
*/
private String getPageEncodingForJspSyntax(JspReader jspReader,
Mark startMark)
throws JasperException {
String encoding = null;
String saveEncoding = null;
jspReader.reset(startMark);
/*
* Determine page encoding from directive of the form <%@ page %>,
* <%@ tag %>, <jsp:directive.page > or <jsp:directive.tag >.
*/
while (true) {
if (jspReader.skipUntil("<") == null) {
break;
}
// If this is a comment, skip until its end
if (jspReader.matches("%--")) {
if (jspReader.skipUntil("--%>") == null) {
// error will be caught in Parser
break;
}
continue;
}
boolean isDirective = jspReader.matches("%@");
if (isDirective) {
jspReader.skipSpaces();
}
else {
isDirective = jspReader.matches("jsp:directive.");
}
if (!isDirective) {
continue;
}
// compare for "tag ", so we don't match "taglib"
if (jspReader.matches("tag ") || jspReader.matches("page")) {
jspReader.skipSpaces();
Attributes attrs = Parser.parseAttributes(this, jspReader);
encoding = getPageEncodingFromDirective(attrs, "pageEncoding");
if (encoding != null) {
break;
}
encoding = getPageEncodingFromDirective(attrs, "contentType");
if (encoding != null) {
saveEncoding = encoding;
}
}
}
if (encoding == null) {
encoding = saveEncoding;
}
return encoding;
}
/*
* Scans the given attributes for the attribute with the given name,
* which is either 'pageEncoding' or 'contentType', and returns the
* specified page encoding.
*
* In the case of 'contentType', the page encoding is taken from the
* content type's 'charset' component.
*
* @param attrs The page directive attributes
* @param attrName The name of the attribute to search for (either
* 'pageEncoding' or 'contentType')
*
* @return The page encoding, or null
*/
private String getPageEncodingFromDirective(Attributes attrs,
String attrName) {
String value = attrs.getValue(attrName);
if (attrName.equals("pageEncoding")) {
return value;
}
// attrName = contentType
String contentType = value;
String encoding = null;
if (contentType != null) {
int loc = contentType.indexOf(CHARSET);
if (loc != -1) {
encoding = contentType.substring(loc + CHARSET.length());
}
}
return encoding;
}
/*
* Resolve the name of the file and update baseDirStack() to keep track of
* the current base directory for each included file.
* The 'root' file is always an 'absolute' path, so no need to put an
* initial value in the baseDirStack.
*/
private String resolveFileName(String inFileName) {
String fileName = inFileName.replace('\\', '/');
boolean isAbsolute = fileName.startsWith("/");
fileName = isAbsolute ? fileName
: (String) baseDirStack.peek() + fileName;
String baseDir =
fileName.substring(0, fileName.lastIndexOf("/") + 1);
baseDirStack.push(baseDir);
return fileName;
}
/*
* Checks to see if the given page contains, as its first element, a <root>
* element whose prefix is bound to the JSP namespace, as in:
*
* <wombat:root xmlns:wombat="http://java.sun.com/JSP/Page" version="1.2">
* ...
* </wombat:root>
*
* @param reader The reader for this page
*
* @return true if this page contains a root element whose prefix is bound
* to the JSP namespace, and false otherwise
*/
private boolean hasJspRoot(JspReader reader) throws JasperException {
// <prefix>:root must be the first element
Mark start = null;
while ((start = reader.skipUntil("<")) != null) {
int c = reader.nextChar();
if (c != '!' && c != '?') break;
}
if (start == null) {
return false;
}
Mark stop = reader.skipUntil(":root");
if (stop == null) {
return false;
}
// call substring to get rid of leading '<'
String prefix = reader.getText(start, stop).substring(1);
start = stop;
stop = reader.skipUntil(">");
if (stop == null) {
return false;
}
// Determine namespace associated with <root> element's prefix
String root = reader.getText(start, stop);
String xmlnsDecl = "xmlns:" + prefix;
int index = root.indexOf(xmlnsDecl);
if (index == -1) {
return false;
}
index += xmlnsDecl.length();
while (index < root.length()
&& Character.isWhitespace(root.charAt(index))) {
index++;
}
if (index < root.length() && root.charAt(index) == '=') {
index++;
while (index < root.length()
&& Character.isWhitespace(root.charAt(index))) {
index++;
}
if (index < root.length() && root.charAt(index++) == '"'
&& root.regionMatches(index, JSP_URI, 0,
JSP_URI.length())) {
return true;
}
}
return false;
}
private JarFile getJarFile(URL jarFileUrl) throws IOException {
JarFile jarFile = null;
if (jarFileUrl != null) {
JarURLConnection conn = (JarURLConnection) jarFileUrl.openConnection();
conn.setUseCaches(false);
conn.connect();
jarFile = conn.getJarFile();
}
return jarFile;
}
}
@@ -0,0 +1,148 @@
/*
* 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.jasper.compiler;
import java.util.*;
import javax.servlet.jsp.tagext.*;
import org.apache.jasper.JasperException;
/**
* Class responsible for determining the scripting variables that every
* custom action needs to declare.
*
* @author Jan Luehe
*/
class ScriptingVariabler {
private static final Integer MAX_SCOPE = new Integer(Integer.MAX_VALUE);
/*
* Assigns an identifier (of type integer) to every custom tag, in order
* to help identify, for every custom tag, the scripting variables that it
* needs to declare.
*/
static class CustomTagCounter extends Node.Visitor {
private int count;
private Node.CustomTag parent;
public void visit(Node.CustomTag n) throws JasperException {
n.setCustomTagParent(parent);
Node.CustomTag tmpParent = parent;
parent = n;
visitBody(n);
parent = tmpParent;
n.setNumCount(new Integer(count++));
}
}
/*
* For every custom tag, determines the scripting variables it needs to
* declare.
*/
static class ScriptingVariableVisitor extends Node.Visitor {
private ErrorDispatcher err;
private Hashtable scriptVars;
public ScriptingVariableVisitor(ErrorDispatcher err) {
this.err = err;
scriptVars = new Hashtable();
}
public void visit(Node.CustomTag n) throws JasperException {
setScriptingVars(n, VariableInfo.AT_BEGIN);
setScriptingVars(n, VariableInfo.NESTED);
visitBody(n);
setScriptingVars(n, VariableInfo.AT_END);
}
private void setScriptingVars(Node.CustomTag n, int scope)
throws JasperException {
TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
VariableInfo[] varInfos = n.getVariableInfos();
if (tagVarInfos.length == 0 && varInfos.length == 0) {
return;
}
Vector vec = new Vector();
Integer ownRange = null;
if (scope == VariableInfo.AT_BEGIN
|| scope == VariableInfo.AT_END) {
Node.CustomTag parent = n.getCustomTagParent();
if (parent == null)
ownRange = MAX_SCOPE;
else
ownRange = parent.getNumCount();
} else {
// NESTED
ownRange = n.getNumCount();
}
if (varInfos.length > 0) {
for (int i=0; i<varInfos.length; i++) {
if (varInfos[i].getScope() != scope
|| !varInfos[i].getDeclare()) {
continue;
}
String varName = varInfos[i].getVarName();
Integer currentRange = (Integer) scriptVars.get(varName);
if (currentRange == null
|| ownRange.compareTo(currentRange) > 0) {
scriptVars.put(varName, ownRange);
vec.add(varInfos[i]);
}
}
} else {
for (int i=0; i<tagVarInfos.length; i++) {
if (tagVarInfos[i].getScope() != scope
|| !tagVarInfos[i].getDeclare()) {
continue;
}
String varName = tagVarInfos[i].getNameGiven();
if (varName == null) {
varName = n.getTagData().getAttributeString(
tagVarInfos[i].getNameFromAttribute());
if (varName == null) {
err.jspError(n, "jsp.error.scripting.variable.missing_name",
tagVarInfos[i].getNameFromAttribute());
}
}
Integer currentRange = (Integer) scriptVars.get(varName);
if (currentRange == null
|| ownRange.compareTo(currentRange) > 0) {
scriptVars.put(varName, ownRange);
vec.add(tagVarInfos[i]);
}
}
}
n.setScriptingVars(vec, scope);
}
}
public static void set(Node.Nodes page, ErrorDispatcher err)
throws JasperException {
page.visit(new CustomTagCounter());
page.visit(new ScriptingVariableVisitor(err));
}
}
@@ -0,0 +1,176 @@
/*
* 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.jasper.compiler;
import java.io.IOException;
import java.io.PrintWriter;
/**
* This is what is used to generate servlets.
*
* @author Anil K. Vijendran
* @author Kin-man Chung
*/
public class ServletWriter {
public static int TAB_WIDTH = 2;
public static String SPACES = " ";
// Current indent level:
private int indent = 0;
private int virtual_indent = 0;
// The sink writer:
PrintWriter writer;
// servlet line numbers start from 1
private int javaLine = 1;
public ServletWriter(PrintWriter writer) {
this.writer = writer;
}
public void close() throws IOException {
writer.close();
}
// -------------------- Access informations --------------------
public int getJavaLine() {
return javaLine;
}
// -------------------- Formatting --------------------
public void pushIndent() {
virtual_indent += TAB_WIDTH;
if (virtual_indent >= 0 && virtual_indent <= SPACES.length())
indent = virtual_indent;
}
public void popIndent() {
virtual_indent -= TAB_WIDTH;
if (virtual_indent >= 0 && virtual_indent <= SPACES.length())
indent = virtual_indent;
}
/**
* Print a standard comment for echo outputed chunk.
* @param start The starting position of the JSP chunk being processed.
* @param stop The ending position of the JSP chunk being processed.
*/
public void printComment(Mark start, Mark stop, char[] chars) {
if (start != null && stop != null) {
println("// from="+start);
println("// to="+stop);
}
if (chars != null)
for(int i = 0; i < chars.length;) {
printin();
print("// ");
while (chars[i] != '\n' && i < chars.length)
writer.print(chars[i++]);
}
}
/**
* Prints the given string followed by '\n'
*/
public void println(String s) {
javaLine++;
writer.println(s);
}
/**
* Prints a '\n'
*/
public void println() {
javaLine++;
writer.println("");
}
/**
* Prints the current indention
*/
public void printin() {
writer.print(SPACES.substring(0, indent));
}
/**
* Prints the current indention, followed by the given string
*/
public void printin(String s) {
writer.print(SPACES.substring(0, indent));
writer.print(s);
}
/**
* Prints the current indention, and then the string, and a '\n'.
*/
public void printil(String s) {
javaLine++;
writer.print(SPACES.substring(0, indent));
writer.println(s);
}
/**
* Prints the given char.
*
* Use println() to print a '\n'.
*/
public void print(char c) {
writer.print(c);
}
/**
* Prints the given int.
*/
public void print(int i) {
writer.print(i);
}
/**
* Prints the given string.
*
* The string must not contain any '\n', otherwise the line count will be
* off.
*/
public void print(String s) {
writer.print(s);
}
/**
* Prints the given string.
*
* If the string spans multiple lines, the line count will be adjusted
* accordingly.
*/
public void printMultiLn(String s) {
int index = 0;
// look for hidden newlines inside strings
while ((index=s.indexOf('\n',index)) > -1 ) {
javaLine++;
index++;
}
writer.print(s);
}
}
@@ -0,0 +1,171 @@
/*
* 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.jasper.compiler;
import java.util.List;
import java.util.ArrayList;
/**
* Represents a source map (SMAP), which serves to associate lines
* of the input JSP file(s) to lines in the generated servlet in the
* final .class file, according to the JSR-045 spec.
*
* @author Shawn Bayern
*/
public class SmapGenerator {
//*********************************************************************
// Overview
/*
* The SMAP syntax is reasonably straightforward. The purpose of this
* class is currently twofold:
* - to provide a simple but low-level Java interface to build
* a logical SMAP
* - to serialize this logical SMAP for eventual inclusion directly
* into a .class file.
*/
//*********************************************************************
// Private state
private String outputFileName;
private String defaultStratum = "Java";
private List strata = new ArrayList();
private List embedded = new ArrayList();
private boolean doEmbedded = true;
//*********************************************************************
// Methods for adding mapping data
/**
* Sets the filename (without path information) for the generated
* source file. E.g., "foo$jsp.java".
*/
public synchronized void setOutputFileName(String x) {
outputFileName = x;
}
/**
* Adds the given SmapStratum object, representing a Stratum with
* logically associated FileSection and LineSection blocks, to
* the current SmapGenerator. If <tt>default</tt> is true, this
* stratum is made the default stratum, overriding any previously
* set default.
*
* @param stratum the SmapStratum object to add
* @param defaultStratum if <tt>true</tt>, this SmapStratum is considered
* to represent the default SMAP stratum unless
* overwritten
*/
public synchronized void addStratum(SmapStratum stratum,
boolean defaultStratum) {
strata.add(stratum);
if (defaultStratum)
this.defaultStratum = stratum.getStratumName();
}
/**
* Adds the given string as an embedded SMAP with the given stratum name.
*
* @param smap the SMAP to embed
* @param stratumName the name of the stratum output by the compilation
* that produced the <tt>smap</tt> to be embedded
*/
public synchronized void addSmap(String smap, String stratumName) {
embedded.add("*O " + stratumName + "\n"
+ smap
+ "*C " + stratumName + "\n");
}
/**
* Instructs the SmapGenerator whether to actually print any embedded
* SMAPs or not. Intended for situations without an SMAP resolver.
*
* @param status If <tt>false</tt>, ignore any embedded SMAPs.
*/
public void setDoEmbedded(boolean status) {
doEmbedded = status;
}
//*********************************************************************
// Methods for serializing the logical SMAP
public synchronized String getString() {
// check state and initialize buffer
if (outputFileName == null)
throw new IllegalStateException();
StringBuffer out = new StringBuffer();
// start the SMAP
out.append("SMAP\n");
out.append(outputFileName + '\n');
out.append(defaultStratum + '\n');
// include embedded SMAPs
if (doEmbedded) {
int nEmbedded = embedded.size();
for (int i = 0; i < nEmbedded; i++) {
out.append(embedded.get(i));
}
}
// print our StratumSections, FileSections, and LineSections
int nStrata = strata.size();
for (int i = 0; i < nStrata; i++) {
SmapStratum s = (SmapStratum) strata.get(i);
out.append(s.getString());
}
// end the SMAP
out.append("*E\n");
return out.toString();
}
public String toString() { return getString(); }
//*********************************************************************
// For testing (and as an example of use)...
public static void main(String args[]) {
SmapGenerator g = new SmapGenerator();
g.setOutputFileName("foo.java");
SmapStratum s = new SmapStratum("JSP");
s.addFile("foo.jsp");
s.addFile("bar.jsp", "/foo/foo/bar.jsp");
s.addLineData(1, "foo.jsp", 1, 1, 1);
s.addLineData(2, "foo.jsp", 1, 6, 1);
s.addLineData(3, "foo.jsp", 2, 10, 5);
s.addLineData(20, "bar.jsp", 1, 30, 1);
g.addStratum(s, true);
System.out.print(g);
System.out.println("---");
SmapGenerator embedded = new SmapGenerator();
embedded.setOutputFileName("blargh.tier2");
s = new SmapStratum("Tier2");
s.addFile("1.tier2");
s.addLineData(1, "1.tier2", 1, 1, 1);
embedded.addStratum(s, true);
g.addSmap(embedded.toString(), "JSP");
System.out.println(g);
}
}
@@ -0,0 +1,336 @@
/*
* 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.jasper.compiler;
import java.util.List;
import java.util.ArrayList;
/**
* Represents the line and file mappings associated with a JSR-045
* "stratum".
*
* @author Jayson Falkner
* @author Shawn Bayern
*/
public class SmapStratum {
//*********************************************************************
// Class for storing LineInfo data
/**
* Represents a single LineSection in an SMAP, associated with
* a particular stratum.
*/
public static class LineInfo {
private int inputStartLine = -1;
private int outputStartLine = -1;
private int lineFileID = 0;
private int inputLineCount = 1;
private int outputLineIncrement = 1;
private boolean lineFileIDSet = false;
/** Sets InputStartLine. */
public void setInputStartLine(int inputStartLine) {
if (inputStartLine < 0)
throw new IllegalArgumentException("" + inputStartLine);
this.inputStartLine = inputStartLine;
}
/** Sets OutputStartLine. */
public void setOutputStartLine(int outputStartLine) {
if (outputStartLine < 0)
throw new IllegalArgumentException("" + outputStartLine);
this.outputStartLine = outputStartLine;
}
/**
* Sets lineFileID. Should be called only when different from
* that of prior LineInfo object (in any given context) or 0
* if the current LineInfo has no (logical) predecessor.
* <tt>LineInfo</tt> will print this file number no matter what.
*/
public void setLineFileID(int lineFileID) {
if (lineFileID < 0)
throw new IllegalArgumentException("" + lineFileID);
this.lineFileID = lineFileID;
this.lineFileIDSet = true;
}
/** Sets InputLineCount. */
public void setInputLineCount(int inputLineCount) {
if (inputLineCount < 0)
throw new IllegalArgumentException("" + inputLineCount);
this.inputLineCount = inputLineCount;
}
/** Sets OutputLineIncrement. */
public void setOutputLineIncrement(int outputLineIncrement) {
if (outputLineIncrement < 0)
throw new IllegalArgumentException("" + outputLineIncrement);
this.outputLineIncrement = outputLineIncrement;
}
/**
* Retrieves the current LineInfo as a String, print all values
* only when appropriate (but LineInfoID if and only if it's been
* specified, as its necessity is sensitive to context).
*/
public String getString() {
if (inputStartLine == -1 || outputStartLine == -1)
throw new IllegalStateException();
StringBuffer out = new StringBuffer();
out.append(inputStartLine);
if (lineFileIDSet)
out.append("#" + lineFileID);
if (inputLineCount != 1)
out.append("," + inputLineCount);
out.append(":" + outputStartLine);
if (outputLineIncrement != 1)
out.append("," + outputLineIncrement);
out.append('\n');
return out.toString();
}
public String toString() {
return getString();
}
}
//*********************************************************************
// Private state
private String stratumName;
private List fileNameList;
private List filePathList;
private List lineData;
private int lastFileID;
//*********************************************************************
// Constructor
/**
* Constructs a new SmapStratum object for the given stratum name
* (e.g., JSP).
*
* @param stratumName the name of the stratum (e.g., JSP)
*/
public SmapStratum(String stratumName) {
this.stratumName = stratumName;
fileNameList = new ArrayList();
filePathList = new ArrayList();
lineData = new ArrayList();
lastFileID = 0;
}
//*********************************************************************
// Methods to add mapping information
/**
* Adds record of a new file, by filename.
*
* @param filename the filename to add, unqualified by path.
*/
public void addFile(String filename) {
addFile(filename, filename);
}
/**
* Adds record of a new file, by filename and path. The path
* may be relative to a source compilation path.
*
* @param filename the filename to add, unqualified by path
* @param filePath the path for the filename, potentially relative
* to a source compilation path
*/
public void addFile(String filename, String filePath) {
int pathIndex = filePathList.indexOf(filePath);
if (pathIndex == -1) {
fileNameList.add(filename);
filePathList.add(filePath);
}
}
/**
* Combines consecutive LineInfos wherever possible
*/
public void optimizeLineSection() {
/* Some debugging code
for (int i = 0; i < lineData.size(); i++) {
LineInfo li = (LineInfo)lineData.get(i);
System.out.print(li.toString());
}
*/
//Incorporate each LineInfo into the previous LineInfo's
//outputLineIncrement, if possible
int i = 0;
while (i < lineData.size() - 1) {
LineInfo li = (LineInfo)lineData.get(i);
LineInfo liNext = (LineInfo)lineData.get(i + 1);
if (!liNext.lineFileIDSet
&& liNext.inputStartLine == li.inputStartLine
&& liNext.inputLineCount == 1
&& li.inputLineCount == 1
&& liNext.outputStartLine
== li.outputStartLine
+ li.inputLineCount * li.outputLineIncrement) {
li.setOutputLineIncrement(
liNext.outputStartLine
- li.outputStartLine
+ liNext.outputLineIncrement);
lineData.remove(i + 1);
} else {
i++;
}
}
//Incorporate each LineInfo into the previous LineInfo's
//inputLineCount, if possible
i = 0;
while (i < lineData.size() - 1) {
LineInfo li = (LineInfo)lineData.get(i);
LineInfo liNext = (LineInfo)lineData.get(i + 1);
if (!liNext.lineFileIDSet
&& liNext.inputStartLine == li.inputStartLine + li.inputLineCount
&& liNext.outputLineIncrement == li.outputLineIncrement
&& liNext.outputStartLine
== li.outputStartLine
+ li.inputLineCount * li.outputLineIncrement) {
li.setInputLineCount(li.inputLineCount + liNext.inputLineCount);
lineData.remove(i + 1);
} else {
i++;
}
}
}
/**
* Adds complete information about a simple line mapping. Specify
* all the fields in this method; the back-end machinery takes care
* of printing only those that are necessary in the final SMAP.
* (My view is that fields are optional primarily for spatial efficiency,
* not for programmer convenience. Could always add utility methods
* later.)
*
* @param inputStartLine starting line in the source file
* (SMAP <tt>InputStartLine</tt>)
* @param inputFileName the filepath (or name) from which the input comes
* (yields SMAP <tt>LineFileID</tt>) Use unqualified names
* carefully, and only when they uniquely identify a file.
* @param inputLineCount the number of lines in the input to map
* (SMAP <tt>LineFileCount</tt>)
* @param outputStartLine starting line in the output file
* (SMAP <tt>OutputStartLine</tt>)
* @param outputLineIncrement number of output lines to map to each
* input line (SMAP <tt>OutputLineIncrement</tt>). <i>Given the
* fact that the name starts with "output", I continuously have
* the subconscious urge to call this field
* <tt>OutputLineExcrement</tt>.</i>
*/
public void addLineData(
int inputStartLine,
String inputFileName,
int inputLineCount,
int outputStartLine,
int outputLineIncrement) {
// check the input - what are you doing here??
int fileIndex = filePathList.indexOf(inputFileName);
if (fileIndex == -1) // still
throw new IllegalArgumentException(
"inputFileName: " + inputFileName);
//Jasper incorrectly SMAPs certain Nodes, giving them an
//outputStartLine of 0. This can cause a fatal error in
//optimizeLineSection, making it impossible for Jasper to
//compile the JSP. Until we can fix the underlying
//SMAPping problem, we simply ignore the flawed SMAP entries.
if (outputStartLine == 0)
return;
// build the LineInfo
LineInfo li = new LineInfo();
li.setInputStartLine(inputStartLine);
li.setInputLineCount(inputLineCount);
li.setOutputStartLine(outputStartLine);
li.setOutputLineIncrement(outputLineIncrement);
if (fileIndex != lastFileID)
li.setLineFileID(fileIndex);
lastFileID = fileIndex;
// save it
lineData.add(li);
}
//*********************************************************************
// Methods to retrieve information
/**
* Returns the name of the stratum.
*/
public String getStratumName() {
return stratumName;
}
/**
* Returns the given stratum as a String: a StratumSection,
* followed by at least one FileSection and at least one LineSection.
*/
public String getString() {
// check state and initialize buffer
if (fileNameList.size() == 0 || lineData.size() == 0)
return null;
StringBuffer out = new StringBuffer();
// print StratumSection
out.append("*S " + stratumName + "\n");
// print FileSection
out.append("*F\n");
int bound = fileNameList.size();
for (int i = 0; i < bound; i++) {
if (filePathList.get(i) != null) {
out.append("+ " + i + " " + fileNameList.get(i) + "\n");
// Source paths must be relative, not absolute, so we
// remove the leading "/", if one exists.
String filePath = (String)filePathList.get(i);
if (filePath.startsWith("/")) {
filePath = filePath.substring(1);
}
out.append(filePath + "\n");
} else {
out.append(i + " " + fileNameList.get(i) + "\n");
}
}
// print LineSection
out.append("*L\n");
bound = lineData.size();
for (int i = 0; i < bound; i++) {
LineInfo li = (LineInfo)lineData.get(i);
out.append(li.getString());
}
return out.toString();
}
public String toString() {
return getString();
}
}
@@ -0,0 +1,729 @@
/*
* 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.jasper.compiler;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
/**
* Contains static utilities for generating SMAP data based on the
* current version of Jasper.
*
* @author Jayson Falkner
* @author Shawn Bayern
* @author Robert Field (inner SDEInstaller class)
* @author Mark Roth
* @author Kin-man Chung
*/
public class SmapUtil {
private org.apache.juli.logging.Log log=
org.apache.juli.logging.LogFactory.getLog( SmapUtil.class );
//*********************************************************************
// Constants
public static final String SMAP_ENCODING = "UTF-8";
//*********************************************************************
// Public entry points
/**
* Generates an appropriate SMAP representing the current compilation
* context. (JSR-045.)
*
* @param ctxt Current compilation context
* @param pageNodes The current JSP page
* @return a SMAP for the page
*/
public static String[] generateSmap(
JspCompilationContext ctxt,
Node.Nodes pageNodes)
throws IOException {
// Scan the nodes for presence of Jasper generated inner classes
PreScanVisitor psVisitor = new PreScanVisitor();
try {
pageNodes.visit(psVisitor);
} catch (JasperException ex) {
}
HashMap map = psVisitor.getMap();
// set up our SMAP generator
SmapGenerator g = new SmapGenerator();
/** Disable reading of input SMAP because:
1. There is a bug here: getRealPath() is null if .jsp is in a jar
Bugzilla 14660.
2. Mappings from other sources into .jsp files are not supported.
TODO: fix 1. if 2. is not true.
// determine if we have an input SMAP
String smapPath = inputSmapPath(ctxt.getRealPath(ctxt.getJspFile()));
File inputSmap = new File(smapPath);
if (inputSmap.exists()) {
byte[] embeddedSmap = null;
byte[] subSmap = SDEInstaller.readWhole(inputSmap);
String subSmapString = new String(subSmap, SMAP_ENCODING);
g.addSmap(subSmapString, "JSP");
}
**/
// now, assemble info about our own stratum (JSP) using JspLineMap
SmapStratum s = new SmapStratum("JSP");
g.setOutputFileName(unqualify(ctxt.getServletJavaFileName()));
// Map out Node.Nodes
evaluateNodes(pageNodes, s, map, ctxt.getOptions().getMappedFile());
s.optimizeLineSection();
g.addStratum(s, true);
if (ctxt.getOptions().isSmapDumped()) {
File outSmap = new File(ctxt.getClassFileName() + ".smap");
PrintWriter so =
new PrintWriter(
new OutputStreamWriter(
new FileOutputStream(outSmap),
SMAP_ENCODING));
so.print(g.getString());
so.close();
}
String classFileName = ctxt.getClassFileName();
int innerClassCount = map.size();
String [] smapInfo = new String[2 + innerClassCount*2];
smapInfo[0] = classFileName;
smapInfo[1] = g.getString();
int count = 2;
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String innerClass = (String) entry.getKey();
s = (SmapStratum) entry.getValue();
s.optimizeLineSection();
g = new SmapGenerator();
g.setOutputFileName(unqualify(ctxt.getServletJavaFileName()));
g.addStratum(s, true);
String innerClassFileName =
classFileName.substring(0, classFileName.indexOf(".class")) +
'$' + innerClass + ".class";
if (ctxt.getOptions().isSmapDumped()) {
File outSmap = new File(innerClassFileName + ".smap");
PrintWriter so =
new PrintWriter(
new OutputStreamWriter(
new FileOutputStream(outSmap),
SMAP_ENCODING));
so.print(g.getString());
so.close();
}
smapInfo[count] = innerClassFileName;
smapInfo[count+1] = g.getString();
count += 2;
}
return smapInfo;
}
public static void installSmap(String[] smap)
throws IOException {
if (smap == null) {
return;
}
for (int i = 0; i < smap.length; i += 2) {
File outServlet = new File(smap[i]);
SDEInstaller.install(outServlet, smap[i+1].getBytes());
}
}
//*********************************************************************
// Private utilities
/**
* Returns an unqualified version of the given file path.
*/
private static String unqualify(String path) {
path = path.replace('\\', '/');
return path.substring(path.lastIndexOf('/') + 1);
}
/**
* Returns a file path corresponding to a potential SMAP input
* for the given compilation input (JSP file).
*/
private static String inputSmapPath(String path) {
return path.substring(0, path.lastIndexOf('.') + 1) + "smap";
}
//*********************************************************************
// Installation logic (from Robert Field, JSR-045 spec lead)
private static class SDEInstaller {
private org.apache.juli.logging.Log log=
org.apache.juli.logging.LogFactory.getLog( SDEInstaller.class );
static final String nameSDE = "SourceDebugExtension";
byte[] orig;
byte[] sdeAttr;
byte[] gen;
int origPos = 0;
int genPos = 0;
int sdeIndex;
public static void main(String[] args) throws IOException {
if (args.length == 2) {
install(new File(args[0]), new File(args[1]));
} else if (args.length == 3) {
install(
new File(args[0]),
new File(args[1]),
new File(args[2]));
} else {
System.err.println(
"Usage: <command> <input class file> "
+ "<attribute file> <output class file name>\n"
+ "<command> <input/output class file> <attribute file>");
}
}
static void install(File inClassFile, File attrFile, File outClassFile)
throws IOException {
new SDEInstaller(inClassFile, attrFile, outClassFile);
}
static void install(File inOutClassFile, File attrFile)
throws IOException {
File tmpFile = new File(inOutClassFile.getPath() + "tmp");
new SDEInstaller(inOutClassFile, attrFile, tmpFile);
if (!inOutClassFile.delete()) {
throw new IOException("inOutClassFile.delete() failed");
}
if (!tmpFile.renameTo(inOutClassFile)) {
throw new IOException("tmpFile.renameTo(inOutClassFile) failed");
}
}
static void install(File classFile, byte[] smap) throws IOException {
File tmpFile = new File(classFile.getPath() + "tmp");
new SDEInstaller(classFile, smap, tmpFile);
if (!classFile.delete()) {
throw new IOException("classFile.delete() failed");
}
if (!tmpFile.renameTo(classFile)) {
throw new IOException("tmpFile.renameTo(classFile) failed");
}
}
SDEInstaller(File inClassFile, byte[] sdeAttr, File outClassFile)
throws IOException {
if (!inClassFile.exists()) {
throw new FileNotFoundException("no such file: " + inClassFile);
}
this.sdeAttr = sdeAttr;
// get the bytes
orig = readWhole(inClassFile);
gen = new byte[orig.length + sdeAttr.length + 100];
// do it
addSDE();
// write result
FileOutputStream outStream = new FileOutputStream(outClassFile);
outStream.write(gen, 0, genPos);
outStream.close();
}
SDEInstaller(File inClassFile, File attrFile, File outClassFile)
throws IOException {
this(inClassFile, readWhole(attrFile), outClassFile);
}
static byte[] readWhole(File input) throws IOException {
FileInputStream inStream = new FileInputStream(input);
int len = (int)input.length();
byte[] bytes = new byte[len];
if (inStream.read(bytes, 0, len) != len) {
throw new IOException("expected size: " + len);
}
inStream.close();
return bytes;
}
void addSDE() throws UnsupportedEncodingException, IOException {
int i;
copy(4 + 2 + 2); // magic min/maj version
int constantPoolCountPos = genPos;
int constantPoolCount = readU2();
if (log.isDebugEnabled())
log.debug("constant pool count: " + constantPoolCount);
writeU2(constantPoolCount);
// copy old constant pool return index of SDE symbol, if found
sdeIndex = copyConstantPool(constantPoolCount);
if (sdeIndex < 0) {
// if "SourceDebugExtension" symbol not there add it
writeUtf8ForSDE();
// increment the countantPoolCount
sdeIndex = constantPoolCount;
++constantPoolCount;
randomAccessWriteU2(constantPoolCountPos, constantPoolCount);
if (log.isDebugEnabled())
log.debug("SourceDebugExtension not found, installed at: " + sdeIndex);
} else {
if (log.isDebugEnabled())
log.debug("SourceDebugExtension found at: " + sdeIndex);
}
copy(2 + 2 + 2); // access, this, super
int interfaceCount = readU2();
writeU2(interfaceCount);
if (log.isDebugEnabled())
log.debug("interfaceCount: " + interfaceCount);
copy(interfaceCount * 2);
copyMembers(); // fields
copyMembers(); // methods
int attrCountPos = genPos;
int attrCount = readU2();
writeU2(attrCount);
if (log.isDebugEnabled())
log.debug("class attrCount: " + attrCount);
// copy the class attributes, return true if SDE attr found (not copied)
if (!copyAttrs(attrCount)) {
// we will be adding SDE and it isn't already counted
++attrCount;
randomAccessWriteU2(attrCountPos, attrCount);
if (log.isDebugEnabled())
log.debug("class attrCount incremented");
}
writeAttrForSDE(sdeIndex);
}
void copyMembers() {
int count = readU2();
writeU2(count);
if (log.isDebugEnabled())
log.debug("members count: " + count);
for (int i = 0; i < count; ++i) {
copy(6); // access, name, descriptor
int attrCount = readU2();
writeU2(attrCount);
if (log.isDebugEnabled())
log.debug("member attr count: " + attrCount);
copyAttrs(attrCount);
}
}
boolean copyAttrs(int attrCount) {
boolean sdeFound = false;
for (int i = 0; i < attrCount; ++i) {
int nameIndex = readU2();
// don't write old SDE
if (nameIndex == sdeIndex) {
sdeFound = true;
if (log.isDebugEnabled())
log.debug("SDE attr found");
} else {
writeU2(nameIndex); // name
int len = readU4();
writeU4(len);
copy(len);
if (log.isDebugEnabled())
log.debug("attr len: " + len);
}
}
return sdeFound;
}
void writeAttrForSDE(int index) {
writeU2(index);
writeU4(sdeAttr.length);
for (int i = 0; i < sdeAttr.length; ++i) {
writeU1(sdeAttr[i]);
}
}
void randomAccessWriteU2(int pos, int val) {
int savePos = genPos;
genPos = pos;
writeU2(val);
genPos = savePos;
}
int readU1() {
return ((int)orig[origPos++]) & 0xFF;
}
int readU2() {
int res = readU1();
return (res << 8) + readU1();
}
int readU4() {
int res = readU2();
return (res << 16) + readU2();
}
void writeU1(int val) {
gen[genPos++] = (byte)val;
}
void writeU2(int val) {
writeU1(val >> 8);
writeU1(val & 0xFF);
}
void writeU4(int val) {
writeU2(val >> 16);
writeU2(val & 0xFFFF);
}
void copy(int count) {
for (int i = 0; i < count; ++i) {
gen[genPos++] = orig[origPos++];
}
}
byte[] readBytes(int count) {
byte[] bytes = new byte[count];
for (int i = 0; i < count; ++i) {
bytes[i] = orig[origPos++];
}
return bytes;
}
void writeBytes(byte[] bytes) {
for (int i = 0; i < bytes.length; ++i) {
gen[genPos++] = bytes[i];
}
}
int copyConstantPool(int constantPoolCount)
throws UnsupportedEncodingException, IOException {
int sdeIndex = -1;
// copy const pool index zero not in class file
for (int i = 1; i < constantPoolCount; ++i) {
int tag = readU1();
writeU1(tag);
switch (tag) {
case 7 : // Class
case 8 : // String
if (log.isDebugEnabled())
log.debug(i + " copying 2 bytes");
copy(2);
break;
case 9 : // Field
case 10 : // Method
case 11 : // InterfaceMethod
case 3 : // Integer
case 4 : // Float
case 12 : // NameAndType
if (log.isDebugEnabled())
log.debug(i + " copying 4 bytes");
copy(4);
break;
case 5 : // Long
case 6 : // Double
if (log.isDebugEnabled())
log.debug(i + " copying 8 bytes");
copy(8);
i++;
break;
case 1 : // Utf8
int len = readU2();
writeU2(len);
byte[] utf8 = readBytes(len);
String str = new String(utf8, "UTF-8");
if (log.isDebugEnabled())
log.debug(i + " read class attr -- '" + str + "'");
if (str.equals(nameSDE)) {
sdeIndex = i;
}
writeBytes(utf8);
break;
default :
throw new IOException("unexpected tag: " + tag);
}
}
return sdeIndex;
}
void writeUtf8ForSDE() {
int len = nameSDE.length();
writeU1(1); // Utf8 tag
writeU2(len);
for (int i = 0; i < len; ++i) {
writeU1(nameSDE.charAt(i));
}
}
}
public static void evaluateNodes(
Node.Nodes nodes,
SmapStratum s,
HashMap innerClassMap,
boolean breakAtLF) {
try {
nodes.visit(new SmapGenVisitor(s, breakAtLF, innerClassMap));
} catch (JasperException ex) {
}
}
static class SmapGenVisitor extends Node.Visitor {
private SmapStratum smap;
private boolean breakAtLF;
private HashMap innerClassMap;
SmapGenVisitor(SmapStratum s, boolean breakAtLF, HashMap map) {
this.smap = s;
this.breakAtLF = breakAtLF;
this.innerClassMap = map;
}
public void visitBody(Node n) throws JasperException {
SmapStratum smapSave = smap;
String innerClass = n.getInnerClassName();
if (innerClass != null) {
this.smap = (SmapStratum) innerClassMap.get(innerClass);
}
super.visitBody(n);
smap = smapSave;
}
public void visit(Node.Declaration n) throws JasperException {
doSmapText(n);
}
public void visit(Node.Expression n) throws JasperException {
doSmapText(n);
}
public void visit(Node.Scriptlet n) throws JasperException {
doSmapText(n);
}
public void visit(Node.IncludeAction n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.ForwardAction n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.GetProperty n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.SetProperty n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.UseBean n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.PlugIn n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.CustomTag n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.UninterpretedTag n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.JspElement n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.JspText n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.NamedAttribute n) throws JasperException {
visitBody(n);
}
public void visit(Node.JspBody n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.InvokeAction n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.DoBodyAction n) throws JasperException {
doSmap(n);
visitBody(n);
}
public void visit(Node.ELExpression n) throws JasperException {
doSmap(n);
}
public void visit(Node.TemplateText n) throws JasperException {
Mark mark = n.getStart();
if (mark == null) {
return;
}
//Add the file information
String fileName = mark.getFile();
smap.addFile(unqualify(fileName), fileName);
//Add a LineInfo that corresponds to the beginning of this node
int iInputStartLine = mark.getLineNumber();
int iOutputStartLine = n.getBeginJavaLine();
int iOutputLineIncrement = breakAtLF? 1: 0;
smap.addLineData(iInputStartLine, fileName, 1, iOutputStartLine,
iOutputLineIncrement);
// Output additional mappings in the text
java.util.ArrayList extraSmap = n.getExtraSmap();
if (extraSmap != null) {
for (int i = 0; i < extraSmap.size(); i++) {
iOutputStartLine += iOutputLineIncrement;
smap.addLineData(
iInputStartLine+((Integer)extraSmap.get(i)).intValue(),
fileName,
1,
iOutputStartLine,
iOutputLineIncrement);
}
}
}
private void doSmap(
Node n,
int inLineCount,
int outIncrement,
int skippedLines) {
Mark mark = n.getStart();
if (mark == null) {
return;
}
String unqualifiedName = unqualify(mark.getFile());
smap.addFile(unqualifiedName, mark.getFile());
smap.addLineData(
mark.getLineNumber() + skippedLines,
mark.getFile(),
inLineCount - skippedLines,
n.getBeginJavaLine() + skippedLines,
outIncrement);
}
private void doSmap(Node n) {
doSmap(n, 1, n.getEndJavaLine() - n.getBeginJavaLine(), 0);
}
private void doSmapText(Node n) {
String text = n.getText();
int index = 0;
int next = 0;
int lineCount = 1;
int skippedLines = 0;
boolean slashStarSeen = false;
boolean beginning = true;
// Count lines inside text, but skipping comment lines at the
// beginning of the text.
while ((next = text.indexOf('\n', index)) > -1) {
if (beginning) {
String line = text.substring(index, next).trim();
if (!slashStarSeen && line.startsWith("/*")) {
slashStarSeen = true;
}
if (slashStarSeen) {
skippedLines++;
int endIndex = line.indexOf("*/");
if (endIndex >= 0) {
// End of /* */ comment
slashStarSeen = false;
if (endIndex < line.length() - 2) {
// Some executable code after comment
skippedLines--;
beginning = false;
}
}
} else if (line.length() == 0 || line.startsWith("//")) {
skippedLines++;
} else {
beginning = false;
}
}
lineCount++;
index = next + 1;
}
doSmap(n, lineCount, 1, skippedLines);
}
}
private static class PreScanVisitor extends Node.Visitor {
HashMap map = new HashMap();
public void doVisit(Node n) {
String inner = n.getInnerClassName();
if (inner != null && !map.containsKey(inner)) {
map.put(inner, new SmapStratum("JSP"));
}
}
HashMap getMap() {
return map;
}
}
}
@@ -0,0 +1,116 @@
/*
* 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.jasper.compiler;
public interface TagConstants {
public static final String JSP_URI = "http://java.sun.com/JSP/Page";
public static final String DIRECTIVE_ACTION = "directive.";
public static final String ROOT_ACTION = "root";
public static final String JSP_ROOT_ACTION = "jsp:root";
public static final String PAGE_DIRECTIVE_ACTION = "directive.page";
public static final String JSP_PAGE_DIRECTIVE_ACTION = "jsp:directive.page";
public static final String INCLUDE_DIRECTIVE_ACTION = "directive.include";
public static final String JSP_INCLUDE_DIRECTIVE_ACTION = "jsp:directive.include";
public static final String DECLARATION_ACTION = "declaration";
public static final String JSP_DECLARATION_ACTION = "jsp:declaration";
public static final String SCRIPTLET_ACTION = "scriptlet";
public static final String JSP_SCRIPTLET_ACTION = "jsp:scriptlet";
public static final String EXPRESSION_ACTION = "expression";
public static final String JSP_EXPRESSION_ACTION = "jsp:expression";
public static final String USE_BEAN_ACTION = "useBean";
public static final String JSP_USE_BEAN_ACTION = "jsp:useBean";
public static final String SET_PROPERTY_ACTION = "setProperty";
public static final String JSP_SET_PROPERTY_ACTION = "jsp:setProperty";
public static final String GET_PROPERTY_ACTION = "getProperty";
public static final String JSP_GET_PROPERTY_ACTION = "jsp:getProperty";
public static final String INCLUDE_ACTION = "include";
public static final String JSP_INCLUDE_ACTION = "jsp:include";
public static final String FORWARD_ACTION = "forward";
public static final String JSP_FORWARD_ACTION = "jsp:forward";
public static final String PARAM_ACTION = "param";
public static final String JSP_PARAM_ACTION = "jsp:param";
public static final String PARAMS_ACTION = "params";
public static final String JSP_PARAMS_ACTION = "jsp:params";
public static final String PLUGIN_ACTION = "plugin";
public static final String JSP_PLUGIN_ACTION = "jsp:plugin";
public static final String FALLBACK_ACTION = "fallback";
public static final String JSP_FALLBACK_ACTION = "jsp:fallback";
public static final String TEXT_ACTION = "text";
public static final String JSP_TEXT_ACTION = "jsp:text";
public static final String JSP_TEXT_ACTION_END = "</jsp:text>";
public static final String ATTRIBUTE_ACTION = "attribute";
public static final String JSP_ATTRIBUTE_ACTION = "jsp:attribute";
public static final String BODY_ACTION = "body";
public static final String JSP_BODY_ACTION = "jsp:body";
public static final String ELEMENT_ACTION = "element";
public static final String JSP_ELEMENT_ACTION = "jsp:element";
public static final String OUTPUT_ACTION = "output";
public static final String JSP_OUTPUT_ACTION = "jsp:output";
public static final String TAGLIB_DIRECTIVE_ACTION = "taglib";
public static final String JSP_TAGLIB_DIRECTIVE_ACTION = "jsp:taglib";
/*
* Tag Files
*/
public static final String INVOKE_ACTION = "invoke";
public static final String JSP_INVOKE_ACTION = "jsp:invoke";
public static final String DOBODY_ACTION = "doBody";
public static final String JSP_DOBODY_ACTION = "jsp:doBody";
/*
* Tag File Directives
*/
public static final String TAG_DIRECTIVE_ACTION = "directive.tag";
public static final String JSP_TAG_DIRECTIVE_ACTION = "jsp:directive.tag";
public static final String ATTRIBUTE_DIRECTIVE_ACTION = "directive.attribute";
public static final String JSP_ATTRIBUTE_DIRECTIVE_ACTION = "jsp:directive.attribute";
public static final String VARIABLE_DIRECTIVE_ACTION = "directive.variable";
public static final String JSP_VARIABLE_DIRECTIVE_ACTION = "jsp:directive.variable";
/*
* Directive attributes
*/
public static final String URN_JSPTAGDIR = "urn:jsptagdir:";
public static final String URN_JSPTLD = "urn:jsptld:";
}
@@ -0,0 +1,726 @@
/*
* 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.jasper.compiler;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.HashMap;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.servlet.jsp.tagext.TagAttributeInfo;
import javax.servlet.jsp.tagext.TagExtraInfo;
import javax.servlet.jsp.tagext.TagFileInfo;
import javax.servlet.jsp.tagext.TagInfo;
import javax.servlet.jsp.tagext.TagLibraryInfo;
import javax.servlet.jsp.tagext.TagVariableInfo;
import javax.servlet.jsp.tagext.VariableInfo;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.servlet.JspServletWrapper;
import org.apache.jasper.runtime.JspSourceDependent;
/**
* 1. Processes and extracts the directive info in a tag file. 2. Compiles and
* loads tag files used in a JSP file.
*
* @author Kin-man Chung
*/
class TagFileProcessor {
private Vector tempVector;
/**
* A visitor the tag file
*/
private static class TagFileDirectiveVisitor extends Node.Visitor {
private static final JspUtil.ValidAttribute[] tagDirectiveAttrs = {
new JspUtil.ValidAttribute("display-name"),
new JspUtil.ValidAttribute("body-content"),
new JspUtil.ValidAttribute("dynamic-attributes"),
new JspUtil.ValidAttribute("small-icon"),
new JspUtil.ValidAttribute("large-icon"),
new JspUtil.ValidAttribute("description"),
new JspUtil.ValidAttribute("example"),
new JspUtil.ValidAttribute("pageEncoding"),
new JspUtil.ValidAttribute("language"),
new JspUtil.ValidAttribute("import"),
new JspUtil.ValidAttribute("deferredSyntaxAllowedAsLiteral"), // JSP 2.1
new JspUtil.ValidAttribute("trimDirectiveWhitespaces"), // JSP 2.1
new JspUtil.ValidAttribute("isELIgnored") };
private static final JspUtil.ValidAttribute[] attributeDirectiveAttrs = {
new JspUtil.ValidAttribute("name", true),
new JspUtil.ValidAttribute("required"),
new JspUtil.ValidAttribute("fragment"),
new JspUtil.ValidAttribute("rtexprvalue"),
new JspUtil.ValidAttribute("type"),
new JspUtil.ValidAttribute("deferredValue"), // JSP 2.1
new JspUtil.ValidAttribute("deferredValueType"), // JSP 2.1
new JspUtil.ValidAttribute("deferredMethod"), // JSP 2
new JspUtil.ValidAttribute("deferredMethodSignature"), // JSP 21
new JspUtil.ValidAttribute("description") };
private static final JspUtil.ValidAttribute[] variableDirectiveAttrs = {
new JspUtil.ValidAttribute("name-given"),
new JspUtil.ValidAttribute("name-from-attribute"),
new JspUtil.ValidAttribute("alias"),
new JspUtil.ValidAttribute("variable-class"),
new JspUtil.ValidAttribute("scope"),
new JspUtil.ValidAttribute("declare"),
new JspUtil.ValidAttribute("description") };
private ErrorDispatcher err;
private TagLibraryInfo tagLibInfo;
private String name = null;
private String path = null;
private TagExtraInfo tei = null;
private String bodycontent = null;
private String description = null;
private String displayName = null;
private String smallIcon = null;
private String largeIcon = null;
private String dynamicAttrsMapName;
private String example = null;
private Vector attributeVector;
private Vector variableVector;
private static final String ATTR_NAME = "the name attribute of the attribute directive";
private static final String VAR_NAME_GIVEN = "the name-given attribute of the variable directive";
private static final String VAR_NAME_FROM = "the name-from-attribute attribute of the variable directive";
private static final String VAR_ALIAS = "the alias attribute of the variable directive";
private static final String TAG_DYNAMIC = "the dynamic-attributes attribute of the tag directive";
private HashMap nameTable = new HashMap();
private HashMap nameFromTable = new HashMap();
public TagFileDirectiveVisitor(Compiler compiler,
TagLibraryInfo tagLibInfo, String name, String path) {
err = compiler.getErrorDispatcher();
this.tagLibInfo = tagLibInfo;
this.name = name;
this.path = path;
attributeVector = new Vector();
variableVector = new Vector();
}
public void visit(Node.TagDirective n) throws JasperException {
JspUtil.checkAttributes("Tag directive", n, tagDirectiveAttrs, err);
bodycontent = checkConflict(n, bodycontent, "body-content");
if (bodycontent != null
&& !bodycontent
.equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY)
&& !bodycontent
.equalsIgnoreCase(TagInfo.BODY_CONTENT_TAG_DEPENDENT)
&& !bodycontent
.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) {
err.jspError(n, "jsp.error.tagdirective.badbodycontent",
bodycontent);
}
dynamicAttrsMapName = checkConflict(n, dynamicAttrsMapName,
"dynamic-attributes");
if (dynamicAttrsMapName != null) {
checkUniqueName(dynamicAttrsMapName, TAG_DYNAMIC, n);
}
smallIcon = checkConflict(n, smallIcon, "small-icon");
largeIcon = checkConflict(n, largeIcon, "large-icon");
description = checkConflict(n, description, "description");
displayName = checkConflict(n, displayName, "display-name");
example = checkConflict(n, example, "example");
}
private String checkConflict(Node n, String oldAttrValue, String attr)
throws JasperException {
String result = oldAttrValue;
String attrValue = n.getAttributeValue(attr);
if (attrValue != null) {
if (oldAttrValue != null && !oldAttrValue.equals(attrValue)) {
err.jspError(n, "jsp.error.tag.conflict.attr", attr,
oldAttrValue, attrValue);
}
result = attrValue;
}
return result;
}
public void visit(Node.AttributeDirective n) throws JasperException {
JspUtil.checkAttributes("Attribute directive", n,
attributeDirectiveAttrs, err);
// JSP 2.1 Table JSP.8-3
// handle deferredValue and deferredValueType
boolean deferredValue = false;
boolean deferredValueSpecified = false;
String deferredValueString = n.getAttributeValue("deferredValue");
if (deferredValueString != null) {
deferredValueSpecified = true;
deferredValue = JspUtil.booleanValue(deferredValueString);
}
String deferredValueType = n.getAttributeValue("deferredValueType");
if (deferredValueType != null) {
if (deferredValueSpecified && !deferredValue) {
err.jspError(n, "jsp.error.deferredvaluetypewithoutdeferredvalue");
} else {
deferredValue = true;
}
} else if (deferredValue) {
deferredValueType = "java.lang.Object";
} else {
deferredValueType = "java.lang.String";
}
// JSP 2.1 Table JSP.8-3
// handle deferredMethod and deferredMethodSignature
boolean deferredMethod = false;
boolean deferredMethodSpecified = false;
String deferredMethodString = n.getAttributeValue("deferredMethod");
if (deferredMethodString != null) {
deferredMethodSpecified = true;
deferredMethod = JspUtil.booleanValue(deferredMethodString);
}
String deferredMethodSignature = n
.getAttributeValue("deferredMethodSignature");
if (deferredMethodSignature != null) {
if (deferredMethodSpecified && !deferredMethod) {
err.jspError(n, "jsp.error.deferredmethodsignaturewithoutdeferredmethod");
} else {
deferredMethod = true;
}
} else if (deferredMethod) {
deferredMethodSignature = "void methodname()";
}
if (deferredMethod && deferredValue) {
err.jspError(n, "jsp.error.deferredmethodandvalue");
}
String attrName = n.getAttributeValue("name");
boolean required = JspUtil.booleanValue(n
.getAttributeValue("required"));
boolean rtexprvalue = true;
String rtexprvalueString = n.getAttributeValue("rtexprvalue");
if (rtexprvalueString != null) {
rtexprvalue = JspUtil.booleanValue(rtexprvalueString);
}
boolean fragment = JspUtil.booleanValue(n
.getAttributeValue("fragment"));
String type = n.getAttributeValue("type");
if (fragment) {
// type is fixed to "JspFragment" and a translation error
// must occur if specified.
if (type != null) {
err.jspError(n, "jsp.error.fragmentwithtype");
}
// rtexprvalue is fixed to "true" and a translation error
// must occur if specified.
rtexprvalue = true;
if (rtexprvalueString != null) {
err.jspError(n, "jsp.error.frgmentwithrtexprvalue");
}
} else {
if (type == null)
type = "java.lang.String";
if (deferredValue) {
type = ValueExpression.class.getName();
} else if (deferredMethod) {
type = MethodExpression.class.getName();
}
}
if (("2.0".equals(tagLibInfo.getRequiredVersion()) || ("1.2".equals(tagLibInfo.getRequiredVersion())))
&& (deferredMethodSpecified || deferredMethod
|| deferredValueSpecified || deferredValue)) {
err.jspError("jsp.error.invalid.version", path);
}
TagAttributeInfo tagAttributeInfo = new TagAttributeInfo(attrName,
required, type, rtexprvalue, fragment, null, deferredValue,
deferredMethod, deferredValueType, deferredMethodSignature);
attributeVector.addElement(tagAttributeInfo);
checkUniqueName(attrName, ATTR_NAME, n, tagAttributeInfo);
}
public void visit(Node.VariableDirective n) throws JasperException {
JspUtil.checkAttributes("Variable directive", n,
variableDirectiveAttrs, err);
String nameGiven = n.getAttributeValue("name-given");
String nameFromAttribute = n
.getAttributeValue("name-from-attribute");
if (nameGiven == null && nameFromAttribute == null) {
err.jspError("jsp.error.variable.either.name");
}
if (nameGiven != null && nameFromAttribute != null) {
err.jspError("jsp.error.variable.both.name");
}
String alias = n.getAttributeValue("alias");
if (nameFromAttribute != null && alias == null
|| nameFromAttribute == null && alias != null) {
err.jspError("jsp.error.variable.alias");
}
String className = n.getAttributeValue("variable-class");
if (className == null)
className = "java.lang.String";
String declareStr = n.getAttributeValue("declare");
boolean declare = true;
if (declareStr != null)
declare = JspUtil.booleanValue(declareStr);
int scope = VariableInfo.NESTED;
String scopeStr = n.getAttributeValue("scope");
if (scopeStr != null) {
if ("NESTED".equals(scopeStr)) {
// Already the default
} else if ("AT_BEGIN".equals(scopeStr)) {
scope = VariableInfo.AT_BEGIN;
} else if ("AT_END".equals(scopeStr)) {
scope = VariableInfo.AT_END;
}
}
if (nameFromAttribute != null) {
/*
* An alias has been specified. We use 'nameGiven' to hold the
* value of the alias, and 'nameFromAttribute' to hold the name
* of the attribute whose value (at invocation-time) denotes the
* name of the variable that is being aliased
*/
nameGiven = alias;
checkUniqueName(nameFromAttribute, VAR_NAME_FROM, n);
checkUniqueName(alias, VAR_ALIAS, n);
} else {
// name-given specified
checkUniqueName(nameGiven, VAR_NAME_GIVEN, n);
}
variableVector.addElement(new TagVariableInfo(nameGiven,
nameFromAttribute, className, declare, scope));
}
/*
* Returns the vector of attributes corresponding to attribute
* directives.
*/
public Vector getAttributesVector() {
return attributeVector;
}
/*
* Returns the vector of variables corresponding to variable directives.
*/
public Vector getVariablesVector() {
return variableVector;
}
/*
* Returns the value of the dynamic-attributes tag directive attribute.
*/
public String getDynamicAttributesMapName() {
return dynamicAttrsMapName;
}
public TagInfo getTagInfo() throws JasperException {
if (name == null) {
// XXX Get it from tag file name
}
if (bodycontent == null) {
bodycontent = TagInfo.BODY_CONTENT_SCRIPTLESS;
}
String tagClassName = JspUtil.getTagHandlerClassName(
path, tagLibInfo.getReliableURN(), err);
TagVariableInfo[] tagVariableInfos = new TagVariableInfo[variableVector
.size()];
variableVector.copyInto(tagVariableInfos);
TagAttributeInfo[] tagAttributeInfo = new TagAttributeInfo[attributeVector
.size()];
attributeVector.copyInto(tagAttributeInfo);
return new JasperTagInfo(name, tagClassName, bodycontent,
description, tagLibInfo, tei, tagAttributeInfo,
displayName, smallIcon, largeIcon, tagVariableInfos,
dynamicAttrsMapName);
}
static class NameEntry {
private String type;
private Node node;
private TagAttributeInfo attr;
NameEntry(String type, Node node, TagAttributeInfo attr) {
this.type = type;
this.node = node;
this.attr = attr;
}
String getType() {
return type;
}
Node getNode() {
return node;
}
TagAttributeInfo getTagAttributeInfo() {
return attr;
}
}
/**
* Reports a translation error if names specified in attributes of
* directives are not unique in this translation unit.
*
* The value of the following attributes must be unique. 1. 'name'
* attribute of an attribute directive 2. 'name-given' attribute of a
* variable directive 3. 'alias' attribute of variable directive 4.
* 'dynamic-attributes' of a tag directive except that
* 'dynamic-attributes' can (and must) have the same value when it
* appears in multiple tag directives.
*
* Also, 'name-from' attribute of a variable directive cannot have the
* same value as that from another variable directive.
*/
private void checkUniqueName(String name, String type, Node n)
throws JasperException {
checkUniqueName(name, type, n, null);
}
private void checkUniqueName(String name, String type, Node n,
TagAttributeInfo attr) throws JasperException {
HashMap table = (type == VAR_NAME_FROM) ? nameFromTable : nameTable;
NameEntry nameEntry = (NameEntry) table.get(name);
if (nameEntry != null) {
if (type != TAG_DYNAMIC || nameEntry.getType() != TAG_DYNAMIC) {
int line = nameEntry.getNode().getStart().getLineNumber();
err.jspError(n, "jsp.error.tagfile.nameNotUnique", type,
nameEntry.getType(), Integer.toString(line));
}
} else {
table.put(name, new NameEntry(type, n, attr));
}
}
/**
* Perform miscellean checks after the nodes are visited.
*/
void postCheck() throws JasperException {
// Check that var.name-from-attributes has valid values.
Iterator iter = nameFromTable.keySet().iterator();
while (iter.hasNext()) {
String nameFrom = (String) iter.next();
NameEntry nameEntry = (NameEntry) nameTable.get(nameFrom);
NameEntry nameFromEntry = (NameEntry) nameFromTable
.get(nameFrom);
Node nameFromNode = nameFromEntry.getNode();
if (nameEntry == null) {
err.jspError(nameFromNode,
"jsp.error.tagfile.nameFrom.noAttribute", nameFrom);
} else {
Node node = nameEntry.getNode();
TagAttributeInfo tagAttr = nameEntry.getTagAttributeInfo();
if (!"java.lang.String".equals(tagAttr.getTypeName())
|| !tagAttr.isRequired()
|| tagAttr.canBeRequestTime()) {
err.jspError(nameFromNode,
"jsp.error.tagfile.nameFrom.badAttribute",
nameFrom, Integer.toString(node.getStart()
.getLineNumber()));
}
}
}
}
}
/**
* Parses the tag file, and collects information on the directives included
* in it. The method is used to obtain the info on the tag file, when the
* handler that it represents is referenced. The tag file is not compiled
* here.
*
* @param pc
* the current ParserController used in this compilation
* @param name
* the tag name as specified in the TLD
* @param tagfile
* the path for the tagfile
* @param tagLibInfo
* the TagLibraryInfo object associated with this TagInfo
* @return a TagInfo object assembled from the directives in the tag file.
* @deprecated Use {@link TagFileProcessor#parseTagFileDirectives(
* ParserController, String, String, URL, TagLibraryInfo)}
* See https://issues.apache.org/bugzilla/show_bug.cgi?id=46471
*/
public static TagInfo parseTagFileDirectives(ParserController pc,
String name, String path, TagLibraryInfo tagLibInfo)
throws JasperException {
return parseTagFileDirectives(pc, name, path,
pc.getJspCompilationContext().getTagFileJarUrl(path),
tagLibInfo);
}
/**
* Parses the tag file, and collects information on the directives included
* in it. The method is used to obtain the info on the tag file, when the
* handler that it represents is referenced. The tag file is not compiled
* here.
*
* @param pc
* the current ParserController used in this compilation
* @param name
* the tag name as specified in the TLD
* @param tagfile
* the path for the tagfile
* @param tagFileJarUrl
* the url for the Jar containign the tag file
* @param tagLibInfo
* the TagLibraryInfo object associated with this TagInfo
* @return a TagInfo object assembled from the directives in the tag file.
*/
public static TagInfo parseTagFileDirectives(ParserController pc,
String name, String path, URL tagFileJarUrl, TagLibraryInfo tagLibInfo)
throws JasperException {
ErrorDispatcher err = pc.getCompiler().getErrorDispatcher();
Node.Nodes page = null;
try {
page = pc.parseTagFileDirectives(path, tagFileJarUrl);
} catch (FileNotFoundException e) {
err.jspError("jsp.error.file.not.found", path);
} catch (IOException e) {
err.jspError("jsp.error.file.not.found", path);
}
TagFileDirectiveVisitor tagFileVisitor = new TagFileDirectiveVisitor(pc
.getCompiler(), tagLibInfo, name, path);
page.visit(tagFileVisitor);
tagFileVisitor.postCheck();
return tagFileVisitor.getTagInfo();
}
/**
* Compiles and loads a tagfile.
*/
private Class loadTagFile(Compiler compiler, String tagFilePath,
TagInfo tagInfo, PageInfo parentPageInfo) throws JasperException {
URL tagFileJarUrl = null;
if (tagFilePath.startsWith("/META-INF/")) {
try {
tagFileJarUrl = new URL("jar:" +
compiler.getCompilationContext().getTldLocation(
tagInfo.getTagLibrary().getURI())[0] + "!/");
} catch (MalformedURLException e) {
// Ignore - tagFileJarUrl will be null
}
}
String tagFileJarPath;
if (tagFileJarUrl == null) {
tagFileJarPath = "";
} else {
tagFileJarPath = tagFileJarUrl.toString();
}
JspCompilationContext ctxt = compiler.getCompilationContext();
JspRuntimeContext rctxt = ctxt.getRuntimeContext();
JspServletWrapper wrapper = rctxt.getWrapper(tagFileJarPath + tagFilePath);
synchronized (rctxt) {
if (wrapper == null) {
wrapper = new JspServletWrapper(ctxt.getServletContext(), ctxt
.getOptions(), tagFilePath, tagInfo, ctxt
.getRuntimeContext(), tagFileJarUrl);
rctxt.addWrapper(tagFileJarPath + tagFilePath, wrapper);
// Use same classloader and classpath for compiling tag files
wrapper.getJspEngineContext().setClassLoader(
(URLClassLoader) ctxt.getClassLoader());
wrapper.getJspEngineContext().setClassPath(ctxt.getClassPath());
} else {
// Make sure that JspCompilationContext gets the latest TagInfo
// for the tag file. TagInfo instance was created the last
// time the tag file was scanned for directives, and the tag
// file may have been modified since then.
wrapper.getJspEngineContext().setTagInfo(tagInfo);
}
Class tagClazz;
int tripCount = wrapper.incTripCount();
try {
if (tripCount > 0) {
// When tripCount is greater than zero, a circular
// dependency exists. The circularily dependant tag
// file is compiled in prototype mode, to avoid infinite
// recursion.
JspServletWrapper tempWrapper = new JspServletWrapper(ctxt
.getServletContext(), ctxt.getOptions(),
tagFilePath, tagInfo, ctxt.getRuntimeContext(),
ctxt.getTagFileJarUrl(tagFilePath));
tagClazz = tempWrapper.loadTagFilePrototype();
tempVector.add(tempWrapper.getJspEngineContext()
.getCompiler());
} else {
tagClazz = wrapper.loadTagFile();
}
} finally {
wrapper.decTripCount();
}
// Add the dependants for this tag file to its parent's
// dependant list. The only reliable dependency information
// can only be obtained from the tag instance.
try {
Object tagIns = tagClazz.newInstance();
if (tagIns instanceof JspSourceDependent) {
Iterator iter = ((List) ((JspSourceDependent) tagIns)
.getDependants()).iterator();
while (iter.hasNext()) {
parentPageInfo.addDependant((String) iter.next());
}
}
} catch (Exception e) {
// ignore errors
}
return tagClazz;
}
}
/*
* Visitor which scans the page and looks for tag handlers that are tag
* files, compiling (if necessary) and loading them.
*/
private class TagFileLoaderVisitor extends Node.Visitor {
private Compiler compiler;
private PageInfo pageInfo;
TagFileLoaderVisitor(Compiler compiler) {
this.compiler = compiler;
this.pageInfo = compiler.getPageInfo();
}
public void visit(Node.CustomTag n) throws JasperException {
TagFileInfo tagFileInfo = n.getTagFileInfo();
if (tagFileInfo != null) {
String tagFilePath = tagFileInfo.getPath();
if (tagFilePath.startsWith("/META-INF/")) {
// For tags in JARs, add the TLD and the tag as a dependency
String[] location =
compiler.getCompilationContext().getTldLocation(
tagFileInfo.getTagInfo().getTagLibrary().getURI());
// Add TLD
pageInfo.addDependant("jar:" + location[0] + "!/" +
location[1]);
// Add Tag
pageInfo.addDependant("jar:" + location[0] + "!" +
tagFilePath);
} else {
pageInfo.addDependant(tagFilePath);
}
Class c = loadTagFile(compiler, tagFilePath, n.getTagInfo(),
pageInfo);
n.setTagHandlerClass(c);
}
visitBody(n);
}
}
/**
* Implements a phase of the translation that compiles (if necessary) the
* tag files used in a JSP files. The directives in the tag files are
* assumed to have been proccessed and encapsulated as TagFileInfo in the
* CustomTag nodes.
*/
public void loadTagFiles(Compiler compiler, Node.Nodes page)
throws JasperException {
tempVector = new Vector();
page.visit(new TagFileLoaderVisitor(compiler));
}
/**
* Removed the java and class files for the tag prototype generated from the
* current compilation.
*
* @param classFileName
* If non-null, remove only the class file with with this name.
*/
public void removeProtoTypeFiles(String classFileName) {
Iterator iter = tempVector.iterator();
while (iter.hasNext()) {
Compiler c = (Compiler) iter.next();
if (classFileName == null) {
c.removeGeneratedClassFiles();
} else if (classFileName.equals(c.getCompilationContext()
.getClassFileName())) {
c.removeGeneratedClassFiles();
tempVector.remove(c);
return;
}
}
}
}
@@ -0,0 +1,768 @@
/*
* 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.jasper.compiler;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import javax.servlet.jsp.tagext.FunctionInfo;
import javax.servlet.jsp.tagext.PageData;
import javax.servlet.jsp.tagext.TagAttributeInfo;
import javax.servlet.jsp.tagext.TagExtraInfo;
import javax.servlet.jsp.tagext.TagFileInfo;
import javax.servlet.jsp.tagext.TagInfo;
import javax.servlet.jsp.tagext.TagLibraryInfo;
import javax.servlet.jsp.tagext.TagLibraryValidator;
import javax.servlet.jsp.tagext.TagVariableInfo;
import javax.servlet.jsp.tagext.ValidationMessage;
import javax.servlet.jsp.tagext.VariableInfo;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.xmlparser.ParserUtils;
import org.apache.jasper.xmlparser.TreeNode;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* Implementation of the TagLibraryInfo class from the JSP spec.
*
* @author Anil K. Vijendran
* @author Mandar Raje
* @author Pierre Delisle
* @author Kin-man Chung
* @author Jan Luehe
*/
class TagLibraryInfoImpl extends TagLibraryInfo implements TagConstants {
// Logger
private Log log = LogFactory.getLog(TagLibraryInfoImpl.class);
private JspCompilationContext ctxt;
private PageInfo pi;
private ErrorDispatcher err;
private ParserController parserController;
private final void print(String name, String value, PrintWriter w) {
if (value != null) {
w.print(name + " = {\n\t");
w.print(value);
w.print("\n}\n");
}
}
public String toString() {
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
print("tlibversion", tlibversion, out);
print("jspversion", jspversion, out);
print("shortname", shortname, out);
print("urn", urn, out);
print("info", info, out);
print("uri", uri, out);
print("tagLibraryValidator", "" + tagLibraryValidator, out);
for (int i = 0; i < tags.length; i++)
out.println(tags[i].toString());
for (int i = 0; i < tagFiles.length; i++)
out.println(tagFiles[i].toString());
for (int i = 0; i < functions.length; i++)
out.println(functions[i].toString());
return sw.toString();
}
// XXX FIXME
// resolveRelativeUri and/or getResourceAsStream don't seem to properly
// handle relative paths when dealing when home and getDocBase are set
// the following is a workaround until these problems are resolved.
private InputStream getResourceAsStream(String uri)
throws FileNotFoundException {
try {
// see if file exists on the filesystem first
String real = ctxt.getRealPath(uri);
if (real == null) {
return ctxt.getResourceAsStream(uri);
} else {
return new FileInputStream(real);
}
} catch (FileNotFoundException ex) {
// if file not found on filesystem, get the resource through
// the context
return ctxt.getResourceAsStream(uri);
}
}
/**
* Constructor.
*/
public TagLibraryInfoImpl(JspCompilationContext ctxt, ParserController pc, PageInfo pi,
String prefix, String uriIn, String[] location, ErrorDispatcher err)
throws JasperException {
super(prefix, uriIn);
this.ctxt = ctxt;
this.parserController = pc;
this.pi = pi;
this.err = err;
InputStream in = null;
JarFile jarFile = null;
if (location == null) {
// The URI points to the TLD itself or to a JAR file in which the
// TLD is stored
location = generateTLDLocation(uri, ctxt);
}
try {
if (!location[0].endsWith("jar")) {
// Location points to TLD file
try {
in = getResourceAsStream(location[0]);
if (in == null) {
throw new FileNotFoundException(location[0]);
}
} catch (FileNotFoundException ex) {
err.jspError("jsp.error.file.not.found", location[0]);
}
parseTLD(ctxt, location[0], in, null);
// Add TLD to dependency list
PageInfo pageInfo = ctxt.createCompiler().getPageInfo();
if (pageInfo != null) {
pageInfo.addDependant(location[0]);
}
} else {
// Tag library is packaged in JAR file
try {
URL jarFileUrl = new URL("jar:" + location[0] + "!/");
JarURLConnection conn = (JarURLConnection) jarFileUrl
.openConnection();
conn.setUseCaches(false);
conn.connect();
jarFile = conn.getJarFile();
ZipEntry jarEntry = jarFile.getEntry(location[1]);
in = jarFile.getInputStream(jarEntry);
parseTLD(ctxt, location[0], in, jarFileUrl);
} catch (Exception ex) {
err.jspError("jsp.error.tld.unable_to_read", location[0],
location[1], ex.toString());
}
}
} finally {
if (in != null) {
try {
in.close();
} catch (Throwable t) {
}
}
if (jarFile != null) {
try {
jarFile.close();
} catch (Throwable t) {
}
}
}
}
public TagLibraryInfo[] getTagLibraryInfos() {
Collection coll = pi.getTaglibs();
return (TagLibraryInfo[]) coll.toArray(new TagLibraryInfo[0]);
}
/*
* @param ctxt The JSP compilation context @param uri The TLD's uri @param
* in The TLD's input stream @param jarFileUrl The JAR file containing the
* TLD, or null if the tag library is not packaged in a JAR
*/
private void parseTLD(JspCompilationContext ctxt, String uri,
InputStream in, URL jarFileUrl) throws JasperException {
Vector tagVector = new Vector();
Vector tagFileVector = new Vector();
Hashtable functionTable = new Hashtable();
// Create an iterator over the child elements of our <taglib> element
ParserUtils pu = new ParserUtils();
TreeNode tld = pu.parseXMLDocument(uri, in);
// Check to see if the <taglib> root element contains a 'version'
// attribute, which was added in JSP 2.0 to replace the <jsp-version>
// subelement
this.jspversion = tld.findAttribute("version");
// Process each child element of our <taglib> element
Iterator list = tld.findChildren();
while (list.hasNext()) {
TreeNode element = (TreeNode) list.next();
String tname = element.getName();
if ("tlibversion".equals(tname) // JSP 1.1
|| "tlib-version".equals(tname)) { // JSP 1.2
this.tlibversion = element.getBody();
} else if ("jspversion".equals(tname)
|| "jsp-version".equals(tname)) {
this.jspversion = element.getBody();
} else if ("shortname".equals(tname) || "short-name".equals(tname))
this.shortname = element.getBody();
else if ("uri".equals(tname))
this.urn = element.getBody();
else if ("info".equals(tname) || "description".equals(tname))
this.info = element.getBody();
else if ("validator".equals(tname))
this.tagLibraryValidator = createValidator(element);
else if ("tag".equals(tname))
tagVector.addElement(createTagInfo(element, jspversion));
else if ("tag-file".equals(tname)) {
TagFileInfo tagFileInfo = createTagFileInfo(element, uri,
jarFileUrl);
tagFileVector.addElement(tagFileInfo);
} else if ("function".equals(tname)) { // JSP2.0
FunctionInfo funcInfo = createFunctionInfo(element);
String funcName = funcInfo.getName();
if (functionTable.containsKey(funcName)) {
err.jspError("jsp.error.tld.fn.duplicate.name", funcName,
uri);
}
functionTable.put(funcName, funcInfo);
} else if ("display-name".equals(tname) || // Ignored elements
"small-icon".equals(tname) || "large-icon".equals(tname)
|| "listener".equals(tname)) {
;
} else if ("taglib-extension".equals(tname)) {
// Recognized but ignored
} else {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.warning.unknown.element.in.taglib", tname));
}
}
}
if (tlibversion == null) {
err.jspError("jsp.error.tld.mandatory.element.missing",
"tlib-version");
}
if (jspversion == null) {
err.jspError("jsp.error.tld.mandatory.element.missing",
"jsp-version");
}
this.tags = new TagInfo[tagVector.size()];
tagVector.copyInto(this.tags);
this.tagFiles = new TagFileInfo[tagFileVector.size()];
tagFileVector.copyInto(this.tagFiles);
this.functions = new FunctionInfo[functionTable.size()];
int i = 0;
Enumeration enumeration = functionTable.elements();
while (enumeration.hasMoreElements()) {
this.functions[i++] = (FunctionInfo) enumeration.nextElement();
}
}
/*
* @param uri The uri of the TLD @param ctxt The compilation context
*
* @return String array whose first element denotes the path to the TLD. If
* the path to the TLD points to a jar file, then the second element denotes
* the name of the TLD entry in the jar file, which is hardcoded to
* META-INF/taglib.tld.
*/
private String[] generateTLDLocation(String uri, JspCompilationContext ctxt)
throws JasperException {
int uriType = TldLocationsCache.uriType(uri);
if (uriType == TldLocationsCache.ABS_URI) {
err.jspError("jsp.error.taglibDirective.absUriCannotBeResolved",
uri);
} else if (uriType == TldLocationsCache.NOROOT_REL_URI) {
uri = ctxt.resolveRelativeUri(uri);
}
String[] location = new String[2];
location[0] = uri;
if (location[0].endsWith("jar")) {
URL url = null;
try {
url = ctxt.getResource(location[0]);
} catch (Exception ex) {
err.jspError("jsp.error.tld.unable_to_get_jar", location[0], ex
.toString());
}
if (url == null) {
err.jspError("jsp.error.tld.missing_jar", location[0]);
}
location[0] = url.toString();
location[1] = "META-INF/taglib.tld";
}
return location;
}
private TagInfo createTagInfo(TreeNode elem, String jspVersion)
throws JasperException {
String tagName = null;
String tagClassName = null;
String teiClassName = null;
/*
* Default body content for JSP 1.2 tag handlers (<body-content> has
* become mandatory in JSP 2.0, because the default would be invalid for
* simple tag handlers)
*/
String bodycontent = "JSP";
String info = null;
String displayName = null;
String smallIcon = null;
String largeIcon = null;
boolean dynamicAttributes = false;
Vector attributeVector = new Vector();
Vector variableVector = new Vector();
Iterator list = elem.findChildren();
while (list.hasNext()) {
TreeNode element = (TreeNode) list.next();
String tname = element.getName();
if ("name".equals(tname)) {
tagName = element.getBody();
} else if ("tagclass".equals(tname) || "tag-class".equals(tname)) {
tagClassName = element.getBody();
} else if ("teiclass".equals(tname) || "tei-class".equals(tname)) {
teiClassName = element.getBody();
} else if ("bodycontent".equals(tname)
|| "body-content".equals(tname)) {
bodycontent = element.getBody();
} else if ("display-name".equals(tname)) {
displayName = element.getBody();
} else if ("small-icon".equals(tname)) {
smallIcon = element.getBody();
} else if ("large-icon".equals(tname)) {
largeIcon = element.getBody();
} else if ("icon".equals(tname)) {
TreeNode icon = element.findChild("small-icon");
if (icon != null) {
smallIcon = icon.getBody();
}
icon = element.findChild("large-icon");
if (icon != null) {
largeIcon = icon.getBody();
}
} else if ("info".equals(tname) || "description".equals(tname)) {
info = element.getBody();
} else if ("variable".equals(tname)) {
variableVector.addElement(createVariable(element));
} else if ("attribute".equals(tname)) {
attributeVector
.addElement(createAttribute(element, jspVersion));
} else if ("dynamic-attributes".equals(tname)) {
dynamicAttributes = JspUtil.booleanValue(element.getBody());
} else if ("example".equals(tname)) {
// Ignored elements
} else if ("tag-extension".equals(tname)) {
// Ignored
} else {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.warning.unknown.element.in.tag", tname));
}
}
}
TagExtraInfo tei = null;
if (teiClassName != null && !teiClassName.equals("")) {
try {
Class teiClass = ctxt.getClassLoader().loadClass(teiClassName);
tei = (TagExtraInfo) teiClass.newInstance();
} catch (Exception e) {
err.jspError("jsp.error.teiclass.instantiation", teiClassName,
e);
}
}
TagAttributeInfo[] tagAttributeInfo = new TagAttributeInfo[attributeVector
.size()];
attributeVector.copyInto(tagAttributeInfo);
TagVariableInfo[] tagVariableInfos = new TagVariableInfo[variableVector
.size()];
variableVector.copyInto(tagVariableInfos);
TagInfo taginfo = new TagInfo(tagName, tagClassName, bodycontent, info,
this, tei, tagAttributeInfo, displayName, smallIcon, largeIcon,
tagVariableInfos, dynamicAttributes);
return taginfo;
}
/*
* Parses the tag file directives of the given TagFile and turns them into a
* TagInfo.
*
* @param elem The <tag-file> element in the TLD @param uri The location of
* the TLD, in case the tag file is specified relative to it @param jarFile
* The JAR file, in case the tag file is packaged in a JAR
*
* @return TagInfo correspoding to tag file directives
*/
private TagFileInfo createTagFileInfo(TreeNode elem, String uri,
URL jarFileUrl) throws JasperException {
String name = null;
String path = null;
Iterator list = elem.findChildren();
while (list.hasNext()) {
TreeNode child = (TreeNode) list.next();
String tname = child.getName();
if ("name".equals(tname)) {
name = child.getBody();
} else if ("path".equals(tname)) {
path = child.getBody();
} else if ("example".equals(tname)) {
// Ignore <example> element: Bugzilla 33538
} else if ("tag-extension".equals(tname)) {
// Ignore <tag-extension> element: Bugzilla 33538
} else if ("icon".equals(tname)
|| "display-name".equals(tname)
|| "description".equals(tname)) {
// Ignore these elements: Bugzilla 38015
} else {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.warning.unknown.element.in.tagfile", tname));
}
}
}
if (path.startsWith("/META-INF/tags")) {
// Tag file packaged in JAR
// See https://issues.apache.org/bugzilla/show_bug.cgi?id=46471
// This needs to be removed once all the broken code that depends on
// it has been removed
ctxt.setTagFileJarUrl(path, jarFileUrl);
} else if (!path.startsWith("/WEB-INF/tags")) {
err.jspError("jsp.error.tagfile.illegalPath", path);
}
TagInfo tagInfo = TagFileProcessor.parseTagFileDirectives(
parserController, name, path, jarFileUrl, this);
return new TagFileInfo(name, path, tagInfo);
}
TagAttributeInfo createAttribute(TreeNode elem, String jspVersion) {
String name = null;
String type = null;
String expectedType = null;
String methodSignature = null;
boolean required = false, rtexprvalue = false, reqTime = false, isFragment = false, deferredValue = false, deferredMethod = false;
Iterator list = elem.findChildren();
while (list.hasNext()) {
TreeNode element = (TreeNode) list.next();
String tname = element.getName();
if ("name".equals(tname)) {
name = element.getBody();
} else if ("required".equals(tname)) {
String s = element.getBody();
if (s != null)
required = JspUtil.booleanValue(s);
} else if ("rtexprvalue".equals(tname)) {
String s = element.getBody();
if (s != null)
rtexprvalue = JspUtil.booleanValue(s);
} else if ("type".equals(tname)) {
type = element.getBody();
if ("1.2".equals(jspVersion)
&& (type.equals("Boolean") || type.equals("Byte")
|| type.equals("Character")
|| type.equals("Double")
|| type.equals("Float")
|| type.equals("Integer")
|| type.equals("Long") || type.equals("Object")
|| type.equals("Short") || type
.equals("String"))) {
type = "java.lang." + type;
}
} else if ("fragment".equals(tname)) {
String s = element.getBody();
if (s != null) {
isFragment = JspUtil.booleanValue(s);
}
} else if ("deferred-value".equals(tname)) {
deferredValue = true;
type = "javax.el.ValueExpression";
TreeNode child = element.findChild("type");
if (child != null) {
expectedType = child.getBody();
if (expectedType != null) {
expectedType = expectedType.trim();
}
} else {
expectedType = "java.lang.Object";
}
} else if ("deferred-method".equals(tname)) {
deferredMethod = true;
type = "javax.el.MethodExpression";
TreeNode child = element.findChild("method-signature");
if (child != null) {
methodSignature = child.getBody();
if (methodSignature != null) {
methodSignature = methodSignature.trim();
}
} else {
methodSignature = "java.lang.Object method()";
}
} else if ("description".equals(tname) || // Ignored elements
false) {
;
} else {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.warning.unknown.element.in.attribute", tname));
}
}
}
if (isFragment) {
/*
* According to JSP.C-3 ("TLD Schema Element Structure - tag"),
* 'type' and 'rtexprvalue' must not be specified if 'fragment' has
* been specified (this will be enforced by validating parser).
* Also, if 'fragment' is TRUE, 'type' is fixed at
* javax.servlet.jsp.tagext.JspFragment, and 'rtexprvalue' is fixed
* at true. See also JSP.8.5.2.
*/
type = "javax.servlet.jsp.tagext.JspFragment";
rtexprvalue = true;
}
if (!rtexprvalue && type == null) {
// According to JSP spec, for static values (those determined at
// translation time) the type is fixed at java.lang.String.
type = "java.lang.String";
}
return new TagAttributeInfo(name, required, type, rtexprvalue,
isFragment, null, deferredValue, deferredMethod, expectedType,
methodSignature);
}
TagVariableInfo createVariable(TreeNode elem) {
String nameGiven = null;
String nameFromAttribute = null;
String className = "java.lang.String";
boolean declare = true;
int scope = VariableInfo.NESTED;
Iterator list = elem.findChildren();
while (list.hasNext()) {
TreeNode element = (TreeNode) list.next();
String tname = element.getName();
if ("name-given".equals(tname))
nameGiven = element.getBody();
else if ("name-from-attribute".equals(tname))
nameFromAttribute = element.getBody();
else if ("variable-class".equals(tname))
className = element.getBody();
else if ("declare".equals(tname)) {
String s = element.getBody();
if (s != null)
declare = JspUtil.booleanValue(s);
} else if ("scope".equals(tname)) {
String s = element.getBody();
if (s != null) {
if ("NESTED".equals(s)) {
scope = VariableInfo.NESTED;
} else if ("AT_BEGIN".equals(s)) {
scope = VariableInfo.AT_BEGIN;
} else if ("AT_END".equals(s)) {
scope = VariableInfo.AT_END;
}
}
} else if ("description".equals(tname) || // Ignored elements
false) {
} else {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.warning.unknown.element.in.variable", tname));
}
}
}
return new TagVariableInfo(nameGiven, nameFromAttribute, className,
declare, scope);
}
private TagLibraryValidator createValidator(TreeNode elem)
throws JasperException {
String validatorClass = null;
Map initParams = new Hashtable();
Iterator list = elem.findChildren();
while (list.hasNext()) {
TreeNode element = (TreeNode) list.next();
String tname = element.getName();
if ("validator-class".equals(tname))
validatorClass = element.getBody();
else if ("init-param".equals(tname)) {
String[] initParam = createInitParam(element);
initParams.put(initParam[0], initParam[1]);
} else if ("description".equals(tname) || // Ignored elements
false) {
} else {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.warning.unknown.element.in.validator", tname));
}
}
}
TagLibraryValidator tlv = null;
if (validatorClass != null && !validatorClass.equals("")) {
try {
Class tlvClass = ctxt.getClassLoader()
.loadClass(validatorClass);
tlv = (TagLibraryValidator) tlvClass.newInstance();
} catch (Exception e) {
err.jspError("jsp.error.tlvclass.instantiation",
validatorClass, e);
}
}
if (tlv != null) {
tlv.setInitParameters(initParams);
}
return tlv;
}
String[] createInitParam(TreeNode elem) {
String[] initParam = new String[2];
Iterator list = elem.findChildren();
while (list.hasNext()) {
TreeNode element = (TreeNode) list.next();
String tname = element.getName();
if ("param-name".equals(tname)) {
initParam[0] = element.getBody();
} else if ("param-value".equals(tname)) {
initParam[1] = element.getBody();
} else if ("description".equals(tname)) {
// Do nothing
} else {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.warning.unknown.element.in.initParam", tname));
}
}
}
return initParam;
}
FunctionInfo createFunctionInfo(TreeNode elem) {
String name = null;
String klass = null;
String signature = null;
Iterator list = elem.findChildren();
while (list.hasNext()) {
TreeNode element = (TreeNode) list.next();
String tname = element.getName();
if ("name".equals(tname)) {
name = element.getBody();
} else if ("function-class".equals(tname)) {
klass = element.getBody();
} else if ("function-signature".equals(tname)) {
signature = element.getBody();
} else if ("display-name".equals(tname) || // Ignored elements
"small-icon".equals(tname) || "large-icon".equals(tname)
|| "description".equals(tname) || "example".equals(tname)) {
} else {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.warning.unknown.element.in.function", tname));
}
}
}
return new FunctionInfo(name, klass, signature);
}
// *********************************************************************
// Until javax.servlet.jsp.tagext.TagLibraryInfo is fixed
/**
* The instance (if any) for the TagLibraryValidator class.
*
* @return The TagLibraryValidator instance, if any.
*/
public TagLibraryValidator getTagLibraryValidator() {
return tagLibraryValidator;
}
/**
* Translation-time validation of the XML document associated with the JSP
* page. This is a convenience method on the associated TagLibraryValidator
* class.
*
* @param thePage
* The JSP page object
* @return A string indicating whether the page is valid or not.
*/
public ValidationMessage[] validate(PageData thePage) {
TagLibraryValidator tlv = getTagLibraryValidator();
if (tlv == null)
return null;
String uri = getURI();
if (uri.startsWith("/")) {
uri = URN_JSPTLD + uri;
}
return tlv.validate(getPrefixString(), uri, thePage);
}
protected TagLibraryValidator tagLibraryValidator;
}
@@ -0,0 +1,240 @@
/*
* 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.jasper.compiler;
import java.util.*;
import java.io.*;
import javax.servlet.ServletContext;
import org.apache.jasper.JasperException;
import org.apache.jasper.xmlparser.ParserUtils;
import org.apache.jasper.xmlparser.TreeNode;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
/**
* Manages tag plugin optimizations.
* @author Kin-man Chung
*/
public class TagPluginManager {
private static final String TAG_PLUGINS_XML = "/WEB-INF/tagPlugins.xml";
private static final String TAG_PLUGINS_ROOT_ELEM = "tag-plugins";
private boolean initialized = false;
private HashMap tagPlugins = null;
private ServletContext ctxt;
private PageInfo pageInfo;
public TagPluginManager(ServletContext ctxt) {
this.ctxt = ctxt;
}
public void apply(Node.Nodes page, ErrorDispatcher err, PageInfo pageInfo)
throws JasperException {
init(err);
if (tagPlugins == null || tagPlugins.size() == 0) {
return;
}
this.pageInfo = pageInfo;
page.visit(new Node.Visitor() {
public void visit(Node.CustomTag n)
throws JasperException {
invokePlugin(n);
visitBody(n);
}
});
}
private void init(ErrorDispatcher err) throws JasperException {
if (initialized)
return;
InputStream is = ctxt.getResourceAsStream(TAG_PLUGINS_XML);
if (is == null)
return;
TreeNode root = (new ParserUtils()).parseXMLDocument(TAG_PLUGINS_XML,
is);
if (root == null) {
return;
}
if (!TAG_PLUGINS_ROOT_ELEM.equals(root.getName())) {
err.jspError("jsp.error.plugin.wrongRootElement", TAG_PLUGINS_XML,
TAG_PLUGINS_ROOT_ELEM);
}
tagPlugins = new HashMap();
Iterator pluginList = root.findChildren("tag-plugin");
while (pluginList.hasNext()) {
TreeNode pluginNode = (TreeNode) pluginList.next();
TreeNode tagClassNode = pluginNode.findChild("tag-class");
if (tagClassNode == null) {
// Error
return;
}
String tagClass = tagClassNode.getBody().trim();
TreeNode pluginClassNode = pluginNode.findChild("plugin-class");
if (pluginClassNode == null) {
// Error
return;
}
String pluginClassStr = pluginClassNode.getBody();
TagPlugin tagPlugin = null;
try {
Class pluginClass = Class.forName(pluginClassStr);
tagPlugin = (TagPlugin) pluginClass.newInstance();
} catch (Exception e) {
throw new JasperException(e);
}
if (tagPlugin == null) {
return;
}
tagPlugins.put(tagClass, tagPlugin);
}
initialized = true;
}
/**
* Invoke tag plugin for the given custom tag, if a plugin exists for
* the custom tag's tag handler.
*
* The given custom tag node will be manipulated by the plugin.
*/
private void invokePlugin(Node.CustomTag n) {
TagPlugin tagPlugin = (TagPlugin)
tagPlugins.get(n.getTagHandlerClass().getName());
if (tagPlugin == null) {
return;
}
TagPluginContext tagPluginContext = new TagPluginContextImpl(n, pageInfo);
n.setTagPluginContext(tagPluginContext);
tagPlugin.doTag(tagPluginContext);
}
static class TagPluginContextImpl implements TagPluginContext {
private Node.CustomTag node;
private Node.Nodes curNodes;
private PageInfo pageInfo;
private HashMap pluginAttributes;
TagPluginContextImpl(Node.CustomTag n, PageInfo pageInfo) {
this.node = n;
this.pageInfo = pageInfo;
curNodes = new Node.Nodes();
n.setAtETag(curNodes);
curNodes = new Node.Nodes();
n.setAtSTag(curNodes);
n.setUseTagPlugin(true);
pluginAttributes = new HashMap();
}
public TagPluginContext getParentContext() {
Node parent = node.getParent();
if (! (parent instanceof Node.CustomTag)) {
return null;
}
return ((Node.CustomTag) parent).getTagPluginContext();
}
public void setPluginAttribute(String key, Object value) {
pluginAttributes.put(key, value);
}
public Object getPluginAttribute(String key) {
return pluginAttributes.get(key);
}
public boolean isScriptless() {
return node.getChildInfo().isScriptless();
}
public boolean isConstantAttribute(String attribute) {
Node.JspAttribute attr = getNodeAttribute(attribute);
if (attr == null)
return false;
return attr.isLiteral();
}
public String getConstantAttribute(String attribute) {
Node.JspAttribute attr = getNodeAttribute(attribute);
if (attr == null)
return null;
return attr.getValue();
}
public boolean isAttributeSpecified(String attribute) {
return getNodeAttribute(attribute) != null;
}
public String getTemporaryVariableName() {
return node.getRoot().nextTemporaryVariableName();
}
public void generateImport(String imp) {
pageInfo.addImport(imp);
}
public void generateDeclaration(String id, String text) {
if (pageInfo.isPluginDeclared(id)) {
return;
}
curNodes.add(new Node.Declaration(text, node.getStart(), null));
}
public void generateJavaSource(String sourceCode) {
curNodes.add(new Node.Scriptlet(sourceCode, node.getStart(),
null));
}
public void generateAttribute(String attributeName) {
curNodes.add(new Node.AttributeGenerator(node.getStart(),
attributeName,
node));
}
public void dontUseTagPlugin() {
node.setUseTagPlugin(false);
}
public void generateBody() {
// Since we'll generate the body anyway, this is really a nop,
// except for the fact that it lets us put the Java sources the
// plugins produce in the correct order (w.r.t the body).
curNodes = node.getAtETag();
}
private Node.JspAttribute getNodeAttribute(String attribute) {
Node.JspAttribute[] attrs = node.getJspAttributes();
for (int i=0; attrs != null && i < attrs.length; i++) {
if (attrs[i].getName().equals(attribute)) {
return attrs[i];
}
}
return null;
}
}
}
@@ -0,0 +1,115 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jasper.compiler;
import org.apache.jasper.JasperException;
import org.apache.jasper.Options;
/**
*/
public class TextOptimizer {
/**
* A visitor to concatenate contiguous template texts.
*/
static class TextCatVisitor extends Node.Visitor {
private Options options;
private PageInfo pageInfo;
private int textNodeCount = 0;
private Node.TemplateText firstTextNode = null;
private StringBuffer textBuffer;
private final String emptyText = new String("");
public TextCatVisitor(Compiler compiler) {
options = compiler.getCompilationContext().getOptions();
pageInfo = compiler.getPageInfo();
}
public void doVisit(Node n) throws JasperException {
collectText();
}
/*
* The following directis are ignored in text concatenation
*/
public void visit(Node.PageDirective n) throws JasperException {
}
public void visit(Node.TagDirective n) throws JasperException {
}
public void visit(Node.TaglibDirective n) throws JasperException {
}
public void visit(Node.AttributeDirective n) throws JasperException {
}
public void visit(Node.VariableDirective n) throws JasperException {
}
/*
* Don't concatenate text across body boundaries
*/
public void visitBody(Node n) throws JasperException {
super.visitBody(n);
collectText();
}
public void visit(Node.TemplateText n) throws JasperException {
if ((options.getTrimSpaces() || pageInfo.isTrimDirectiveWhitespaces())
&& n.isAllSpace()) {
n.setText(emptyText);
return;
}
if (textNodeCount++ == 0) {
firstTextNode = n;
textBuffer = new StringBuffer(n.getText());
} else {
// Append text to text buffer
textBuffer.append(n.getText());
n.setText(emptyText);
}
}
/**
* This method breaks concatenation mode. As a side effect it copies
* the concatenated string to the first text node
*/
private void collectText() {
if (textNodeCount > 1) {
// Copy the text in buffer into the first template text node.
firstTextNode.setText(textBuffer.toString());
}
textNodeCount = 0;
}
}
public static void concatenate(Compiler compiler, Node.Nodes page)
throws JasperException {
TextCatVisitor v = new TextCatVisitor(compiler);
page.visit(v);
// Cleanup, in case the page ends with a template text
v.collectText();
}
}
@@ -0,0 +1,549 @@
/*
* 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.jasper.compiler;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.xml.sax.InputSource;
import javax.servlet.ServletContext;
import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
import org.apache.jasper.xmlparser.ParserUtils;
import org.apache.jasper.xmlparser.TreeNode;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* A container for all tag libraries that are defined "globally"
* for the web application.
*
* Tag Libraries can be defined globally in one of two ways:
* 1. Via <taglib> elements in web.xml:
* the uri and location of the tag-library are specified in
* the <taglib> element.
* 2. Via packaged jar files that contain .tld files
* within the META-INF directory, or some subdirectory
* of it. The taglib is 'global' if it has the <uri>
* element defined.
*
* A mapping between the taglib URI and its associated TaglibraryInfoImpl
* is maintained in this container.
* Actually, that's what we'd like to do. However, because of the
* way the classes TagLibraryInfo and TagInfo have been defined,
* it is not currently possible to share an instance of TagLibraryInfo
* across page invocations. A bug has been submitted to the spec lead.
* In the mean time, all we do is save the 'location' where the
* TLD associated with a taglib URI can be found.
*
* When a JSP page has a taglib directive, the mappings in this container
* are first searched (see method getLocation()).
* If a mapping is found, then the location of the TLD is returned.
* If no mapping is found, then the uri specified
* in the taglib directive is to be interpreted as the location for
* the TLD of this tag library.
*
* @author Pierre Delisle
* @author Jan Luehe
*/
public class TldLocationsCache {
// Logger
private Log log = LogFactory.getLog(TldLocationsCache.class);
/**
* The types of URI one may specify for a tag library
*/
public static final int ABS_URI = 0;
public static final int ROOT_REL_URI = 1;
public static final int NOROOT_REL_URI = 2;
private static final String WEB_XML = "/WEB-INF/web.xml";
private static final String FILE_PROTOCOL = "file:";
private static final String JAR_FILE_SUFFIX = ".jar";
// Names of JARs that are known not to contain any TLDs
private static HashSet<String> noTldJars;
/**
* The mapping of the 'global' tag library URI to the location (resource
* path) of the TLD associated with that tag library. The location is
* returned as a String array:
* [0] The location
* [1] If the location is a jar file, this is the location of the tld.
*/
private Hashtable mappings;
private boolean initialized;
private ServletContext ctxt;
private boolean redeployMode;
//*********************************************************************
// Constructor and Initilizations
/*
* Initializes the set of JARs that are known not to contain any TLDs
*/
static {
noTldJars = new HashSet<String>();
// Bootstrap JARs
noTldJars.add("bootstrap.jar");
noTldJars.add("commons-daemon.jar");
noTldJars.add("tomcat-juli.jar");
// Main JARs
noTldJars.add("annotations-api.jar");
noTldJars.add("catalina.jar");
noTldJars.add("catalina-ant.jar");
noTldJars.add("catalina-ha.jar");
noTldJars.add("catalina-tribes.jar");
noTldJars.add("el-api.jar");
noTldJars.add("jasper.jar");
noTldJars.add("jasper-el.jar");
noTldJars.add("jasper-jdt.jar");
noTldJars.add("jsp-api.jar");
noTldJars.add("servlet-api.jar");
noTldJars.add("tomcat-coyote.jar");
noTldJars.add("tomcat-dbcp.jar");
// i18n JARs
noTldJars.add("tomcat-i18n-en.jar");
noTldJars.add("tomcat-i18n-es.jar");
noTldJars.add("tomcat-i18n-fr.jar");
noTldJars.add("tomcat-i18n-ja.jar");
// Misc JARs not included with Tomcat
noTldJars.add("ant.jar");
noTldJars.add("commons-dbcp.jar");
noTldJars.add("commons-beanutils.jar");
noTldJars.add("commons-fileupload-1.0.jar");
noTldJars.add("commons-pool.jar");
noTldJars.add("commons-digester.jar");
noTldJars.add("commons-logging.jar");
noTldJars.add("commons-collections.jar");
noTldJars.add("jmx.jar");
noTldJars.add("jmx-tools.jar");
noTldJars.add("xercesImpl.jar");
noTldJars.add("xmlParserAPIs.jar");
noTldJars.add("xml-apis.jar");
// JARs from J2SE runtime
noTldJars.add("sunjce_provider.jar");
noTldJars.add("ldapsec.jar");
noTldJars.add("localedata.jar");
noTldJars.add("dnsns.jar");
noTldJars.add("tools.jar");
noTldJars.add("sunpkcs11.jar");
}
public TldLocationsCache(ServletContext ctxt) {
this(ctxt, true);
}
/** Constructor.
*
* @param ctxt the servlet context of the web application in which Jasper
* is running
* @param redeployMode if true, then the compiler will allow redeploying
* a tag library from the same jar, at the expense of slowing down the
* server a bit. Note that this may only work on JDK 1.3.1_01a and later,
* because of JDK bug 4211817 fixed in this release.
* If redeployMode is false, a faster but less capable mode will be used.
*/
public TldLocationsCache(ServletContext ctxt, boolean redeployMode) {
this.ctxt = ctxt;
this.redeployMode = redeployMode;
mappings = new Hashtable();
initialized = false;
}
/**
* Sets the list of JARs that are known not to contain any TLDs.
*
* @param jarNames List of comma-separated names of JAR files that are
* known not to contain any TLDs
*/
public static void setNoTldJars(String jarNames) {
if (jarNames != null) {
noTldJars.clear();
StringTokenizer tokenizer = new StringTokenizer(jarNames, ",");
while (tokenizer.hasMoreElements()) {
noTldJars.add(tokenizer.nextToken());
}
}
}
/**
* Gets the 'location' of the TLD associated with the given taglib 'uri'.
*
* Returns null if the uri is not associated with any tag library 'exposed'
* in the web application. A tag library is 'exposed' either explicitly in
* web.xml or implicitly via the uri tag in the TLD of a taglib deployed
* in a jar file (WEB-INF/lib).
*
* @param uri The taglib uri
*
* @return An array of two Strings: The first element denotes the real
* path to the TLD. If the path to the TLD points to a jar file, then the
* second element denotes the name of the TLD entry in the jar file.
* Returns null if the uri is not associated with any tag library 'exposed'
* in the web application.
*/
public String[] getLocation(String uri) throws JasperException {
if (!initialized) {
init();
}
return (String[]) mappings.get(uri);
}
/**
* Returns the type of a URI:
* ABS_URI
* ROOT_REL_URI
* NOROOT_REL_URI
*/
public static int uriType(String uri) {
if (uri.indexOf(':') != -1) {
return ABS_URI;
} else if (uri.startsWith("/")) {
return ROOT_REL_URI;
} else {
return NOROOT_REL_URI;
}
}
private void init() throws JasperException {
if (initialized) return;
try {
processWebDotXml();
scanJars();
processTldsInFileSystem("/WEB-INF/");
initialized = true;
} catch (Exception ex) {
throw new JasperException(Localizer.getMessage(
"jsp.error.internal.tldinit", ex.getMessage()));
}
}
/*
* Populates taglib map described in web.xml.
*/
private void processWebDotXml() throws Exception {
InputStream is = null;
try {
// Acquire input stream to web application deployment descriptor
String altDDName = (String)ctxt.getAttribute(
Constants.ALT_DD_ATTR);
URL uri = null;
if (altDDName != null) {
try {
uri = new URL(FILE_PROTOCOL+altDDName.replace('\\', '/'));
} catch (MalformedURLException e) {
if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.error.internal.filenotfound",
altDDName));
}
}
} else {
uri = ctxt.getResource(WEB_XML);
if (uri == null && log.isWarnEnabled()) {
log.warn(Localizer.getMessage(
"jsp.error.internal.filenotfound",
WEB_XML));
}
}
if (uri == null) {
return;
}
is = uri.openStream();
InputSource ip = new InputSource(is);
ip.setSystemId(uri.toExternalForm());
// Parse the web application deployment descriptor
TreeNode webtld = null;
// altDDName is the absolute path of the DD
if (altDDName != null) {
webtld = new ParserUtils().parseXMLDocument(altDDName, ip);
} else {
webtld = new ParserUtils().parseXMLDocument(WEB_XML, ip);
}
// Allow taglib to be an element of the root or jsp-config (JSP2.0)
TreeNode jspConfig = webtld.findChild("jsp-config");
if (jspConfig != null) {
webtld = jspConfig;
}
Iterator taglibs = webtld.findChildren("taglib");
while (taglibs.hasNext()) {
// Parse the next <taglib> element
TreeNode taglib = (TreeNode) taglibs.next();
String tagUri = null;
String tagLoc = null;
TreeNode child = taglib.findChild("taglib-uri");
if (child != null)
tagUri = child.getBody();
child = taglib.findChild("taglib-location");
if (child != null)
tagLoc = child.getBody();
// Save this location if appropriate
if (tagLoc == null)
continue;
if (uriType(tagLoc) == NOROOT_REL_URI)
tagLoc = "/WEB-INF/" + tagLoc;
String tagLoc2 = null;
if (tagLoc.endsWith(JAR_FILE_SUFFIX)) {
tagLoc = ctxt.getResource(tagLoc).toString();
tagLoc2 = "META-INF/taglib.tld";
}
mappings.put(tagUri, new String[] { tagLoc, tagLoc2 });
}
} finally {
if (is != null) {
try {
is.close();
} catch (Throwable t) {}
}
}
}
/**
* Scans the given JarURLConnection for TLD files located in META-INF
* (or a subdirectory of it), adding an implicit map entry to the taglib
* map for any TLD that has a <uri> element.
*
* @param conn The JarURLConnection to the JAR file to scan
* @param ignore true if any exceptions raised when processing the given
* JAR should be ignored, false otherwise
*/
private void scanJar(JarURLConnection conn, boolean ignore)
throws JasperException {
JarFile jarFile = null;
String resourcePath = conn.getJarFileURL().toString();
try {
if (redeployMode) {
conn.setUseCaches(false);
}
jarFile = conn.getJarFile();
Enumeration entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = (JarEntry) entries.nextElement();
String name = entry.getName();
if (!name.startsWith("META-INF/")) continue;
if (!name.endsWith(".tld")) continue;
InputStream stream = jarFile.getInputStream(entry);
try {
String uri = getUriFromTld(resourcePath, stream);
// Add implicit map entry only if its uri is not already
// present in the map
if (uri != null && mappings.get(uri) == null) {
mappings.put(uri, new String[]{ resourcePath, name });
}
} finally {
if (stream != null) {
try {
stream.close();
} catch (Throwable t) {
// do nothing
}
}
}
}
} catch (Exception ex) {
if (!redeployMode) {
// if not in redeploy mode, close the jar in case of an error
if (jarFile != null) {
try {
jarFile.close();
} catch (Throwable t) {
// ignore
}
}
}
if (!ignore) {
throw new JasperException(ex);
}
} finally {
if (redeployMode) {
// if in redeploy mode, always close the jar
if (jarFile != null) {
try {
jarFile.close();
} catch (Throwable t) {
// ignore
}
}
}
}
}
/*
* Searches the filesystem under /WEB-INF for any TLD files, and adds
* an implicit map entry to the taglib map for any TLD that has a <uri>
* element.
*/
private void processTldsInFileSystem(String startPath)
throws Exception {
Set dirList = ctxt.getResourcePaths(startPath);
if (dirList != null) {
Iterator it = dirList.iterator();
while (it.hasNext()) {
String path = (String) it.next();
if (path.endsWith("/")) {
processTldsInFileSystem(path);
}
if (!path.endsWith(".tld")) {
continue;
}
InputStream stream = ctxt.getResourceAsStream(path);
String uri = null;
try {
uri = getUriFromTld(path, stream);
} finally {
if (stream != null) {
try {
stream.close();
} catch (Throwable t) {
// do nothing
}
}
}
// Add implicit map entry only if its uri is not already
// present in the map
if (uri != null && mappings.get(uri) == null) {
mappings.put(uri, new String[] { path, null });
}
}
}
}
/*
* Returns the value of the uri element of the given TLD, or null if the
* given TLD does not contain any such element.
*/
private String getUriFromTld(String resourcePath, InputStream in)
throws JasperException
{
// Parse the tag library descriptor at the specified resource path
TreeNode tld = new ParserUtils().parseXMLDocument(resourcePath, in);
TreeNode uri = tld.findChild("uri");
if (uri != null) {
String body = uri.getBody();
if (body != null)
return body;
}
return null;
}
/*
* Scans all JARs accessible to the webapp's classloader and its
* parent classloaders for TLDs.
*
* The list of JARs always includes the JARs under WEB-INF/lib, as well as
* all shared JARs in the classloader delegation chain of the webapp's
* classloader.
*
* Considering JARs in the classloader delegation chain constitutes a
* Tomcat-specific extension to the TLD search
* order defined in the JSP spec. It allows tag libraries packaged as JAR
* files to be shared by web applications by simply dropping them in a
* location that all web applications have access to (e.g.,
* <CATALINA_HOME>/common/lib).
*
* The set of shared JARs to be scanned for TLDs is narrowed down by
* the <tt>noTldJars</tt> class variable, which contains the names of JARs
* that are known not to contain any TLDs.
*/
private void scanJars() throws Exception {
ClassLoader webappLoader
= Thread.currentThread().getContextClassLoader();
ClassLoader loader = webappLoader;
while (loader != null) {
if (loader instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) loader).getURLs();
for (int i=0; i<urls.length; i++) {
URLConnection conn = urls[i].openConnection();
if (conn instanceof JarURLConnection) {
if (needScanJar(loader, webappLoader,
((JarURLConnection) conn).getJarFile().getName())) {
scanJar((JarURLConnection) conn, true);
}
} else {
String urlStr = urls[i].toString();
if (urlStr.startsWith(FILE_PROTOCOL)
&& urlStr.endsWith(JAR_FILE_SUFFIX)
&& needScanJar(loader, webappLoader, urlStr)) {
URL jarURL = new URL("jar:" + urlStr + "!/");
scanJar((JarURLConnection) jarURL.openConnection(),
true);
}
}
}
}
loader = loader.getParent();
}
}
/*
* Determines if the JAR file with the given <tt>jarPath</tt> needs to be
* scanned for TLDs.
*
* @param loader The current classloader in the parent chain
* @param webappLoader The webapp classloader
* @param jarPath The JAR file path
*
* @return TRUE if the JAR file identified by <tt>jarPath</tt> needs to be
* scanned for TLDs, FALSE otherwise
*/
private boolean needScanJar(ClassLoader loader, ClassLoader webappLoader,
String jarPath) {
if (loader == webappLoader) {
// JARs under WEB-INF/lib must be scanned unconditionally according
// to the spec.
return true;
} else {
String jarName = jarPath;
int slash = jarPath.lastIndexOf('/');
if (slash >= 0) {
jarName = jarPath.substring(slash + 1);
}
return (!noTldJars.contains(jarName));
}
}
}
@@ -0,0 +1,37 @@
/*
* 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.jasper.compiler.tagplugin;
/**
* This interface is to be implemented by the plugin author, to supply
* an alternate implementation of the tag handlers. It can be used to
* specify the Java codes to be generated when a tag is invoked.
*
* An implementation of this interface must be registered in a file
* named "tagPlugins.xml" under WEB-INF.
*/
public interface TagPlugin {
/**
* Generate codes for a custom tag.
* @param ctxt a TagPluginContext for accessing Jasper functions
*/
void doTag(TagPluginContext ctxt);
}
@@ -0,0 +1,124 @@
/*
* 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.jasper.compiler.tagplugin;
/**
* This interface allows the plugin author to make inqueries about the
* properties of the current tag, and to use Jasper resources to generate
* direct Java codes in place of tag handler invocations.
*/
public interface TagPluginContext {
/**
* @return true if the body of the tag is scriptless.
*/
boolean isScriptless();
/**
* @param attribute Name of the attribute
* @return true if the attribute is specified in the tag
*/
boolean isAttributeSpecified(String attribute);
/**
* @return An unique temporary variable name that the plugin can use.
*/
String getTemporaryVariableName();
/**
* Generate an import statement
* @param s Name of the import class, '*' allowed.
*/
void generateImport(String s);
/**
* Generate a declaration in the of the generated class. This can be
* used to declare an innter class, a method, or a class variable.
* @param id An unique ID identifying the declaration. It is not
* part of the declaration, and is used to ensure that the
* declaration will only appear once. If this method is
* invoked with the same id more than once in the translation
* unit, only the first declaration will be taken.
* @param text The text of the declaration.
**/
void generateDeclaration(String id, String text);
/**
* Generate Java source codes
*/
void generateJavaSource(String s);
/**
* @return true if the attribute is specified and its value is a
* translation-time constant.
*/
boolean isConstantAttribute(String attribute);
/**
* @return A string that is the value of a constant attribute. Undefined
* if the attribute is not a (translation-time) constant.
* null if the attribute is not specified.
*/
String getConstantAttribute(String attribute);
/**
* Generate codesto evaluate value of a attribute in the custom tag
* The codes is a Java expression.
* NOTE: Currently cannot handle attributes that are fragments.
* @param attribute The specified attribute
*/
void generateAttribute(String attribute);
/**
* Generate codes for the body of the custom tag
*/
void generateBody();
/**
* Abandon optimization for this tag handler, and instruct
* Jasper to generate the tag handler calls, as usual.
* Should be invoked if errors are detected, or when the tag body
* is deemed too compilicated for optimization.
*/
void dontUseTagPlugin();
/**
* Get the PluginContext for the parent of this custom tag. NOTE:
* The operations available for PluginContext so obtained is limited
* to getPluginAttribute and setPluginAttribute, and queries (e.g.
* isScriptless(). There should be no calls to generate*().
* @return The pluginContext for the parent node.
* null if the parent is not a custom tag, or if the pluginConxt
* if not available (because useTagPlugin is false, e.g).
*/
TagPluginContext getParentContext();
/**
* Associate the attribute with a value in the current tagplugin context.
* The plugin attributes can be used for communication among tags that
* must work together as a group. See <c:when> for an example.
*/
void setPluginAttribute(String attr, Object value);
/**
* Get the value of an attribute in the current tagplugin context.
*/
Object getPluginAttribute(String attr);
}
@@ -0,0 +1,99 @@
/*
* 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.jasper.el;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.FunctionMapper;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
/**
* Implementation of ELContext
*
* @author Jacob Hookom
*/
public final class ELContextImpl extends ELContext {
private final static FunctionMapper NullFunctionMapper = new FunctionMapper() {
public Method resolveFunction(String prefix, String localName) {
return null;
}
};
private final static class VariableMapperImpl extends VariableMapper {
private Map<String, ValueExpression> vars;
public ValueExpression resolveVariable(String variable) {
if (vars == null) {
return null;
}
return vars.get(variable);
}
public ValueExpression setVariable(String variable,
ValueExpression expression) {
if (vars == null)
vars = new HashMap<String, ValueExpression>();
return vars.put(variable, expression);
}
}
private final ELResolver resolver;
private FunctionMapper functionMapper = NullFunctionMapper; // immutable
private VariableMapper variableMapper;
public ELContextImpl() {
this(ELResolverImpl.DefaultResolver);
}
public ELContextImpl(ELResolver resolver) {
this.resolver = resolver;
}
public ELResolver getELResolver() {
return this.resolver;
}
public FunctionMapper getFunctionMapper() {
return this.functionMapper;
}
public VariableMapper getVariableMapper() {
if (this.variableMapper == null) {
this.variableMapper = new VariableMapperImpl();
}
return this.variableMapper;
}
public void setFunctionMapper(FunctionMapper functionMapper) {
this.functionMapper = functionMapper;
}
public void setVariableMapper(VariableMapper variableMapper) {
this.variableMapper = variableMapper;
}
}
@@ -0,0 +1,78 @@
/*
* 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.jasper.el;
import java.util.Locale;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;
/**
* Simple ELContextWrapper for runtime evaluation of EL w/ dynamic FunctionMappers
*
* @author jhook
*/
public final class ELContextWrapper extends ELContext {
private final ELContext target;
private final FunctionMapper fnMapper;
public ELContextWrapper(ELContext target, FunctionMapper fnMapper) {
this.target = target;
this.fnMapper = fnMapper;
}
public ELResolver getELResolver() {
return this.target.getELResolver();
}
public FunctionMapper getFunctionMapper() {
if (this.fnMapper != null) return this.fnMapper;
return this.target.getFunctionMapper();
}
public VariableMapper getVariableMapper() {
return this.target.getVariableMapper();
}
public Object getContext(Class key) {
return this.target.getContext(key);
}
public Locale getLocale() {
return this.target.getLocale();
}
public boolean isPropertyResolved() {
return this.target.isPropertyResolved();
}
public void putContext(Class key, Object contextObject) throws NullPointerException {
this.target.putContext(key, contextObject);
}
public void setLocale(Locale locale) {
this.target.setLocale(locale);
}
public void setPropertyResolved(boolean resolved) {
this.target.setPropertyResolved(resolved);
}
}
@@ -0,0 +1,146 @@
/*
* 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.jasper.el;
import java.util.Iterator;
import javax.el.ArrayELResolver;
import javax.el.BeanELResolver;
import javax.el.CompositeELResolver;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.ListELResolver;
import javax.el.MapELResolver;
import javax.el.PropertyNotFoundException;
import javax.el.PropertyNotWritableException;
import javax.el.ResourceBundleELResolver;
import javax.servlet.jsp.el.VariableResolver;
public final class ELResolverImpl extends ELResolver {
public final static ELResolver DefaultResolver = new CompositeELResolver();
static {
((CompositeELResolver) DefaultResolver).add(new MapELResolver());
((CompositeELResolver) DefaultResolver).add(new ResourceBundleELResolver());
((CompositeELResolver) DefaultResolver).add(new ListELResolver());
((CompositeELResolver) DefaultResolver).add(new ArrayELResolver());
((CompositeELResolver) DefaultResolver).add(new BeanELResolver());
}
private final VariableResolver variableResolver;
public ELResolverImpl(VariableResolver variableResolver) {
this.variableResolver = variableResolver;
}
public Object getValue(ELContext context, Object base, Object property)
throws NullPointerException, PropertyNotFoundException, ELException {
if (context == null) {
throw new NullPointerException();
}
if (base == null) {
context.setPropertyResolved(true);
if (property != null) {
try {
return this.variableResolver.resolveVariable(property
.toString());
} catch (javax.servlet.jsp.el.ELException e) {
throw new ELException(e.getMessage(), e.getCause());
}
}
}
if (!context.isPropertyResolved()) {
return DefaultResolver.getValue(context, base, property);
}
return null;
}
public Class<?> getType(ELContext context, Object base, Object property)
throws NullPointerException, PropertyNotFoundException, ELException {
if (context == null) {
throw new NullPointerException();
}
if (base == null) {
context.setPropertyResolved(true);
if (property != null) {
try {
Object obj = this.variableResolver.resolveVariable(property
.toString());
return (obj != null) ? obj.getClass() : null;
} catch (javax.servlet.jsp.el.ELException e) {
throw new ELException(e.getMessage(), e.getCause());
}
}
}
if (!context.isPropertyResolved()) {
return DefaultResolver.getType(context, base, property);
}
return null;
}
public void setValue(ELContext context, Object base, Object property,
Object value) throws NullPointerException,
PropertyNotFoundException, PropertyNotWritableException,
ELException {
if (context == null) {
throw new NullPointerException();
}
if (base == null) {
context.setPropertyResolved(true);
throw new PropertyNotWritableException(
"Legacy VariableResolver wrapped, not writable");
}
if (!context.isPropertyResolved()) {
DefaultResolver.setValue(context, base, property, value);
}
}
public boolean isReadOnly(ELContext context, Object base, Object property)
throws NullPointerException, PropertyNotFoundException, ELException {
if (context == null) {
throw new NullPointerException();
}
if (base == null) {
context.setPropertyResolved(true);
return true;
}
return DefaultResolver.isReadOnly(context, base, property);
}
public Iterator<java.beans.FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
return DefaultResolver.getFeatureDescriptors(context, base);
}
public Class<?> getCommonPropertyType(ELContext context, Object base) {
if (base == null) {
return String.class;
}
return DefaultResolver.getCommonPropertyType(context, base);
}
}
@@ -0,0 +1,58 @@
/*
* 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.jasper.el;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.ELParseException;
import javax.servlet.jsp.el.Expression;
import javax.servlet.jsp.el.ExpressionEvaluator;
import javax.servlet.jsp.el.FunctionMapper;
import javax.servlet.jsp.el.VariableResolver;
public final class ExpressionEvaluatorImpl extends ExpressionEvaluator {
private final ExpressionFactory factory;
public ExpressionEvaluatorImpl(ExpressionFactory factory) {
this.factory = factory;
}
public Expression parseExpression(String expression, Class expectedType,
FunctionMapper fMapper) throws ELException {
try {
ELContextImpl ctx = new ELContextImpl(ELResolverImpl.DefaultResolver);
if (fMapper != null) {
ctx.setFunctionMapper(new FunctionMapperImpl(fMapper));
}
ValueExpression ve = this.factory.createValueExpression(ctx, expression, expectedType);
return new ExpressionImpl(ve);
} catch (javax.el.ELException e) {
throw new ELParseException(e.getMessage());
}
}
public Object evaluate(String expression, Class expectedType,
VariableResolver vResolver, FunctionMapper fMapper)
throws ELException {
return this.parseExpression(expression, expectedType, fMapper).evaluate(vResolver);
}
}
@@ -0,0 +1,38 @@
/*
* 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.jasper.el;
import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.Expression;
import javax.servlet.jsp.el.VariableResolver;
public final class ExpressionImpl extends Expression {
private final ValueExpression ve;
public ExpressionImpl(ValueExpression ve) {
this.ve = ve;
}
public Object evaluate(VariableResolver vResolver) throws ELException {
ELContext ctx = new ELContextImpl(new ELResolverImpl(vResolver));
return ve.getValue(ctx);
}
}
@@ -0,0 +1,35 @@
/*
* 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.jasper.el;
import java.lang.reflect.Method;
import javax.servlet.jsp.el.FunctionMapper;
public final class FunctionMapperImpl extends javax.el.FunctionMapper {
private final FunctionMapper fnMapper;
public FunctionMapperImpl(FunctionMapper fnMapper) {
this.fnMapper = fnMapper;
}
public Method resolveFunction(String prefix, String localName) {
return this.fnMapper.resolveFunction(prefix, localName);
}
}
@@ -0,0 +1,26 @@
/*
* 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.jasper.el;
import javax.el.ELException;
public class JspELException extends ELException {
public JspELException(String mark, ELException e) {
super(mark + " " + e.getMessage(), e.getCause());
}
}
@@ -0,0 +1,108 @@
/*
* 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.jasper.el;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.MethodExpression;
import javax.el.MethodInfo;
import javax.el.MethodNotFoundException;
import javax.el.PropertyNotFoundException;
public final class JspMethodExpression extends MethodExpression implements
Externalizable {
private String mark;
private MethodExpression target;
public JspMethodExpression() {
super();
}
public JspMethodExpression(String mark, MethodExpression target) {
this.target = target;
this.mark = mark;
}
public MethodInfo getMethodInfo(ELContext context)
throws NullPointerException, PropertyNotFoundException,
MethodNotFoundException, ELException {
try {
return this.target.getMethodInfo(context);
} catch (MethodNotFoundException e) {
if (e instanceof JspMethodNotFoundException) throw e;
throw new JspMethodNotFoundException(this.mark, e);
} catch (PropertyNotFoundException e) {
if (e instanceof JspPropertyNotFoundException) throw e;
throw new JspPropertyNotFoundException(this.mark, e);
} catch (ELException e) {
if (e instanceof JspELException) throw e;
throw new JspELException(this.mark, e);
}
}
public Object invoke(ELContext context, Object[] params)
throws NullPointerException, PropertyNotFoundException,
MethodNotFoundException, ELException {
try {
return this.target.invoke(context, params);
} catch (MethodNotFoundException e) {
if (e instanceof JspMethodNotFoundException) throw e;
throw new JspMethodNotFoundException(this.mark, e);
} catch (PropertyNotFoundException e) {
if (e instanceof JspPropertyNotFoundException) throw e;
throw new JspPropertyNotFoundException(this.mark, e);
} catch (ELException e) {
if (e instanceof JspELException) throw e;
throw new JspELException(this.mark, e);
}
}
public boolean equals(Object obj) {
return this.target.equals(obj);
}
public int hashCode() {
return this.target.hashCode();
}
public String getExpressionString() {
return this.target.getExpressionString();
}
public boolean isLiteralText() {
return this.target.isLiteralText();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(this.mark);
out.writeObject(this.target);
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
this.mark = in.readUTF();
this.target = (MethodExpression) in.readObject();
}
}
@@ -0,0 +1,26 @@
/*
* 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.jasper.el;
import javax.el.MethodNotFoundException;
public class JspMethodNotFoundException extends MethodNotFoundException {
public JspMethodNotFoundException(String mark, MethodNotFoundException e) {
super(mark + " " + e.getMessage(), e.getCause());
}
}
@@ -0,0 +1,28 @@
/*
* 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.jasper.el;
import javax.el.PropertyNotFoundException;
public final class JspPropertyNotFoundException extends
PropertyNotFoundException {
public JspPropertyNotFoundException(String mark, PropertyNotFoundException e) {
super(mark + " " + e.getMessage(), e.getCause());
}
}
@@ -0,0 +1,27 @@
/*
* 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.jasper.el;
import javax.el.PropertyNotWritableException;
public class JspPropertyNotWritableException extends
PropertyNotWritableException {
public JspPropertyNotWritableException(String mark, PropertyNotWritableException e) {
super(mark + " " + e.getMessage(), e.getCause());
}
}
@@ -0,0 +1,137 @@
/*
* 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.jasper.el;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.PropertyNotFoundException;
import javax.el.PropertyNotWritableException;
import javax.el.ValueExpression;
/**
* Wrapper for providing context to ValueExpressions
*
* @author Jacob Hookom
*/
public final class JspValueExpression extends ValueExpression implements
Externalizable {
private ValueExpression target;
private String mark;
public JspValueExpression() {
super();
}
public JspValueExpression(String mark, ValueExpression target) {
this.target = target;
this.mark = mark;
}
public Class<?> getExpectedType() {
return this.target.getExpectedType();
}
public Class<?> getType(ELContext context) throws NullPointerException,
PropertyNotFoundException, ELException {
try {
return this.target.getType(context);
} catch (PropertyNotFoundException e) {
if (e instanceof JspPropertyNotFoundException) throw e;
throw new JspPropertyNotFoundException(this.mark, e);
} catch (ELException e) {
if (e instanceof JspELException) throw e;
throw new JspELException(this.mark, e);
}
}
public boolean isReadOnly(ELContext context) throws NullPointerException,
PropertyNotFoundException, ELException {
try {
return this.target.isReadOnly(context);
} catch (PropertyNotFoundException e) {
if (e instanceof JspPropertyNotFoundException) throw e;
throw new JspPropertyNotFoundException(this.mark, e);
} catch (ELException e) {
if (e instanceof JspELException) throw e;
throw new JspELException(this.mark, e);
}
}
public void setValue(ELContext context, Object value)
throws NullPointerException, PropertyNotFoundException,
PropertyNotWritableException, ELException {
try {
this.target.setValue(context, value);
} catch (PropertyNotWritableException e) {
if (e instanceof JspPropertyNotWritableException) throw e;
throw new JspPropertyNotWritableException(this.mark, e);
} catch (PropertyNotFoundException e) {
if (e instanceof JspPropertyNotFoundException) throw e;
throw new JspPropertyNotFoundException(this.mark, e);
} catch (ELException e) {
if (e instanceof JspELException) throw e;
throw new JspELException(this.mark, e);
}
}
public Object getValue(ELContext context) throws NullPointerException,
PropertyNotFoundException, ELException {
try {
return this.target.getValue(context);
} catch (PropertyNotFoundException e) {
if (e instanceof JspPropertyNotFoundException) throw e;
throw new JspPropertyNotFoundException(this.mark, e);
} catch (ELException e) {
if (e instanceof JspELException) throw e;
throw new JspELException(this.mark, e);
}
}
public boolean equals(Object obj) {
return this.target.equals(obj);
}
public int hashCode() {
return this.target.hashCode();
}
public String getExpressionString() {
return this.target.getExpressionString();
}
public boolean isLiteralText() {
return this.target.isLiteralText();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(this.mark);
out.writeObject(this.target);
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
this.mark = in.readUTF();
this.target = (ValueExpression) in.readObject();
}
}
@@ -0,0 +1,35 @@
/*
* 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.jasper.el;
import javax.el.ELContext;
import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.VariableResolver;
public final class VariableResolverImpl implements VariableResolver {
private final ELContext ctx;
public VariableResolverImpl(ELContext ctx) {
this.ctx = ctx;
}
public Object resolveVariable(String pName) throws ELException {
return this.ctx.getELResolver().getValue(this.ctx, null, pName);
}
}
@@ -0,0 +1,61 @@
/*
* 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.jasper.runtime;
import java.lang.reflect.InvocationTargetException;
import javax.naming.NamingException;
import org.apache.AnnotationProcessor;
/**
* Verify the annotation and Process it.
*
* @author Fabien Carrion
* @author Remy Maucherat
* @version $Revision: 467222 $, $Date: 2006-10-24 05:17:11 +0200 (Tue, 24 Oct 2006) $
*/
public class AnnotationHelper {
/**
* Call postConstruct method on the specified instance. Note: In Jasper, this
* calls naming resources injection as well.
*/
public static void postConstruct(AnnotationProcessor processor, Object instance)
throws IllegalAccessException, InvocationTargetException, NamingException {
if (processor != null) {
processor.processAnnotations(instance);
processor.postConstruct(instance);
}
}
/**
* Call preDestroy method on the specified instance.
*/
public static void preDestroy(AnnotationProcessor processor, Object instance)
throws IllegalAccessException, InvocationTargetException {
if (processor != null) {
processor.preDestroy(instance);
}
}
}
@@ -0,0 +1,604 @@
/*
* 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.jasper.runtime;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import org.apache.jasper.Constants;
/**
* Write text to a character-output stream, buffering characters so as
* to provide for the efficient writing of single characters, arrays,
* and strings.
*
* Provide support for discarding for the output that has been buffered.
*
* @author Rajiv Mordani
* @author Jan Luehe
*/
public class BodyContentImpl extends BodyContent {
private static final String LINE_SEPARATOR =
System.getProperty("line.separator");
private static final boolean LIMIT_BUFFER =
Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "false")).booleanValue();
private char[] cb;
private int nextChar;
private boolean closed;
// Enclosed writer to which any output is written
private Writer writer;
/**
* Constructor.
*/
public BodyContentImpl(JspWriter enclosingWriter) {
super(enclosingWriter);
bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE;
cb = new char[bufferSize];
nextChar = 0;
closed = false;
}
/**
* Write a single character.
*/
public void write(int c) throws IOException {
if (writer != null) {
writer.write(c);
} else {
ensureOpen();
if (nextChar >= bufferSize) {
reAllocBuff (1);
}
cb[nextChar++] = (char) c;
}
}
/**
* Write a portion of an array of characters.
*
* <p> Ordinarily this method stores characters from the given array into
* this stream's buffer, flushing the buffer to the underlying stream as
* needed. If the requested length is at least as large as the buffer,
* however, then this method will flush the buffer and write the characters
* directly to the underlying stream. Thus redundant
* <code>DiscardableBufferedWriter</code>s will not copy data
* unnecessarily.
*
* @param cbuf A character array
* @param off Offset from which to start reading characters
* @param len Number of characters to write
*/
public void write(char[] cbuf, int off, int len) throws IOException {
if (writer != null) {
writer.write(cbuf, off, len);
} else {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
if (len >= bufferSize - nextChar)
reAllocBuff (len);
System.arraycopy(cbuf, off, cb, nextChar, len);
nextChar+=len;
}
}
/**
* Write an array of characters. This method cannot be inherited from the
* Writer class because it must suppress I/O exceptions.
*/
public void write(char[] buf) throws IOException {
if (writer != null) {
writer.write(buf);
} else {
write(buf, 0, buf.length);
}
}
/**
* Write a portion of a String.
*
* @param s String to be written
* @param off Offset from which to start reading characters
* @param len Number of characters to be written
*/
public void write(String s, int off, int len) throws IOException {
if (writer != null) {
writer.write(s, off, len);
} else {
ensureOpen();
if (len >= bufferSize - nextChar)
reAllocBuff(len);
s.getChars(off, off + len, cb, nextChar);
nextChar += len;
}
}
/**
* Write a string. This method cannot be inherited from the Writer class
* because it must suppress I/O exceptions.
*/
public void write(String s) throws IOException {
if (writer != null) {
writer.write(s);
} else {
write(s, 0, s.length());
}
}
/**
* Write a line separator. The line separator string is defined by the
* system property <tt>line.separator</tt>, and is not necessarily a single
* newline ('\n') character.
*
* @throws IOException If an I/O error occurs
*/
public void newLine() throws IOException {
if (writer != null) {
writer.write(LINE_SEPARATOR);
} else {
write(LINE_SEPARATOR);
}
}
/**
* Print a boolean value. The string produced by <code>{@link
* java.lang.String#valueOf(boolean)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param b The <code>boolean</code> to be printed
* @throws IOException
*/
public void print(boolean b) throws IOException {
if (writer != null) {
writer.write(b ? "true" : "false");
} else {
write(b ? "true" : "false");
}
}
/**
* Print a character. The character is translated into one or more bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param c The <code>char</code> to be printed
* @throws IOException
*/
public void print(char c) throws IOException {
if (writer != null) {
writer.write(String.valueOf(c));
} else {
write(String.valueOf(c));
}
}
/**
* Print an integer. The string produced by <code>{@link
* java.lang.String#valueOf(int)}</code> is translated into bytes according
* to the platform's default character encoding, and these bytes are
* written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param i The <code>int</code> to be printed
* @throws IOException
*/
public void print(int i) throws IOException {
if (writer != null) {
writer.write(String.valueOf(i));
} else {
write(String.valueOf(i));
}
}
/**
* Print a long integer. The string produced by <code>{@link
* java.lang.String#valueOf(long)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param l The <code>long</code> to be printed
* @throws IOException
*/
public void print(long l) throws IOException {
if (writer != null) {
writer.write(String.valueOf(l));
} else {
write(String.valueOf(l));
}
}
/**
* Print a floating-point number. The string produced by <code>{@link
* java.lang.String#valueOf(float)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param f The <code>float</code> to be printed
* @throws IOException
*/
public void print(float f) throws IOException {
if (writer != null) {
writer.write(String.valueOf(f));
} else {
write(String.valueOf(f));
}
}
/**
* Print a double-precision floating-point number. The string produced by
* <code>{@link java.lang.String#valueOf(double)}</code> is translated into
* bytes according to the platform's default character encoding, and these
* bytes are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param d The <code>double</code> to be printed
* @throws IOException
*/
public void print(double d) throws IOException {
if (writer != null) {
writer.write(String.valueOf(d));
} else {
write(String.valueOf(d));
}
}
/**
* Print an array of characters. The characters are converted into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param s The array of chars to be printed
*
* @throws NullPointerException If <code>s</code> is <code>null</code>
* @throws IOException
*/
public void print(char[] s) throws IOException {
if (writer != null) {
writer.write(s);
} else {
write(s);
}
}
/**
* Print a string. If the argument is <code>null</code> then the string
* <code>"null"</code> is printed. Otherwise, the string's characters are
* converted into bytes according to the platform's default character
* encoding, and these bytes are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param s The <code>String</code> to be printed
* @throws IOException
*/
public void print(String s) throws IOException {
if (s == null) s = "null";
if (writer != null) {
writer.write(s);
} else {
write(s);
}
}
/**
* Print an object. The string produced by the <code>{@link
* java.lang.String#valueOf(Object)}</code> method is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param obj The <code>Object</code> to be printed
* @throws IOException
*/
public void print(Object obj) throws IOException {
if (writer != null) {
writer.write(String.valueOf(obj));
} else {
write(String.valueOf(obj));
}
}
/**
* Terminate the current line by writing the line separator string. The
* line separator string is defined by the system property
* <code>line.separator</code>, and is not necessarily a single newline
* character (<code>'\n'</code>).
*
* @throws IOException
*/
public void println() throws IOException {
newLine();
}
/**
* Print a boolean value and then terminate the line. This method behaves
* as though it invokes <code>{@link #print(boolean)}</code> and then
* <code>{@link #println()}</code>.
*
* @throws IOException
*/
public void println(boolean x) throws IOException {
print(x);
println();
}
/**
* Print a character and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(char)}</code> and then
* <code>{@link #println()}</code>.
*
* @throws IOException
*/
public void println(char x) throws IOException {
print(x);
println();
}
/**
* Print an integer and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(int)}</code> and then
* <code>{@link #println()}</code>.
*
* @throws IOException
*/
public void println(int x) throws IOException {
print(x);
println();
}
/**
* Print a long integer and then terminate the line. This method behaves
* as though it invokes <code>{@link #print(long)}</code> and then
* <code>{@link #println()}</code>.
*
* @throws IOException
*/
public void println(long x) throws IOException {
print(x);
println();
}
/**
* Print a floating-point number and then terminate the line. This method
* behaves as though it invokes <code>{@link #print(float)}</code> and then
* <code>{@link #println()}</code>.
*
* @throws IOException
*/
public void println(float x) throws IOException {
print(x);
println();
}
/**
* Print a double-precision floating-point number and then terminate the
* line. This method behaves as though it invokes <code>{@link
* #print(double)}</code> and then <code>{@link #println()}</code>.
*
* @throws IOException
*/
public void println(double x) throws IOException{
print(x);
println();
}
/**
* Print an array of characters and then terminate the line. This method
* behaves as though it invokes <code>{@link #print(char[])}</code> and
* then <code>{@link #println()}</code>.
*
* @throws IOException
*/
public void println(char x[]) throws IOException {
print(x);
println();
}
/**
* Print a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*
* @throws IOException
*/
public void println(String x) throws IOException {
print(x);
println();
}
/**
* Print an Object and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(Object)}</code> and then
* <code>{@link #println()}</code>.
*
* @throws IOException
*/
public void println(Object x) throws IOException {
print(x);
println();
}
/**
* Clear the contents of the buffer. If the buffer has been already
* been flushed then the clear operation shall throw an IOException
* to signal the fact that some data has already been irrevocably
* written to the client response stream.
*
* @throws IOException If an I/O error occurs
*/
public void clear() throws IOException {
if (writer != null) {
throw new IOException();
} else {
nextChar = 0;
if (LIMIT_BUFFER && (cb.length > Constants.DEFAULT_TAG_BUFFER_SIZE)) {
bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE;
cb = new char[bufferSize];
}
}
}
/**
* Clears the current contents of the buffer. Unlike clear(), this
* mehtod will not throw an IOException if the buffer has already been
* flushed. It merely clears the current content of the buffer and
* returns.
*
* @throws IOException If an I/O error occurs
*/
public void clearBuffer() throws IOException {
if (writer == null) {
this.clear();
}
}
/**
* Close the stream, flushing it first. Once a stream has been closed,
* further write() or flush() invocations will cause an IOException to be
* thrown. Closing a previously-closed stream, however, has no effect.
*
* @throws IOException If an I/O error occurs
*/
public void close() throws IOException {
if (writer != null) {
writer.close();
} else {
closed = true;
}
}
/**
* This method returns the size of the buffer used by the JspWriter.
*
* @return the size of the buffer in bytes, or 0 is unbuffered.
*/
public int getBufferSize() {
// According to the spec, the JspWriter returned by
// JspContext.pushBody(java.io.Writer writer) must behave as
// though it were unbuffered. This means that its getBufferSize()
// must always return 0.
return (writer == null) ? bufferSize : 0;
}
/**
* @return the number of bytes unused in the buffer
*/
public int getRemaining() {
return (writer == null) ? bufferSize-nextChar : 0;
}
/**
* Return the value of this BodyJspWriter as a Reader.
* Note: this is after evaluation!! There are no scriptlets,
* etc in this stream.
*
* @return the value of this BodyJspWriter as a Reader
*/
public Reader getReader() {
return (writer == null) ? new CharArrayReader (cb, 0, nextChar) : null;
}
/**
* Return the value of the BodyJspWriter as a String.
* Note: this is after evaluation!! There are no scriptlets,
* etc in this stream.
*
* @return the value of the BodyJspWriter as a String
*/
public String getString() {
return (writer == null) ? new String(cb, 0, nextChar) : null;
}
/**
* Write the contents of this BodyJspWriter into a Writer.
* Subclasses are likely to do interesting things with the
* implementation so some things are extra efficient.
*
* @param out The writer into which to place the contents of this body
* evaluation
*/
public void writeOut(Writer out) throws IOException {
if (writer == null) {
out.write(cb, 0, nextChar);
// Flush not called as the writer passed could be a BodyContent and
// it doesn't allow to flush.
}
}
/**
* Sets the writer to which all output is written.
*/
void setWriter(Writer writer) {
this.writer = writer;
closed = false;
if (writer == null) {
clearBody();
}
}
private void ensureOpen() throws IOException {
if (closed) throw new IOException("Stream closed");
}
/**
* Reallocates buffer since the spec requires it to be unbounded.
*/
private void reAllocBuff(int len) {
if (bufferSize + len <= cb.length) {
bufferSize = cb.length;
return;
}
if (len < cb.length) {
len = cb.length;
}
bufferSize = cb.length + len;
char[] tmp = new char[bufferSize];
System.arraycopy(cb, 0, tmp, 0, cb.length);
cb = tmp;
tmp = null;
}
}
@@ -0,0 +1,88 @@
/*
* 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.jasper.runtime;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.HttpJspPage;
import javax.servlet.jsp.JspFactory;
import org.apache.jasper.compiler.Localizer;
/**
* This is the super class of all JSP-generated servlets.
*
* @author Anil K. Vijendran
*/
public abstract class HttpJspBase
extends HttpServlet
implements HttpJspPage
{
protected HttpJspBase() {
}
public final void init(ServletConfig config)
throws ServletException
{
super.init(config);
jspInit();
_jspInit();
}
public String getServletInfo() {
return Localizer.getMessage("jsp.engine.info");
}
public final void destroy() {
jspDestroy();
_jspDestroy();
}
/**
* Entry point into service.
*/
public final void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
_jspService(request, response);
}
public void jspInit() {
}
public void _jspInit() {
}
public void jspDestroy() {
}
protected void _jspDestroy() {
}
public abstract void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}
@@ -0,0 +1,138 @@
/*
* 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.jasper.runtime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.el.ArrayELResolver;
import javax.el.BeanELResolver;
import javax.el.CompositeELResolver;
import javax.el.ELContextEvent;
import javax.el.ELContextListener;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.ListELResolver;
import javax.el.MapELResolver;
import javax.el.ResourceBundleELResolver;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.el.ImplicitObjectELResolver;
import javax.servlet.jsp.el.ScopedAttributeELResolver;
import org.apache.el.ExpressionFactoryImpl;
import org.apache.jasper.el.ELContextImpl;
/**
* Implementation of JspApplicationContext
*
* @author Jacob Hookom
*/
public class JspApplicationContextImpl implements JspApplicationContext {
private final static String KEY = JspApplicationContextImpl.class.getName();
private final static ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
private final List<ELContextListener> contextListeners = new ArrayList<ELContextListener>();
private final List<ELResolver> resolvers = new ArrayList<ELResolver>();
private boolean instantiated = false;
private ELResolver resolver;
public JspApplicationContextImpl() {
}
public void addELContextListener(ELContextListener listener) {
if (listener == null) {
throw new IllegalArgumentException("ELConextListener was null");
}
this.contextListeners.add(listener);
}
public static JspApplicationContextImpl getInstance(ServletContext context) {
if (context == null) {
throw new IllegalArgumentException("ServletContext was null");
}
JspApplicationContextImpl impl = (JspApplicationContextImpl) context
.getAttribute(KEY);
if (impl == null) {
impl = new JspApplicationContextImpl();
context.setAttribute(KEY, impl);
}
return impl;
}
public ELContextImpl createELContext(JspContext context) {
if (context == null) {
throw new IllegalArgumentException("JspContext was null");
}
// create ELContext for JspContext
ELResolver r = this.createELResolver();
ELContextImpl ctx = new ELContextImpl(r);
ctx.putContext(JspContext.class, context);
// alert all ELContextListeners
ELContextEvent event = new ELContextEvent(ctx);
for (int i = 0; i < this.contextListeners.size(); i++) {
this.contextListeners.get(i).contextCreated(event);
}
return ctx;
}
private ELResolver createELResolver() {
this.instantiated = true;
if (this.resolver == null) {
CompositeELResolver r = new CompositeELResolver();
r.add(new ImplicitObjectELResolver());
for (Iterator itr = this.resolvers.iterator(); itr.hasNext();) {
r.add((ELResolver) itr.next());
}
r.add(new MapELResolver());
r.add(new ResourceBundleELResolver());
r.add(new ListELResolver());
r.add(new ArrayELResolver());
r.add(new BeanELResolver());
r.add(new ScopedAttributeELResolver());
this.resolver = r;
}
return this.resolver;
}
public void addELResolver(ELResolver resolver) throws IllegalStateException {
if (resolver == null) {
throw new IllegalArgumentException("ELResolver was null");
}
if (this.instantiated) {
throw new IllegalStateException(
"cannot call addELResolver after the first request has been made");
}
this.resolvers.add(resolver);
}
public ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
}
@@ -0,0 +1,462 @@
/*
* 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.jasper.runtime;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.el.ELContext;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.ExpressionEvaluator;
import javax.servlet.jsp.el.VariableResolver;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.VariableInfo;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.util.Enumerator;
/**
* Implementation of a JSP Context Wrapper.
*
* The JSP Context Wrapper is a JspContext created and maintained by a tag
* handler implementation. It wraps the Invoking JSP Context, that is, the
* JspContext instance passed to the tag handler by the invoking page via
* setJspContext().
*
* @author Kin-man Chung
* @author Jan Luehe
* @author Jacob Hookom
*/
public class JspContextWrapper extends PageContext implements VariableResolver {
// Invoking JSP context
private PageContext invokingJspCtxt;
private transient HashMap<String, Object> pageAttributes;
// ArrayList of NESTED scripting variables
private ArrayList nestedVars;
// ArrayList of AT_BEGIN scripting variables
private ArrayList atBeginVars;
// ArrayList of AT_END scripting variables
private ArrayList atEndVars;
private Map aliases;
private HashMap<String, Object> originalNestedVars;
public JspContextWrapper(JspContext jspContext, ArrayList nestedVars,
ArrayList atBeginVars, ArrayList atEndVars, Map aliases) {
this.invokingJspCtxt = (PageContext) jspContext;
this.nestedVars = nestedVars;
this.atBeginVars = atBeginVars;
this.atEndVars = atEndVars;
this.pageAttributes = new HashMap<String, Object>(16);
this.aliases = aliases;
if (nestedVars != null) {
this.originalNestedVars = new HashMap<String, Object>(nestedVars.size());
}
syncBeginTagFile();
}
public void initialize(Servlet servlet, ServletRequest request,
ServletResponse response, String errorPageURL,
boolean needsSession, int bufferSize, boolean autoFlush)
throws IOException, IllegalStateException, IllegalArgumentException {
}
public Object getAttribute(String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
return pageAttributes.get(name);
}
public Object getAttribute(String name, int scope) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (scope == PAGE_SCOPE) {
return pageAttributes.get(name);
}
return invokingJspCtxt.getAttribute(name, scope);
}
public void setAttribute(String name, Object value) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (value != null) {
pageAttributes.put(name, value);
} else {
removeAttribute(name, PAGE_SCOPE);
}
}
public void setAttribute(String name, Object value, int scope) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (scope == PAGE_SCOPE) {
if (value != null) {
pageAttributes.put(name, value);
} else {
removeAttribute(name, PAGE_SCOPE);
}
} else {
invokingJspCtxt.setAttribute(name, value, scope);
}
}
public Object findAttribute(String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
Object o = pageAttributes.get(name);
if (o == null) {
o = invokingJspCtxt.getAttribute(name, REQUEST_SCOPE);
if (o == null) {
if (getSession() != null) {
o = invokingJspCtxt.getAttribute(name, SESSION_SCOPE);
}
if (o == null) {
o = invokingJspCtxt.getAttribute(name, APPLICATION_SCOPE);
}
}
}
return o;
}
public void removeAttribute(String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
pageAttributes.remove(name);
invokingJspCtxt.removeAttribute(name, REQUEST_SCOPE);
if (getSession() != null) {
invokingJspCtxt.removeAttribute(name, SESSION_SCOPE);
}
invokingJspCtxt.removeAttribute(name, APPLICATION_SCOPE);
}
public void removeAttribute(String name, int scope) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (scope == PAGE_SCOPE) {
pageAttributes.remove(name);
} else {
invokingJspCtxt.removeAttribute(name, scope);
}
}
public int getAttributesScope(String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (pageAttributes.get(name) != null) {
return PAGE_SCOPE;
} else {
return invokingJspCtxt.getAttributesScope(name);
}
}
public Enumeration<String> getAttributeNamesInScope(int scope) {
if (scope == PAGE_SCOPE) {
return new Enumerator(pageAttributes.keySet().iterator());
}
return invokingJspCtxt.getAttributeNamesInScope(scope);
}
public void release() {
invokingJspCtxt.release();
}
public JspWriter getOut() {
return invokingJspCtxt.getOut();
}
public HttpSession getSession() {
return invokingJspCtxt.getSession();
}
public Object getPage() {
return invokingJspCtxt.getPage();
}
public ServletRequest getRequest() {
return invokingJspCtxt.getRequest();
}
public ServletResponse getResponse() {
return invokingJspCtxt.getResponse();
}
public Exception getException() {
return invokingJspCtxt.getException();
}
public ServletConfig getServletConfig() {
return invokingJspCtxt.getServletConfig();
}
public ServletContext getServletContext() {
return invokingJspCtxt.getServletContext();
}
public void forward(String relativeUrlPath) throws ServletException,
IOException {
invokingJspCtxt.forward(relativeUrlPath);
}
public void include(String relativeUrlPath) throws ServletException,
IOException {
invokingJspCtxt.include(relativeUrlPath);
}
public void include(String relativeUrlPath, boolean flush)
throws ServletException, IOException {
invokingJspCtxt.include(relativeUrlPath, false);
}
public VariableResolver getVariableResolver() {
return this;
}
public BodyContent pushBody() {
return invokingJspCtxt.pushBody();
}
public JspWriter pushBody(Writer writer) {
return invokingJspCtxt.pushBody(writer);
}
public JspWriter popBody() {
return invokingJspCtxt.popBody();
}
public ExpressionEvaluator getExpressionEvaluator() {
return invokingJspCtxt.getExpressionEvaluator();
}
public void handlePageException(Exception ex) throws IOException,
ServletException {
// Should never be called since handleException() called with a
// Throwable in the generated servlet.
handlePageException((Throwable) ex);
}
public void handlePageException(Throwable t) throws IOException,
ServletException {
invokingJspCtxt.handlePageException(t);
}
/**
* VariableResolver interface
*/
public Object resolveVariable(String pName) throws ELException {
ELContext ctx = this.getELContext();
return ctx.getELResolver().getValue(ctx, null, pName);
}
/**
* Synchronize variables at begin of tag file
*/
public void syncBeginTagFile() {
saveNestedVariables();
}
/**
* Synchronize variables before fragment invokation
*/
public void syncBeforeInvoke() {
copyTagToPageScope(VariableInfo.NESTED);
copyTagToPageScope(VariableInfo.AT_BEGIN);
}
/**
* Synchronize variables at end of tag file
*/
public void syncEndTagFile() {
copyTagToPageScope(VariableInfo.AT_BEGIN);
copyTagToPageScope(VariableInfo.AT_END);
restoreNestedVariables();
}
/**
* Copies the variables of the given scope from the virtual page scope of
* this JSP context wrapper to the page scope of the invoking JSP context.
*
* @param scope
* variable scope (one of NESTED, AT_BEGIN, or AT_END)
*/
private void copyTagToPageScope(int scope) {
Iterator iter = null;
switch (scope) {
case VariableInfo.NESTED:
if (nestedVars != null) {
iter = nestedVars.iterator();
}
break;
case VariableInfo.AT_BEGIN:
if (atBeginVars != null) {
iter = atBeginVars.iterator();
}
break;
case VariableInfo.AT_END:
if (atEndVars != null) {
iter = atEndVars.iterator();
}
break;
}
while ((iter != null) && iter.hasNext()) {
String varName = (String) iter.next();
Object obj = getAttribute(varName);
varName = findAlias(varName);
if (obj != null) {
invokingJspCtxt.setAttribute(varName, obj);
} else {
invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE);
}
}
}
/**
* Saves the values of any NESTED variables that are present in the invoking
* JSP context, so they can later be restored.
*/
private void saveNestedVariables() {
if (nestedVars != null) {
Iterator iter = nestedVars.iterator();
while (iter.hasNext()) {
String varName = (String) iter.next();
varName = findAlias(varName);
Object obj = invokingJspCtxt.getAttribute(varName);
if (obj != null) {
originalNestedVars.put(varName, obj);
}
}
}
}
/**
* Restores the values of any NESTED variables in the invoking JSP context.
*/
private void restoreNestedVariables() {
if (nestedVars != null) {
Iterator iter = nestedVars.iterator();
while (iter.hasNext()) {
String varName = (String) iter.next();
varName = findAlias(varName);
Object obj = originalNestedVars.get(varName);
if (obj != null) {
invokingJspCtxt.setAttribute(varName, obj);
} else {
invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE);
}
}
}
}
/**
* Checks to see if the given variable name is used as an alias, and if so,
* returns the variable name for which it is used as an alias.
*
* @param varName
* The variable name to check
* @return The variable name for which varName is used as an alias, or
* varName if it is not being used as an alias
*/
private String findAlias(String varName) {
if (aliases == null)
return varName;
String alias = (String) aliases.get(varName);
if (alias == null) {
return varName;
}
return alias;
}
//private ELContextImpl elContext;
public ELContext getELContext() {
// instead decorate!!!
return this.invokingJspCtxt.getELContext();
/*
if (this.elContext != null) {
JspFactory jspFact = JspFactory.getDefaultFactory();
ServletContext servletContext = this.getServletContext();
JspApplicationContextImpl jspCtx = (JspApplicationContextImpl) jspFact
.getJspApplicationContext(servletContext);
this.elContext = jspCtx.createELContext(this);
}
return this.elContext;
*/
}
}
@@ -0,0 +1,202 @@
/*
* 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.jasper.runtime;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspEngineInfo;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.PageContext;
import org.apache.jasper.Constants;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* Implementation of JspFactory.
*
* @author Anil K. Vijendran
*/
public class JspFactoryImpl extends JspFactory {
// Logger
private Log log = LogFactory.getLog(JspFactoryImpl.class);
private static final String SPEC_VERSION = "2.1";
private static final boolean USE_POOL =
Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.JspFactoryImpl.USE_POOL", "true")).booleanValue();
private static final int POOL_SIZE =
Integer.valueOf(System.getProperty("org.apache.jasper.runtime.JspFactoryImpl.POOL_SIZE", "8")).intValue();
private ThreadLocal<PageContextPool> localPool = new ThreadLocal<PageContextPool>();
public PageContext getPageContext(Servlet servlet, ServletRequest request,
ServletResponse response, String errorPageURL, boolean needsSession,
int bufferSize, boolean autoflush) {
if( Constants.IS_SECURITY_ENABLED ) {
PrivilegedGetPageContext dp = new PrivilegedGetPageContext(
(JspFactoryImpl)this, servlet, request, response, errorPageURL,
needsSession, bufferSize, autoflush);
return (PageContext)AccessController.doPrivileged(dp);
} else {
return internalGetPageContext(servlet, request, response,
errorPageURL, needsSession,
bufferSize, autoflush);
}
}
public void releasePageContext(PageContext pc) {
if( pc == null )
return;
if( Constants.IS_SECURITY_ENABLED ) {
PrivilegedReleasePageContext dp = new PrivilegedReleasePageContext(
(JspFactoryImpl)this,pc);
AccessController.doPrivileged(dp);
} else {
internalReleasePageContext(pc);
}
}
public JspEngineInfo getEngineInfo() {
return new JspEngineInfo() {
public String getSpecificationVersion() {
return SPEC_VERSION;
}
};
}
private PageContext internalGetPageContext(Servlet servlet, ServletRequest request,
ServletResponse response, String errorPageURL, boolean needsSession,
int bufferSize, boolean autoflush) {
try {
PageContext pc;
if (USE_POOL) {
PageContextPool pool = localPool.get();
if (pool == null) {
pool = new PageContextPool();
localPool.set(pool);
}
pc = pool.get();
if (pc == null) {
pc = new PageContextImpl();
}
} else {
pc = new PageContextImpl();
}
pc.initialize(servlet, request, response, errorPageURL,
needsSession, bufferSize, autoflush);
return pc;
} catch (Throwable ex) {
/* FIXME: need to do something reasonable here!! */
log.fatal("Exception initializing page context", ex);
return null;
}
}
private void internalReleasePageContext(PageContext pc) {
pc.release();
if (USE_POOL && (pc instanceof PageContextImpl)) {
localPool.get().put(pc);
}
}
private class PrivilegedGetPageContext implements PrivilegedAction {
private JspFactoryImpl factory;
private Servlet servlet;
private ServletRequest request;
private ServletResponse response;
private String errorPageURL;
private boolean needsSession;
private int bufferSize;
private boolean autoflush;
PrivilegedGetPageContext(JspFactoryImpl factory, Servlet servlet,
ServletRequest request, ServletResponse response, String errorPageURL,
boolean needsSession, int bufferSize, boolean autoflush) {
this.factory = factory;
this.servlet = servlet;
this.request = request;
this.response = response;
this.errorPageURL = errorPageURL;
this.needsSession = needsSession;
this.bufferSize = bufferSize;
this.autoflush = autoflush;
}
public Object run() {
return factory.internalGetPageContext(servlet, request, response,
errorPageURL, needsSession, bufferSize, autoflush);
}
}
private class PrivilegedReleasePageContext implements PrivilegedAction {
private JspFactoryImpl factory;
private PageContext pageContext;
PrivilegedReleasePageContext(JspFactoryImpl factory,
PageContext pageContext) {
this.factory = factory;
this.pageContext = pageContext;
}
public Object run() {
factory.internalReleasePageContext(pageContext);
return null;
}
}
protected final class PageContextPool {
private PageContext[] pool;
private int current = -1;
public PageContextPool() {
this.pool = new PageContext[POOL_SIZE];
}
public void put(PageContext o) {
if (current < (POOL_SIZE - 1)) {
current++;
pool[current] = o;
}
}
public PageContext get() {
PageContext item = null;
if (current >= 0) {
item = pool[current];
current--;
}
return item;
}
}
public JspApplicationContext getJspApplicationContext(ServletContext context) {
return JspApplicationContextImpl.getInstance(context);
}
}
@@ -0,0 +1,65 @@
/*
* 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.jasper.runtime;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
/**
* Helper class from which all Jsp Fragment helper classes extend.
* This class allows for the emulation of numerous fragments within
* a single class, which in turn reduces the load on the class loader
* since there are potentially many JspFragments in a single page.
* <p>
* The class also provides various utility methods for JspFragment
* implementations.
*
* @author Mark Roth
*/
public abstract class JspFragmentHelper
extends JspFragment
{
protected int discriminator;
protected JspContext jspContext;
protected PageContext _jspx_page_context;
protected JspTag parentTag;
public JspFragmentHelper( int discriminator, JspContext jspContext,
JspTag parentTag )
{
this.discriminator = discriminator;
this.jspContext = jspContext;
this._jspx_page_context = null;
if( jspContext instanceof PageContext ) {
_jspx_page_context = (PageContext)jspContext;
}
this.parentTag = parentTag;
}
public JspContext getJspContext() {
return this.jspContext;
}
public JspTag getParentTag() {
return this.parentTag;
}
}
@@ -0,0 +1,39 @@
/*
* 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.jasper.runtime;
/**
* Interface for tracking the source files dependencies, for the purpose
* of compiling out of date pages. This is used for
* 1) files that are included by page directives
* 2) files that are included by include-prelude and include-coda in jsp:config
* 3) files that are tag files and referenced
* 4) TLDs referenced
*/
public interface JspSourceDependent {
/**
* Returns a list of files names that the current page has a source
* dependency on.
*/
// FIXME: Type used is Object due to very weird behavior
// with Eclipse JDT 3.1 in Java 5 mode
public Object getDependants();
}
@@ -0,0 +1,590 @@
/*
* 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.jasper.runtime;
import java.io.IOException;
import java.io.Writer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.servlet.ServletResponse;
import javax.servlet.jsp.JspWriter;
import org.apache.jasper.Constants;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.security.SecurityUtil;
/**
* Write text to a character-output stream, buffering characters so as
* to provide for the efficient writing of single characters, arrays,
* and strings.
*
* Provide support for discarding for the output that has been
* buffered.
*
* This needs revisiting when the buffering problems in the JSP spec
* are fixed -akv
*
* @author Anil K. Vijendran
*/
public class JspWriterImpl extends JspWriter {
private Writer out;
private ServletResponse response;
private char cb[];
private int nextChar;
private boolean flushed = false;
private boolean closed = false;
public JspWriterImpl() {
super( Constants.DEFAULT_BUFFER_SIZE, true );
}
/**
* Create a buffered character-output stream that uses a default-sized
* output buffer.
*
* @param response A Servlet Response
*/
public JspWriterImpl(ServletResponse response) {
this(response, Constants.DEFAULT_BUFFER_SIZE, true);
}
/**
* Create a new buffered character-output stream that uses an output
* buffer of the given size.
*
* @param response A Servlet Response
* @param sz Output-buffer size, a positive integer
*
* @exception IllegalArgumentException If sz is <= 0
*/
public JspWriterImpl(ServletResponse response, int sz,
boolean autoFlush) {
super(sz, autoFlush);
if (sz < 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.response = response;
cb = sz == 0 ? null : new char[sz];
nextChar = 0;
}
void init( ServletResponse response, int sz, boolean autoFlush ) {
this.response= response;
if( sz > 0 && ( cb == null || sz > cb.length ) )
cb=new char[sz];
nextChar = 0;
this.autoFlush=autoFlush;
this.bufferSize=sz;
}
/** Package-level access
*/
void recycle() {
flushed = false;
closed = false;
out = null;
nextChar = 0;
response = null;
}
/**
* Flush the output buffer to the underlying character stream, without
* flushing the stream itself. This method is non-private only so that it
* may be invoked by PrintStream.
*/
protected final void flushBuffer() throws IOException {
if (bufferSize == 0)
return;
flushed = true;
ensureOpen();
if (nextChar == 0)
return;
initOut();
out.write(cb, 0, nextChar);
nextChar = 0;
}
private void initOut() throws IOException {
if (out == null) {
out = response.getWriter();
}
}
private String getLocalizeMessage(final String message){
if (SecurityUtil.isPackageProtectionEnabled()){
return (String)AccessController.doPrivileged(new PrivilegedAction(){
public Object run(){
return Localizer.getMessage(message);
}
});
} else {
return Localizer.getMessage(message);
}
}
/**
* Discard the output buffer.
*/
public final void clear() throws IOException {
if ((bufferSize == 0) && (out != null))
// clear() is illegal after any unbuffered output (JSP.5.5)
throw new IllegalStateException(
getLocalizeMessage("jsp.error.ise_on_clear"));
if (flushed)
throw new IOException(
getLocalizeMessage("jsp.error.attempt_to_clear_flushed_buffer"));
ensureOpen();
nextChar = 0;
}
public void clearBuffer() throws IOException {
if (bufferSize == 0)
throw new IllegalStateException(
getLocalizeMessage("jsp.error.ise_on_clear"));
ensureOpen();
nextChar = 0;
}
private final void bufferOverflow() throws IOException {
throw new IOException(getLocalizeMessage("jsp.error.overflow"));
}
/**
* Flush the stream.
*
*/
public void flush() throws IOException {
flushBuffer();
if (out != null) {
out.flush();
}
}
/**
* Close the stream.
*
*/
public void close() throws IOException {
if (response == null || closed)
// multiple calls to close is OK
return;
flush();
if (out != null)
out.close();
out = null;
closed = true;
}
/**
* @return the number of bytes unused in the buffer
*/
public int getRemaining() {
return bufferSize - nextChar;
}
/** check to make sure that the stream has not been closed */
private void ensureOpen() throws IOException {
if (response == null || closed)
throw new IOException("Stream closed");
}
/**
* Write a single character.
*/
public void write(int c) throws IOException {
ensureOpen();
if (bufferSize == 0) {
initOut();
out.write(c);
}
else {
if (nextChar >= bufferSize)
if (autoFlush)
flushBuffer();
else
bufferOverflow();
cb[nextChar++] = (char) c;
}
}
/**
* Our own little min method, to avoid loading java.lang.Math if we've run
* out of file descriptors and we're trying to print a stack trace.
*/
private int min(int a, int b) {
if (a < b) return a;
return b;
}
/**
* Write a portion of an array of characters.
*
* <p> Ordinarily this method stores characters from the given array into
* this stream's buffer, flushing the buffer to the underlying stream as
* needed. If the requested length is at least as large as the buffer,
* however, then this method will flush the buffer and write the characters
* directly to the underlying stream. Thus redundant
* <code>DiscardableBufferedWriter</code>s will not copy data unnecessarily.
*
* @param cbuf A character array
* @param off Offset from which to start reading characters
* @param len Number of characters to write
*/
public void write(char cbuf[], int off, int len)
throws IOException
{
ensureOpen();
if (bufferSize == 0) {
initOut();
out.write(cbuf, off, len);
return;
}
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
if (len >= bufferSize) {
/* If the request length exceeds the size of the output buffer,
flush the buffer and then write the data directly. In this
way buffered streams will cascade harmlessly. */
if (autoFlush)
flushBuffer();
else
bufferOverflow();
initOut();
out.write(cbuf, off, len);
return;
}
int b = off, t = off + len;
while (b < t) {
int d = min(bufferSize - nextChar, t - b);
System.arraycopy(cbuf, b, cb, nextChar, d);
b += d;
nextChar += d;
if (nextChar >= bufferSize)
if (autoFlush)
flushBuffer();
else
bufferOverflow();
}
}
/**
* Write an array of characters. This method cannot be inherited from the
* Writer class because it must suppress I/O exceptions.
*/
public void write(char buf[]) throws IOException {
write(buf, 0, buf.length);
}
/**
* Write a portion of a String.
*
* @param s String to be written
* @param off Offset from which to start reading characters
* @param len Number of characters to be written
*/
public void write(String s, int off, int len) throws IOException {
ensureOpen();
if (bufferSize == 0) {
initOut();
out.write(s, off, len);
return;
}
int b = off, t = off + len;
while (b < t) {
int d = min(bufferSize - nextChar, t - b);
s.getChars(b, b + d, cb, nextChar);
b += d;
nextChar += d;
if (nextChar >= bufferSize)
if (autoFlush)
flushBuffer();
else
bufferOverflow();
}
}
/**
* Write a string. This method cannot be inherited from the Writer class
* because it must suppress I/O exceptions.
*/
public void write(String s) throws IOException {
// Simple fix for Bugzilla 35410
// Calling the other write function so as to init the buffer anyways
if(s == null) {
write(s, 0, 0);
} else {
write(s, 0, s.length());
}
}
static String lineSeparator = System.getProperty("line.separator");
/**
* Write a line separator. The line separator string is defined by the
* system property <tt>line.separator</tt>, and is not necessarily a single
* newline ('\n') character.
*
* @exception IOException If an I/O error occurs
*/
public void newLine() throws IOException {
write(lineSeparator);
}
/* Methods that do not terminate lines */
/**
* Print a boolean value. The string produced by <code>{@link
* java.lang.String#valueOf(boolean)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param b The <code>boolean</code> to be printed
*/
public void print(boolean b) throws IOException {
write(b ? "true" : "false");
}
/**
* Print a character. The character is translated into one or more bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param c The <code>char</code> to be printed
*/
public void print(char c) throws IOException {
write(String.valueOf(c));
}
/**
* Print an integer. The string produced by <code>{@link
* java.lang.String#valueOf(int)}</code> is translated into bytes according
* to the platform's default character encoding, and these bytes are
* written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param i The <code>int</code> to be printed
*/
public void print(int i) throws IOException {
write(String.valueOf(i));
}
/**
* Print a long integer. The string produced by <code>{@link
* java.lang.String#valueOf(long)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param l The <code>long</code> to be printed
*/
public void print(long l) throws IOException {
write(String.valueOf(l));
}
/**
* Print a floating-point number. The string produced by <code>{@link
* java.lang.String#valueOf(float)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param f The <code>float</code> to be printed
*/
public void print(float f) throws IOException {
write(String.valueOf(f));
}
/**
* Print a double-precision floating-point number. The string produced by
* <code>{@link java.lang.String#valueOf(double)}</code> is translated into
* bytes according to the platform's default character encoding, and these
* bytes are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param d The <code>double</code> to be printed
*/
public void print(double d) throws IOException {
write(String.valueOf(d));
}
/**
* Print an array of characters. The characters are converted into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param s The array of chars to be printed
*
* @throws NullPointerException If <code>s</code> is <code>null</code>
*/
public void print(char s[]) throws IOException {
write(s);
}
/**
* Print a string. If the argument is <code>null</code> then the string
* <code>"null"</code> is printed. Otherwise, the string's characters are
* converted into bytes according to the platform's default character
* encoding, and these bytes are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param s The <code>String</code> to be printed
*/
public void print(String s) throws IOException {
if (s == null) {
s = "null";
}
write(s);
}
/**
* Print an object. The string produced by the <code>{@link
* java.lang.String#valueOf(Object)}</code> method is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param obj The <code>Object</code> to be printed
*/
public void print(Object obj) throws IOException {
write(String.valueOf(obj));
}
/* Methods that do terminate lines */
/**
* Terminate the current line by writing the line separator string. The
* line separator string is defined by the system property
* <code>line.separator</code>, and is not necessarily a single newline
* character (<code>'\n'</code>).
*
* Need to change this from PrintWriter because the default
* println() writes to the sink directly instead of through the
* write method...
*/
public void println() throws IOException {
newLine();
}
/**
* Print a boolean value and then terminate the line. This method behaves
* as though it invokes <code>{@link #print(boolean)}</code> and then
* <code>{@link #println()}</code>.
*/
public void println(boolean x) throws IOException {
print(x);
println();
}
/**
* Print a character and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(char)}</code> and then <code>{@link
* #println()}</code>.
*/
public void println(char x) throws IOException {
print(x);
println();
}
/**
* Print an integer and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(int)}</code> and then <code>{@link
* #println()}</code>.
*/
public void println(int x) throws IOException {
print(x);
println();
}
/**
* Print a long integer and then terminate the line. This method behaves
* as though it invokes <code>{@link #print(long)}</code> and then
* <code>{@link #println()}</code>.
*/
public void println(long x) throws IOException {
print(x);
println();
}
/**
* Print a floating-point number and then terminate the line. This method
* behaves as though it invokes <code>{@link #print(float)}</code> and then
* <code>{@link #println()}</code>.
*/
public void println(float x) throws IOException {
print(x);
println();
}
/**
* Print a double-precision floating-point number and then terminate the
* line. This method behaves as though it invokes <code>{@link
* #print(double)}</code> and then <code>{@link #println()}</code>.
*/
public void println(double x) throws IOException {
print(x);
println();
}
/**
* Print an array of characters and then terminate the line. This method
* behaves as though it invokes <code>{@link #print(char[])}</code> and then
* <code>{@link #println()}</code>.
*/
public void println(char x[]) throws IOException {
print(x);
println();
}
/**
* Print a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*/
public void println(String x) throws IOException {
print(x);
println();
}
/**
* Print an Object and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(Object)}</code> and then
* <code>{@link #println()}</code>.
*/
public void println(Object x) throws IOException {
print(x);
println();
}
}
@@ -0,0 +1,951 @@
/*
* 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.jasper.runtime;
import java.io.IOException;
import java.io.Writer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Enumeration;
import java.util.HashMap;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.ExpressionEvaluator;
import javax.servlet.jsp.el.VariableResolver;
import javax.servlet.jsp.tagext.BodyContent;
import org.apache.jasper.Constants;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.el.ELContextImpl;
import org.apache.jasper.el.ExpressionEvaluatorImpl;
import org.apache.jasper.el.FunctionMapperImpl;
import org.apache.jasper.el.VariableResolverImpl;
import org.apache.jasper.security.SecurityUtil;
import org.apache.jasper.util.Enumerator;
/**
* Implementation of the PageContext class from the JSP spec. Also doubles as a
* VariableResolver for the EL.
*
* @author Anil K. Vijendran
* @author Larry Cable
* @author Hans Bergsten
* @author Pierre Delisle
* @author Mark Roth
* @author Jan Luehe
* @author Jacob Hookom
*/
public class PageContextImpl extends PageContext {
private static final JspFactory jspf = JspFactory.getDefaultFactory();
private BodyContentImpl[] outs;
private int depth;
// per-servlet state
private Servlet servlet;
private ServletConfig config;
private ServletContext context;
private JspApplicationContextImpl applicationContext;
private String errorPageURL;
// page-scope attributes
private transient HashMap<String, Object> attributes;
// per-request state
private transient ServletRequest request;
private transient ServletResponse response;
private transient HttpSession session;
private transient ELContextImpl elContext;
private boolean isIncluded;
// initial output stream
private transient JspWriter out;
private transient JspWriterImpl baseOut;
/*
* Constructor.
*/
PageContextImpl() {
this.outs = new BodyContentImpl[0];
this.attributes = new HashMap<String, Object>(16);
this.depth = -1;
}
public void initialize(Servlet servlet, ServletRequest request,
ServletResponse response, String errorPageURL,
boolean needsSession, int bufferSize, boolean autoFlush)
throws IOException {
_initialize(servlet, request, response, errorPageURL, needsSession,
bufferSize, autoFlush);
}
private void _initialize(Servlet servlet, ServletRequest request,
ServletResponse response, String errorPageURL,
boolean needsSession, int bufferSize, boolean autoFlush)
throws IOException {
// initialize state
this.servlet = servlet;
this.config = servlet.getServletConfig();
this.context = config.getServletContext();
this.errorPageURL = errorPageURL;
this.request = request;
this.response = response;
// initialize application context
this.applicationContext = JspApplicationContextImpl.getInstance(context);
// Setup session (if required)
if (request instanceof HttpServletRequest && needsSession)
this.session = ((HttpServletRequest) request).getSession();
if (needsSession && session == null)
throw new IllegalStateException(
"Page needs a session and none is available");
// initialize the initial out ...
depth = -1;
if (this.baseOut == null) {
this.baseOut = new JspWriterImpl(response, bufferSize, autoFlush);
} else {
this.baseOut.init(response, bufferSize, autoFlush);
}
this.out = baseOut;
// register names/values as per spec
setAttribute(OUT, this.out);
setAttribute(REQUEST, request);
setAttribute(RESPONSE, response);
if (session != null)
setAttribute(SESSION, session);
setAttribute(PAGE, servlet);
setAttribute(CONFIG, config);
setAttribute(PAGECONTEXT, this);
setAttribute(APPLICATION, context);
isIncluded = request.getAttribute("javax.servlet.include.servlet_path") != null;
}
public void release() {
out = baseOut;
try {
if (isIncluded) {
((JspWriterImpl) out).flushBuffer();
// push it into the including jspWriter
} else {
// Old code:
// out.flush();
// Do not flush the buffer even if we're not included (i.e.
// we are the main page. The servlet will flush it and close
// the stream.
((JspWriterImpl) out).flushBuffer();
}
} catch (IOException ex) {
IllegalStateException ise = new IllegalStateException(Localizer.getMessage("jsp.error.flush"), ex);
throw ise;
} finally {
servlet = null;
config = null;
context = null;
applicationContext = null;
elContext = null;
errorPageURL = null;
request = null;
response = null;
depth = -1;
baseOut.recycle();
session = null;
attributes.clear();
}
}
public Object getAttribute(final String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (SecurityUtil.isPackageProtectionEnabled()) {
return AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return doGetAttribute(name);
}
});
} else {
return doGetAttribute(name);
}
}
private Object doGetAttribute(String name) {
return attributes.get(name);
}
public Object getAttribute(final String name, final int scope) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (SecurityUtil.isPackageProtectionEnabled()) {
return AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return doGetAttribute(name, scope);
}
});
} else {
return doGetAttribute(name, scope);
}
}
private Object doGetAttribute(String name, int scope) {
switch (scope) {
case PAGE_SCOPE:
return attributes.get(name);
case REQUEST_SCOPE:
return request.getAttribute(name);
case SESSION_SCOPE:
if (session == null) {
throw new IllegalStateException(Localizer
.getMessage("jsp.error.page.noSession"));
}
return session.getAttribute(name);
case APPLICATION_SCOPE:
return context.getAttribute(name);
default:
throw new IllegalArgumentException("Invalid scope");
}
}
public void setAttribute(final String name, final Object attribute) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (SecurityUtil.isPackageProtectionEnabled()) {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
doSetAttribute(name, attribute);
return null;
}
});
} else {
doSetAttribute(name, attribute);
}
}
private void doSetAttribute(String name, Object attribute) {
if (attribute != null) {
attributes.put(name, attribute);
} else {
removeAttribute(name, PAGE_SCOPE);
}
}
public void setAttribute(final String name, final Object o, final int scope) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (SecurityUtil.isPackageProtectionEnabled()) {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
doSetAttribute(name, o, scope);
return null;
}
});
} else {
doSetAttribute(name, o, scope);
}
}
private void doSetAttribute(String name, Object o, int scope) {
if (o != null) {
switch (scope) {
case PAGE_SCOPE:
attributes.put(name, o);
break;
case REQUEST_SCOPE:
request.setAttribute(name, o);
break;
case SESSION_SCOPE:
if (session == null) {
throw new IllegalStateException(Localizer
.getMessage("jsp.error.page.noSession"));
}
session.setAttribute(name, o);
break;
case APPLICATION_SCOPE:
context.setAttribute(name, o);
break;
default:
throw new IllegalArgumentException("Invalid scope");
}
} else {
removeAttribute(name, scope);
}
}
public void removeAttribute(final String name, final int scope) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (SecurityUtil.isPackageProtectionEnabled()) {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
doRemoveAttribute(name, scope);
return null;
}
});
} else {
doRemoveAttribute(name, scope);
}
}
private void doRemoveAttribute(String name, int scope) {
switch (scope) {
case PAGE_SCOPE:
attributes.remove(name);
break;
case REQUEST_SCOPE:
request.removeAttribute(name);
break;
case SESSION_SCOPE:
if (session == null) {
throw new IllegalStateException(Localizer
.getMessage("jsp.error.page.noSession"));
}
session.removeAttribute(name);
break;
case APPLICATION_SCOPE:
context.removeAttribute(name);
break;
default:
throw new IllegalArgumentException("Invalid scope");
}
}
public int getAttributesScope(final String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (SecurityUtil.isPackageProtectionEnabled()) {
return ((Integer) AccessController
.doPrivileged(new PrivilegedAction() {
public Object run() {
return new Integer(doGetAttributeScope(name));
}
})).intValue();
} else {
return doGetAttributeScope(name);
}
}
private int doGetAttributeScope(String name) {
if (attributes.get(name) != null)
return PAGE_SCOPE;
if (request.getAttribute(name) != null)
return REQUEST_SCOPE;
if (session != null) {
try {
if (session.getAttribute(name) != null)
return SESSION_SCOPE;
} catch(IllegalStateException ise) {
// Session has been invalidated.
// Ignore and fall through to application scope.
}
}
if (context.getAttribute(name) != null)
return APPLICATION_SCOPE;
return 0;
}
public Object findAttribute(final String name) {
if (SecurityUtil.isPackageProtectionEnabled()) {
return AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
return doFindAttribute(name);
}
});
} else {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
return doFindAttribute(name);
}
}
private Object doFindAttribute(String name) {
Object o = attributes.get(name);
if (o != null)
return o;
o = request.getAttribute(name);
if (o != null)
return o;
if (session != null) {
try {
o = session.getAttribute(name);
} catch(IllegalStateException ise) {
// Session has been invalidated.
// Ignore and fall through to application scope.
}
if (o != null)
return o;
}
return context.getAttribute(name);
}
public Enumeration<String> getAttributeNamesInScope(final int scope) {
if (SecurityUtil.isPackageProtectionEnabled()) {
return (Enumeration) AccessController
.doPrivileged(new PrivilegedAction() {
public Object run() {
return doGetAttributeNamesInScope(scope);
}
});
} else {
return doGetAttributeNamesInScope(scope);
}
}
private Enumeration doGetAttributeNamesInScope(int scope) {
switch (scope) {
case PAGE_SCOPE:
return new Enumerator(attributes.keySet().iterator());
case REQUEST_SCOPE:
return request.getAttributeNames();
case SESSION_SCOPE:
if (session == null) {
throw new IllegalStateException(Localizer
.getMessage("jsp.error.page.noSession"));
}
return session.getAttributeNames();
case APPLICATION_SCOPE:
return context.getAttributeNames();
default:
throw new IllegalArgumentException("Invalid scope");
}
}
public void removeAttribute(final String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (SecurityUtil.isPackageProtectionEnabled()) {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
doRemoveAttribute(name);
return null;
}
});
} else {
doRemoveAttribute(name);
}
}
private void doRemoveAttribute(String name) {
removeAttribute(name, PAGE_SCOPE);
removeAttribute(name, REQUEST_SCOPE);
if( session != null ) {
try {
removeAttribute(name, SESSION_SCOPE);
} catch(IllegalStateException ise) {
// Session has been invalidated.
// Ignore and fall throw to application scope.
}
}
removeAttribute(name, APPLICATION_SCOPE);
}
public JspWriter getOut() {
return out;
}
public HttpSession getSession() {
return session;
}
public Servlet getServlet() {
return servlet;
}
public ServletConfig getServletConfig() {
return config;
}
public ServletContext getServletContext() {
return config.getServletContext();
}
public ServletRequest getRequest() {
return request;
}
public ServletResponse getResponse() {
return response;
}
/**
* Returns the exception associated with this page context, if any. <p/>
* Added wrapping for Throwables to avoid ClassCastException: see Bugzilla
* 31171 for details.
*
* @return The Exception associated with this page context, if any.
*/
public Exception getException() {
Throwable t = JspRuntimeLibrary.getThrowable(request);
// Only wrap if needed
if ((t != null) && (!(t instanceof Exception))) {
t = new JspException(t);
}
return (Exception) t;
}
public Object getPage() {
return servlet;
}
private final String getAbsolutePathRelativeToContext(String relativeUrlPath) {
String path = relativeUrlPath;
if (!path.startsWith("/")) {
String uri = (String) request
.getAttribute("javax.servlet.include.servlet_path");
if (uri == null)
uri = ((HttpServletRequest) request).getServletPath();
String baseURI = uri.substring(0, uri.lastIndexOf('/'));
path = baseURI + '/' + path;
}
return path;
}
public void include(String relativeUrlPath) throws ServletException,
IOException {
JspRuntimeLibrary
.include(request, response, relativeUrlPath, out, true);
}
public void include(final String relativeUrlPath, final boolean flush)
throws ServletException, IOException {
if (SecurityUtil.isPackageProtectionEnabled()) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
doInclude(relativeUrlPath, flush);
return null;
}
});
} catch (PrivilegedActionException e) {
Exception ex = e.getException();
if (ex instanceof IOException) {
throw (IOException) ex;
} else {
throw (ServletException) ex;
}
}
} else {
doInclude(relativeUrlPath, flush);
}
}
private void doInclude(String relativeUrlPath, boolean flush)
throws ServletException, IOException {
JspRuntimeLibrary.include(request, response, relativeUrlPath, out,
flush);
}
public VariableResolver getVariableResolver() {
return new VariableResolverImpl(this.getELContext());
}
public void forward(final String relativeUrlPath) throws ServletException,
IOException {
if (SecurityUtil.isPackageProtectionEnabled()) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
doForward(relativeUrlPath);
return null;
}
});
} catch (PrivilegedActionException e) {
Exception ex = e.getException();
if (ex instanceof IOException) {
throw (IOException) ex;
} else {
throw (ServletException) ex;
}
}
} else {
doForward(relativeUrlPath);
}
}
private void doForward(String relativeUrlPath) throws ServletException,
IOException {
// JSP.4.5 If the buffer was flushed, throw IllegalStateException
try {
out.clear();
} catch (IOException ex) {
IllegalStateException ise = new IllegalStateException(Localizer
.getMessage("jsp.error.attempt_to_clear_flushed_buffer"));
ise.initCause(ex);
throw ise;
}
// Make sure that the response object is not the wrapper for include
while (response instanceof ServletResponseWrapperInclude) {
response = ((ServletResponseWrapperInclude) response).getResponse();
}
final String path = getAbsolutePathRelativeToContext(relativeUrlPath);
String includeUri = (String) request
.getAttribute(Constants.INC_SERVLET_PATH);
if (includeUri != null)
request.removeAttribute(Constants.INC_SERVLET_PATH);
try {
context.getRequestDispatcher(path).forward(request, response);
} finally {
if (includeUri != null)
request.setAttribute(Constants.INC_SERVLET_PATH, includeUri);
}
}
public BodyContent pushBody() {
return (BodyContent) pushBody(null);
}
public JspWriter pushBody(Writer writer) {
depth++;
if (depth >= outs.length) {
BodyContentImpl[] newOuts = new BodyContentImpl[depth + 1];
for (int i = 0; i < outs.length; i++) {
newOuts[i] = outs[i];
}
newOuts[depth] = new BodyContentImpl(out);
outs = newOuts;
}
outs[depth].setWriter(writer);
out = outs[depth];
// Update the value of the "out" attribute in the page scope
// attribute namespace of this PageContext
setAttribute(OUT, out);
return outs[depth];
}
public JspWriter popBody() {
depth--;
if (depth >= 0) {
out = outs[depth];
} else {
out = baseOut;
}
// Update the value of the "out" attribute in the page scope
// attribute namespace of this PageContext
setAttribute(OUT, out);
return out;
}
/**
* Provides programmatic access to the ExpressionEvaluator. The JSP
* Container must return a valid instance of an ExpressionEvaluator that can
* parse EL expressions.
*/
public ExpressionEvaluator getExpressionEvaluator() {
return new ExpressionEvaluatorImpl(this.applicationContext.getExpressionFactory());
}
public void handlePageException(Exception ex) throws IOException,
ServletException {
// Should never be called since handleException() called with a
// Throwable in the generated servlet.
handlePageException((Throwable) ex);
}
public void handlePageException(final Throwable t) throws IOException,
ServletException {
if (t == null)
throw new NullPointerException("null Throwable");
if (SecurityUtil.isPackageProtectionEnabled()) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
doHandlePageException(t);
return null;
}
});
} catch (PrivilegedActionException e) {
Exception ex = e.getException();
if (ex instanceof IOException) {
throw (IOException) ex;
} else {
throw (ServletException) ex;
}
}
} else {
doHandlePageException(t);
}
}
private void doHandlePageException(Throwable t) throws IOException,
ServletException {
if (errorPageURL != null && !errorPageURL.equals("")) {
/*
* Set request attributes. Do not set the
* javax.servlet.error.exception attribute here (instead, set in the
* generated servlet code for the error page) in order to prevent
* the ErrorReportValve, which is invoked as part of forwarding the
* request to the error page, from throwing it if the response has
* not been committed (the response will have been committed if the
* error page is a JSP page).
*/
request.setAttribute("javax.servlet.jsp.jspException", t);
request.setAttribute("javax.servlet.error.status_code",
new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
request.setAttribute("javax.servlet.error.request_uri",
((HttpServletRequest) request).getRequestURI());
request.setAttribute("javax.servlet.error.servlet_name", config
.getServletName());
try {
forward(errorPageURL);
} catch (IllegalStateException ise) {
include(errorPageURL);
}
// The error page could be inside an include.
Object newException = request
.getAttribute("javax.servlet.error.exception");
// t==null means the attribute was not set.
if ((newException != null) && (newException == t)) {
request.removeAttribute("javax.servlet.error.exception");
}
// now clear the error code - to prevent double handling.
request.removeAttribute("javax.servlet.error.status_code");
request.removeAttribute("javax.servlet.error.request_uri");
request.removeAttribute("javax.servlet.error.status_code");
request.removeAttribute("javax.servlet.jsp.jspException");
} else {
// Otherwise throw the exception wrapped inside a ServletException.
// Set the exception as the root cause in the ServletException
// to get a stack trace for the real problem
if (t instanceof IOException)
throw (IOException) t;
if (t instanceof ServletException)
throw (ServletException) t;
if (t instanceof RuntimeException)
throw (RuntimeException) t;
Throwable rootCause = null;
if (t instanceof JspException) {
rootCause = ((JspException) t).getRootCause();
} else if (t instanceof ELException) {
rootCause = ((ELException) t).getRootCause();
}
if (rootCause != null) {
throw new ServletException(t.getClass().getName() + ": "
+ t.getMessage(), rootCause);
}
throw new ServletException(t);
}
}
private static String XmlEscape(String s) {
if (s == null)
return null;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '<') {
sb.append("&lt;");
} else if (c == '>') {
sb.append("&gt;");
} else if (c == '\'') {
sb.append("&#039;"); // &apos;
} else if (c == '&') {
sb.append("&amp;");
} else if (c == '"') {
sb.append("&#034;"); // &quot;
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* Proprietary method to evaluate EL expressions. XXX - This method should
* go away once the EL interpreter moves out of JSTL and into its own
* project. For now, this is necessary because the standard machinery is too
* slow.
*
* @param expression
* The expression to be evaluated
* @param expectedType
* The expected resulting type
* @param pageContext
* The page context
* @param functionMap
* Maps prefix and name to Method
* @return The result of the evaluation
*/
public static Object proprietaryEvaluate(final String expression,
final Class expectedType, final PageContext pageContext,
final ProtectedFunctionMapper functionMap, final boolean escape)
throws ELException {
Object retValue;
final ExpressionFactory exprFactory = jspf.getJspApplicationContext(pageContext.getServletContext()).getExpressionFactory();
if (SecurityUtil.isPackageProtectionEnabled()) {
try {
retValue = AccessController
.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
ELContextImpl ctx = (ELContextImpl) pageContext.getELContext();
ctx.setFunctionMapper(new FunctionMapperImpl(functionMap));
ValueExpression ve = exprFactory.createValueExpression(ctx, expression, expectedType);
return ve.getValue(ctx);
}
});
} catch (PrivilegedActionException ex) {
Exception realEx = ex.getException();
if (realEx instanceof ELException) {
throw (ELException) realEx;
} else {
throw new ELException(realEx);
}
}
} else {
ELContextImpl ctx = (ELContextImpl) pageContext.getELContext();
ctx.setFunctionMapper(new FunctionMapperImpl(functionMap));
ValueExpression ve = exprFactory.createValueExpression(ctx, expression, expectedType);
retValue = ve.getValue(ctx);
}
if (escape && retValue != null) {
retValue = XmlEscape(retValue.toString());
}
return retValue;
}
public ELContext getELContext() {
if (this.elContext == null) {
this.elContext = this.applicationContext.createELContext(this);
}
return this.elContext;
}
}
@@ -0,0 +1,134 @@
/*
* 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.jasper.runtime;
import java.util.Enumeration;
import java.util.Vector;
import javax.servlet.ServletConfig;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import org.apache.jasper.Constants;
/**
* Thread-local based pool of tag handlers that can be reused.
*
* @author Jan Luehe
* @author Costin Manolache
*/
public class PerThreadTagHandlerPool extends TagHandlerPool {
private int maxSize;
// For cleanup
private Vector perThreadDataVector;
private ThreadLocal perThread;
private static class PerThreadData {
Tag handlers[];
int current;
}
/**
* Constructs a tag handler pool with the default capacity.
*/
public PerThreadTagHandlerPool() {
super();
perThreadDataVector = new Vector();
}
protected void init(ServletConfig config) {
maxSize = Constants.MAX_POOL_SIZE;
String maxSizeS = getOption(config, OPTION_MAXSIZE, null);
if (maxSizeS != null) {
maxSize = Integer.parseInt(maxSizeS);
if (maxSize < 0) {
maxSize = Constants.MAX_POOL_SIZE;
}
}
perThread = new ThreadLocal() {
protected Object initialValue() {
PerThreadData ptd = new PerThreadData();
ptd.handlers = new Tag[maxSize];
ptd.current = -1;
perThreadDataVector.addElement(ptd);
return ptd;
}
};
}
/**
* Gets the next available tag handler from this tag handler pool,
* instantiating one if this tag handler pool is empty.
*
* @param handlerClass Tag handler class
*
* @return Reused or newly instantiated tag handler
*
* @throws JspException if a tag handler cannot be instantiated
*/
public Tag get(Class handlerClass) throws JspException {
PerThreadData ptd = (PerThreadData)perThread.get();
if(ptd.current >=0 ) {
return ptd.handlers[ptd.current--];
} else {
try {
return (Tag) handlerClass.newInstance();
} catch (Exception e) {
throw new JspException(e.getMessage(), e);
}
}
}
/**
* Adds the given tag handler to this tag handler pool, unless this tag
* handler pool has already reached its capacity, in which case the tag
* handler's release() method is called.
*
* @param handler Tag handler to add to this tag handler pool
*/
public void reuse(Tag handler) {
PerThreadData ptd=(PerThreadData)perThread.get();
if (ptd.current < (ptd.handlers.length - 1)) {
ptd.handlers[++ptd.current] = handler;
} else {
handler.release();
}
}
/**
* Calls the release() method of all tag handlers in this tag handler pool.
*/
public void release() {
Enumeration enumeration = perThreadDataVector.elements();
while (enumeration.hasMoreElements()) {
PerThreadData ptd = (PerThreadData)enumeration.nextElement();
if (ptd.handlers != null) {
for (int i=ptd.current; i>=0; i--) {
if (ptd.handlers[i] != null) {
ptd.handlers[i].release();
}
}
}
}
}
}
@@ -0,0 +1,196 @@
/*
* 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.jasper.runtime;
import java.util.HashMap;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.lang.reflect.Method;
import javax.servlet.jsp.el.FunctionMapper;
import org.apache.jasper.security.SecurityUtil;
/**
* Maps EL functions to their Java method counterparts. Keeps the actual Method
* objects protected so that JSP pages can't indirectly do reflection.
*
* @author Mark Roth
* @author Kin-man Chung
*/
public final class ProtectedFunctionMapper extends javax.el.FunctionMapper
implements FunctionMapper {
/**
* Maps "prefix:name" to java.lang.Method objects.
*/
private HashMap fnmap = null;
/**
* If there is only one function in the map, this is the Method for it.
*/
private Method theMethod = null;
/**
* Constructor has protected access.
*/
private ProtectedFunctionMapper() {
}
/**
* Generated Servlet and Tag Handler implementations call this method to
* retrieve an instance of the ProtectedFunctionMapper. This is necessary
* since generated code does not have access to create instances of classes
* in this package.
*
* @return A new protected function mapper.
*/
public static ProtectedFunctionMapper getInstance() {
ProtectedFunctionMapper funcMapper;
if (SecurityUtil.isPackageProtectionEnabled()) {
funcMapper = (ProtectedFunctionMapper) AccessController
.doPrivileged(new PrivilegedAction() {
public Object run() {
return new ProtectedFunctionMapper();
}
});
} else {
funcMapper = new ProtectedFunctionMapper();
}
funcMapper.fnmap = new java.util.HashMap();
return funcMapper;
}
/**
* Stores a mapping from the given EL function prefix and name to the given
* Java method.
*
* @param fnQName
* The EL function qualified name (including prefix)
* @param c
* The class containing the Java method
* @param methodName
* The name of the Java method
* @param args
* The arguments of the Java method
* @throws RuntimeException
* if no method with the given signature could be found.
*/
public void mapFunction(String fnQName, final Class c,
final String methodName, final Class[] args) {
java.lang.reflect.Method method;
if (SecurityUtil.isPackageProtectionEnabled()) {
try {
method = (java.lang.reflect.Method) AccessController
.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
return c.getDeclaredMethod(methodName, args);
}
});
} catch (PrivilegedActionException ex) {
throw new RuntimeException(
"Invalid function mapping - no such method: "
+ ex.getException().getMessage());
}
} else {
try {
method = c.getDeclaredMethod(methodName, args);
} catch (NoSuchMethodException e) {
throw new RuntimeException(
"Invalid function mapping - no such method: "
+ e.getMessage());
}
}
this.fnmap.put(fnQName, method);
}
/**
* Creates an instance for this class, and stores the Method for the given
* EL function prefix and name. This method is used for the case when there
* is only one function in the EL expression.
*
* @param fnQName
* The EL function qualified name (including prefix)
* @param c
* The class containing the Java method
* @param methodName
* The name of the Java method
* @param args
* The arguments of the Java method
* @throws RuntimeException
* if no method with the given signature could be found.
*/
public static ProtectedFunctionMapper getMapForFunction(String fnQName,
final Class c, final String methodName, final Class[] args) {
java.lang.reflect.Method method;
ProtectedFunctionMapper funcMapper;
if (SecurityUtil.isPackageProtectionEnabled()) {
funcMapper = (ProtectedFunctionMapper) AccessController
.doPrivileged(new PrivilegedAction() {
public Object run() {
return new ProtectedFunctionMapper();
}
});
try {
method = (java.lang.reflect.Method) AccessController
.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
return c.getDeclaredMethod(methodName, args);
}
});
} catch (PrivilegedActionException ex) {
throw new RuntimeException(
"Invalid function mapping - no such method: "
+ ex.getException().getMessage());
}
} else {
funcMapper = new ProtectedFunctionMapper();
try {
method = c.getDeclaredMethod(methodName, args);
} catch (NoSuchMethodException e) {
throw new RuntimeException(
"Invalid function mapping - no such method: "
+ e.getMessage());
}
}
funcMapper.theMethod = method;
return funcMapper;
}
/**
* Resolves the specified local name and prefix into a Java.lang.Method.
* Returns null if the prefix and local name are not found.
*
* @param prefix
* the prefix of the function
* @param localName
* the short name of the function
* @return the result of the method mapping. Null means no entry found.
*/
public Method resolveFunction(String prefix, String localName) {
if (this.fnmap != null) {
return (Method) this.fnmap.get(prefix + ":" + localName);
}
return theMethod;
}
}
@@ -0,0 +1,76 @@
/*
* 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.jasper.runtime;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.jsp.JspWriter;
/**
* ServletResponseWrapper used by the JSP 'include' action.
*
* This wrapper response object is passed to RequestDispatcher.include(), so
* that the output of the included resource is appended to that of the
* including page.
*
* @author Pierre Delisle
*/
public class ServletResponseWrapperInclude extends HttpServletResponseWrapper {
/**
* PrintWriter which appends to the JspWriter of the including page.
*/
private PrintWriter printWriter;
private JspWriter jspWriter;
public ServletResponseWrapperInclude(ServletResponse response,
JspWriter jspWriter) {
super((HttpServletResponse)response);
this.printWriter = new PrintWriter(jspWriter);
this.jspWriter = jspWriter;
}
/**
* Returns a wrapper around the JspWriter of the including page.
*/
public PrintWriter getWriter() throws IOException {
return printWriter;
}
public ServletOutputStream getOutputStream() throws IOException {
throw new IllegalStateException();
}
/**
* Clears the output buffer of the JspWriter associated with the including
* page.
*/
public void resetBuffer() {
try {
jspWriter.clearBuffer();
} catch (IOException ioe) {
}
}
}
@@ -0,0 +1,191 @@
/*
* 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.jasper.runtime;
import javax.servlet.ServletConfig;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import org.apache.AnnotationProcessor;
import org.apache.jasper.Constants;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* Pool of tag handlers that can be reused.
*
* @author Jan Luehe
*/
public class TagHandlerPool {
private Tag[] handlers;
public static String OPTION_TAGPOOL="tagpoolClassName";
public static String OPTION_MAXSIZE="tagpoolMaxSize";
private Log log = LogFactory.getLog(TagHandlerPool.class);
// index of next available tag handler
private int current;
protected AnnotationProcessor annotationProcessor = null;
public static TagHandlerPool getTagHandlerPool( ServletConfig config) {
TagHandlerPool result=null;
String tpClassName=getOption( config, OPTION_TAGPOOL, null);
if( tpClassName != null ) {
try {
Class c=Class.forName( tpClassName );
result=(TagHandlerPool)c.newInstance();
} catch (Exception e) {
e.printStackTrace();
result=null;
}
}
if( result==null ) result=new TagHandlerPool();
result.init(config);
return result;
}
protected void init( ServletConfig config ) {
int maxSize=-1;
String maxSizeS=getOption(config, OPTION_MAXSIZE, null);
if( maxSizeS != null ) {
try {
maxSize=Integer.parseInt(maxSizeS);
} catch( Exception ex) {
maxSize=-1;
}
}
if( maxSize <0 ) {
maxSize=Constants.MAX_POOL_SIZE;
}
this.handlers = new Tag[maxSize];
this.current = -1;
this.annotationProcessor =
(AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
}
/**
* Constructs a tag handler pool with the default capacity.
*/
public TagHandlerPool() {
// Nothing - jasper generated servlets call the other constructor,
// this should be used in future + init .
}
/**
* Constructs a tag handler pool with the given capacity.
*
* @param capacity Tag handler pool capacity
* @deprecated Use static getTagHandlerPool
*/
public TagHandlerPool(int capacity) {
this.handlers = new Tag[capacity];
this.current = -1;
}
/**
* Gets the next available tag handler from this tag handler pool,
* instantiating one if this tag handler pool is empty.
*
* @param handlerClass Tag handler class
*
* @return Reused or newly instantiated tag handler
*
* @throws JspException if a tag handler cannot be instantiated
*/
public Tag get(Class handlerClass) throws JspException {
Tag handler = null;
synchronized( this ) {
if (current >= 0) {
handler = handlers[current--];
return handler;
}
}
// Out of sync block - there is no need for other threads to
// wait for us to construct a tag for this thread.
try {
Tag instance = (Tag) handlerClass.newInstance();
AnnotationHelper.postConstruct(annotationProcessor, instance);
return instance;
} catch (Exception e) {
throw new JspException(e.getMessage(), e);
}
}
/**
* Adds the given tag handler to this tag handler pool, unless this tag
* handler pool has already reached its capacity, in which case the tag
* handler's release() method is called.
*
* @param handler Tag handler to add to this tag handler pool
*/
public void reuse(Tag handler) {
synchronized( this ) {
if (current < (handlers.length - 1)) {
handlers[++current] = handler;
return;
}
}
// There is no need for other threads to wait for us to release
handler.release();
if (annotationProcessor != null) {
try {
AnnotationHelper.preDestroy(annotationProcessor, handler);
} catch (Exception e) {
log.warn("Error processing preDestroy on tag instance of "
+ handler.getClass().getName(), e);
}
}
}
/**
* Calls the release() method of all available tag handlers in this tag
* handler pool.
*/
public synchronized void release() {
for (int i = current; i >= 0; i--) {
handlers[i].release();
if (annotationProcessor != null) {
try {
AnnotationHelper.preDestroy(annotationProcessor, handlers[i]);
} catch (Exception e) {
log.warn("Error processing preDestroy on tag instance of "
+ handlers[i].getClass().getName(), e);
}
}
}
}
protected static String getOption( ServletConfig config, String name, String defaultV) {
if( config == null ) return defaultV;
String value=config.getInitParameter(name);
if( value != null ) return value;
if( config.getServletContext() ==null )
return defaultV;
value=config.getServletContext().getInitParameter(name);
if( value!=null ) return value;
return defaultV;
}
}
@@ -0,0 +1,111 @@
/*
* 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.jasper.security;
/**
* Static class used to preload java classes when using the
* Java SecurityManager so that the defineClassInPackage
* RuntimePermission does not trigger an AccessControlException.
*
* @author Jean-Francois Arcand
*/
public final class SecurityClassLoad {
private static org.apache.juli.logging.Log log=
org.apache.juli.logging.LogFactory.getLog( SecurityClassLoad.class );
public static void securityClassLoad(ClassLoader loader){
if( System.getSecurityManager() == null ){
return;
}
String basePackage = "org.apache.jasper.";
try {
loader.loadClass( basePackage +
"runtime.JspFactoryImpl$PrivilegedGetPageContext");
loader.loadClass( basePackage +
"runtime.JspFactoryImpl$PrivilegedReleasePageContext");
loader.loadClass( basePackage +
"runtime.JspRuntimeLibrary");
loader.loadClass( basePackage +
"runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper");
loader.loadClass( basePackage +
"runtime.ServletResponseWrapperInclude");
loader.loadClass( basePackage +
"runtime.TagHandlerPool");
loader.loadClass( basePackage +
"runtime.JspFragmentHelper");
loader.loadClass( basePackage +
"runtime.ProtectedFunctionMapper");
loader.loadClass( basePackage +
"runtime.ProtectedFunctionMapper$1");
loader.loadClass( basePackage +
"runtime.ProtectedFunctionMapper$2");
loader.loadClass( basePackage +
"runtime.ProtectedFunctionMapper$3");
loader.loadClass( basePackage +
"runtime.ProtectedFunctionMapper$4");
loader.loadClass( basePackage +
"runtime.PageContextImpl");
loader.loadClass( basePackage +
"runtime.PageContextImpl$1");
loader.loadClass( basePackage +
"runtime.PageContextImpl$2");
loader.loadClass( basePackage +
"runtime.PageContextImpl$3");
loader.loadClass( basePackage +
"runtime.PageContextImpl$4");
loader.loadClass( basePackage +
"runtime.PageContextImpl$5");
loader.loadClass( basePackage +
"runtime.PageContextImpl$6");
loader.loadClass( basePackage +
"runtime.PageContextImpl$7");
loader.loadClass( basePackage +
"runtime.PageContextImpl$8");
loader.loadClass( basePackage +
"runtime.PageContextImpl$9");
loader.loadClass( basePackage +
"runtime.PageContextImpl$10");
loader.loadClass( basePackage +
"runtime.PageContextImpl$11");
loader.loadClass( basePackage +
"runtime.PageContextImpl$12");
loader.loadClass( basePackage +
"runtime.PageContextImpl$13");
loader.loadClass( basePackage +
"runtime.JspContextWrapper");
loader.loadClass( basePackage +
"servlet.JspServletWrapper");
loader.loadClass( basePackage +
"runtime.JspWriterImpl$1");
} catch (ClassNotFoundException ex) {
log.error("SecurityClassLoad", ex);
}
}
}
@@ -0,0 +1,81 @@
/*
* 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.jasper.security;
import org.apache.jasper.Constants;
/**
* Util class for Security related operations.
*
* @author Jean-Francois Arcand
*/
public final class SecurityUtil{
private static boolean packageDefinitionEnabled =
System.getProperty("package.definition") == null ? false : true;
/**
* Return the <code>SecurityManager</code> only if Security is enabled AND
* package protection mechanism is enabled.
*/
public static boolean isPackageProtectionEnabled(){
if (packageDefinitionEnabled && Constants.IS_SECURITY_ENABLED){
return true;
}
return false;
}
/**
* Filter the specified message string for characters that are sensitive
* in HTML. This avoids potential attacks caused by including JavaScript
* codes in the request URL that is often reported in error messages.
*
* @param message The message string to be filtered
*/
public static String filter(String message) {
if (message == null)
return (null);
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuffer result = new StringBuffer(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("&lt;");
break;
case '>':
result.append("&gt;");
break;
case '&':
result.append("&amp;");
break;
case '"':
result.append("&quot;");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
}
}
@@ -0,0 +1,172 @@
/*
* 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.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.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 CodeSource codeSource;
private String className;
private ClassLoader parent;
private SecurityManager securityManager;
public JasperLoader(URL[] urls, ClassLoader parent,
PermissionCollection permissionCollection,
CodeSource codeSource) {
super(urls, parent);
this.permissionCollection = permissionCollection;
this.codeSource = codeSource;
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.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;
}
}
@@ -0,0 +1,441 @@
/*
* 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.jasper.servlet;
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;
/**
* The base URL (document root) for this context.
*/
protected URL myResourceBaseURL;
// ----------------------------------------------------------- Constructors
/**
* Create a new instance of this ServletContext implementation.
*
* @param aLogWriter PrintWriter which is used for <code>log()</code> calls
* @param aResourceBaseURL Resource base URL
*/
public JspCServletContext(PrintWriter aLogWriter, URL aResourceBaseURL) {
myAttributes = new Hashtable();
myLogWriter = aLogWriter;
myResourceBaseURL = aResourceBaseURL;
}
// --------------------------------------------------------- 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 context path.
*/
public String getContextPath() {
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) {
if (!myResourceBaseURL.getProtocol().equals("file"))
return (null);
if (!path.startsWith("/"))
return (null);
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 {
if (!path.startsWith("/"))
throw new MalformedURLException("Path '" + path +
"' does not start with '/'");
URL url = new URL(myResourceBaseURL, path.substring(1));
InputStream is = null;
try {
is = url.openStream();
} catch (Throwable t) {
url = null;
} finally {
if (is != null) {
try {
is.close();
} catch (Throwable t2) {
// Ignore
}
}
}
return url;
}
/**
* 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 (getResource(path).openStream());
} 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);
}
}
@@ -0,0 +1,347 @@
/*
* 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.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.PeriodicEventListener;
import org.apache.jasper.Constants;
import org.apache.jasper.EmbeddedServletOptions;
import org.apache.jasper.Options;
import org.apache.jasper.compiler.JspRuntimeContext;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.security.SecurityUtil;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* 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 implements PeriodicEventListener {
// 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();
}
public void periodicEvent() {
rctxt.checkCompile();
}
// -------------------------------------------------------- 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
String msg = Localizer.getMessage(
"jsp.error.file.not.found",jspUri);
// Strictly, filtering this is an application
// responsibility but just in case...
throw new ServletException(
SecurityUtil.filter(msg));
} 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);
}
}
@@ -0,0 +1,527 @@
/*
* 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.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.AnnotationProcessor;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.Options;
import org.apache.jasper.compiler.ErrorDispatcher;
import org.apache.jasper.compiler.JavacErrorDetail;
import org.apache.jasper.compiler.JspRuntimeContext;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.runtime.JspSourceDependent;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* 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 {
// Logger
private Log log = LogFactory.getLog(JspServletWrapper.class);
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.
*/
public 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();
AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
if (annotationProcessor != null) {
annotationProcessor.processAnnotations(servlet);
annotationProcessor.postConstruct(servlet);
}
} catch (IllegalAccessException e) {
throw new JasperException(e);
} catch (InstantiationException e) {
throw new JasperException(e);
} catch (Exception e) {
throw new JasperException(e);
}
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;
}
} 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);
}
}
try {
/*
* (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();
AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
if (annotationProcessor != null) {
try {
annotationProcessor.preDestroy(theServlet);
} catch (Exception e) {
// Log any exception, since it can't be passed along
log.error(Localizer.getMessage("jsp.error.file.not.found",
e.getMessage()), e);
}
}
}
}
/**
* @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,
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);
}
if (options.getDisplaySourceFragment()) {
return new JasperException(Localizer.getMessage
("jsp.exception", detail.getJspFileName(),
"" + jspLineNumber) +
"\n\n" + detail.getJspExtract() +
"\n\nStacktrace:", ex);
} else {
return new JasperException(Localizer.getMessage
("jsp.exception", detail.getJspFileName(),
"" + jspLineNumber), 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);
}
}
}
}
@@ -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.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>
@@ -0,0 +1,328 @@
/*
* 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.jasper.tagplugins.jstl;
import org.apache.jasper.Constants;
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['&'] = "&amp;".toCharArray();
specialCharactersRepresentation['<'] = "&lt;".toCharArray();
specialCharactersRepresentation['>'] = "&gt;".toCharArray();
specialCharactersRepresentation['"'] = "&#034;".toCharArray();
specialCharactersRepresentation['\''] = "&#039;".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(";" + Constants.SESSION_PARAMETER_NAME + "=")) != -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):
*
* & -> &amp;
* < -> &lt;
* > -> &gt;
* " -> &#034;
* ' -> &#039;
*
* 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 &lt;import&gt: " +
"Target servlet called getWriter(), then getOutputStream()");
isWriterUsed = true;
return new PrintWriter(sw);
}
public ServletOutputStream getOutputStream() {
if (isWriterUsed)
throw new IllegalStateException("Unexpected internal error during &lt;import&gt: " +
"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
}
}
}
@@ -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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.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("}");
}
}
@@ -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.jasper.tagplugins.jstl.core;
import org.apache.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("}");
}
}
@@ -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.jasper.tagplugins.jstl.core;
import org.apache.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" +
"}"
);
}
}
@@ -0,0 +1,119 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
public class ForTokens implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
boolean hasVar, hasVarStatus, hasBegin, hasEnd, hasStep;
//init the flags
hasVar = ctxt.isAttributeSpecified("var");
hasVarStatus = ctxt.isAttributeSpecified("varStatus");
hasBegin = ctxt.isAttributeSpecified("begin");
hasEnd = ctxt.isAttributeSpecified("end");
hasStep = ctxt.isAttributeSpecified("step");
if(hasVarStatus){
ctxt.dontUseTagPlugin();
return;
}
//define all the temp variables' names
String itemsName = ctxt.getTemporaryVariableName();
String delimsName = ctxt.getTemporaryVariableName();
String stName = ctxt.getTemporaryVariableName();
String beginName = ctxt.getTemporaryVariableName();
String endName = ctxt.getTemporaryVariableName();
String stepName = ctxt.getTemporaryVariableName();
String index = ctxt.getTemporaryVariableName();
String temp = ctxt.getTemporaryVariableName();
String tokensCountName = ctxt.getTemporaryVariableName();
//get the value of the "items" attribute
ctxt.generateJavaSource("String " + itemsName + " = (String)");
ctxt.generateAttribute("items");
ctxt.generateJavaSource(";");
//get the value of the "delim" attribute
ctxt.generateJavaSource("String " + delimsName + " = (String)");
ctxt.generateAttribute("delims");
ctxt.generateJavaSource(";");
//new a StringTokenizer Object according to the "items" and the "delim"
ctxt.generateJavaSource("java.util.StringTokenizer " + stName + " = " +
"new java.util.StringTokenizer(" + itemsName + ", " + delimsName + ");");
//if "begin" specified, move the token to the "begin" place
//and record the begin index. default begin place is 0.
ctxt.generateJavaSource("int " + tokensCountName + " = " + stName + ".countTokens();");
if(hasBegin){
ctxt.generateJavaSource("int " + beginName + " = " );
ctxt.generateAttribute("begin");
ctxt.generateJavaSource(";");
ctxt.generateJavaSource("for(int " + index + " = 0; " + index + " < " + beginName + " && " + stName + ".hasMoreTokens(); " + index + "++, " + stName + ".nextToken()){}");
}else{
ctxt.generateJavaSource("int " + beginName + " = 0;");
}
//when "end" is specified, if the "end" is more than the last index,
//record the end place as the last index, otherwise, record it as "end";
//default end place is the last index
if(hasEnd){
ctxt.generateJavaSource("int " + endName + " = 0;" );
ctxt.generateJavaSource("if((" + tokensCountName + " - 1) < ");
ctxt.generateAttribute("end");
ctxt.generateJavaSource("){");
ctxt.generateJavaSource(" " + endName + " = " + tokensCountName + " - 1;");
ctxt.generateJavaSource("}else{");
ctxt.generateJavaSource(" " + endName + " = ");
ctxt.generateAttribute("end");
ctxt.generateJavaSource(";}");
}else{
ctxt.generateJavaSource("int " + endName + " = " + tokensCountName + " - 1;");
}
//get the step value from "step" if specified.
//default step value is 1.
if(hasStep){
ctxt.generateJavaSource("int " + stepName + " = " );
ctxt.generateAttribute("step");
ctxt.generateJavaSource(";");
}else{
ctxt.generateJavaSource("int " + stepName + " = 1;");
}
//the loop
ctxt.generateJavaSource("for(int " + index + " = " + beginName + "; " + index + " <= " + endName + "; " + index + "++){");
ctxt.generateJavaSource(" String " + temp + " = " + stName + ".nextToken();");
ctxt.generateJavaSource(" if(((" + index + " - " + beginName + ") % " + stepName + ") == 0){");
//if var specified, put the current token into the attribute "var" defines.
if(hasVar){
String strVar = ctxt.getConstantAttribute("var");
ctxt.generateJavaSource(" pageContext.setAttribute(\"" + strVar + "\", " + temp + ");");
}
ctxt.generateBody();
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource("}");
}
}
@@ -0,0 +1,50 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.*;
public final class If implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
String condV = ctxt.getTemporaryVariableName();
ctxt.generateJavaSource("boolean " + condV + "=");
ctxt.generateAttribute("test");
ctxt.generateJavaSource(";");
if (ctxt.isAttributeSpecified("var")) {
String scope = "PageContext.PAGE_SCOPE";
if (ctxt.isAttributeSpecified("scope")) {
String scopeStr = ctxt.getConstantAttribute("scope");
if ("request".equals(scopeStr)) {
scope = "PageContext.REQUEST_SCOPE";
} else if ("session".equals(scopeStr)) {
scope = "PageContext.SESSION_SCOPE";
} else if ("application".equals(scopeStr)) {
scope = "PageContext.APPLICATION_SCOPE";
}
}
ctxt.generateJavaSource("_jspx_page_context.setAttribute(");
ctxt.generateAttribute("var");
ctxt.generateJavaSource(", new Boolean(" + condV + ")," + scope + ");");
}
ctxt.generateJavaSource("if (" + condV + "){");
ctxt.generateBody();
ctxt.generateJavaSource("}");
}
}
@@ -0,0 +1,382 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
import org.apache.jasper.tagplugins.jstl.Util;
public class Import implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
boolean hasContext, hasVar, hasScope, hasVarReader, hasCharEncoding;
//flags
hasContext = ctxt.isAttributeSpecified("context");
hasVar = ctxt.isAttributeSpecified("var");
hasScope = ctxt.isAttributeSpecified("scope");
hasVarReader = ctxt.isAttributeSpecified("varReader");
hasCharEncoding = ctxt.isAttributeSpecified("charEncoding");
//variables' names
String urlName = ctxt.getTemporaryVariableName();
String contextName = ctxt.getTemporaryVariableName();
String iauName = ctxt.getTemporaryVariableName(); // is absolute url
String urlObjName = ctxt.getTemporaryVariableName(); //URL object
String ucName = ctxt.getTemporaryVariableName(); //URLConnection
String inputStreamName = ctxt.getTemporaryVariableName();
String tempReaderName = ctxt.getTemporaryVariableName();
String tempReaderName2 = ctxt.getTemporaryVariableName();
String charSetName = ctxt.getTemporaryVariableName();
String charEncodingName = ctxt.getTemporaryVariableName();
String contentTypeName = ctxt.getTemporaryVariableName();
String varReaderName = ctxt.getTemporaryVariableName();
String servletContextName = ctxt.getTemporaryVariableName();
String servletPathName = ctxt.getTemporaryVariableName();
String requestDispatcherName = ctxt.getTemporaryVariableName();
String irwName = ctxt.getTemporaryVariableName(); //ImportResponseWrapper name
String brName = ctxt.getTemporaryVariableName(); //BufferedReader name
String sbName = ctxt.getTemporaryVariableName(); //StringBuffer name
String tempStringName = ctxt.getTemporaryVariableName();
//is absolute url
ctxt.generateJavaSource("boolean " + iauName + ";");
//get the url value
ctxt.generateJavaSource("String " + urlName + " = ");
ctxt.generateAttribute("url");
ctxt.generateJavaSource(";");
//validate the url
ctxt.generateJavaSource("if(" + urlName + " == null || " + urlName + ".equals(\"\")){");
ctxt.generateJavaSource(" throw new JspTagException(\"The \\\"url\\\" attribute " +
"illegally evaluated to \\\"null\\\" or \\\"\\\" in &lt;import&gt;\");");
ctxt.generateJavaSource("}");
//initialize the is_absolute_url
ctxt.generateJavaSource(iauName + " = " +
"org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + urlName + ");");
//validate the context
if(hasContext){
ctxt.generateJavaSource("String " + contextName + " = ");
ctxt.generateAttribute("context");
ctxt.generateJavaSource(";");
ctxt.generateJavaSource("if((!" + contextName + ".startsWith(\"/\")) " +
"|| (!" + urlName + ".startsWith(\"/\"))){");
ctxt.generateJavaSource(" throw new JspTagException" +
"(\"In URL tags, when the \\\"context\\\" attribute is specified, " +
"values of both \\\"context\\\" and \\\"url\\\" must start with \\\"/\\\".\");");
ctxt.generateJavaSource("}");
}
//define charset
ctxt.generateJavaSource("String " + charSetName + " = null;");
//if the charEncoding attribute is specified
if(hasCharEncoding){
//initialize the charEncoding
ctxt.generateJavaSource("String " + charEncodingName + " = ");
ctxt.generateAttribute("charEncoding");
ctxt.generateJavaSource(";");
//assign appropriate value tp the charset
ctxt.generateJavaSource("if(null != " + charEncodingName + " " +
"&& !" + charEncodingName + ".equals(\"\")){");
ctxt.generateJavaSource(" " + charSetName + " = "
+ charEncodingName + ";");
ctxt.generateJavaSource("}");
}
//reshape the url string
ctxt.generateJavaSource("if(!"+iauName+"){");
ctxt.generateJavaSource(" if(!" + urlName + ".startsWith(\"/\")){");
ctxt.generateJavaSource(" String " + servletPathName + " = " +
"((HttpServletRequest)pageContext.getRequest()).getServletPath();");
ctxt.generateJavaSource(" " + urlName + " = "
+ servletPathName + ".substring(0," + servletPathName + ".lastIndexOf('/')) + '/' + " + urlName + ";");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource("}");
//if the varReader attribute specified
if(hasVarReader){
//get the String value of varReader
ctxt.generateJavaSource("String " + varReaderName + " = ");
ctxt.generateAttribute("varReader");
ctxt.generateJavaSource(";");
//if the url is absolute url
ctxt.generateJavaSource("if(" + iauName + "){");
//get the content of the target
ctxt.generateJavaSource(" java.net.URL " + urlObjName + " = new java.net.URL(" + urlName + ");");
ctxt.generateJavaSource(" java.net.URLConnection " + ucName + " = "
+ urlObjName + ".openConnection();");
ctxt.generateJavaSource(" java.io.InputStream " + inputStreamName + " = "
+ ucName + ".getInputStream();");
ctxt.generateJavaSource(" if(" + charSetName + " == null){");
ctxt.generateJavaSource(" String " + contentTypeName + " = "
+ ucName + ".getContentType();");
ctxt.generateJavaSource(" if(null != " + contentTypeName + "){");
ctxt.generateJavaSource(" " + charSetName + " = " +
"org.apache.jasper.tagplugins.jstl.Util.getContentTypeAttribute(" + contentTypeName + ", \"charset\");");
ctxt.generateJavaSource(" if(" + charSetName + " == null) "
+ charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
ctxt.generateJavaSource(" }else{");
ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" }");
if(!hasCharEncoding){
ctxt.generateJavaSource(" String " + contentTypeName + " = " + ucName + ".getContentType();");
}
//define the Reader
ctxt.generateJavaSource(" java.io.Reader " + tempReaderName + " = null;");
//initialize the Reader object
ctxt.generateJavaSource(" try{");
ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ", " + charSetName + ");");
ctxt.generateJavaSource(" }catch(Exception ex){");
ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ", org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING);");
ctxt.generateJavaSource(" }");
//validate the response
ctxt.generateJavaSource(" if(" + ucName + " instanceof java.net.HttpURLConnection){");
ctxt.generateJavaSource(" int status = ((java.net.HttpURLConnection) " + ucName + ").getResponseCode();");
ctxt.generateJavaSource(" if(status < 200 || status > 299){");
ctxt.generateJavaSource(" throw new JspTagException(status + \" \" + " + urlName + ");");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" }");
//set attribute in the page context scope
ctxt.generateJavaSource(" pageContext.setAttribute(" + varReaderName + ", " + tempReaderName + ");");
//if the url is relative
ctxt.generateJavaSource("}else{");
//if the url is relative, http request is needed
ctxt.generateJavaSource(" if (!(pageContext.getRequest() instanceof HttpServletRequest " +
"&& pageContext.getResponse() instanceof HttpServletResponse)){");
ctxt.generateJavaSource(" throw new JspTagException(\"Relative &lt;import&gt; from non-HTTP request not allowed\");");
ctxt.generateJavaSource(" }");
//get the servlet context of the context defined in the context attribute
ctxt.generateJavaSource(" ServletContext " + servletContextName + " = null;");
if(hasContext){
ctxt.generateJavaSource(" if(null != " + contextName + "){");
ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext().getContext(" + contextName + ");" );
ctxt.generateJavaSource(" }else{");
ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();");
ctxt.generateJavaSource(" }");
}else{
ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();");
}
//
ctxt.generateJavaSource(" if(" + servletContextName + " == null){");
if(hasContext){
ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for Context: \\\" \"+" + contextName + "+\" \\\" and URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");");
}else{
ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");");
}
ctxt.generateJavaSource(" }");
//get the request dispatcher
ctxt.generateJavaSource(" RequestDispatcher " + requestDispatcherName + " = " + servletContextName + ".getRequestDispatcher(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));");
ctxt.generateJavaSource(" if(" + requestDispatcherName + " == null) throw new JspTagException(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));");
//initialize a ImportResponseWrapper to include the resource
ctxt.generateJavaSource(" org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper " + irwName + " = new org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper((HttpServletResponse) pageContext.getResponse());");
ctxt.generateJavaSource(" if(" + charSetName + " == null){");
ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" " + irwName + ".setCharEncoding(" + charSetName + ");");
ctxt.generateJavaSource(" try{");
ctxt.generateJavaSource(" " + requestDispatcherName + ".include(pageContext.getRequest(), " + irwName + ");");
ctxt.generateJavaSource(" }catch(java.io.IOException ex){");
ctxt.generateJavaSource(" throw new JspException(ex);");
ctxt.generateJavaSource(" }catch(RuntimeException ex){");
ctxt.generateJavaSource(" throw new JspException(ex);");
ctxt.generateJavaSource(" }catch(ServletException ex){");
ctxt.generateJavaSource(" Throwable rc = ex.getRootCause();");
ctxt.generateJavaSource(" if (rc == null)");
ctxt.generateJavaSource(" throw new JspException(ex);");
ctxt.generateJavaSource(" else");
ctxt.generateJavaSource(" throw new JspException(rc);");
ctxt.generateJavaSource(" }");
//validate the response status
ctxt.generateJavaSource(" if(" + irwName + ".getStatus() < 200 || " + irwName + ".getStatus() > 299){");
ctxt.generateJavaSource(" throw new JspTagException(" + irwName + ".getStatus()+\" \" + org.apache.jasper.tagplugins.jstl.Util.stripSession(" + urlName + "));");
ctxt.generateJavaSource(" }");
//push in the page context
ctxt.generateJavaSource(" java.io.Reader " + tempReaderName + " = new java.io.StringReader(" + irwName + ".getString());");
ctxt.generateJavaSource(" pageContext.setAttribute(" + varReaderName + ", " + tempReaderName + ");");
ctxt.generateJavaSource("}");
//execute the body action
ctxt.generateBody();
//close the reader
ctxt.generateJavaSource("java.io.Reader " + tempReaderName2 + " = (java.io.Reader)pageContext.getAttribute(" + varReaderName + ");");
ctxt.generateJavaSource("if(" + tempReaderName2 + " != null) " + tempReaderName2 + ".close();");
ctxt.generateJavaSource("pageContext.removeAttribute(" + varReaderName + ",1);");
}
//if the varReader is not specified
else{
ctxt.generateJavaSource("pageContext.setAttribute(\"url_without_param\"," + urlName + ");");
ctxt.generateBody();
ctxt.generateJavaSource(urlName + " = (String)pageContext.getAttribute(\"url_without_param\");");
ctxt.generateJavaSource("pageContext.removeAttribute(\"url_without_param\");");
String strScope = "page";
if(hasScope){
strScope = ctxt.getConstantAttribute("scope");
}
int iScope = Util.getScope(strScope);
ctxt.generateJavaSource("String " + tempStringName + " = null;");
ctxt.generateJavaSource("if(" + iauName + "){");
//get the content of the target
ctxt.generateJavaSource(" java.net.URL " + urlObjName + " = new java.net.URL(" + urlName + ");");
ctxt.generateJavaSource(" java.net.URLConnection " + ucName + " = " + urlObjName + ".openConnection();");
ctxt.generateJavaSource(" java.io.InputStream " + inputStreamName + " = " + ucName + ".getInputStream();");
ctxt.generateJavaSource(" java.io.Reader " + tempReaderName + " = null;");
ctxt.generateJavaSource(" if(" + charSetName + " == null){");
ctxt.generateJavaSource(" String " + contentTypeName + " = "
+ ucName + ".getContentType();");
ctxt.generateJavaSource(" if(null != " + contentTypeName + "){");
ctxt.generateJavaSource(" " + charSetName + " = " +
"org.apache.jasper.tagplugins.jstl.Util.getContentTypeAttribute(" + contentTypeName + ", \"charset\");");
ctxt.generateJavaSource(" if(" + charSetName + " == null) "
+ charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
ctxt.generateJavaSource(" }else{");
ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" try{");
ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + "," + charSetName + ");");
ctxt.generateJavaSource(" }catch(Exception ex){");
//ctxt.generateJavaSource(" throw new JspTagException(ex.toString());");
ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ",org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING);");
ctxt.generateJavaSource(" }");
//validate the response
ctxt.generateJavaSource(" if(" + ucName + " instanceof java.net.HttpURLConnection){");
ctxt.generateJavaSource(" int status = ((java.net.HttpURLConnection) " + ucName + ").getResponseCode();");
ctxt.generateJavaSource(" if(status < 200 || status > 299){");
ctxt.generateJavaSource(" throw new JspTagException(status + \" \" + " + urlName + ");");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" java.io.BufferedReader " + brName + " = new java.io.BufferedReader(" + tempReaderName + ");");
ctxt.generateJavaSource(" StringBuffer " + sbName + " = new StringBuffer();");
String index = ctxt.getTemporaryVariableName();
ctxt.generateJavaSource(" int " + index + ";");
ctxt.generateJavaSource(" while(("+index+" = "+brName+".read()) != -1) "+sbName+".append((char)"+index+");");
ctxt.generateJavaSource(" " + tempStringName + " = " +sbName + ".toString();");
ctxt.generateJavaSource("}else{");
//if the url is relative, http request is needed.
ctxt.generateJavaSource(" if (!(pageContext.getRequest() instanceof HttpServletRequest " +
"&& pageContext.getResponse() instanceof HttpServletResponse)){");
ctxt.generateJavaSource(" throw new JspTagException(\"Relative &lt;import&gt; from non-HTTP request not allowed\");");
ctxt.generateJavaSource(" }");
//get the servlet context of the context defined in the context attribute
ctxt.generateJavaSource(" ServletContext " + servletContextName + " = null;");
if(hasContext){
ctxt.generateJavaSource(" if(null != " + contextName + "){");
ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext().getContext(" + contextName + ");" );
ctxt.generateJavaSource(" }else{");
ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();");
ctxt.generateJavaSource(" }");
}else{
ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();");
}
//
ctxt.generateJavaSource(" if(" + servletContextName + " == null){");
if(hasContext){
ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for Context: \\\" \" +" + contextName + "+ \" \\\" and URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");");
}else{
ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");");
}
ctxt.generateJavaSource(" }");
//get the request dispatcher
ctxt.generateJavaSource(" RequestDispatcher " + requestDispatcherName + " = " + servletContextName + ".getRequestDispatcher(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));");
ctxt.generateJavaSource(" if(" + requestDispatcherName + " == null) throw new JspTagException(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));");
//initialize a ImportResponseWrapper to include the resource
ctxt.generateJavaSource(" org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper " + irwName + " = new org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper((HttpServletResponse) pageContext.getResponse());");
ctxt.generateJavaSource(" if(" + charSetName + " == null){");
ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" " + irwName + ".setCharEncoding(" + charSetName + ");");
ctxt.generateJavaSource(" try{");
ctxt.generateJavaSource(" " + requestDispatcherName + ".include(pageContext.getRequest(), " + irwName + ");");
ctxt.generateJavaSource(" }catch(java.io.IOException ex){");
ctxt.generateJavaSource(" throw new JspException(ex);");
ctxt.generateJavaSource(" }catch(RuntimeException ex){");
ctxt.generateJavaSource(" throw new JspException(ex);");
ctxt.generateJavaSource(" }catch(ServletException ex){");
ctxt.generateJavaSource(" Throwable rc = ex.getRootCause();");
ctxt.generateJavaSource(" if (rc == null)");
ctxt.generateJavaSource(" throw new JspException(ex);");
ctxt.generateJavaSource(" else");
ctxt.generateJavaSource(" throw new JspException(rc);");
ctxt.generateJavaSource(" }");
//validate the response status
ctxt.generateJavaSource(" if(" + irwName + ".getStatus() < 200 || " + irwName + ".getStatus() > 299){");
ctxt.generateJavaSource(" throw new JspTagException(" + irwName + ".getStatus()+\" \" + org.apache.jasper.tagplugins.jstl.Util.stripSession(" + urlName + "));");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" " + tempStringName + " = " + irwName + ".getString();");
ctxt.generateJavaSource("}");
if(hasVar){
String strVar = ctxt.getConstantAttribute("var");
ctxt.generateJavaSource("pageContext.setAttribute(\""+strVar+"\"," + tempStringName + "," + iScope + ");");
}else{
ctxt.generateJavaSource("pageContext.getOut().print(" + tempStringName + ");");
}
}
}
}
@@ -0,0 +1,32 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.*;
public final class Otherwise implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
// See When.java for the reason whey "}" is need at the beginng and
// not at the end.
ctxt.generateJavaSource("} else {");
ctxt.generateBody();
}
}
@@ -0,0 +1,90 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
public final class Out implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
//these two data member are to indicate
//whether the corresponding attribute is specified
boolean hasDefault=false, hasEscapeXml=false;
hasDefault = ctxt.isAttributeSpecified("default");
hasEscapeXml = ctxt.isAttributeSpecified("escapeXml");
//strValName, strEscapeXmlName & strDefName are two variables' name
//standing for value, escapeXml and default attribute
String strValName = ctxt.getTemporaryVariableName();
String strDefName = ctxt.getTemporaryVariableName();
String strEscapeXmlName = ctxt.getTemporaryVariableName();
//according to the tag file, the value attribute is mandatory.
ctxt.generateJavaSource("String " + strValName + " = null;");
ctxt.generateJavaSource("if(");
ctxt.generateAttribute("value");
ctxt.generateJavaSource("!=null){");
ctxt.generateJavaSource(" " + strValName + " = (");
ctxt.generateAttribute("value");
ctxt.generateJavaSource(").toString();");
ctxt.generateJavaSource("}");
//initiate the strDefName with null.
//if the default has been specified, then assign the value to it;
ctxt.generateJavaSource("String " + strDefName + " = null;\n");
if(hasDefault){
ctxt.generateJavaSource("if(");
ctxt.generateAttribute("default");
ctxt.generateJavaSource(" != null){");
ctxt.generateJavaSource(strDefName + " = (");
ctxt.generateAttribute("default");
ctxt.generateJavaSource(").toString();");
ctxt.generateJavaSource("}");
}
//initiate the strEscapeXmlName with true;
//if the escapeXml is specified, assign the value to it;
ctxt.generateJavaSource("boolean " + strEscapeXmlName + " = true;");
if(hasEscapeXml){
ctxt.generateJavaSource(strEscapeXmlName + " = Boolean.parseBoolean((");
ctxt.generateAttribute("default");
ctxt.generateJavaSource(").toString());");
}
//main part.
ctxt.generateJavaSource("if(null != " + strValName +"){");
ctxt.generateJavaSource(" if(" + strEscapeXmlName + "){");
ctxt.generateJavaSource(" " + strValName + " = org.apache.jasper.tagplugins.jstl.Util.escapeXml(" + strValName + ");");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" out.write(" + strValName + ");");
ctxt.generateJavaSource("}else{");
ctxt.generateJavaSource(" if(null != " + strDefName + "){");
ctxt.generateJavaSource(" if(" + strEscapeXmlName + "){");
ctxt.generateJavaSource(" " + strDefName + " = org.apache.jasper.tagplugins.jstl.Util.escapeXml(" + strDefName + ");");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" out.write(" + strDefName + ");");
ctxt.generateJavaSource(" }else{");
ctxt.generateBody();
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource("}");
}
}
@@ -0,0 +1,77 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
public class Param implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
//don't support the body content
//define names of all the temp variables
String nameName = ctxt.getTemporaryVariableName();
String valueName = ctxt.getTemporaryVariableName();
String urlName = ctxt.getTemporaryVariableName();
String encName = ctxt.getTemporaryVariableName();
String index = ctxt.getTemporaryVariableName();
//if the param tag has no parents, throw a exception
TagPluginContext parent = ctxt.getParentContext();
if(parent == null){
ctxt.generateJavaSource(" throw new JspTagExcption" +
"(\"&lt;param&gt; outside &lt;import&gt; or &lt;urlEncode&gt;\");");
return;
}
//get the url string before adding this param
ctxt.generateJavaSource("String " + urlName + " = " +
"(String)pageContext.getAttribute(\"url_without_param\");");
//get the value of "name"
ctxt.generateJavaSource("String " + nameName + " = ");
ctxt.generateAttribute("name");
ctxt.generateJavaSource(";");
//if the "name" is null then do nothing.
//else add such string "name=value" to the url.
//and the url should be encoded
ctxt.generateJavaSource("if(" + nameName + " != null && !" + nameName + ".equals(\"\")){");
ctxt.generateJavaSource(" String " + valueName + " = ");
ctxt.generateAttribute("value");
ctxt.generateJavaSource(";");
ctxt.generateJavaSource(" if(" + valueName + " == null) " + valueName + " = \"\";");
ctxt.generateJavaSource(" String " + encName + " = pageContext.getResponse().getCharacterEncoding();");
ctxt.generateJavaSource(" " + nameName + " = java.net.URLEncoder.encode(" + nameName + ", " + encName + ");");
ctxt.generateJavaSource(" " + valueName + " = java.net.URLEncoder.encode(" + valueName + ", " + encName + ");");
ctxt.generateJavaSource(" int " + index + ";");
ctxt.generateJavaSource(" " + index + " = " + urlName + ".indexOf(\'?\');");
//if the current param is the first one, add a "?" ahead of it
//else add a "&" ahead of it
ctxt.generateJavaSource(" if(" + index + " == -1){");
ctxt.generateJavaSource(" " + urlName + " = " + urlName + " + \"?\" + " + nameName + " + \"=\" + " + valueName + ";");
ctxt.generateJavaSource(" }else{");
ctxt.generateJavaSource(" " + urlName + " = " + urlName + " + \"&\" + " + nameName + " + \"=\" + " + valueName + ";");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" pageContext.setAttribute(\"url_without_param\"," + urlName + ");");
ctxt.generateJavaSource("}");
}
}
@@ -0,0 +1,83 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
public class Redirect implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
//flag for the existence of the "context"
boolean hasContext = ctxt.isAttributeSpecified("context");
//names of the temp variables
String urlName = ctxt.getTemporaryVariableName();
String contextName = ctxt.getTemporaryVariableName();
String baseUrlName = ctxt.getTemporaryVariableName();
String resultName = ctxt.getTemporaryVariableName();
String responseName = ctxt.getTemporaryVariableName();
//get context
ctxt.generateJavaSource("String " + contextName + " = null;");
if(hasContext){
ctxt.generateJavaSource(contextName + " = ");
ctxt.generateAttribute("context");
ctxt.generateJavaSource(";");
}
//get the url
ctxt.generateJavaSource("String " + urlName + " = ");
ctxt.generateAttribute("url");
ctxt.generateJavaSource(";");
//get the raw url according to "url" and "context"
ctxt.generateJavaSource("String " + baseUrlName + " = " +
"org.apache.jasper.tagplugins.jstl.Util.resolveUrl(" + urlName + ", " + contextName + ", pageContext);");
ctxt.generateJavaSource("pageContext.setAttribute" +
"(\"url_without_param\", " + baseUrlName + ");");
//add params
ctxt.generateBody();
ctxt.generateJavaSource("String " + resultName + " = " +
"(String)pageContext.getAttribute(\"url_without_param\");");
ctxt.generateJavaSource("pageContext.removeAttribute" +
"(\"url_without_param\");");
//get the response object
ctxt.generateJavaSource("HttpServletResponse " + responseName + " = " +
"((HttpServletResponse) pageContext.getResponse());");
//if the url is relative, encode it
ctxt.generateJavaSource("if(!org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + resultName + ")){");
ctxt.generateJavaSource(" " + resultName + " = "
+ responseName + ".encodeRedirectURL(" + resultName + ");");
ctxt.generateJavaSource("}");
//do redirect
ctxt.generateJavaSource("try{");
ctxt.generateJavaSource(" " + responseName + ".sendRedirect(" + resultName + ");");
ctxt.generateJavaSource("}catch(java.io.IOException ex){");
ctxt.generateJavaSource(" throw new JspTagException(ex.toString(), ex);");
ctxt.generateJavaSource("}");
}
}
@@ -0,0 +1,45 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
import org.apache.jasper.tagplugins.jstl.Util;
public class Remove implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
//scope flag
boolean hasScope = ctxt.isAttributeSpecified("scope");
//the value of the "var"
String strVar = ctxt.getConstantAttribute("var");
//remove attribute from certain scope.
//default scope is "page".
if(hasScope){
int iScope = Util.getScope(ctxt.getConstantAttribute("scope"));
ctxt.generateJavaSource("pageContext.removeAttribute(\"" + strVar + "\"," + iScope + ");");
}else{
ctxt.generateJavaSource("pageContext.removeAttribute(\"" + strVar + "\");");
}
}
}
@@ -0,0 +1,167 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
import org.apache.jasper.tagplugins.jstl.Util;
public class Set implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
//the flags to indicate whether the attributes have been specified
boolean hasValue = false, hasVar = false, hasScope = false,
hasTarget = false;
//the scope name
String strScope;
//the id of the scope
int iScope;
//initialize the flags
hasValue = ctxt.isAttributeSpecified("value");
hasVar = ctxt.isAttributeSpecified("var");
hasScope = ctxt.isAttributeSpecified("scope");
hasTarget = ctxt.isAttributeSpecified("target");
//the temp variables name
String resultName = ctxt.getTemporaryVariableName();
String targetName = ctxt.getTemporaryVariableName();
String propertyName = ctxt.getTemporaryVariableName();
//initialize the "result" which will be assigned to the var or target.property
ctxt.generateJavaSource("Object " + resultName + " = null;");
if(hasValue){
ctxt.generateJavaSource(resultName + " = ");
ctxt.generateAttribute("value");
ctxt.generateJavaSource(";");
}else{
ctxt.dontUseTagPlugin();
return;
}
//initialize the strScope
if(hasScope){
strScope = ctxt.getConstantAttribute("scope");
}else{
strScope = "page";
}
//get the iScope according to the strScope
iScope = Util.getScope(strScope);
//if the attribute var has been specified then assign the result to the var;
if(hasVar){
String strVar = ctxt.getConstantAttribute("var");
ctxt.generateJavaSource("if(null != " + resultName + "){");
ctxt.generateJavaSource(" pageContext.setAttribute(\"" + strVar + "\"," + resultName + "," + iScope + ");");
ctxt.generateJavaSource("} else {");
if(hasScope){
ctxt.generateJavaSource(" pageContext.removeAttribute(\"" + strVar + "\"," + iScope + ");");
}else{
ctxt.generateJavaSource(" pageContext.removeAttribute(\"" + strVar + "\");");
}
ctxt.generateJavaSource("}");
//else assign the result to the target.property
}else if(hasTarget){
//generate the temp variable name
String pdName = ctxt.getTemporaryVariableName();
String successFlagName = ctxt.getTemporaryVariableName();
String index = ctxt.getTemporaryVariableName();
String methodName = ctxt.getTemporaryVariableName();
//initialize the property
ctxt.generateJavaSource("String " + propertyName + " = null;");
ctxt.generateJavaSource("if(");
ctxt.generateAttribute("property");
ctxt.generateJavaSource(" != null){");
ctxt.generateJavaSource(" " + propertyName + " = (");
ctxt.generateAttribute("property");
ctxt.generateJavaSource(").toString();");
ctxt.generateJavaSource("}");
//initialize the target
ctxt.generateJavaSource("Object " + targetName + " = ");
ctxt.generateAttribute("target");
ctxt.generateJavaSource(";");
//the target is ok
ctxt.generateJavaSource("if(" + targetName + " != null){");
//if the target is a map, then put the result into the map with the key property
ctxt.generateJavaSource(" if(" + targetName + " instanceof java.util.Map){");
ctxt.generateJavaSource(" if(null != " + resultName + "){");
ctxt.generateJavaSource(" ((java.util.Map) " + targetName + ").put(" + propertyName + "," + resultName + ");");
ctxt.generateJavaSource(" }else{");
ctxt.generateJavaSource(" ((java.util.Map) " + targetName + ").remove(" + propertyName + ");");
ctxt.generateJavaSource(" }");
//else assign the result to the target.property
ctxt.generateJavaSource(" }else{");
ctxt.generateJavaSource(" try{");
//get all the property of the target
ctxt.generateJavaSource(" java.beans.PropertyDescriptor " + pdName + "[] = java.beans.Introspector.getBeanInfo(" + targetName + ".getClass()).getPropertyDescriptors();");
//the success flag is to imply whether the assign is successful
ctxt.generateJavaSource(" boolean " + successFlagName + " = false;");
//find the right property
ctxt.generateJavaSource(" for(int " + index + "=0;" + index + "<" + pdName + ".length;" + index + "++){");
ctxt.generateJavaSource(" if(" + pdName + "[" + index + "].getName().equals(" + propertyName + ")){");
//get the "set" method;
ctxt.generateJavaSource(" java.lang.reflect.Method " + methodName + " = " + pdName + "[" + index + "].getWriteMethod();");
ctxt.generateJavaSource(" if(null == " + methodName + "){");
ctxt.generateJavaSource(" throw new JspException(\"No setter method in &lt;set&gt; for property \"+" + propertyName + ");");
ctxt.generateJavaSource(" }");
//invoke the method through the reflection
ctxt.generateJavaSource(" if(" + resultName + " != null){");
ctxt.generateJavaSource(" " + methodName + ".invoke(" + targetName + ", new Object[]{(" + methodName + ".getParameterTypes()[0]).cast(" + resultName + ")});");
ctxt.generateJavaSource(" }else{");
ctxt.generateJavaSource(" " + methodName + ".invoke(" + targetName + ", new Object[]{null});");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" " + successFlagName + " = true;");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" if(!" + successFlagName + "){");
ctxt.generateJavaSource(" throw new JspException(\"Invalid property in &lt;set&gt;:\"+" + propertyName + ");");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" }");
//catch the el exception and throw it as a JspException
ctxt.generateJavaSource(" catch (IllegalAccessException ex) {");
ctxt.generateJavaSource(" throw new JspException(ex);");
ctxt.generateJavaSource(" } catch (java.beans.IntrospectionException ex) {");
ctxt.generateJavaSource(" throw new JspException(ex);");
ctxt.generateJavaSource(" } catch (java.lang.reflect.InvocationTargetException ex) {");
ctxt.generateJavaSource(" throw new JspException(ex);");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource("}else{");
ctxt.generateJavaSource(" throw new JspException();");
ctxt.generateJavaSource("}");
}
}
}
@@ -0,0 +1,101 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
import org.apache.jasper.tagplugins.jstl.Util;
public class Url implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
//flags
boolean hasVar, hasContext, hasScope;
//init flags
hasVar = ctxt.isAttributeSpecified("var");
hasContext = ctxt.isAttributeSpecified("context");
hasScope = ctxt.isAttributeSpecified("scope");
//define name of the temp variables
String valueName = ctxt.getTemporaryVariableName();
String contextName = ctxt.getTemporaryVariableName();
String baseUrlName = ctxt.getTemporaryVariableName();
String resultName = ctxt.getTemporaryVariableName();
String responseName = ctxt.getTemporaryVariableName();
//get the scope
String strScope = "page";
if(hasScope){
strScope = ctxt.getConstantAttribute("scope");
}
int iScope = Util.getScope(strScope);
//get the value
ctxt.generateJavaSource("String " + valueName + " = ");
ctxt.generateAttribute("value");
ctxt.generateJavaSource(";");
//get the context
ctxt.generateJavaSource("String " + contextName + " = null;");
if(hasContext){
ctxt.generateJavaSource(contextName + " = ");
ctxt.generateAttribute("context");
ctxt.generateJavaSource(";");
}
//get the raw url
ctxt.generateJavaSource("String " + baseUrlName + " = " +
"org.apache.jasper.tagplugins.jstl.Util.resolveUrl(" + valueName + ", " + contextName + ", pageContext);");
ctxt.generateJavaSource("pageContext.setAttribute" +
"(\"url_without_param\", " + baseUrlName + ");");
//add params
ctxt.generateBody();
ctxt.generateJavaSource("String " + resultName + " = " +
"(String)pageContext.getAttribute(\"url_without_param\");");
ctxt.generateJavaSource("pageContext.removeAttribute(\"url_without_param\");");
//if the url is relative, encode it
ctxt.generateJavaSource("if(!org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + resultName + ")){");
ctxt.generateJavaSource(" HttpServletResponse " + responseName + " = " +
"((HttpServletResponse) pageContext.getResponse());");
ctxt.generateJavaSource(" " + resultName + " = "
+ responseName + ".encodeURL(" + resultName + ");");
ctxt.generateJavaSource("}");
//if "var" is specified, the url string store in the attribute var defines
if(hasVar){
String strVar = ctxt.getConstantAttribute("var");
ctxt.generateJavaSource("pageContext.setAttribute" +
"(\"" + strVar + "\", " + resultName + ", " + iScope + ");");
//if var is not specified, just print out the url string
}else{
ctxt.generateJavaSource("try{");
ctxt.generateJavaSource(" pageContext.getOut().print(" + resultName + ");");
ctxt.generateJavaSource("}catch(java.io.IOException ex){");
ctxt.generateJavaSource(" throw new JspTagException(ex.toString(), ex);");
ctxt.generateJavaSource("}");
}
}
}
@@ -0,0 +1,50 @@
/*
* 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.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.*;
public final class When implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
// Get the parent context to determine if this is the first <c:when>
TagPluginContext parentContext = ctxt.getParentContext();
if (parentContext == null) {
ctxt.dontUseTagPlugin();
return;
}
if ("true".equals(parentContext.getPluginAttribute("hasBeenHere"))) {
ctxt.generateJavaSource("} else if(");
// See comment below for the reason we generate the extra "}" here.
}
else {
ctxt.generateJavaSource("if(");
parentContext.setPluginAttribute("hasBeenHere", "true");
}
ctxt.generateAttribute("test");
ctxt.generateJavaSource("){");
ctxt.generateBody();
// We don't generate the closing "}" for the "if" here because there
// may be whitespaces in between <c:when>'s. Instead we delay
// generating it until the next <c:when> or <c:otherwise> or
// <c:choose>
}
}
@@ -0,0 +1,63 @@
<?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.
-->
<tag-plugins>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.If</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.Choose</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.WhenTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.When</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.Otherwise</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.ForEach</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.Out</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.SetTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.Set</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.common.core.RemoveTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.Remove</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.Catch</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.ForTokensTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.ForTokens</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.ImportTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.Import</plugin-class>
</tag-plugin>
</tag-plugins>
@@ -0,0 +1,176 @@
/*
* 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.jasper.util;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* Adapter class that wraps an <code>Enumeration</code> around a Java2
* collection classes object <code>Iterator</code> so that existing APIs
* returning Enumerations can easily run on top of the new collections.
* Constructors are provided to easliy create such wrappers.
*
* @author Craig R. McClanahan
* @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (Tue, 24 Oct 2006) $
*/
public final class Enumerator implements Enumeration {
// ----------------------------------------------------------- Constructors
/**
* Return an Enumeration over the values of the specified Collection.
*
* @param collection Collection whose values should be enumerated
*/
public Enumerator(Collection collection) {
this(collection.iterator());
}
/**
* Return an Enumeration over the values of the specified Collection.
*
* @param collection Collection whose values should be enumerated
* @param clone true to clone iterator
*/
public Enumerator(Collection collection, boolean clone) {
this(collection.iterator(), clone);
}
/**
* Return an Enumeration over the values returned by the
* specified Iterator.
*
* @param iterator Iterator to be wrapped
*/
public Enumerator(Iterator iterator) {
super();
this.iterator = iterator;
}
/**
* Return an Enumeration over the values returned by the
* specified Iterator.
*
* @param iterator Iterator to be wrapped
* @param clone true to clone iterator
*/
public Enumerator(Iterator iterator, boolean clone) {
super();
if (!clone) {
this.iterator = iterator;
} else {
List list = new ArrayList();
while (iterator.hasNext()) {
list.add(iterator.next());
}
this.iterator = list.iterator();
}
}
/**
* Return an Enumeration over the values of the specified Map.
*
* @param map Map whose values should be enumerated
*/
public Enumerator(Map map) {
this(map.values().iterator());
}
/**
* Return an Enumeration over the values of the specified Map.
*
* @param map Map whose values should be enumerated
* @param clone true to clone iterator
*/
public Enumerator(Map map, boolean clone) {
this(map.values().iterator(), clone);
}
// ----------------------------------------------------- Instance Variables
/**
* The <code>Iterator</code> over which the <code>Enumeration</code>
* represented by this class actually operates.
*/
private Iterator iterator = null;
// --------------------------------------------------------- Public Methods
/**
* Tests if this enumeration contains more elements.
*
* @return <code>true</code> if and only if this enumeration object
* contains at least one more element to provide, <code>false</code>
* otherwise
*/
public boolean hasMoreElements() {
return (iterator.hasNext());
}
/**
* Returns the next element of this enumeration if this enumeration
* has at least one more element to provide.
*
* @return the next element of this enumeration
*
* @exception NoSuchElementException if no more elements exist
*/
public Object nextElement() throws NoSuchElementException {
return (iterator.next());
}
}

Some files were not shown because too many files have changed in this diff Show More