JBossWeb SVN: r1108 - in trunk: java/org/apache/catalina and 5 other directories.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2009-06-11 14:06:11 -0400 (Thu, 11 Jun 2009)
New Revision: 1108
Modified:
trunk/ROADMAP.txt
trunk/java/org/apache/catalina/Wrapper.java
trunk/java/org/apache/catalina/connector/MapperListener.java
trunk/java/org/apache/catalina/core/StandardContext.java
trunk/java/org/apache/catalina/core/StandardWrapper.java
trunk/java/org/apache/catalina/deploy/SecurityCollection.java
trunk/java/org/apache/catalina/deploy/SecurityConstraint.java
trunk/java/org/apache/catalina/realm/RealmBase.java
trunk/java/org/apache/catalina/startup/WebRuleSet.java
Log:
- Add the new web elements. Not sure I got the omission thing right, though. Enabled is a todo.
Modified: trunk/ROADMAP.txt
===================================================================
--- trunk/ROADMAP.txt 2009-06-11 13:57:24 UTC (rev 1107)
+++ trunk/ROADMAP.txt 2009-06-11 18:06:11 UTC (rev 1108)
@@ -2,12 +2,9 @@
Standalone:
- Access control annotations
-- Update digester XML parsing rules for web.xml updates (session tracking-mode, cookie-config, servlet enabled,
- servlets and filters async-supported, http-method-omission)
- Enforce web.xml fragments merging rules
-- Migrate relevant components to JAR repository (in paticular classloader)
- Lazy webapp startup valve
-- Abstract JMX in custom modeler better
+- JMX abstraction: redo MapperListener with regular listeners, and abstract JMX in modeler
- JSP 2.2 changes
- EL 1.1 changes
Modified: trunk/java/org/apache/catalina/Wrapper.java
===================================================================
--- trunk/java/org/apache/catalina/Wrapper.java 2009-06-11 13:57:24 UTC (rev 1107)
+++ trunk/java/org/apache/catalina/Wrapper.java 2009-06-11 18:06:11 UTC (rev 1108)
@@ -120,6 +120,20 @@
/**
+ * Return the enabled value.
+ */
+ public boolean getEnabled();
+
+
+ /**
+ * Set the enabled value.
+ *
+ * @param value New async supported value
+ */
+ public void setEnabled(boolean enabled);
+
+
+ /**
* Return the InstanceSupport object for this Wrapper instance.
*/
public InstanceSupport getInstanceSupport();
Modified: trunk/java/org/apache/catalina/connector/MapperListener.java
===================================================================
--- trunk/java/org/apache/catalina/connector/MapperListener.java 2009-06-11 13:57:24 UTC (rev 1107)
+++ trunk/java/org/apache/catalina/connector/MapperListener.java 2009-06-11 18:06:11 UTC (rev 1108)
@@ -513,6 +513,7 @@
("mapperListener.registerWrapper",
wrapperName, contextName));
+ // FIXME: need to handle enabled flag
String[] mappings = (String[])
mBeanServer.invoke(objectName, "findMappings", null, null);
Object wrapper =
Modified: trunk/java/org/apache/catalina/core/StandardContext.java
===================================================================
--- trunk/java/org/apache/catalina/core/StandardContext.java 2009-06-11 13:57:24 UTC (rev 1107)
+++ trunk/java/org/apache/catalina/core/StandardContext.java 2009-06-11 18:06:11 UTC (rev 1108)
@@ -29,6 +29,7 @@
import java.util.EnumSet;
import java.util.EventListener;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
@@ -314,7 +315,7 @@
/**
* Session tracking modes.
*/
- protected Set<SessionTrackingMode> sessionTrackingModes = defaultSessionTrackingModes;
+ protected Set<SessionTrackingMode> sessionTrackingModes = null;
/**
@@ -1710,7 +1711,11 @@
public Set<SessionTrackingMode> getSessionTrackingModes() {
- return sessionTrackingModes;
+ if (sessionTrackingModes == null) {
+ return defaultSessionTrackingModes;
+ } else {
+ return sessionTrackingModes;
+ }
}
@@ -1720,6 +1725,19 @@
}
+ public void addSessionTrackingMode(String trackingMode) {
+ SessionTrackingMode mode = SessionTrackingMode.valueOf(trackingMode);
+ if (mode == null) {
+ // FIXME: error message
+ throw new IllegalArgumentException();
+ }
+ if (sessionTrackingModes == null) {
+ sessionTrackingModes = new HashSet<SessionTrackingMode>();
+ }
+ sessionTrackingModes.add(mode);
+ }
+
+
/**
* Return the "replace welcome files" property.
*/
@@ -2476,6 +2494,7 @@
public void addServletMapping(String pattern, String name,
boolean jspWildCard) {
// Validate the proposed mapping
+ Wrapper wrapper = (Wrapper) findChild(name);
if (findChild(name) == null)
throw new IllegalArgumentException
(sm.getString("standardContext.servletMap.name", name));
@@ -2488,16 +2507,17 @@
String name2 = (String) servletMappings.get(pattern);
if (name2 != null) {
// Don't allow more than one servlet on the same pattern
- Wrapper wrapper = (Wrapper) findChild(name2);
- wrapper.removeMapping(pattern);
+ Wrapper wrapper2 = (Wrapper) findChild(name2);
+ wrapper2.removeMapping(pattern);
mapper.removeWrapper(pattern);
}
servletMappings.put(pattern, name);
- Wrapper wrapper = (Wrapper) findChild(name);
wrapper.addMapping(pattern);
// Update context mapper
- mapper.addWrapper(pattern, wrapper, jspWildCard);
+ if (wrapper.getEnabled()) {
+ mapper.addWrapper(pattern, wrapper, jspWildCard);
+ }
fireContainerEvent("addServletMapping", pattern);
@@ -4189,6 +4209,8 @@
try {
+
+
// Create context attributes that will be required
if (ok) {
postContextAttributes();
Modified: trunk/java/org/apache/catalina/core/StandardWrapper.java
===================================================================
--- trunk/java/org/apache/catalina/core/StandardWrapper.java 2009-06-11 13:57:24 UTC (rev 1107)
+++ trunk/java/org/apache/catalina/core/StandardWrapper.java 2009-06-11 18:06:11 UTC (rev 1108)
@@ -112,6 +112,12 @@
/**
+ * Enabled flag.
+ */
+ protected boolean enabled = true;
+
+
+ /**
* The date and time at which this servlet will become available (in
* milliseconds since the epoch), or zero if the servlet is available.
* If this value equals Long.MAX_VALUE, the unavailability of this
@@ -310,14 +316,6 @@
/**
- * Return the Servlet description.
- */
- public String getDescription() {
- return description;
- }
-
-
- /**
* Set the async supported value.
*
* @param value New async supported value
@@ -330,6 +328,14 @@
/**
+ * Return the Servlet description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+
+ /**
* Set the description.
*/
public void setDescription(String description) {
@@ -354,6 +360,26 @@
/**
+ * Return the enabled value.
+ */
+ public boolean getEnabled() {
+ return enabled;
+ }
+
+
+ /**
+ * Set the enabled value.
+ *
+ * @param value New enabled value
+ */
+ public void setEnabled(boolean value) {
+ boolean oldEnabled = this.enabled;
+ this.enabled = value;
+ support.firePropertyChange("enabled", oldEnabled, enabled);
+ }
+
+
+ /**
* Return the available date/time for this servlet, in milliseconds since
* the epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
* that unavailability is permanent and any request for this servlet will return
Modified: trunk/java/org/apache/catalina/deploy/SecurityCollection.java
===================================================================
--- trunk/java/org/apache/catalina/deploy/SecurityCollection.java 2009-06-11 13:57:24 UTC (rev 1107)
+++ trunk/java/org/apache/catalina/deploy/SecurityCollection.java 2009-06-11 18:06:11 UTC (rev 1108)
@@ -98,6 +98,12 @@
/**
+ * The HTTP methods not covered by this web resource collection.
+ */
+ private String methodOmissions[] = new String[0];
+
+
+ /**
* The name of this web resource collection.
*/
private String name = null;
@@ -176,6 +182,22 @@
/**
+ * Add an HTTP request method to be skipped from this web resource collection.
+ */
+ public void addMethodOmission(String method) {
+
+ if (method == null)
+ return;
+ String results[] = new String[methodOmissions.length + 1];
+ for (int i = 0; i < methodOmissions.length; i++)
+ results[i] = methodOmissions[i];
+ results[methodOmissions.length] = method;
+ methodOmissions = results;
+
+ }
+
+
+ /**
* Add a URL pattern to be part of this web resource collection.
*/
public void addPattern(String pattern) {
@@ -226,6 +248,37 @@
/**
+ * Return <code>true</code> if the specified HTTP request method is
+ * not part of this web resource collection.
+ *
+ * @param method Request method to check
+ */
+ public boolean findMethodOmission(String method) {
+
+ if (methods.length == 0)
+ return (true);
+ for (int i = 0; i < methodOmissions.length; i++) {
+ if (methodOmissions[i].equals(method))
+ return (true);
+ }
+ return (false);
+
+ }
+
+
+ /**
+ * Return the set of HTTP request methods that are not part of this web
+ * resource collection, or a zero-length array if no request methods
+ * is omitted.
+ */
+ public String[] findMethodOmissions() {
+
+ return (methodOmissions);
+
+ }
+
+
+ /**
* Is the specified pattern part of this web resource collection?
*
* @param pattern Pattern to be compared
@@ -284,6 +337,36 @@
/**
+ * Remove the specified HTTP request method from those that are not part
+ * of this web resource collection.
+ *
+ * @param method Request method to be removed
+ */
+ public void removeMethodOmission(String method) {
+
+ if (method == null)
+ return;
+ int n = -1;
+ for (int i = 0; i < methodOmissions.length; i++) {
+ if (methodOmissions[i].equals(method)) {
+ n = i;
+ break;
+ }
+ }
+ if (n >= 0) {
+ int j = 0;
+ String results[] = new String[methodOmissions.length - 1];
+ for (int i = 0; i < methodOmissions.length; i++) {
+ if (i != n)
+ results[j++] = methodOmissions[i];
+ }
+ methodOmissions = results;
+ }
+
+ }
+
+
+ /**
* Remove the specified URL pattern from those that are part of this
* web resource collection.
*
Modified: trunk/java/org/apache/catalina/deploy/SecurityConstraint.java
===================================================================
--- trunk/java/org/apache/catalina/deploy/SecurityConstraint.java 2009-06-11 13:57:24 UTC (rev 1107)
+++ trunk/java/org/apache/catalina/deploy/SecurityConstraint.java 2009-06-11 18:06:11 UTC (rev 1108)
@@ -304,6 +304,8 @@
for (int i = 0; i < collections.length; i++) {
if (!collections[i].findMethod(method))
continue;
+ if (collections[i].findMethodOmission(method))
+ continue;
String patterns[] = collections[i].findPatterns();
for (int j = 0; j < patterns.length; j++) {
if (matchPattern(uri, patterns[j]))
Modified: trunk/java/org/apache/catalina/realm/RealmBase.java
===================================================================
--- trunk/java/org/apache/catalina/realm/RealmBase.java 2009-06-11 13:57:24 UTC (rev 1107)
+++ trunk/java/org/apache/catalina/realm/RealmBase.java 2009-06-11 18:06:11 UTC (rev 1108)
@@ -493,6 +493,9 @@
}
for(int j=0; j < collection.length; j++){
+ if(collection[j].findMethodOmission(method)) {
+ continue;
+ }
String [] patterns = collection[j].findPatterns();
// If patterns is null, continue to avoid an NPE
@@ -537,6 +540,9 @@
}
for(int j=0; j < collection.length; j++){
+ if(collection[j].findMethodOmission(method)) {
+ continue;
+ }
String [] patterns = collection[j].findPatterns();
// If patterns is null, continue to avoid an NPE
@@ -606,6 +612,9 @@
int pos = -1;
for(int j=0; j < collection.length; j++){
String [] patterns = collection[j].findPatterns();
+ if(collection[j].findMethodOmission(method)) {
+ continue;
+ }
// If patterns is null, continue to avoid an NPE
// See Bugzilla 30624
Modified: trunk/java/org/apache/catalina/startup/WebRuleSet.java
===================================================================
--- trunk/java/org/apache/catalina/startup/WebRuleSet.java 2009-06-11 13:57:24 UTC (rev 1107)
+++ trunk/java/org/apache/catalina/startup/WebRuleSet.java 2009-06-11 18:06:11 UTC (rev 1108)
@@ -202,6 +202,10 @@
"addFilterDef",
"org.apache.catalina.deploy.FilterDef");
+ digester.addCallMethod(prefix + elementName + "/filter/async-supported",
+ "setAsyncSupported", 1, new Class[] { Boolean.TYPE });
+ digester.addCallParam(prefix + elementName + "/filter/async-supported", 0);
+
digester.addCallMethod(prefix + elementName + "/filter/description",
"setDescription", 0);
digester.addCallMethod(prefix + elementName + "/filter/display-name",
@@ -325,6 +329,8 @@
"org.apache.catalina.deploy.SecurityCollection");
digester.addCallMethod(prefix + elementName + "/security-constraint/web-resource-collection/http-method",
"addMethod", 0);
+ digester.addCallMethod(prefix + elementName + "/security-constraint/web-resource-collection/http-method-omission",
+ "addMethodOmission", 0);
digester.addCallMethod(prefix + elementName + "/security-constraint/web-resource-collection/url-pattern",
"addPattern", 0);
digester.addCallMethod(prefix + elementName + "/security-constraint/web-resource-collection/web-resource-name",
@@ -339,9 +345,17 @@
"addChild",
"org.apache.catalina.Container");
+ digester.addCallMethod(prefix + elementName + "/servlet/async-supported",
+ "setAsyncSupported", 1, new Class[] { Boolean.TYPE });
+ digester.addCallParam(prefix + elementName + "/servlet/async-supported", 0);
+
digester.addCallMethod(prefix + elementName + "/servlet/description",
"setDescription", 0);
+ digester.addCallMethod(prefix + elementName + "/servlet/enabled",
+ "setEnabled", 1, new Class[] { Boolean.TYPE });
+ digester.addCallParam(prefix + elementName + "/servlet/enabled", 0);
+
digester.addCallMethod(prefix + elementName + "/servlet/init-param",
"addInitParameter", 2);
digester.addCallParam(prefix + elementName + "/servlet/init-param/param-name",
@@ -378,6 +392,30 @@
"setSessionTimeout", 1,
new Class[] { Integer.TYPE });
digester.addCallParam(prefix + elementName + "/session-config/session-timeout", 0);
+ digester.addCallMethod(prefix + elementName + "/session-config/tracking-mode", "addSessionTrackingMode", 0);
+
+ digester.addObjectCreate(prefix + elementName + "/session-config/cookie-config",
+ "org.apache.catalina.deploy.SessionCookie");
+ digester.addSetNext(prefix + elementName + "/session-config/cookie-config",
+ "setSessionCookie",
+ "org.apache.catalina.deploy.SessionCookie");
+ digester.addCallMethod(prefix + elementName + "/session-config/cookie-config/cookie-name",
+ "setName", 0);
+ digester.addCallMethod(prefix + elementName + "/session-config/cookie-config/cookie-domain",
+ "setDomain", 0);
+ digester.addCallMethod(prefix + elementName + "/session-config/cookie-config/cookie-path",
+ "setPath", 0);
+ digester.addCallMethod(prefix + elementName + "/session-config/cookie-config/cookie-comment",
+ "setComment", 0);
+ digester.addCallMethod(prefix + elementName + "/session-config/cookie-config/http-only",
+ "setHttpOnly", 1, new Class[] { Boolean.TYPE });
+ digester.addCallParam(prefix + elementName + "/session-config/cookie-config/http-only", 0);
+ digester.addCallMethod(prefix + elementName + "/session-config/cookie-config/secure",
+ "setSecure", 1, new Class[] { Boolean.TYPE });
+ digester.addCallParam(prefix + elementName + "/session-config/cookie-config/secure", 0);
+ digester.addCallMethod(prefix + elementName + "/session-config/cookie-config/max-age",
+ "setMaxAge", 1, new Class[] { Integer.TYPE });
+ digester.addCallParam(prefix + elementName + "/session-config/cookie-config/max-age", 0);
digester.addCallMethod(prefix + elementName + "/taglib",
"addTaglib", 2);
15 years, 9 months
JBossWeb SVN: r1107 - sandbox/webapps/src.
by jbossweb-commits@lists.jboss.org
Author: jfrederic.clere(a)jboss.com
Date: 2009-06-11 09:57:24 -0400 (Thu, 11 Jun 2009)
New Revision: 1107
Modified:
sandbox/webapps/src/MyCookies.java
Log:
Add a cookie with comment :-)
Modified: sandbox/webapps/src/MyCookies.java
===================================================================
--- sandbox/webapps/src/MyCookies.java 2009-06-11 12:30:07 UTC (rev 1106)
+++ sandbox/webapps/src/MyCookies.java 2009-06-11 13:57:24 UTC (rev 1107)
@@ -108,9 +108,16 @@
/* create the cookies */
for (int i=0; i<mytest.length; i++) {
- Cookie cookie = CreateCookie(mytest[i]);
- response.addCookie(cookie);
+ try {
+ Cookie cookie = CreateCookie(mytest[i]);
+ response.addCookie(cookie);
+ } catch (Exception ex) {
+ out.println("Cookie test: " + i + " Failed");
+ }
}
+ Cookie cookie = new Cookie("commented", "commented cookie");
+ cookie.setComment("This is a comment");
+ response.addCookie(cookie);
out.println("<P>");
15 years, 9 months
JBossWeb SVN: r1106 - trunk.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2009-06-11 08:30:07 -0400 (Thu, 11 Jun 2009)
New Revision: 1106
Modified:
trunk/build.properties.default
trunk/build.xml
trunk/dist.xml
Log:
- Update to pool 1.5.
- Remove deployer packaging.
Modified: trunk/build.properties.default
===================================================================
--- trunk/build.properties.default 2009-06-11 12:29:25 UTC (rev 1105)
+++ trunk/build.properties.default 2009-06-11 12:30:07 UTC (rev 1106)
@@ -48,16 +48,9 @@
commons-dbcp-src.loc=${base-commons.loc}/dbcp/source/commons-dbcp-1.2.2-src.tar.gz
# ----- Commons Pool, version 1.1 or later -----
-commons-pool.home=${base.path}/commons-pool-1.4-src
-commons-pool-src.loc=${base-commons.loc}/pool/source/commons-pool-1.4-src.tar.gz
+commons-pool.home=${base.path}/commons-pool-1.5-src
+commons-pool-src.loc=${base-commons.loc}/pool/source/commons-pool-1.5-src.tar.gz
-# ----- Commons Collections, version 2.0 or later -----
-commons-collections.home=${base.path}/commons-collections-3.2.1-src
-commons-collections.lib=${commons-collections.home}
-commons-collections.jar=${commons-collections.lib}/commons-collections-3.2.1.jar
-commons-collections.loc=${base-jakarta.loc}/commons/collections/binaries/commons-collections-3.2.1.tar.gz
-commons-collections-src.loc=${base-commons.loc}/collections/source/commons-collections-3.2.1-src.tar.gz
-
# ----- NSIS, version 2.0 or later -----
nsis.home=${base.path}/nsis-2.44
nsis.exe=${nsis.home}/makensis.exe
Modified: trunk/build.xml
===================================================================
--- trunk/build.xml 2009-06-11 12:29:25 UTC (rev 1105)
+++ trunk/build.xml 2009-06-11 12:30:07 UTC (rev 1106)
@@ -36,7 +36,7 @@
<property name="test.runner" value="junit.textui.TestRunner"/>
<!-- Can't be lower - jsp uses templates -->
- <property name="compile.source" value="1.5"/>
+ <property name="compile.source" value="1.6"/>
<!-- JAR artifacts -->
<property name="bootstrap.jar" value="${tomcat.build}/bin/bootstrap.jar"/>
@@ -690,10 +690,6 @@
<!-- Build Tomcat DBCP bundle -->
<antcall target="downloadgz">
- <param name="sourcefile" value="${commons-collections-src.loc}"/>
- <param name="destfile" value="${tomcat-dbcp.jar}" />
- </antcall>
- <antcall target="downloadgz">
<param name="sourcefile" value="${commons-pool-src.loc}"/>
<param name="destfile" value="${tomcat-dbcp.jar}" />
</antcall>
@@ -786,8 +782,8 @@
debug="${compile.debug}"
optimize="${compile.optimize}"
deprecation="${compile.deprecation}"
- source="${compile.source}"
- target="${compile.target}"
+ source="1.5"
+ target="1.5"
excludes="**/CVS/**,**/.svn/**">
<include name="**" />
</javac>
Modified: trunk/dist.xml
===================================================================
--- trunk/dist.xml 2009-06-11 12:29:25 UTC (rev 1105)
+++ trunk/dist.xml 2009-06-11 12:30:07 UTC (rev 1106)
@@ -256,7 +256,7 @@
<!-- ==================== RELEASE: Create Release ======================= -->
- <target name="release" depends="clean,dist-static,dist-deployer,installer,package-zip,package-tgz,package-deployer-zip,package-deployer-tgz,dist-source,dist-javadoc,package-docs-tgz,package-src-zip,package-src-tgz"
+ <target name="release" depends="clean,dist-static,installer,package-zip,package-tgz,dist-source,dist-javadoc,package-docs-tgz,package-src-zip,package-src-tgz"
description="Create a JBoss Web packaged distribution">
<filter token="VERSION" value="${version}"/>
15 years, 9 months
JBossWeb SVN: r1105 - in trunk/java/org/apache/jasper: compiler and 1 other directory.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2009-06-11 08:29:25 -0400 (Thu, 11 Jun 2009)
New Revision: 1105
Removed:
trunk/java/org/apache/jasper/JspC.java
trunk/java/org/apache/jasper/compiler/AntCompiler.java
trunk/java/org/apache/jasper/compiler/TldLocationsCache.java
Modified:
trunk/java/org/apache/jasper/EmbeddedServletOptions.java
trunk/java/org/apache/jasper/Options.java
trunk/java/org/apache/jasper/compiler/JspConfig.java
Log:
- Remove the legacy XML processing (still there for easy comparisons in the 2.1 branch).
- Remove jspc (which cannot work anymore with a Servlet 3.0 webapp).
Modified: trunk/java/org/apache/jasper/EmbeddedServletOptions.java
===================================================================
--- trunk/java/org/apache/jasper/EmbeddedServletOptions.java 2009-06-11 11:11:18 UTC (rev 1104)
+++ trunk/java/org/apache/jasper/EmbeddedServletOptions.java 2009-06-11 12:29:25 UTC (rev 1105)
@@ -28,7 +28,6 @@
import org.apache.jasper.compiler.JspConfig;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.compiler.TagPluginManager;
-import org.apache.jasper.compiler.TldLocationsCache;
import org.apache.jasper.xmlparser.ParserUtils;
import org.jboss.logging.Logger;
@@ -151,11 +150,6 @@
private String compilerClassName = null;
/**
- * Cache for the TLD locations
- */
- private TldLocationsCache tldLocationsCache = null;
-
- /**
* Jsp config information
*/
private JspConfig jspConfig = null;
@@ -344,14 +338,6 @@
errorOnUseBeanInvalidClassAttribute = b;
}
- public TldLocationsCache getTldLocationsCache() {
- return tldLocationsCache;
- }
-
- public void setTldLocationsCache( TldLocationsCache tldC ) {
- tldLocationsCache = tldC;
- }
-
public String getJavaEncoding() {
return javaEncoding;
}
@@ -645,10 +631,6 @@
}
}
- // 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);
Deleted: trunk/java/org/apache/jasper/JspC.java
===================================================================
--- trunk/java/org/apache/jasper/JspC.java 2009-06-11 11:11:18 UTC (rev 1104)
+++ trunk/java/org/apache/jasper/JspC.java 2009-06-11 12:29:25 UTC (rev 1105)
@@ -1,1418 +0,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.
- */
-
-package org.apache.jasper;
-
-import java.io.BufferedReader;
-import java.io.CharArrayWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Writer;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Stack;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import org.apache.jasper.compiler.Compiler;
-import org.apache.jasper.compiler.JspConfig;
-import org.apache.jasper.compiler.JspRuntimeContext;
-import org.apache.jasper.compiler.Localizer;
-import org.apache.jasper.compiler.TagPluginManager;
-import org.apache.jasper.compiler.TldLocationsCache;
-import org.apache.jasper.servlet.JspCServletContext;
-
-import org.apache.tools.ant.AntClassLoader;
-import org.apache.tools.ant.Project;
-import org.apache.tools.ant.util.FileUtils;
-import org.jboss.logging.Logger;
-import org.jboss.logging.Logger;
-
-/**
- * Shell for the jspc compiler. Handles all options associated with the
- * command line and creates compilation contexts which it then compiles
- * according to the specified options.
- *
- * This version can process files from a _single_ webapp at once, i.e.
- * a single docbase can be specified.
- *
- * It can be used as an Ant task using:
- * <pre>
- * <taskdef classname="org.apache.jasper.JspC" name="jasper2" >
- * <classpath>
- * <pathelement location="${java.home}/../lib/tools.jar"/>
- * <fileset dir="${ENV.CATALINA_HOME}/server/lib">
- * <include name="*.jar"/>
- * </fileset>
- * <fileset dir="${ENV.CATALINA_HOME}/common/lib">
- * <include name="*.jar"/>
- * </fileset>
- * <path refid="myjars"/>
- * </classpath>
- * </taskdef>
- *
- * <jasper2 verbose="0"
- * package="my.package"
- * uriroot="${webapps.dir}/${webapp.name}"
- * webXmlFragment="${build.dir}/generated_web.xml"
- * outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
- * </pre>
- *
- * @author Danno Ferrin
- * @author Pierre Delisle
- * @author Costin Manolache
- * @author Yoav Shapira
- */
-public class JspC implements Options {
-
- public static final String DEFAULT_IE_CLASS_ID =
- "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
-
- // Logger
- protected static Logger log = Logger.getLogger(JspC.class);
-
- protected static final String SWITCH_VERBOSE = "-v";
- protected static final String SWITCH_HELP = "-help";
- protected static final String SWITCH_OUTPUT_DIR = "-d";
- protected static final String SWITCH_PACKAGE_NAME = "-p";
- protected static final String SWITCH_CACHE = "-cache";
- protected static final String SWITCH_CLASS_NAME = "-c";
- protected static final String SWITCH_FULL_STOP = "--";
- protected static final String SWITCH_COMPILE = "-compile";
- protected static final String SWITCH_SOURCE = "-source";
- protected static final String SWITCH_TARGET = "-target";
- protected static final String SWITCH_URI_BASE = "-uribase";
- protected static final String SWITCH_URI_ROOT = "-uriroot";
- protected static final String SWITCH_FILE_WEBAPP = "-webapp";
- protected static final String SWITCH_WEBAPP_INC = "-webinc";
- protected static final String SWITCH_WEBAPP_XML = "-webxml";
- protected static final String SWITCH_MAPPED = "-mapped";
- protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy";
- protected static final String SWITCH_TRIM_SPACES = "-trimSpaces";
- protected static final String SWITCH_CLASSPATH = "-classpath";
- protected static final String SWITCH_DIE = "-die";
- protected static final String SWITCH_POOLING = "-poolingEnabled";
- protected static final String SWITCH_ENCODING = "-javaEncoding";
- protected static final String SWITCH_SMAP = "-smap";
- protected static final String SWITCH_DUMP_SMAP = "-dumpsmap";
-
- protected static final String SHOW_SUCCESS ="-s";
- protected static final String LIST_ERRORS = "-l";
- protected static final int INC_WEBXML = 10;
- protected static final int ALL_WEBXML = 20;
- protected static final int DEFAULT_DIE_LEVEL = 1;
- protected static final int NO_DIE_LEVEL = 0;
-
- protected static final String[] insertBefore =
- { "</web-app>", "<servlet-mapping>", "<session-config>",
- "<mime-mapping>", "<welcome-file-list>", "<error-page>", "<taglib>",
- "<resource-env-ref>", "<resource-ref>", "<security-constraint>",
- "<login-config>", "<security-role>", "<env-entry>", "<ejb-ref>",
- "<ejb-local-ref>" };
-
- protected static int die;
- protected String classPath = null;
- protected URLClassLoader loader = null;
- protected boolean trimSpaces = false;
- protected boolean genStringAsCharArray = false;
- protected boolean xpoweredBy;
- protected boolean mappedFile = false;
- protected boolean poolingEnabled = true;
- protected File scratchDir;
- protected String ieClassId = DEFAULT_IE_CLASS_ID;
- protected String targetPackage;
- protected String targetClassName;
- protected String uriBase;
- protected String uriRoot;
- protected Project project;
- protected int dieLevel;
- protected boolean helpNeeded = false;
- protected boolean compile = false;
- protected boolean smapSuppressed = true;
- protected boolean smapDumped = false;
- protected boolean caching = true;
- protected Map cache = new HashMap();
-
- protected String compiler = null;
-
- protected String compilerTargetVM = "1.4";
- protected String compilerSourceVM = "1.4";
-
- protected boolean classDebugInfo = true;
-
- /**
- * Throw an exception if there's a compilation error, or swallow it.
- * Default is true to preserve old behavior.
- */
- protected boolean failOnError = true;
-
- /**
- * The file extensions to be handled as JSP files.
- * Default list is .jsp and .jspx.
- */
- protected List extensions;
-
- /**
- * The pages.
- */
- protected List pages = new Vector();
-
- /**
- * Needs better documentation, this data member does.
- * True by default.
- */
- protected boolean errorOnUseBeanInvalidClassAttribute = true;
-
- /**
- * The java file encoding. Default
- * is UTF-8. Added per bugzilla 19622.
- */
- protected String javaEncoding = "UTF-8";
-
- // Generation of web.xml fragments
- protected String webxmlFile;
- protected int webxmlLevel;
- protected boolean addWebXmlMappings = false;
-
- protected Writer mapout;
- protected CharArrayWriter servletout;
- protected CharArrayWriter mappingout;
-
- /**
- * The servlet context.
- */
- protected JspCServletContext context;
-
- /**
- * The runtime context.
- * Maintain a dummy JspRuntimeContext for compiling tag files.
- */
- protected JspRuntimeContext rctxt;
-
- /**
- * Cache for the TLD locations
- */
- protected TldLocationsCache tldLocationsCache = null;
-
- protected JspConfig jspConfig = null;
- protected TagPluginManager tagPluginManager = null;
-
- protected boolean verbose = false;
- protected boolean listErrors = false;
- protected boolean showSuccess = false;
- protected int argPos;
- protected boolean fullstop = false;
- protected String args[];
-
- public static void main(String arg[]) {
- if (arg.length == 0) {
- System.out.println(Localizer.getMessage("jspc.usage"));
- } else {
- try {
- JspC jspc = new JspC();
- jspc.setArgs(arg);
- if (jspc.helpNeeded) {
- System.out.println(Localizer.getMessage("jspc.usage"));
- } else {
- jspc.execute();
- }
- } catch (JasperException je) {
- System.err.println(je);
- if (die != NO_DIE_LEVEL) {
- System.exit(die);
- }
- }
- }
- }
-
- public void setArgs(String[] arg) throws JasperException {
- args = arg;
- String tok;
-
- dieLevel = NO_DIE_LEVEL;
- die = dieLevel;
-
- while ((tok = nextArg()) != null) {
- if (tok.equals(SWITCH_VERBOSE)) {
- verbose = true;
- showSuccess = true;
- listErrors = true;
- } else if (tok.equals(SWITCH_OUTPUT_DIR)) {
- tok = nextArg();
- setOutputDir( tok );
- } else if (tok.equals(SWITCH_PACKAGE_NAME)) {
- targetPackage = nextArg();
- } else if (tok.equals(SWITCH_COMPILE)) {
- compile=true;
- } else if (tok.equals(SWITCH_CLASS_NAME)) {
- targetClassName = nextArg();
- } else if (tok.equals(SWITCH_URI_BASE)) {
- uriBase=nextArg();
- } else if (tok.equals(SWITCH_URI_ROOT)) {
- setUriroot( nextArg());
- } else if (tok.equals(SWITCH_FILE_WEBAPP)) {
- setUriroot( nextArg());
- } else if ( tok.equals( SHOW_SUCCESS ) ) {
- showSuccess = true;
- } else if ( tok.equals( LIST_ERRORS ) ) {
- listErrors = true;
- } else if (tok.equals(SWITCH_WEBAPP_INC)) {
- webxmlFile = nextArg();
- if (webxmlFile != null) {
- webxmlLevel = INC_WEBXML;
- }
- } else if (tok.equals(SWITCH_WEBAPP_XML)) {
- webxmlFile = nextArg();
- if (webxmlFile != null) {
- webxmlLevel = ALL_WEBXML;
- }
- } else if (tok.equals(SWITCH_MAPPED)) {
- mappedFile = true;
- } else if (tok.equals(SWITCH_XPOWERED_BY)) {
- xpoweredBy = true;
- } else if (tok.equals(SWITCH_TRIM_SPACES)) {
- setTrimSpaces(true);
- } else if (tok.equals(SWITCH_CACHE)) {
- tok = nextArg();
- if ("false".equals(tok)) {
- caching = false;
- } else {
- caching = true;
- }
- } else if (tok.equals(SWITCH_CLASSPATH)) {
- setClassPath(nextArg());
- } else if (tok.startsWith(SWITCH_DIE)) {
- try {
- dieLevel = Integer.parseInt(
- tok.substring(SWITCH_DIE.length()));
- } catch (NumberFormatException nfe) {
- dieLevel = DEFAULT_DIE_LEVEL;
- }
- die = dieLevel;
- } else if (tok.equals(SWITCH_HELP)) {
- helpNeeded = true;
- } else if (tok.equals(SWITCH_POOLING)) {
- tok = nextArg();
- if ("false".equals(tok)) {
- poolingEnabled = false;
- } else {
- poolingEnabled = true;
- }
- } else if (tok.equals(SWITCH_ENCODING)) {
- setJavaEncoding(nextArg());
- } else if (tok.equals(SWITCH_SOURCE)) {
- setCompilerSourceVM(nextArg());
- } else if (tok.equals(SWITCH_TARGET)) {
- setCompilerTargetVM(nextArg());
- } else if (tok.equals(SWITCH_SMAP)) {
- smapSuppressed = false;
- } else if (tok.equals(SWITCH_DUMP_SMAP)) {
- smapDumped = true;
- } else {
- if (tok.startsWith("-")) {
- throw new JasperException("Unrecognized option: " + tok +
- ". Use -help for help.");
- }
- if (!fullstop) {
- argPos--;
- }
- // Start treating the rest as JSP Pages
- break;
- }
- }
-
- // Add all extra arguments to the list of files
- while( true ) {
- String file = nextFile();
- if( file==null ) {
- break;
- }
- pages.add( file );
- }
- }
-
- public boolean getKeepGenerated() {
- // isn't this why we are running jspc?
- return true;
- }
-
- public boolean getTrimSpaces() {
- return trimSpaces;
- }
-
- public void setTrimSpaces(boolean ts) {
- this.trimSpaces = ts;
- }
-
- public boolean isPoolingEnabled() {
- return poolingEnabled;
- }
-
- public void setPoolingEnabled(boolean poolingEnabled) {
- this.poolingEnabled = poolingEnabled;
- }
-
- public boolean isXpoweredBy() {
- return xpoweredBy;
- }
-
- public void setXpoweredBy(boolean xpoweredBy) {
- this.xpoweredBy = xpoweredBy;
- }
-
- public boolean getDisplaySourceFragment() {
- return true;
- }
-
- public boolean getErrorOnUseBeanInvalidClassAttribute() {
- return errorOnUseBeanInvalidClassAttribute;
- }
-
- public void setErrorOnUseBeanInvalidClassAttribute(boolean b) {
- errorOnUseBeanInvalidClassAttribute = b;
- }
-
- public int getTagPoolSize() {
- return Constants.MAX_POOL_SIZE;
- }
-
- /**
- * Are we supporting HTML mapped servlets?
- */
- public boolean getMappedFile() {
- return mappedFile;
- }
-
- // Off-line compiler, no need for security manager
- public Object getProtectionDomain() {
- return null;
- }
-
- public boolean getSendErrorToClient() {
- // implied send to System.err
- return true;
- }
-
- public void setClassDebugInfo( boolean b ) {
- classDebugInfo=b;
- }
-
- public boolean getClassDebugInfo() {
- // compile with debug info
- return classDebugInfo;
- }
-
- /**
- * @see Options#isCaching()
- */
- public boolean isCaching() {
- return caching;
- }
-
- /**
- * @see Options#isCaching()
- */
- public void setCaching(boolean caching) {
- this.caching = caching;
- }
-
- /**
- * @see Options#getCache()
- */
- public Map getCache() {
- return cache;
- }
-
- /**
- * Background compilation check intervals in seconds
- */
- public int getCheckInterval() {
- return 0;
- }
-
- /**
- * Modification test interval.
- */
- public int getModificationTestInterval() {
- return 0;
- }
-
- /**
- * Is Jasper being used in development mode?
- */
- public boolean getDevelopment() {
- return false;
- }
-
- /**
- * Is the generation of SMAP info for JSR45 debuggin suppressed?
- */
- public boolean isSmapSuppressed() {
- return smapSuppressed;
- }
-
- /**
- * Set smapSuppressed flag.
- */
- public void setSmapSuppressed(boolean smapSuppressed) {
- this.smapSuppressed = smapSuppressed;
- }
-
-
- /**
- * Should SMAP info for JSR45 debugging be dumped to a file?
- */
- public boolean isSmapDumped() {
- return smapDumped;
- }
-
- /**
- * Set smapSuppressed flag.
- */
- public void setSmapDumped(boolean smapDumped) {
- this.smapDumped = smapDumped;
- }
-
-
- /**
- * Determines whether text strings are to be generated as char arrays,
- * which improves performance in some cases.
- *
- * @param genStringAsCharArray true if text strings are to be generated as
- * char arrays, false otherwise
- */
- public void setGenStringAsCharArray(boolean genStringAsCharArray) {
- this.genStringAsCharArray = genStringAsCharArray;
- }
-
- /**
- * Indicates whether text strings are to be generated as char arrays.
- *
- * @return true if text strings are to be generated as char arrays, false
- * otherwise
- */
- public boolean genStringAsCharArray() {
- return genStringAsCharArray;
- }
-
- /**
- * Sets the class-id value to be sent to Internet Explorer when using
- * <jsp:plugin> tags.
- *
- * @param ieClassId Class-id value
- */
- public void setIeClassId(String ieClassId) {
- this.ieClassId = ieClassId;
- }
-
- /**
- * Gets the class-id value that is sent to Internet Explorer when using
- * <jsp:plugin> tags.
- *
- * @return Class-id value
- */
- public String getIeClassId() {
- return ieClassId;
- }
-
- public File getScratchDir() {
- return scratchDir;
- }
-
- public Class getJspCompilerPlugin() {
- // we don't compile, so this is meanlingless
- return null;
- }
-
- public String getJspCompilerPath() {
- // we don't compile, so this is meanlingless
- return null;
- }
-
- /**
- * Compiler to use.
- */
- public String getCompiler() {
- return compiler;
- }
-
- public void setCompiler(String c) {
- compiler=c;
- }
-
- /**
- * Compiler class name to use.
- */
- public String getCompilerClassName() {
- return null;
- }
-
- /**
- * @see Options#getCompilerTargetVM
- */
- public String getCompilerTargetVM() {
- return compilerTargetVM;
- }
-
- public void setCompilerTargetVM(String vm) {
- compilerTargetVM = vm;
- }
-
- /**
- * @see Options#getCompilerSourceVM()
- */
- public String getCompilerSourceVM() {
- return compilerSourceVM;
- }
-
- /**
- * @see Options#getCompilerSourceVM()
- */
- public void setCompilerSourceVM(String vm) {
- compilerSourceVM = vm;
- }
-
- public TldLocationsCache getTldLocationsCache() {
- return tldLocationsCache;
- }
-
- /**
- * Returns the encoding to use for
- * java files. The default is UTF-8.
- *
- * @return String The encoding
- */
- public String getJavaEncoding() {
- return javaEncoding;
- }
-
- /**
- * Sets the encoding to use for
- * java files.
- *
- * @param encodingName The name, e.g. "UTF-8"
- */
- public void setJavaEncoding(String encodingName) {
- javaEncoding = encodingName;
- }
-
- public boolean getFork() {
- return false;
- }
-
- public String getClassPath() {
- if( classPath != null )
- return classPath;
- return System.getProperty("java.class.path");
- }
-
- public void setClassPath(String s) {
- classPath=s;
- }
-
- /**
- * Returns the list of file extensions
- * that are treated as JSP files.
- *
- * @return The list of extensions
- */
- public List getExtensions() {
- return extensions;
- }
-
- /**
- * Adds the given file extension to the
- * list of extensions handled as JSP files.
- *
- * @param extension The extension to add, e.g. "myjsp"
- */
- protected void addExtension(final String extension) {
- if(extension != null) {
- if(extensions == null) {
- extensions = new Vector();
- }
-
- extensions.add(extension);
- }
- }
-
- /**
- * Sets the project.
- *
- * @param theProject The project
- */
- public void setProject(final Project theProject) {
- project = theProject;
- }
-
- /**
- * Returns the project: may be null if not running
- * inside an Ant project.
- *
- * @return The project
- */
- public Project getProject() {
- return project;
- }
-
- /**
- * Base dir for the webapp. Used to generate class names and resolve
- * includes
- */
- public void setUriroot( String s ) {
- if( s==null ) {
- uriRoot = s;
- return;
- }
- try {
- uriRoot = resolveFile(s).getCanonicalPath();
- } catch( Exception ex ) {
- uriRoot = s;
- }
- }
-
- /**
- * Parses comma-separated list of JSP files to be processed. If the argument
- * is null, nothing is done.
- *
- * <p>Each file is interpreted relative to uriroot, unless it is absolute,
- * in which case it must start with uriroot.</p>
- *
- * @param jspFiles Comma-separated list of JSP files to be processed
- */
- public void setJspFiles(final String jspFiles) {
- if(jspFiles == null) {
- return;
- }
-
- StringTokenizer tok = new StringTokenizer(jspFiles, ",");
- while (tok.hasMoreTokens()) {
- pages.add(tok.nextToken());
- }
- }
-
- /**
- * Sets the compile flag.
- *
- * @param b Flag value
- */
- public void setCompile( final boolean b ) {
- compile = b;
- }
-
- /**
- * Sets the verbosity level. The actual number doesn't
- * matter: if it's greater than zero, the verbose flag will
- * be true.
- *
- * @param level Positive means verbose
- */
- public void setVerbose( final int level ) {
- if (level > 0) {
- verbose = true;
- showSuccess = true;
- listErrors = true;
- }
- }
-
- public void setValidateXml( boolean b ) {
- org.apache.jasper.xmlparser.ParserUtils.validating=b;
- }
-
- public void setListErrors( boolean b ) {
- listErrors = b;
- }
-
- public void setOutputDir( String s ) {
- if( s!= null ) {
- scratchDir = resolveFile(s).getAbsoluteFile();
- } else {
- scratchDir=null;
- }
- }
-
- public void setPackage( String p ) {
- targetPackage=p;
- }
-
- /**
- * Class name of the generated file ( without package ).
- * Can only be used if a single file is converted.
- * XXX Do we need this feature ?
- */
- public void setClassName( String p ) {
- targetClassName=p;
- }
-
- /**
- * File where we generate a web.xml fragment with the class definitions.
- */
- public void setWebXmlFragment( String s ) {
- webxmlFile=resolveFile(s).getAbsolutePath();
- webxmlLevel=INC_WEBXML;
- }
-
- /**
- * File where we generate a complete web.xml with the class definitions.
- */
- public void setWebXml( String s ) {
- webxmlFile=resolveFile(s).getAbsolutePath();
- webxmlLevel=ALL_WEBXML;
- }
-
- public void setAddWebXmlMappings(boolean b) {
- addWebXmlMappings = b;
- }
-
- /**
- * Set the option that throws an exception in case of a compilation error.
- */
- public void setFailOnError(final boolean b) {
- failOnError = b;
- }
-
- public boolean getFailOnError() {
- return failOnError;
- }
-
- /**
- * Obtain JSP configuration informantion specified in web.xml.
- */
- public JspConfig getJspConfig() {
- return jspConfig;
- }
-
- public TagPluginManager getTagPluginManager() {
- return tagPluginManager;
- }
-
- public void generateWebMapping( String file, JspCompilationContext clctxt )
- throws IOException
- {
- if (log.isDebugEnabled()) {
- log.debug("Generating web mapping for file " + file
- + " using compilation context " + clctxt);
- }
-
- String className = clctxt.getServletClassName();
- String packageName = clctxt.getServletPackageName();
-
- String thisServletName;
- if ("".equals(packageName)) {
- thisServletName = className;
- } else {
- thisServletName = packageName + '.' + className;
- }
-
- if (servletout != null) {
- servletout.write("\n <servlet>\n <servlet-name>");
- servletout.write(thisServletName);
- servletout.write("</servlet-name>\n <servlet-class>");
- servletout.write(thisServletName);
- servletout.write("</servlet-class>\n </servlet>\n");
- }
- if (mappingout != null) {
- mappingout.write("\n <servlet-mapping>\n <servlet-name>");
- mappingout.write(thisServletName);
- mappingout.write("</servlet-name>\n <url-pattern>");
- mappingout.write(file.replace('\\', '/'));
- mappingout.write("</url-pattern>\n </servlet-mapping>\n");
-
- }
- }
-
- /**
- * Include the generated web.xml inside the webapp's web.xml.
- */
- protected void mergeIntoWebXml() throws IOException {
-
- File webappBase = new File(uriRoot);
- File webXml = new File(webappBase, "WEB-INF/web.xml");
- File webXml2 = new File(webappBase, "WEB-INF/web2.xml");
- String insertStartMarker =
- Localizer.getMessage("jspc.webinc.insertStart");
- String insertEndMarker =
- Localizer.getMessage("jspc.webinc.insertEnd");
-
- BufferedReader reader = new BufferedReader(new FileReader(webXml));
- BufferedReader fragmentReader =
- new BufferedReader(new FileReader(webxmlFile));
- PrintWriter writer = new PrintWriter(new FileWriter(webXml2));
-
- // Insert the <servlet> and <servlet-mapping> declarations
- int pos = -1;
- String line = null;
- while (true) {
- line = reader.readLine();
- if (line == null) {
- break;
- }
- // Skip anything previously generated by JSPC
- if (line.indexOf(insertStartMarker) >= 0) {
- while (true) {
- line = reader.readLine();
- if (line == null) {
- return;
- }
- if (line.indexOf(insertEndMarker) >= 0) {
- line = reader.readLine();
- line = reader.readLine();
- if (line == null) {
- return;
- }
- break;
- }
- }
- }
- for (int i = 0; i < insertBefore.length; i++) {
- pos = line.indexOf(insertBefore[i]);
- if (pos >= 0)
- break;
- }
- if (pos >= 0) {
- writer.print(line.substring(0, pos));
- break;
- } else {
- writer.println(line);
- }
- }
-
- writer.println(insertStartMarker);
- while (true) {
- String line2 = fragmentReader.readLine();
- if (line2 == null) {
- writer.println();
- break;
- }
- writer.println(line2);
- }
- writer.println(insertEndMarker);
- writer.println();
-
- for (int i = 0; i < pos; i++) {
- writer.print(" ");
- }
- writer.println(line.substring(pos));
-
- while (true) {
- line = reader.readLine();
- if (line == null) {
- break;
- }
- writer.println(line);
- }
- writer.close();
-
- reader.close();
- fragmentReader.close();
-
- FileInputStream fis = new FileInputStream(webXml2);
- FileOutputStream fos = new FileOutputStream(webXml);
-
- byte buf[] = new byte[512];
- while (true) {
- int n = fis.read(buf);
- if (n < 0) {
- break;
- }
- fos.write(buf, 0, n);
- }
-
- fis.close();
- fos.close();
-
- webXml2.delete();
- (new File(webxmlFile)).delete();
-
- }
-
- protected void processFile(String file)
- throws JasperException
- {
- if (log.isDebugEnabled()) {
- log.debug("Processing file: " + file);
- }
-
- ClassLoader originalClassLoader = null;
-
- try {
- // set up a scratch/output dir if none is provided
- if (scratchDir == null) {
- String temp = System.getProperty("java.io.tmpdir");
- if (temp == null) {
- temp = "";
- }
- scratchDir = new File(new File(temp).getAbsolutePath());
- }
-
- String jspUri=file.replace('\\','/');
- JspCompilationContext clctxt = new JspCompilationContext
- ( jspUri, false, this, context, null, rctxt );
-
- /* Override the defaults */
- if ((targetClassName != null) && (targetClassName.length() > 0)) {
- clctxt.setServletClassName(targetClassName);
- targetClassName = null;
- }
- if (targetPackage != null) {
- clctxt.setServletPackageName(targetPackage);
- }
-
- originalClassLoader = Thread.currentThread().getContextClassLoader();
- if( loader==null ) {
- initClassLoader( clctxt );
- }
- Thread.currentThread().setContextClassLoader(loader);
-
- clctxt.setClassLoader(loader);
- clctxt.setClassPath(classPath);
-
- Compiler clc = clctxt.createCompiler();
-
- // If compile is set, generate both .java and .class, if
- // .jsp file is newer than .class file;
- // Otherwise only generate .java, if .jsp file is newer than
- // the .java file
- if( clc.isOutDated(compile) ) {
- if (log.isDebugEnabled()) {
- log.debug(jspUri + " is out dated, compiling...");
- }
-
- clc.compile(compile, true);
- }
-
- // Generate mapping
- generateWebMapping( file, clctxt );
- if ( showSuccess ) {
- log.info( "Built File: " + file );
- }
-
- } catch (JasperException je) {
- Throwable rootCause = je;
- while (rootCause instanceof JasperException
- && ((JasperException) rootCause).getRootCause() != null) {
- rootCause = ((JasperException) rootCause).getRootCause();
- }
- if (rootCause != je) {
- log.error(Localizer.getMessage("jspc.error.generalException",
- file),
- rootCause);
- }
-
- // Bugzilla 35114.
- if(getFailOnError()) {
- throw je;
- } else {
- log.error(je.getMessage());
- }
-
- } catch (Exception e) {
- if (e instanceof FileNotFoundException) {
- log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist",
- e.getMessage()));
- }
- throw new JasperException(e);
- } finally {
- if(originalClassLoader != null) {
- Thread.currentThread().setContextClassLoader(originalClassLoader);
- }
- }
- }
-
- /**
- * Locate all jsp files in the webapp. Used if no explicit
- * jsps are specified.
- */
- public void scanFiles( File base ) throws JasperException {
- Stack<String> dirs = new Stack<String>();
- dirs.push(base.toString());
-
- // Make sure default extensions are always included
- if ((getExtensions() == null) || (getExtensions().size() < 2)) {
- addExtension("jsp");
- addExtension("jspx");
- }
-
- while (!dirs.isEmpty()) {
- String s = dirs.pop();
- File f = new File(s);
- if (f.exists() && f.isDirectory()) {
- String[] files = f.list();
- String ext;
- for (int i = 0; (files != null) && i < files.length; i++) {
- File f2 = new File(s, files[i]);
- if (f2.isDirectory()) {
- dirs.push(f2.getPath());
- } else {
- String path = f2.getPath();
- String uri = path.substring(uriRoot.length());
- ext = files[i].substring(files[i].lastIndexOf('.') +1);
- if (getExtensions().contains(ext) ||
- jspConfig.isJspPage(uri)) {
- pages.add(path);
- }
- }
- }
- }
- }
- }
-
- /**
- * Executes the compilation.
- *
- * @throws JasperException If an error occurs
- */
- public void execute() throws JasperException {
- if(log.isDebugEnabled()) {
- log.debug("execute() starting for " + pages.size() + " pages.");
- }
-
- try {
- if (uriRoot == null) {
- if( pages.size() == 0 ) {
- throw new JasperException(
- Localizer.getMessage("jsp.error.jspc.missingTarget"));
- }
- String firstJsp = (String) pages.get( 0 );
- File firstJspF = new File( firstJsp );
- if (!firstJspF.exists()) {
- throw new JasperException(
- Localizer.getMessage("jspc.error.fileDoesNotExist",
- firstJsp));
- }
- locateUriRoot( firstJspF );
- }
-
- if (uriRoot == null) {
- throw new JasperException(
- Localizer.getMessage("jsp.error.jspc.no_uriroot"));
- }
-
- if( context==null ) {
- initServletContext();
- }
-
- // No explicit pages, we'll process all .jsp in the webapp
- if (pages.size() == 0) {
- scanFiles( new File( uriRoot ));
- }
-
- File uriRootF = new File(uriRoot);
- if (!uriRootF.exists() || !uriRootF.isDirectory()) {
- throw new JasperException(
- Localizer.getMessage("jsp.error.jspc.uriroot_not_dir"));
- }
-
- initWebXml();
-
- Iterator iter = pages.iterator();
- while (iter.hasNext()) {
- String nextjsp = iter.next().toString();
- File fjsp = new File(nextjsp);
- if (!fjsp.isAbsolute()) {
- fjsp = new File(uriRootF, nextjsp);
- }
- if (!fjsp.exists()) {
- log.warn(Localizer.getMessage
- ("jspc.error.fileDoesNotExist", fjsp.toString()));
- continue;
- }
- String s = fjsp.getAbsolutePath();
- if (s.startsWith(uriRoot)) {
- nextjsp = s.substring(uriRoot.length());
- }
- if (nextjsp.startsWith("." + File.separatorChar)) {
- nextjsp = nextjsp.substring(2);
- }
- processFile(nextjsp);
- }
-
- completeWebXml();
-
- if (addWebXmlMappings) {
- mergeIntoWebXml();
- }
-
- } catch (IOException ioe) {
- throw new JasperException(ioe);
-
- } catch (JasperException je) {
- Throwable rootCause = je;
- while (rootCause instanceof JasperException
- && ((JasperException) rootCause).getRootCause() != null) {
- rootCause = ((JasperException) rootCause).getRootCause();
- }
- if (rootCause != je) {
- rootCause.printStackTrace();
- }
- throw je;
- }/* finally {
- if (loader != null) {
- Logger.release(loader);
- }
- }*/
- }
-
- // ==================== protected utility methods ====================
-
- protected String nextArg() {
- if ((argPos >= args.length)
- || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) {
- return null;
- } else {
- return args[argPos++];
- }
- }
-
- protected String nextFile() {
- if (fullstop) argPos++;
- if (argPos >= args.length) {
- return null;
- } else {
- return args[argPos++];
- }
- }
-
- protected void initWebXml() {
- try {
- if (webxmlLevel >= INC_WEBXML) {
- File fmapings = new File(webxmlFile);
- mapout = new FileWriter(fmapings);
- servletout = new CharArrayWriter();
- mappingout = new CharArrayWriter();
- } else {
- mapout = null;
- servletout = null;
- mappingout = null;
- }
- if (webxmlLevel >= ALL_WEBXML) {
- mapout.write(Localizer.getMessage("jspc.webxml.header"));
- mapout.flush();
- } else if ((webxmlLevel>= INC_WEBXML) && !addWebXmlMappings) {
- mapout.write(Localizer.getMessage("jspc.webinc.header"));
- mapout.flush();
- }
- } catch (IOException ioe) {
- mapout = null;
- servletout = null;
- mappingout = null;
- }
- }
-
- protected void completeWebXml() {
- if (mapout != null) {
- try {
- servletout.writeTo(mapout);
- mappingout.writeTo(mapout);
- if (webxmlLevel >= ALL_WEBXML) {
- mapout.write(Localizer.getMessage("jspc.webxml.footer"));
- } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) {
- mapout.write(Localizer.getMessage("jspc.webinc.footer"));
- }
- mapout.close();
- } catch (IOException ioe) {
- // noting to do if it fails since we are done with it
- }
- }
- }
-
- protected void initServletContext() {
- try {
- context =new JspCServletContext
- (new PrintWriter(System.out),
- new URL("file:" + uriRoot.replace('\\','/') + '/'));
- tldLocationsCache = new TldLocationsCache(context, true);
- } catch (MalformedURLException me) {
- System.out.println("**" + me);
- }
- rctxt = new JspRuntimeContext(context, this);
- jspConfig = new JspConfig(context);
- tagPluginManager = new TagPluginManager(context);
- }
-
- /**
- * Initializes the classloader as/if needed for the given
- * compilation context.
- *
- * @param clctxt The compilation context
- * @throws IOException If an error occurs
- */
- protected void initClassLoader(JspCompilationContext clctxt)
- throws IOException {
-
- classPath = getClassPath();
-
- ClassLoader jspcLoader = getClass().getClassLoader();
- if (jspcLoader instanceof AntClassLoader) {
- classPath += File.pathSeparator
- + ((AntClassLoader) jspcLoader).getClasspath();
- }
-
- // Turn the classPath into URLs
- ArrayList<URL> urls = new ArrayList<URL>();
- StringTokenizer tokenizer = new StringTokenizer(classPath,
- File.pathSeparator);
- while (tokenizer.hasMoreTokens()) {
- String path = tokenizer.nextToken();
- try {
- File libFile = new File(path);
- urls.add(libFile.toURL());
- } catch (IOException ioe) {
- // Failing a toCanonicalPath on a file that
- // exists() should be a JVM regression test,
- // therefore we have permission to freak uot
- throw new RuntimeException(ioe.toString());
- }
- }
-
- File webappBase = new File(uriRoot);
- if (webappBase.exists()) {
- File classes = new File(webappBase, "/WEB-INF/classes");
- try {
- if (classes.exists()) {
- classPath = classPath + File.pathSeparator
- + classes.getCanonicalPath();
- urls.add(classes.getCanonicalFile().toURL());
- }
- } catch (IOException ioe) {
- // failing a toCanonicalPath on a file that
- // exists() should be a JVM regression test,
- // therefore we have permission to freak out
- throw new RuntimeException(ioe.toString());
- }
- File lib = new File(webappBase, "/WEB-INF/lib");
- if (lib.exists() && lib.isDirectory()) {
- String[] libs = lib.list();
- for (int i = 0; i < libs.length; i++) {
- if( libs[i].length() <5 ) continue;
- String ext=libs[i].substring( libs[i].length() - 4 );
- if (! ".jar".equalsIgnoreCase(ext)) {
- if (".tld".equalsIgnoreCase(ext)) {
- log.warn("TLD files should not be placed in "
- + "/WEB-INF/lib");
- }
- continue;
- }
- try {
- File libFile = new File(lib, libs[i]);
- classPath = classPath + File.pathSeparator
- + libFile.getAbsolutePath();
- urls.add(libFile.getAbsoluteFile().toURL());
- } catch (IOException ioe) {
- // failing a toCanonicalPath on a file that
- // exists() should be a JVM regression test,
- // therefore we have permission to freak out
- throw new RuntimeException(ioe.toString());
- }
- }
- }
- }
-
- // What is this ??
- urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile().toURL());
-
- URL urlsA[]=new URL[urls.size()];
- urls.toArray(urlsA);
- loader = new URLClassLoader(urlsA, this.getClass().getClassLoader());
-
- }
-
- /**
- * Find the WEB-INF dir by looking up in the directory tree.
- * This is used if no explicit docbase is set, but only files.
- * XXX Maybe we should require the docbase.
- */
- protected void locateUriRoot( File f ) {
- String tUriBase = uriBase;
- if (tUriBase == null) {
- tUriBase = "/";
- }
- try {
- if (f.exists()) {
- f = new File(f.getAbsolutePath());
- while (f != null) {
- File g = new File(f, "WEB-INF");
- if (g.exists() && g.isDirectory()) {
- uriRoot = f.getCanonicalPath();
- uriBase = tUriBase;
- if (log.isInfoEnabled()) {
- log.info(Localizer.getMessage(
- "jspc.implicit.uriRoot",
- uriRoot));
- }
- break;
- }
- if (f.exists() && f.isDirectory()) {
- tUriBase = "/" + f.getName() + "/" + tUriBase;
- }
-
- String fParent = f.getParent();
- if (fParent == null) {
- break;
- } else {
- f = new File(fParent);
- }
-
- // If there is no acceptible candidate, uriRoot will
- // remain null to indicate to the CompilerContext to
- // use the current working/user dir.
- }
-
- if (uriRoot != null) {
- File froot = new File(uriRoot);
- uriRoot = froot.getCanonicalPath();
- }
- }
- } catch (IOException ioe) {
- // since this is an optional default and a null value
- // for uriRoot has a non-error meaning, we can just
- // pass straight through
- }
- }
-
- /**
- * Resolves the relative or absolute pathname correctly
- * in both Ant and command-line situations. If Ant launched
- * us, we should use the basedir of the current project
- * to resolve relative paths.
- *
- * See Bugzilla 35571.
- *
- * @param s The file
- * @return The file resolved
- */
- protected File resolveFile(final String s) {
- if(getProject() == null) {
- // Note FileUtils.getFileUtils replaces FileUtils.newFileUtils in Ant 1.6.3
- return FileUtils.newFileUtils().resolveFile(null, s);
- } else {
- return FileUtils.newFileUtils().resolveFile(getProject().getBaseDir(), s);
- }
- }
-}
Modified: trunk/java/org/apache/jasper/Options.java
===================================================================
--- trunk/java/org/apache/jasper/Options.java 2009-06-11 11:11:18 UTC (rev 1104)
+++ trunk/java/org/apache/jasper/Options.java 2009-06-11 12:29:25 UTC (rev 1105)
@@ -22,7 +22,6 @@
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.
@@ -135,19 +134,6 @@
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.
*/
Deleted: trunk/java/org/apache/jasper/compiler/AntCompiler.java
===================================================================
--- trunk/java/org/apache/jasper/compiler/AntCompiler.java 2009-06-11 11:11:18 UTC (rev 1104)
+++ trunk/java/org/apache/jasper/compiler/AntCompiler.java 2009-06-11 12:29:25 UTC (rev 1105)
@@ -1,492 +0,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.
- */
-
-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);
- }
-
- }
-
-}
Modified: trunk/java/org/apache/jasper/compiler/JspConfig.java
===================================================================
--- trunk/java/org/apache/jasper/compiler/JspConfig.java 2009-06-11 11:11:18 UTC (rev 1104)
+++ trunk/java/org/apache/jasper/compiler/JspConfig.java 2009-06-11 12:29:25 UTC (rev 1105)
@@ -71,8 +71,6 @@
public class JspConfig {
- private static final String WEB_XML = "/WEB-INF/web.xml";
-
// Logger
private Logger log = Logger.getLogger(JspConfig.class);
@@ -91,157 +89,6 @@
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 ArrayList<JspPropertyGroup>();
- Iterator jspPropertyList = jspConfig.findChildren("jsp-property-group");
- while (jspPropertyList.hasNext()) {
-
- TreeNode element = (TreeNode) jspPropertyList.next();
- Iterator list = element.findChildren();
-
- ArrayList<String> urlPatterns = new ArrayList<String>();
- String pageEncoding = null;
- String scriptingInvalid = null;
- String elIgnored = null;
- String isXml = null;
- ArrayList<String> includePrelude = new ArrayList<String>();
- ArrayList<String> includeCoda = new ArrayList<String>();
- String deferredSyntaxAllowedAsLiteral = null;
- String trimDirectiveWhitespaces = null;
-
- while (list.hasNext()) {
-
- element = (TreeNode) list.next();
- String tname = element.getName();
-
- if ("url-pattern".equals(tname))
- urlPatterns.add( 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.add(element.getBody());
- else if ("include-coda".equals(tname))
- includeCoda.add(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 = urlPatterns.get(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)) {
- 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.add(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) {
Deleted: trunk/java/org/apache/jasper/compiler/TldLocationsCache.java
===================================================================
--- trunk/java/org/apache/jasper/compiler/TldLocationsCache.java 2009-06-11 11:11:18 UTC (rev 1104)
+++ trunk/java/org/apache/jasper/compiler/TldLocationsCache.java 2009-06-11 12:29:25 UTC (rev 1105)
@@ -1,547 +0,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.
- */
-
-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.jboss.logging.Logger;
-import org.jboss.logging.Logger;
-
-/**
- * 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 Logger log = Logger.getLogger(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) {
- log.warn(Localizer.getMessage(
- "jsp.error.internal.filenotfound",
- altDDName));
- }
- } else {
- uri = ctxt.getResource(WEB_XML);
- if (uri == null) {
- 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));
- }
- }
-}
15 years, 9 months
JBossWeb SVN: r1104 - trunk/java/org/apache/jasper/compiler.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2009-06-11 07:11:18 -0400 (Thu, 11 Jun 2009)
New Revision: 1104
Modified:
trunk/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java
Log:
- Booleans don't actually work, so replace with Strings, part 2.
Modified: trunk/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java
===================================================================
--- trunk/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java 2009-06-11 11:10:55 UTC (rev 1103)
+++ trunk/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java 2009-06-11 11:11:18 UTC (rev 1104)
@@ -46,21 +46,14 @@
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.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Enumeration;
import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Iterator;
import java.util.Map;
-import java.util.Vector;
import javax.servlet.jsp.tagext.FunctionInfo;
import javax.servlet.jsp.tagext.PageData;
@@ -77,8 +70,6 @@
import org.apache.catalina.Globals;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
-import org.apache.jasper.xmlparser.ParserUtils;
-import org.apache.jasper.xmlparser.TreeNode;
import org.jboss.logging.Logger;
/**
@@ -92,6 +83,13 @@
*/
class TagLibraryInfoImpl extends TagLibraryInfo implements TagConstants {
+ /**
+ * 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;
+
// Logger
private Logger log = Logger.getLogger(TagLibraryInfoImpl.class);
@@ -134,28 +132,6 @@
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.
*/
@@ -277,8 +253,12 @@
String type = attributeInfo.getType();
String expectedType = attributeInfo.getExpectedTypeName();
String methodSignature = attributeInfo.getMethodSignature();
- boolean rtexprvalue = attributeInfo.isReqTime();
-
+ boolean rtexprvalue = JspUtil.booleanValue(attributeInfo.getReqTime());
+ boolean fragment = JspUtil.booleanValue(attributeInfo.getFragment());
+ boolean deferredValue = JspUtil.booleanValue(attributeInfo.getDeferredValue());
+ boolean deferredMethod = JspUtil.booleanValue(attributeInfo.getDeferredMethod());
+ boolean required = JspUtil.booleanValue(attributeInfo.getRequired());
+
if (type != null) {
if ("1.2".equals(jspversion)
&& (type.equals("Boolean") || type.equals("Byte")
@@ -293,7 +273,7 @@
}
}
- if (attributeInfo.isDeferredValue()) {
+ if (deferredValue) {
type = "javax.el.ValueExpression";
if (expectedType != null) {
expectedType = expectedType.trim();
@@ -302,7 +282,7 @@
}
}
- if (attributeInfo.isDeferredMethod()) {
+ if (deferredMethod) {
type = "javax.el.MethodExpression";
if (methodSignature != null) {
methodSignature = methodSignature.trim();
@@ -311,7 +291,7 @@
}
}
- if (attributeInfo.isFragment()) {
+ if (fragment) {
/*
* According to JSP.C-3 ("TLD Schema Element Structure - tag"),
* 'type' and 'rtexprvalue' must not be specified if 'fragment' has
@@ -330,9 +310,9 @@
type = "java.lang.String";
}
- return new TagAttributeInfo(attributeInfo.getName(), attributeInfo.isRequired(),
- type, rtexprvalue, attributeInfo.isFragment(), attributeInfo.getDescription(),
- attributeInfo.isDeferredValue(), attributeInfo.isDeferredMethod(), expectedType,
+ return new TagAttributeInfo(attributeInfo.getName(), required,
+ type, rtexprvalue, fragment, attributeInfo.getDescription(),
+ deferredValue, deferredMethod, expectedType,
methodSignature);
}
@@ -352,8 +332,12 @@
if (className != null) {
className = "java.lang.String";
}
+ boolean declare = true;
+ if (variableInfo.getDeclare() != null) {
+ declare = JspUtil.booleanValue(s);
+ }
return new TagVariableInfo(variableInfo.getNameGiven(), variableInfo.getNameFromAttribute(),
- className, variableInfo.isDeclare(), scope);
+ className, declare, scope);
}
protected TagFileInfo createTagFileInfo(org.apache.catalina.deploy.jsp.TagFileInfo tagFileInfo, URL jarFileUrl)
@@ -380,465 +364,22 @@
}
- /*
- * @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
+ /**
+ * Returns the type of a URI:
+ * ABS_URI
+ * ROOT_REL_URI
+ * NOROOT_REL_URI
*/
- 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 {
- log.warn(Localizer.getMessage(
- "jsp.warning.unknown.element.in.taglib", tname));
- }
-
+ 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;
}
-
- 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 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 {
- 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;
- }
-
- 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 {
- 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 {
- 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 {
- 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 {
- log.warn(Localizer.getMessage(
- "jsp.warning.unknown.element.in.variable", tname));
- }
- }
- return new TagVariableInfo(nameGiven, nameFromAttribute, className,
- declare, scope);
- }
-
private TagLibraryValidator createValidator(org.apache.catalina.deploy.jsp.TagLibraryInfo tagLibraryInfo)
throws JasperException {
org.apache.catalina.deploy.jsp.TagLibraryValidatorInfo tlvInfo = tagLibraryInfo.getValidator();
@@ -862,56 +403,6 @@
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 {
- 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 {
- 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
15 years, 9 months
JBossWeb SVN: r1103 - in trunk/java/org/apache/catalina: startup and 1 other directory.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2009-06-11 07:10:55 -0400 (Thu, 11 Jun 2009)
New Revision: 1103
Modified:
trunk/java/org/apache/catalina/deploy/jsp/TagAttributeInfo.java
trunk/java/org/apache/catalina/deploy/jsp/TagVariableInfo.java
trunk/java/org/apache/catalina/startup/TldRuleSet.java
Log:
- Booleans don't actually work, so replace with Strings.
Modified: trunk/java/org/apache/catalina/deploy/jsp/TagAttributeInfo.java
===================================================================
--- trunk/java/org/apache/catalina/deploy/jsp/TagAttributeInfo.java 2009-06-11 10:26:21 UTC (rev 1102)
+++ trunk/java/org/apache/catalina/deploy/jsp/TagAttributeInfo.java 2009-06-11 11:10:55 UTC (rev 1103)
@@ -20,18 +20,18 @@
public class TagAttributeInfo {
protected String name;
protected String type;
- protected boolean reqTime = false;
- protected boolean required = false;
+ protected String reqTime;
+ protected String required;
/*
* private fields for JSP 2.0
*/
- protected boolean fragment = false;
+ protected String fragment;
/*
* private fields for JSP 2.1
*/
protected String description;
- protected boolean deferredValue = false;
- protected boolean deferredMethod = false;
+ protected String deferredValue;
+ protected String deferredMethod;
protected String expectedTypeName;
protected String methodSignature;
@@ -47,52 +47,53 @@
public void setType(String type) {
this.type = type;
}
- public boolean isReqTime() {
+ public String getDescription() {
+ return description;
+ }
+ public void setDescription(String description) {
+ this.description = description;
+ }
+ public String getExpectedTypeName() {
+ return expectedTypeName;
+ }
+ public void setExpectedTypeName(String expectedTypeName) {
+ this.expectedTypeName = expectedTypeName;
+ }
+ public String getMethodSignature() {
+ return methodSignature;
+ }
+ public void setMethodSignature(String methodSignature) {
+ this.methodSignature = methodSignature;
+ }
+ public String getReqTime() {
return reqTime;
}
- public void setReqTime(boolean reqTime) {
+ public void setReqTime(String reqTime) {
this.reqTime = reqTime;
}
- public boolean isRequired() {
+ public String getRequired() {
return required;
}
- public void setRequired(boolean required) {
+ public void setRequired(String required) {
this.required = required;
}
- public boolean isFragment() {
+ public String getFragment() {
return fragment;
}
- public void setFragment(boolean fragment) {
+ public void setFragment(String fragment) {
this.fragment = fragment;
}
- public String getDescription() {
- return description;
- }
- public void setDescription(String description) {
- this.description = description;
- }
- public boolean isDeferredValue() {
+ public String getDeferredValue() {
return deferredValue;
}
- public void setDeferredValue(boolean deferredValue) {
+ public void setDeferredValue(String deferredValue) {
this.deferredValue = deferredValue;
}
- public boolean isDeferredMethod() {
+ public String getDeferredMethod() {
return deferredMethod;
}
- public void setDeferredMethod(boolean deferredMethod) {
+ public void setDeferredMethod(String deferredMethod) {
this.deferredMethod = deferredMethod;
}
- public String getExpectedTypeName() {
- return expectedTypeName;
- }
- public void setExpectedTypeName(String expectedTypeName) {
- this.expectedTypeName = expectedTypeName;
- }
- public String getMethodSignature() {
- return methodSignature;
- }
- public void setMethodSignature(String methodSignature) {
- this.methodSignature = methodSignature;
- }
+
}
Modified: trunk/java/org/apache/catalina/deploy/jsp/TagVariableInfo.java
===================================================================
--- trunk/java/org/apache/catalina/deploy/jsp/TagVariableInfo.java 2009-06-11 10:26:21 UTC (rev 1102)
+++ trunk/java/org/apache/catalina/deploy/jsp/TagVariableInfo.java 2009-06-11 11:10:55 UTC (rev 1103)
@@ -25,7 +25,7 @@
protected String nameGiven; // <name-given>
protected String nameFromAttribute; // <name-from-attribute>
protected String className; // <class>
- protected boolean declare = true; // <declare>
+ protected String declare; // <declare>
protected String scope; // <scope>
public String getNameGiven() {
@@ -46,17 +46,17 @@
public void setClassName(String className) {
this.className = className;
}
- public boolean isDeclare() {
- return declare;
- }
- public void setDeclare(boolean declare) {
- this.declare = declare;
- }
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
+ public String getDeclare() {
+ return declare;
+ }
+ public void setDeclare(String declare) {
+ this.declare = declare;
+ }
}
Modified: trunk/java/org/apache/catalina/startup/TldRuleSet.java
===================================================================
--- trunk/java/org/apache/catalina/startup/TldRuleSet.java 2009-06-11 10:26:21 UTC (rev 1102)
+++ trunk/java/org/apache/catalina/startup/TldRuleSet.java 2009-06-11 11:10:55 UTC (rev 1103)
@@ -196,8 +196,6 @@
"setFragment", 0);
digester.addCallMethod(prefix + "taglib/tag/attribute/description",
"setDescription", 0);
- digester.addCallMethod(prefix + "taglib/tag/attribute/required",
- "setRequired", 0);
digester.addCallMethod(prefix + "taglib/tag/attribute/deferred-value",
"setDeferredValue", 0);
digester.addCallMethod(prefix + "taglib/tag/attribute/deferred-value/type",
15 years, 9 months
JBossWeb SVN: r1102 - trunk/java/org/apache/catalina/loader.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2009-06-11 06:26:21 -0400 (Thu, 11 Jun 2009)
New Revision: 1102
Modified:
trunk/java/org/apache/catalina/loader/WebappClassLoader.java
trunk/java/org/apache/catalina/loader/WebappLoader.java
Log:
- Remove last modification checks for classes.
Modified: trunk/java/org/apache/catalina/loader/WebappClassLoader.java
===================================================================
--- trunk/java/org/apache/catalina/loader/WebappClassLoader.java 2009-06-10 22:51:34 UTC (rev 1101)
+++ trunk/java/org/apache/catalina/loader/WebappClassLoader.java 2009-06-11 10:26:21 UTC (rev 1102)
@@ -71,25 +71,22 @@
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
+import java.util.Map;
import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.jar.Attributes.Name;
-import javax.naming.NamingException;
-import javax.naming.directory.DirContext;
-
import org.apache.catalina.JarRepository;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.util.StringManager;
import org.apache.naming.JndiPermission;
-import org.apache.naming.resources.ResourceAttributes;
import org.apache.tomcat.util.IntrospectionUtils;
/**
@@ -130,7 +127,7 @@
*/
public class WebappClassLoader
extends URLClassLoader
- implements Reloader, Lifecycle
+ implements Lifecycle
{
protected static org.jboss.logging.Logger log=
@@ -249,23 +246,17 @@
/**
- * Associated directory context giving access to the resources in this
- * webapp.
- */
- protected DirContext resources = null;
-
-
- /**
* The cache of ResourceEntry for classes and resources we have loaded,
* keyed by resource name.
*/
- protected HashMap<String, ResourceEntry> resourceEntries = new HashMap<String, ResourceEntry>();
+ protected Map<String, ResourceEntry> resourceEntries = new ConcurrentHashMap<String, ResourceEntry>();
/**
* The list of not found resources.
*/
- protected HashSet<String> notFoundResources = new HashSet<String>();
+ protected Map<String, Object> notFoundResources = new ConcurrentHashMap<String, Object>();
+ protected static final Object VALUE = new Object();
/**
@@ -337,14 +328,14 @@
* The list of JARs last modified dates, in the order they should be
* searched for locally loaded classes or resources.
*/
- protected long[] lastModifiedDates = new long[0];
+ //protected long[] lastModifiedDates = new long[0];
/**
* The list of resources which should be checked when checking for
* modifications.
*/
- protected String[] paths = new String[0];
+ //protected String[] paths = new String[0];
/**
@@ -421,16 +412,6 @@
}
- public DirContext getResources() {
- return resources;
- }
-
-
- public void setResources(DirContext resources) {
- this.resources = resources;
- }
-
-
/**
* Return the "delegate first" flag for this class loader.
*/
@@ -542,79 +523,7 @@
}
- // ------------------------------------------------------- Reloader Methods
-
-
/**
- * Add a new repository to the set of places this ClassLoader can look for
- * classes to be loaded.
- *
- * @param repository Name of a source of classes to be loaded, such as a
- * directory pathname, a JAR file pathname, or a ZIP file pathname
- *
- * @exception IllegalArgumentException if the specified repository is
- * invalid or does not exist
- */
- public void addRepository(String repository) {
-
- // FIXME: remove
- // Ignore any of the standard repositories, as they are set up using
- // either addJar or addRepository
- if (repository.startsWith("/WEB-INF/lib")
- || repository.startsWith("/WEB-INF/classes"))
- return;
-
- }
-
-
- /**
- * Return a String array of the current repositories for this class
- * loader. If there are no repositories, a zero-length array is
- * returned.For security reason, returns a clone of the Array (since
- * String are immutable).
- */
- public String[] findRepositories() {
- return null;
- }
-
-
- /**
- * Have one or more classes or resources been modified so that a reload
- * is appropriate?
- */
- public boolean modified() {
-
- if (log.isDebugEnabled())
- log.debug("modified()");
-
- int length = lastModifiedDates.length;
-
- for (int i = 0; i < length; i++) {
- try {
- long lastModified =
- ((ResourceAttributes) resources.getAttributes(paths[i]))
- .getLastModified();
- if (lastModified != lastModifiedDates[i]) {
- if( log.isDebugEnabled() )
- log.debug(" Resource '" + paths[i]
- + "' was modified; Date is now: "
- + new java.util.Date(lastModified) + " Was: "
- + new java.util.Date(lastModifiedDates[i]));
- return (true);
- }
- } catch (NamingException e) {
- log.error(" Resource '" + paths[i] + "' is missing");
- return (true);
- }
- }
-
- // No classes have been modified
- return (false);
-
- }
-
-
- /**
* Render a String representation of this object.
*/
public String toString() {
@@ -1233,10 +1142,7 @@
notFoundResources.clear();
resourceEntries.clear();
- resources = null;
repositoryURLs = null;
- lastModifiedDates = null;
- paths = null;
parent = null;
repository = null;
@@ -1274,7 +1180,7 @@
// Null out any static or final fields from loaded classes,
// as a workaround for apparent garbage collection bugs
if (ENABLE_CLEAR_REFERENCES) {
- Iterator loadedClasses = ((HashMap) resourceEntries.clone()).values().iterator();
+ Iterator loadedClasses = resourceEntries.values().iterator();
while (loadedClasses.hasNext()) {
ResourceEntry entry = (ResourceEntry) loadedClasses.next();
if (entry.loadedClass != null) {
@@ -1572,32 +1478,9 @@
}
}
- // Register the full path for modification checking
- // Note: Only syncing on a 'constant' object is needed
- synchronized (allPermission) {
-
- int j;
-
- long[] result2 =
- new long[lastModifiedDates.length + 1];
- for (j = 0; j < lastModifiedDates.length; j++) {
- result2[j] = lastModifiedDates[j];
- }
- result2[lastModifiedDates.length] = entry.lastModified;
- lastModifiedDates = result2;
-
- String[] result = new String[paths.length + 1];
- for (j = 0; j < paths.length; j++) {
- result[j] = paths[j];
- }
- result[paths.length] = resource.getPath();
- paths = result;
-
- }
-
}
- if ((entry == null) && (notFoundResources.contains(name)))
+ if ((entry == null) && (notFoundResources.containsKey(name)))
return null;
JarEntry jarEntry = null;
@@ -1680,9 +1563,7 @@
}
if (entry == null) {
- synchronized (notFoundResources) {
- notFoundResources.add(name);
- }
+ notFoundResources.put(name, VALUE);
return null;
}
Modified: trunk/java/org/apache/catalina/loader/WebappLoader.java
===================================================================
--- trunk/java/org/apache/catalina/loader/WebappLoader.java 2009-06-10 22:51:34 UTC (rev 1101)
+++ trunk/java/org/apache/catalina/loader/WebappLoader.java 2009-06-11 10:26:21 UTC (rev 1102)
@@ -415,7 +415,7 @@
* such that the loaded classes should be reloaded?
*/
public boolean modified() {
- return (classLoader.modified());
+ return false;
}
@@ -562,7 +562,6 @@
try {
classLoader = createClassLoader();
- classLoader.setResources(container.getResources());
classLoader.setDelegate(this.delegate);
if (container instanceof StandardContext)
classLoader.setAntiJARLocking(((StandardContext) container).getAntiJARLocking());
15 years, 9 months
JBossWeb SVN: r1101 - trunk/java/org/apache/catalina/startup.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2009-06-10 18:51:34 -0400 (Wed, 10 Jun 2009)
New Revision: 1101
Modified:
trunk/java/org/apache/catalina/startup/WebRuleSet.java
Log:
- Pretty important for JSP: actually parse the version attribute.
Modified: trunk/java/org/apache/catalina/startup/WebRuleSet.java
===================================================================
--- trunk/java/org/apache/catalina/startup/WebRuleSet.java 2009-06-10 22:40:29 UTC (rev 1100)
+++ trunk/java/org/apache/catalina/startup/WebRuleSet.java 2009-06-10 22:51:34 UTC (rev 1101)
@@ -167,6 +167,8 @@
new SetPublicIdRule("setPublicId"));
digester.addRule(prefix + elementName,
new IgnoreAnnotationsRule());
+ digester.addRule(prefix + elementName,
+ new VersionRule());
digester.addCallMethod(prefix + elementName + "/context-param",
"addParameter", 2);
@@ -962,8 +964,8 @@
}
if (digester.getLogger().isDebugEnabled()) {
digester.getLogger().debug
- (context.getClass().getName() + ".setIgnoreAnnotations( " +
- context.getIgnoreAnnotations() + ")");
+ (context.getClass().getName() + ".setVersion( " +
+ context.getVersion() + ")");
}
}
15 years, 9 months
JBossWeb SVN: r1100 - in trunk/java/org/apache/catalina: loader and 1 other directory.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2009-06-10 18:40:29 -0400 (Wed, 10 Jun 2009)
New Revision: 1100
Added:
trunk/java/org/apache/catalina/loader/LegacyWebappClassLoader.java
trunk/java/org/apache/catalina/loader/LegacyWebappLoader.java
Modified:
trunk/java/org/apache/catalina/core/StandardContext.java
trunk/java/org/apache/catalina/loader/WebappClassLoader.java
trunk/java/org/apache/catalina/loader/WebappLoader.java
Log:
- Add the basics for the new CL. Not that happy with the result (but at least it's simpler).
Modified: trunk/java/org/apache/catalina/core/StandardContext.java
===================================================================
--- trunk/java/org/apache/catalina/core/StandardContext.java 2009-06-10 12:42:02 UTC (rev 1099)
+++ trunk/java/org/apache/catalina/core/StandardContext.java 2009-06-10 22:40:29 UTC (rev 1100)
@@ -4278,12 +4278,6 @@
broadcaster.sendNotification(notification);
}
- // Close all JARs right away to avoid always opening a peak number
- // of files on startup
- if (getLoader() instanceof WebappLoader) {
- ((WebappLoader) getLoader()).closeJARs(true);
- }
-
// Reinitializing if something went wrong
if (!ok && started) {
stop();
Added: trunk/java/org/apache/catalina/loader/LegacyWebappClassLoader.java
===================================================================
--- trunk/java/org/apache/catalina/loader/LegacyWebappClassLoader.java (rev 0)
+++ trunk/java/org/apache/catalina/loader/LegacyWebappClassLoader.java 2009-06-10 22:40:29 UTC (rev 1100)
@@ -0,0 +1,2354 @@
+/*
+ * 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.catalina.loader;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes.Name;
+
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.util.StringManager;
+import org.apache.naming.JndiPermission;
+import org.apache.naming.resources.Resource;
+import org.apache.naming.resources.ResourceAttributes;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * Specialized web application class loader.
+ * <p>
+ * This class loader is a full reimplementation of the
+ * <code>URLClassLoader</code> from the JDK. It is desinged to be fully
+ * compatible with a normal <code>URLClassLoader</code>, although its internal
+ * behavior may be completely different.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - This class loader faithfully follows
+ * the delegation model recommended in the specification. The system class
+ * loader will be queried first, then the local repositories, and only then
+ * delegation to the parent class loader will occur. This allows the web
+ * application to override any shared class except the classes from J2SE.
+ * Special handling is provided from the JAXP XML parser interfaces, the JNDI
+ * interfaces, and the classes from the servlet API, which are never loaded
+ * from the webapp repository.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - Due to limitations in Jasper
+ * compilation technology, any repository which contains classes from
+ * the servlet API will be ignored by the class loader.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - The class loader generates source
+ * URLs which include the full JAR URL when a class is loaded from a JAR file,
+ * which allows setting security permission at the class level, even when a
+ * class is contained inside a JAR.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - Local repositories are searched in
+ * the order they are added via the initial constructor and/or any subsequent
+ * calls to <code>addRepository()</code> or <code>addJar()</code>.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - No check for sealing violations or
+ * security is made unless a security manager is present.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @version $Revision: 1061 $ $Date: 2009-05-25 16:32:03 +0200 (Mon, 25 May 2009) $
+ */
+public class LegacyWebappClassLoader
+ extends URLClassLoader
+ implements Reloader, Lifecycle
+ {
+
+ protected static org.jboss.logging.Logger log=
+ org.jboss.logging.Logger.getLogger( LegacyWebappClassLoader.class );
+
+ public static final boolean ENABLE_CLEAR_REFERENCES =
+ Boolean.valueOf(System.getProperty("org.apache.catalina.loader.LegacyWebappClassLoader.ENABLE_CLEAR_REFERENCES", "true")).booleanValue();
+
+ public static final boolean SYSTEM_CL_DELEGATION =
+ Boolean.valueOf(System.getProperty("org.apache.catalina.loader.LegacyWebappClassLoader.SYSTEM_CL_DELEGATION", "true")).booleanValue();
+
+ protected class PrivilegedFindResource
+ implements PrivilegedAction {
+
+ protected File file;
+ protected String path;
+
+ PrivilegedFindResource(File file, String path) {
+ this.file = file;
+ this.path = path;
+ }
+
+ public Object run() {
+ return findResourceInternal(file, path);
+ }
+
+ }
+
+
+ // ------------------------------------------------------- Static Variables
+
+
+ /**
+ * The set of trigger classes that will cause a proposed repository not
+ * to be added if this class is visible to the class loader that loaded
+ * this factory class. Typically, trigger classes will be listed for
+ * components that have been integrated into the JDK for later versions,
+ * but where the corresponding JAR files are required to run on
+ * earlier versions.
+ */
+ protected static final String[] triggers = {
+ "javax.servlet.Servlet" // Servlet API
+ };
+
+
+ /**
+ * Set of package names which are not allowed to be loaded from a webapp
+ * class loader without delegating first.
+ */
+ protected static final String[] packageTriggers = {
+ };
+
+
+ /**
+ * The string manager for this package.
+ */
+ protected static final StringManager sm =
+ StringManager.getManager(Constants.Package);
+
+
+ /**
+ * Use anti JAR locking code, which does URL rerouting when accessing
+ * resources.
+ */
+ boolean antiJARLocking = false;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Construct a new ClassLoader with no defined repositories and no
+ * parent ClassLoader.
+ */
+ public LegacyWebappClassLoader() {
+
+ super(new URL[0]);
+ this.parent = getParent();
+ system = getSystemClassLoader();
+ securityManager = System.getSecurityManager();
+
+ if (securityManager != null) {
+ refreshPolicy();
+ }
+
+ }
+
+
+ /**
+ * Construct a new ClassLoader with no defined repositories and no
+ * parent ClassLoader.
+ */
+ public LegacyWebappClassLoader(ClassLoader parent) {
+
+ super(new URL[0], parent);
+
+ this.parent = getParent();
+
+ system = getSystemClassLoader();
+ securityManager = System.getSecurityManager();
+
+ if (securityManager != null) {
+ refreshPolicy();
+ }
+ }
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * Associated directory context giving access to the resources in this
+ * webapp.
+ */
+ protected DirContext resources = null;
+
+
+ /**
+ * The cache of ResourceEntry for classes and resources we have loaded,
+ * keyed by resource name.
+ */
+ protected HashMap resourceEntries = new HashMap();
+
+
+ /**
+ * The list of not found resources.
+ */
+ protected HashMap notFoundResources = new HashMap();
+
+
+ /**
+ * Should this class loader delegate to the parent class loader
+ * <strong>before</strong> searching its own repositories (i.e. the
+ * usual Java2 delegation model)? If set to <code>false</code>,
+ * this class loader will search its own repositories first, and
+ * delegate to the parent only if the class or resource is not
+ * found locally.
+ */
+ protected boolean delegate = false;
+
+
+ /**
+ * Last time a JAR was accessed.
+ */
+ protected long lastJarAccessed = 0L;
+
+
+ /**
+ * The list of local repositories, in the order they should be searched
+ * for locally loaded classes or resources.
+ */
+ protected String[] repositories = new String[0];
+
+
+ /**
+ * Repositories URLs, used to cache the result of getURLs.
+ */
+ protected URL[] repositoryURLs = null;
+
+
+ /**
+ * Repositories translated as path in the work directory (for Jasper
+ * originally), but which is used to generate fake URLs should getURLs be
+ * called.
+ */
+ protected File[] files = new File[0];
+
+
+ /**
+ * The list of JARs, in the order they should be searched
+ * for locally loaded classes or resources.
+ */
+ protected JarFile[] jarFiles = new JarFile[0];
+
+
+ /**
+ * The list of JARs, in the order they should be searched
+ * for locally loaded classes or resources.
+ */
+ protected File[] jarRealFiles = new File[0];
+
+
+ /**
+ * The path which will be monitored for added Jar files.
+ */
+ protected String jarPath = null;
+
+
+ /**
+ * The list of JARs, in the order they should be searched
+ * for locally loaded classes or resources.
+ */
+ protected String[] jarNames = new String[0];
+
+
+ /**
+ * The list of JARs last modified dates, in the order they should be
+ * searched for locally loaded classes or resources.
+ */
+ protected long[] lastModifiedDates = new long[0];
+
+
+ /**
+ * The list of resources which should be checked when checking for
+ * modifications.
+ */
+ protected String[] paths = new String[0];
+
+
+ /**
+ * A list of read File and Jndi Permission's required if this loader
+ * is for a web application context.
+ */
+ protected ArrayList permissionList = new ArrayList();
+
+
+ /**
+ * Path where resources loaded from JARs will be extracted.
+ */
+ protected File loaderDir = null;
+
+
+ /**
+ * The PermissionCollection for each CodeSource for a web
+ * application context.
+ */
+ protected HashMap loaderPC = new HashMap();
+
+
+ /**
+ * Instance of the SecurityManager installed.
+ */
+ protected SecurityManager securityManager = null;
+
+
+ /**
+ * The parent class loader.
+ */
+ protected ClassLoader parent = null;
+
+
+ /**
+ * The system class loader.
+ */
+ protected ClassLoader system = null;
+
+
+ /**
+ * Has this component been started?
+ */
+ protected boolean started = false;
+
+
+ /**
+ * Has external repositories.
+ */
+ protected boolean hasExternalRepositories = false;
+
+ /**
+ * need conversion for properties files
+ */
+ protected boolean needConvert = false;
+
+
+ /**
+ * All permission.
+ */
+ protected Permission allPermission = new java.security.AllPermission();
+
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Get associated resources.
+ */
+ public DirContext getResources() {
+
+ return this.resources;
+
+ }
+
+
+ /**
+ * Set associated resources.
+ */
+ public void setResources(DirContext resources) {
+
+ this.resources = resources;
+
+ }
+
+
+ /**
+ * Return the "delegate first" flag for this class loader.
+ */
+ public boolean getDelegate() {
+
+ return (this.delegate);
+
+ }
+
+
+ /**
+ * Set the "delegate first" flag for this class loader.
+ *
+ * @param delegate The new "delegate first" flag
+ */
+ public void setDelegate(boolean delegate) {
+
+ this.delegate = delegate;
+
+ }
+
+
+ /**
+ * @return Returns the antiJARLocking.
+ */
+ public boolean getAntiJARLocking() {
+ return antiJARLocking;
+ }
+
+
+ /**
+ * @param antiJARLocking The antiJARLocking to set.
+ */
+ public void setAntiJARLocking(boolean antiJARLocking) {
+ this.antiJARLocking = antiJARLocking;
+ }
+
+
+ /**
+ * If there is a Java SecurityManager create a read FilePermission
+ * or JndiPermission for the file directory path.
+ *
+ * @param path file directory path
+ */
+ public void addPermission(String path) {
+ if (path == null) {
+ return;
+ }
+
+ if (securityManager != null) {
+ Permission permission = null;
+ if( path.startsWith("jndi:") || path.startsWith("jar:jndi:") ) {
+ if (!path.endsWith("/")) {
+ path = path + "/";
+ }
+ permission = new JndiPermission(path + "*");
+ addPermission(permission);
+ } else {
+ if (!path.endsWith(File.separator)) {
+ permission = new FilePermission(path, "read");
+ addPermission(permission);
+ path = path + File.separator;
+ }
+ permission = new FilePermission(path + "-", "read");
+ addPermission(permission);
+ }
+ }
+ }
+
+
+ /**
+ * If there is a Java SecurityManager create a read FilePermission
+ * or JndiPermission for URL.
+ *
+ * @param url URL for a file or directory on local system
+ */
+ public void addPermission(URL url) {
+ if (url != null) {
+ addPermission(url.toString());
+ }
+ }
+
+
+ /**
+ * If there is a Java SecurityManager create a Permission.
+ *
+ * @param permission The permission
+ */
+ public void addPermission(Permission permission) {
+ if ((securityManager != null) && (permission != null)) {
+ permissionList.add(permission);
+ }
+ }
+
+
+ /**
+ * Return the JAR path.
+ */
+ public String getJarPath() {
+
+ return this.jarPath;
+
+ }
+
+
+ /**
+ * Change the Jar path.
+ */
+ public void setJarPath(String jarPath) {
+
+ this.jarPath = jarPath;
+
+ }
+
+
+ /**
+ * Change the work directory.
+ */
+ public void setWorkDir(File workDir) {
+ this.loaderDir = new File(workDir, "loader");
+ }
+
+ /**
+ * Utility method for use in subclasses.
+ * Must be called before Lifecycle methods to have any effect.
+ */
+ protected void setParentClassLoader(ClassLoader pcl) {
+ parent = pcl;
+ }
+
+ // ------------------------------------------------------- Reloader Methods
+
+
+ /**
+ * Add a new repository to the set of places this ClassLoader can look for
+ * classes to be loaded.
+ *
+ * @param repository Name of a source of classes to be loaded, such as a
+ * directory pathname, a JAR file pathname, or a ZIP file pathname
+ *
+ * @exception IllegalArgumentException if the specified repository is
+ * invalid or does not exist
+ */
+ public void addRepository(String repository) {
+
+ // Ignore any of the standard repositories, as they are set up using
+ // either addJar or addRepository
+ if (repository.startsWith("/WEB-INF/lib")
+ || repository.startsWith("/WEB-INF/classes"))
+ return;
+
+ // Add this repository to our underlying class loader
+ try {
+ URL url = new URL(repository);
+ super.addURL(url);
+ hasExternalRepositories = true;
+ repositoryURLs = null;
+ } catch (MalformedURLException e) {
+ IllegalArgumentException iae = new IllegalArgumentException
+ ("Invalid repository: " + repository);
+ iae.initCause(e);
+ throw iae;
+ }
+
+ }
+
+
+ /**
+ * Add a new repository to the set of places this ClassLoader can look for
+ * classes to be loaded.
+ *
+ * @param repository Name of a source of classes to be loaded, such as a
+ * directory pathname, a JAR file pathname, or a ZIP file pathname
+ *
+ * @exception IllegalArgumentException if the specified repository is
+ * invalid or does not exist
+ */
+ synchronized void addRepository(String repository, File file) {
+
+ // Note : There should be only one (of course), but I think we should
+ // keep this a bit generic
+
+ if (repository == null)
+ return;
+
+ if (log.isDebugEnabled())
+ log.debug("addRepository(" + repository + ")");
+
+ int i;
+
+ // Add this repository to our internal list
+ String[] result = new String[repositories.length + 1];
+ for (i = 0; i < repositories.length; i++) {
+ result[i] = repositories[i];
+ }
+ result[repositories.length] = repository;
+ repositories = result;
+
+ // Add the file to the list
+ File[] result2 = new File[files.length + 1];
+ for (i = 0; i < files.length; i++) {
+ result2[i] = files[i];
+ }
+ result2[files.length] = file;
+ files = result2;
+
+ }
+
+
+ synchronized void addJar(String jar, JarFile jarFile, File file)
+ throws IOException {
+
+ if (jar == null)
+ return;
+ if (jarFile == null)
+ return;
+ if (file == null)
+ return;
+
+ if (log.isDebugEnabled())
+ log.debug("addJar(" + jar + ")");
+
+ int i;
+
+ if ((jarPath != null) && (jar.startsWith(jarPath))) {
+
+ String jarName = jar.substring(jarPath.length());
+ while (jarName.startsWith("/"))
+ jarName = jarName.substring(1);
+
+ String[] result = new String[jarNames.length + 1];
+ for (i = 0; i < jarNames.length; i++) {
+ result[i] = jarNames[i];
+ }
+ result[jarNames.length] = jarName;
+ jarNames = result;
+
+ }
+
+ try {
+
+ // Register the JAR for tracking
+
+ long lastModified =
+ ((ResourceAttributes) resources.getAttributes(jar))
+ .getLastModified();
+
+ String[] result = new String[paths.length + 1];
+ for (i = 0; i < paths.length; i++) {
+ result[i] = paths[i];
+ }
+ result[paths.length] = jar;
+ paths = result;
+
+ long[] result3 = new long[lastModifiedDates.length + 1];
+ for (i = 0; i < lastModifiedDates.length; i++) {
+ result3[i] = lastModifiedDates[i];
+ }
+ result3[lastModifiedDates.length] = lastModified;
+ lastModifiedDates = result3;
+
+ } catch (NamingException e) {
+ // Ignore
+ }
+
+ // If the JAR currently contains invalid classes, don't actually use it
+ // for classloading
+ if (!validateJarFile(file))
+ return;
+
+ JarFile[] result2 = new JarFile[jarFiles.length + 1];
+ for (i = 0; i < jarFiles.length; i++) {
+ result2[i] = jarFiles[i];
+ }
+ result2[jarFiles.length] = jarFile;
+ jarFiles = result2;
+
+ // Add the file to the list
+ File[] result4 = new File[jarRealFiles.length + 1];
+ for (i = 0; i < jarRealFiles.length; i++) {
+ result4[i] = jarRealFiles[i];
+ }
+ result4[jarRealFiles.length] = file;
+ jarRealFiles = result4;
+ }
+
+
+ /**
+ * Return a String array of the current repositories for this class
+ * loader. If there are no repositories, a zero-length array is
+ * returned.For security reason, returns a clone of the Array (since
+ * String are immutable).
+ */
+ public String[] findRepositories() {
+
+ return ((String[])repositories.clone());
+
+ }
+
+
+ /**
+ * Have one or more classes or resources been modified so that a reload
+ * is appropriate?
+ */
+ public boolean modified() {
+
+ if (log.isDebugEnabled())
+ log.debug("modified()");
+
+ // Checking for modified loaded resources
+ int length = paths.length;
+
+ // A rare race condition can occur in the updates of the two arrays
+ // It's totally ok if the latest class added is not checked (it will
+ // be checked the next time
+ int length2 = lastModifiedDates.length;
+ if (length > length2)
+ length = length2;
+
+ for (int i = 0; i < length; i++) {
+ try {
+ long lastModified =
+ ((ResourceAttributes) resources.getAttributes(paths[i]))
+ .getLastModified();
+ if (lastModified != lastModifiedDates[i]) {
+ if( log.isDebugEnabled() )
+ log.debug(" Resource '" + paths[i]
+ + "' was modified; Date is now: "
+ + new java.util.Date(lastModified) + " Was: "
+ + new java.util.Date(lastModifiedDates[i]));
+ return (true);
+ }
+ } catch (NamingException e) {
+ log.error(" Resource '" + paths[i] + "' is missing");
+ return (true);
+ }
+ }
+
+ length = jarNames.length;
+
+ // Check if JARs have been added or removed
+ if (getJarPath() != null) {
+
+ try {
+ NamingEnumeration enumeration = resources.list(getJarPath());
+ int i = 0;
+ while (enumeration.hasMoreElements() && (i < length)) {
+ NameClassPair ncPair = (NameClassPair) enumeration.nextElement();
+ String name = ncPair.getName();
+ // Ignore non JARs present in the lib folder
+ if (!name.endsWith(".jar"))
+ continue;
+ if (!name.equals(jarNames[i])) {
+ // Missing JAR
+ log.info(" Additional JARs have been added : '"
+ + name + "'");
+ return (true);
+ }
+ i++;
+ }
+ if (enumeration.hasMoreElements()) {
+ while (enumeration.hasMoreElements()) {
+ NameClassPair ncPair =
+ (NameClassPair) enumeration.nextElement();
+ String name = ncPair.getName();
+ // Additional non-JAR files are allowed
+ if (name.endsWith(".jar")) {
+ // There was more JARs
+ log.info(" Additional JARs have been added");
+ return (true);
+ }
+ }
+ } else if (i < jarNames.length) {
+ // There was less JARs
+ log.info(" Additional JARs have been added");
+ return (true);
+ }
+ } catch (NamingException e) {
+ if (log.isDebugEnabled())
+ log.debug(" Failed tracking modifications of '"
+ + getJarPath() + "'");
+ } catch (ClassCastException e) {
+ log.error(" Failed tracking modifications of '"
+ + getJarPath() + "' : " + e.getMessage());
+ }
+
+ }
+
+ // No classes have been modified
+ return (false);
+
+ }
+
+
+ /**
+ * Render a String representation of this object.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("LegacyWebappClassLoader\r\n");
+ sb.append(" delegate: ");
+ sb.append(delegate);
+ sb.append("\r\n");
+ sb.append(" repositories:\r\n");
+ if (repositories != null) {
+ for (int i = 0; i < repositories.length; i++) {
+ sb.append(" ");
+ sb.append(repositories[i]);
+ sb.append("\r\n");
+ }
+ }
+ if (this.parent != null) {
+ sb.append("----------> Parent Classloader:\r\n");
+ sb.append(this.parent.toString());
+ sb.append("\r\n");
+ }
+ return (sb.toString());
+
+ }
+
+
+ // ---------------------------------------------------- ClassLoader Methods
+
+
+ /**
+ * Add the specified URL to the classloader.
+ */
+ protected void addURL(URL url) {
+ super.addURL(url);
+ hasExternalRepositories = true;
+ repositoryURLs = null;
+ }
+
+
+ /**
+ * Find the specified class in our local repositories, if possible. If
+ * not found, throw <code>ClassNotFoundException</code>.
+ *
+ * @param name Name of the class to be loaded
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class findClass(String name) throws ClassNotFoundException {
+
+ if (log.isDebugEnabled())
+ log.debug(" findClass(" + name + ")");
+
+ // Cannot load anything from local repositories if class loader is stopped
+ if (!started) {
+ throw new ClassNotFoundException(name);
+ }
+
+ // (1) Permission to define this class when using a SecurityManager
+ if (securityManager != null) {
+ int i = name.lastIndexOf('.');
+ if (i >= 0) {
+ try {
+ if (log.isTraceEnabled())
+ log.trace(" securityManager.checkPackageDefinition");
+ securityManager.checkPackageDefinition(name.substring(0,i));
+ } catch (Exception se) {
+ if (log.isTraceEnabled())
+ log.trace(" -->Exception-->ClassNotFoundException", se);
+ throw new ClassNotFoundException(name, se);
+ }
+ }
+ }
+
+ // Ask our superclass to locate this class, if possible
+ // (throws ClassNotFoundException if it is not found)
+ Class clazz = null;
+ try {
+ if (log.isTraceEnabled())
+ log.trace(" findClassInternal(" + name + ")");
+ try {
+ clazz = findClassInternal(name);
+ } catch(ClassNotFoundException cnfe) {
+ if (!hasExternalRepositories) {
+ throw cnfe;
+ }
+ } catch(AccessControlException ace) {
+ throw new ClassNotFoundException(name, ace);
+ } catch (RuntimeException e) {
+ if (log.isTraceEnabled())
+ log.trace(" -->RuntimeException Rethrown", e);
+ throw e;
+ }
+ if ((clazz == null) && hasExternalRepositories) {
+ try {
+ synchronized (this) {
+ clazz = super.findClass(name);
+ }
+ } catch(AccessControlException ace) {
+ throw new ClassNotFoundException(name, ace);
+ } catch (RuntimeException e) {
+ if (log.isTraceEnabled())
+ log.trace(" -->RuntimeException Rethrown", e);
+ throw e;
+ }
+ }
+ if (clazz == null) {
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning ClassNotFoundException");
+ throw new ClassNotFoundException(name);
+ }
+ } catch (ClassNotFoundException e) {
+ if (log.isTraceEnabled())
+ log.trace(" --> Passing on ClassNotFoundException");
+ throw e;
+ }
+
+ // Return the class we have located
+ if (log.isTraceEnabled())
+ log.debug(" Returning class " + clazz);
+ if ((log.isTraceEnabled()) && (clazz != null))
+ log.debug(" Loaded by " + clazz.getClassLoader());
+ return (clazz);
+
+ }
+
+
+ /**
+ * Find the specified resource in our local repository, and return a
+ * <code>URL</code> refering to it, or <code>null</code> if this resource
+ * cannot be found.
+ *
+ * @param name Name of the resource to be found
+ */
+ public URL findResource(final String name) {
+
+ if (log.isDebugEnabled())
+ log.debug(" findResource(" + name + ")");
+
+ URL url = null;
+
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ if (entry == null) {
+ entry = findResourceInternal(name, name);
+ }
+ if (entry != null) {
+ url = entry.source;
+ }
+
+ if ((url == null) && hasExternalRepositories)
+ url = super.findResource(name);
+
+ if (log.isDebugEnabled()) {
+ if (url != null)
+ log.debug(" --> Returning '" + url.toString() + "'");
+ else
+ log.debug(" --> Resource not found, returning null");
+ }
+ return (url);
+
+ }
+
+
+ /**
+ * Return an enumeration of <code>URLs</code> representing all of the
+ * resources with the given name. If no resources with this name are
+ * found, return an empty enumeration.
+ *
+ * @param name Name of the resources to be found
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public Enumeration findResources(String name) throws IOException {
+
+ if (log.isDebugEnabled())
+ log.debug(" findResources(" + name + ")");
+
+ Vector result = new Vector();
+
+ int jarFilesLength = jarFiles.length;
+ int repositoriesLength = repositories.length;
+
+ int i;
+
+ // Looking at the repositories
+ for (i = 0; i < repositoriesLength; i++) {
+ try {
+ String fullPath = repositories[i] + name;
+ resources.lookup(fullPath);
+ // Note : Not getting an exception here means the resource was
+ // found
+ try {
+ result.addElement(getURI(new File(files[i], name)));
+ } catch (MalformedURLException e) {
+ // Ignore
+ }
+ } catch (NamingException e) {
+ }
+ }
+
+ // Looking at the JAR files
+ synchronized (jarFiles) {
+ if (openJARs()) {
+ for (i = 0; i < jarFilesLength; i++) {
+ JarEntry jarEntry = jarFiles[i].getJarEntry(name);
+ if (jarEntry != null) {
+ try {
+ String jarFakeUrl = getURI(jarRealFiles[i]).toString();
+ jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
+ result.addElement(new URL(jarFakeUrl));
+ } catch (MalformedURLException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+ }
+
+ // Adding the results of a call to the superclass
+ if (hasExternalRepositories) {
+
+ Enumeration otherResourcePaths = super.findResources(name);
+
+ while (otherResourcePaths.hasMoreElements()) {
+ result.addElement(otherResourcePaths.nextElement());
+ }
+
+ }
+
+ return result.elements();
+
+ }
+
+
+ /**
+ * Find the resource with the given name. A resource is some data
+ * (images, audio, text, etc.) that can be accessed by class code in a
+ * way that is independent of the location of the code. The name of a
+ * resource is a "/"-separated path name that identifies the resource.
+ * If the resource cannot be found, return <code>null</code>.
+ * <p>
+ * This method searches according to the following algorithm, returning
+ * as soon as it finds the appropriate URL. If the resource cannot be
+ * found, returns <code>null</code>.
+ * <ul>
+ * <li>If the <code>delegate</code> property is set to <code>true</code>,
+ * call the <code>getResource()</code> method of the parent class
+ * loader, if any.</li>
+ * <li>Call <code>findResource()</code> to find this resource in our
+ * locally defined repositories.</li>
+ * <li>Call the <code>getResource()</code> method of the parent class
+ * loader, if any.</li>
+ * </ul>
+ *
+ * @param name Name of the resource to return a URL for
+ */
+ public URL getResource(String name) {
+
+ if (log.isDebugEnabled())
+ log.debug("getResource(" + name + ")");
+ URL url = null;
+
+ // (1) Delegate to parent if requested
+ if (delegate) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ url = loader.getResource(name);
+ if (url != null) {
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning '" + url.toString() + "'");
+ return (url);
+ }
+ }
+
+ // (2) Search local repositories
+ url = findResource(name);
+ if (url != null) {
+ // Locating the repository for special handling in the case
+ // of a JAR
+ if (antiJARLocking) {
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ try {
+ String repository = entry.codeBase.toString();
+ if ((repository.endsWith(".jar"))
+ && (!(name.endsWith(".class")))) {
+ // Copy binary content to the work directory if not present
+ File resourceFile = new File(loaderDir, name);
+ url = getURI(resourceFile);
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning '" + url.toString() + "'");
+ return (url);
+ }
+
+ // (3) Delegate to parent unconditionally if not already attempted
+ if( !delegate ) {
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ url = loader.getResource(name);
+ if (url != null) {
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning '" + url.toString() + "'");
+ return (url);
+ }
+ }
+
+ // (4) Resource was not found
+ if (log.isDebugEnabled())
+ log.debug(" --> Resource not found, returning null");
+ return (null);
+
+ }
+
+
+ /**
+ * Find the resource with the given name, and return an input stream
+ * that can be used for reading it. The search order is as described
+ * for <code>getResource()</code>, after checking to see if the resource
+ * data has been previously cached. If the resource cannot be found,
+ * return <code>null</code>.
+ *
+ * @param name Name of the resource to return an input stream for
+ */
+ public InputStream getResourceAsStream(String name) {
+
+ if (log.isDebugEnabled())
+ log.debug("getResourceAsStream(" + name + ")");
+ InputStream stream = null;
+
+ // (0) Check for a cached copy of this resource
+ stream = findLoadedResource(name);
+ if (stream != null) {
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning stream from cache");
+ return (stream);
+ }
+
+ // (1) Delegate to parent if requested
+ if (delegate) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ stream = loader.getResourceAsStream(name);
+ if (stream != null) {
+ // FIXME - cache???
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning stream from parent");
+ return (stream);
+ }
+ }
+
+ // (2) Search local repositories
+ if (log.isDebugEnabled())
+ log.debug(" Searching local repositories");
+ URL url = findResource(name);
+ if (url != null) {
+ // FIXME - cache???
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning stream from local");
+ stream = findLoadedResource(name);
+ try {
+ if (hasExternalRepositories && (stream == null))
+ stream = url.openStream();
+ } catch (IOException e) {
+ ; // Ignore
+ }
+ if (stream != null)
+ return (stream);
+ }
+
+ // (3) Delegate to parent unconditionally
+ if (!delegate) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader unconditionally " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ stream = loader.getResourceAsStream(name);
+ if (stream != null) {
+ // FIXME - cache???
+ if (log.isDebugEnabled())
+ log.debug(" --> Returning stream from parent");
+ return (stream);
+ }
+ }
+
+ // (4) Resource was not found
+ if (log.isDebugEnabled())
+ log.debug(" --> Resource not found, returning null");
+ return (null);
+
+ }
+
+
+ /**
+ * 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(String name, boolean resolve)
+ throws ClassNotFoundException {
+
+ if (log.isDebugEnabled())
+ log.debug("loadClass(" + name + ", " + resolve + ")");
+ Class clazz = null;
+
+ // Log access to stopped classloader
+ if (!started) {
+ try {
+ throw new IllegalStateException();
+ } catch (IllegalStateException e) {
+ log.info(sm.getString("WebappClassLoader.stopped", name), e);
+ }
+ }
+
+ // (0) Check our previously loaded local class cache
+ clazz = findLoadedClass0(name);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Returning class from cache");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+
+ // (0.1) Check our previously loaded class cache
+ clazz = findLoadedClass(name);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Returning class from cache");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+
+ // (0.2) Try loading the class with the system class loader, to prevent
+ // the webapp from overriding J2SE classes
+ if (SYSTEM_CL_DELEGATION) {
+ try {
+ clazz = Class.forName(name, false, system);
+ if (clazz != null) {
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ // Ignore
+ }
+ }
+
+ // (0.5) Permission to access this class when using a SecurityManager
+ if (securityManager != null) {
+ int i = name.lastIndexOf('.');
+ if (i >= 0) {
+ try {
+ securityManager.checkPackageAccess(name.substring(0,i));
+ } catch (SecurityException se) {
+ String error = "Security Violation, attempt to use " +
+ "Restricted Class: " + name;
+ log.info(error, se);
+ throw new ClassNotFoundException(error, se);
+ }
+ }
+ }
+
+ boolean delegateLoad = delegate || filter(name);
+
+ // (1) Delegate to our parent if requested
+ if (delegateLoad) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader1 " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ try {
+ clazz = Class.forName(name, false, loader);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Loading class from parent");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ ;
+ }
+ }
+
+ // (2) Search local repositories
+ if (log.isDebugEnabled())
+ log.debug(" Searching local repositories");
+ try {
+ clazz = findClass(name);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Loading class from local repository");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ ;
+ }
+
+ // (3) Delegate to parent unconditionally
+ if (!delegateLoad) {
+ if (log.isDebugEnabled())
+ log.debug(" Delegating to parent classloader at end: " + parent);
+ ClassLoader loader = parent;
+ if (loader == null)
+ loader = system;
+ try {
+ clazz = Class.forName(name, false, loader);
+ if (clazz != null) {
+ if (log.isDebugEnabled())
+ log.debug(" Loading class from parent");
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ ;
+ }
+ }
+
+ throw new ClassNotFoundException(name);
+ }
+
+
+ /**
+ * Get the Permissions for a CodeSource. If this instance
+ * of LegacyWebappClassLoader is for a web application context,
+ * add read FilePermission or JndiPermissions for the base
+ * directory (if unpacked),
+ * the context URL, and jar file resources.
+ *
+ * @param codeSource where the code was loaded from
+ * @return PermissionCollection for CodeSource
+ */
+ protected PermissionCollection getPermissions(CodeSource codeSource) {
+
+ String codeUrl = codeSource.getLocation().toString();
+ PermissionCollection pc;
+ if ((pc = (PermissionCollection)loaderPC.get(codeUrl)) == null) {
+ pc = super.getPermissions(codeSource);
+ if (pc != null) {
+ Iterator perms = permissionList.iterator();
+ while (perms.hasNext()) {
+ Permission p = (Permission)perms.next();
+ pc.add(p);
+ }
+ loaderPC.put(codeUrl,pc);
+ }
+ }
+ return (pc);
+
+ }
+
+
+ /**
+ * Returns the search path of URLs for loading classes and resources.
+ * This includes the original list of URLs specified to the constructor,
+ * along with any URLs subsequently appended by the addURL() method.
+ * @return the search path of URLs for loading classes and resources.
+ */
+ public URL[] getURLs() {
+
+ if (repositoryURLs != null) {
+ return repositoryURLs;
+ }
+
+ URL[] external = super.getURLs();
+
+ int filesLength = files.length;
+ int jarFilesLength = jarRealFiles.length;
+ int length = filesLength + jarFilesLength + external.length;
+ int i;
+
+ try {
+
+ URL[] urls = new URL[length];
+ for (i = 0; i < length; i++) {
+ if (i < filesLength) {
+ urls[i] = getURL(files[i], true);
+ } else if (i < filesLength + jarFilesLength) {
+ urls[i] = getURL(jarRealFiles[i - filesLength], true);
+ } else {
+ urls[i] = external[i - filesLength - jarFilesLength];
+ }
+ }
+
+ repositoryURLs = urls;
+
+ } catch (MalformedURLException e) {
+ repositoryURLs = new URL[0];
+ }
+
+ return repositoryURLs;
+
+ }
+
+
+ // ------------------------------------------------------ Lifecycle Methods
+
+
+ /**
+ * Add a lifecycle event listener to this component.
+ *
+ * @param listener The listener to add
+ */
+ public void addLifecycleListener(LifecycleListener listener) {
+ }
+
+
+ /**
+ * Get the lifecycle listeners associated with this lifecycle. If this
+ * Lifecycle has no listeners registered, a zero-length array is returned.
+ */
+ public LifecycleListener[] findLifecycleListeners() {
+ return new LifecycleListener[0];
+ }
+
+
+ /**
+ * Remove a lifecycle event listener from this component.
+ *
+ * @param listener The listener to remove
+ */
+ public void removeLifecycleListener(LifecycleListener listener) {
+ }
+
+
+ /**
+ * Start the class loader.
+ *
+ * @exception LifecycleException if a lifecycle error occurs
+ */
+ public void start() throws LifecycleException {
+
+ started = true;
+ String encoding = null;
+ try {
+ encoding = System.getProperty("file.encoding");
+ } catch (Exception e) {
+ return;
+ }
+ if (encoding.indexOf("EBCDIC")!=-1) {
+ needConvert = true;
+ }
+
+ }
+
+
+ /**
+ * Stop the class loader.
+ *
+ * @exception LifecycleException if a lifecycle error occurs
+ */
+ public void stop() throws LifecycleException {
+
+ // Clearing references should be done before setting started to
+ // false, due to possible side effects
+ clearReferences();
+
+ started = false;
+
+ int length = files.length;
+ for (int i = 0; i < length; i++) {
+ files[i] = null;
+ }
+
+ length = jarFiles.length;
+ for (int i = 0; i < length; i++) {
+ try {
+ if (jarFiles[i] != null) {
+ jarFiles[i].close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+ jarFiles[i] = null;
+ }
+
+ notFoundResources.clear();
+ resourceEntries.clear();
+ resources = null;
+ repositories = null;
+ repositoryURLs = null;
+ files = null;
+ jarFiles = null;
+ jarRealFiles = null;
+ jarPath = null;
+ jarNames = null;
+ lastModifiedDates = null;
+ paths = null;
+ hasExternalRepositories = false;
+ parent = null;
+
+ permissionList.clear();
+ loaderPC.clear();
+
+ if (loaderDir != null) {
+ deleteDir(loaderDir);
+ }
+
+ }
+
+
+ /**
+ * Used to periodically signal to the classloader to release
+ * JAR resources.
+ */
+ public void closeJARs(boolean force) {
+ if (jarFiles.length > 0) {
+ synchronized (jarFiles) {
+ if (force || (System.currentTimeMillis()
+ > (lastJarAccessed + 90000))) {
+ for (int i = 0; i < jarFiles.length; i++) {
+ try {
+ if (jarFiles[i] != null) {
+ jarFiles[i].close();
+ jarFiles[i] = null;
+ }
+ } catch (IOException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Failed to close JAR", e);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * Clear references.
+ */
+ protected void clearReferences() {
+
+ // Unregister any JDBC drivers loaded by this classloader
+ Enumeration drivers = DriverManager.getDrivers();
+ while (drivers.hasMoreElements()) {
+ Driver driver = (Driver) drivers.nextElement();
+ if (driver.getClass().getClassLoader() == this) {
+ try {
+ DriverManager.deregisterDriver(driver);
+ } catch (SQLException e) {
+ log.warn("SQL driver deregistration failed", e);
+ }
+ }
+ }
+
+ // Null out any static or final fields from loaded classes,
+ // as a workaround for apparent garbage collection bugs
+ if (ENABLE_CLEAR_REFERENCES) {
+ Iterator loadedClasses = ((HashMap) resourceEntries.clone()).values().iterator();
+ while (loadedClasses.hasNext()) {
+ ResourceEntry entry = (ResourceEntry) loadedClasses.next();
+ if (entry.loadedClass != null) {
+ Class clazz = entry.loadedClass;
+ try {
+ Field[] fields = clazz.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ int mods = field.getModifiers();
+ if (field.getType().isPrimitive()
+ || (field.getName().indexOf("$") != -1)) {
+ continue;
+ }
+ if (Modifier.isStatic(mods)) {
+ try {
+ field.setAccessible(true);
+ if (Modifier.isFinal(mods)) {
+ if (!((field.getType().getName().startsWith("java."))
+ || (field.getType().getName().startsWith("javax.")))) {
+ nullInstance(field.get(null));
+ }
+ } else {
+ field.set(null, null);
+ if (log.isDebugEnabled()) {
+ log.debug("Set field " + field.getName()
+ + " to null in class " + clazz.getName());
+ }
+ }
+ } catch (Throwable t) {
+ if (log.isDebugEnabled()) {
+ log.debug("Could not set field " + field.getName()
+ + " to null in class " + clazz.getName(), t);
+ }
+ }
+ }
+ }
+ } catch (Throwable t) {
+ if (log.isDebugEnabled()) {
+ log.debug("Could not clean fields for class " + clazz.getName(), t);
+ }
+ }
+ }
+ }
+ }
+
+ // Clear the IntrospectionUtils cache.
+ IntrospectionUtils.clear();
+
+ // Clear the classloader reference in the VM's bean introspector
+ java.beans.Introspector.flushCaches();
+
+ }
+
+
+ protected void nullInstance(Object instance) {
+ if (instance == null) {
+ return;
+ }
+ Field[] fields = instance.getClass().getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ int mods = field.getModifiers();
+ if (field.getType().isPrimitive()
+ || (field.getName().indexOf("$") != -1)) {
+ continue;
+ }
+ try {
+ field.setAccessible(true);
+ if (Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
+ // Doing something recursively is too risky
+ continue;
+ } else {
+ Object value = field.get(instance);
+ if (null != value) {
+ Class valueClass = value.getClass();
+ if (!loadedByThisOrChild(valueClass)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Not setting field " + field.getName() +
+ " to null in object of class " +
+ instance.getClass().getName() +
+ " because the referenced object was of type " +
+ valueClass.getName() +
+ " which was not loaded by this LegacyWebappClassLoader.");
+ }
+ } else {
+ field.set(instance, null);
+ if (log.isDebugEnabled()) {
+ log.debug("Set field " + field.getName()
+ + " to null in class " + instance.getClass().getName());
+ }
+ }
+ }
+ }
+ } catch (Throwable t) {
+ if (log.isDebugEnabled()) {
+ log.debug("Could not set field " + field.getName()
+ + " to null in object instance of class "
+ + instance.getClass().getName(), t);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Determine whether a class was loaded by this class loader or one of
+ * its child class loaders.
+ */
+ protected boolean loadedByThisOrChild(Class clazz)
+ {
+ boolean result = false;
+ for (ClassLoader classLoader = clazz.getClassLoader();
+ null != classLoader; classLoader = classLoader.getParent()) {
+ if (classLoader.equals(this)) {
+ result = true;
+ break;
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Used to periodically signal to the classloader to release JAR resources.
+ */
+ protected boolean openJARs() {
+ if (started && (jarFiles.length > 0)) {
+ lastJarAccessed = System.currentTimeMillis();
+ if (jarFiles[0] == null) {
+ for (int i = 0; i < jarFiles.length; i++) {
+ try {
+ jarFiles[i] = new JarFile(jarRealFiles[i]);
+ } catch (IOException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Failed to open JAR", e);
+ }
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * Find specified class in local repositories.
+ *
+ * @return the loaded class, or null if the class isn't found
+ */
+ protected Class findClassInternal(String name)
+ throws ClassNotFoundException {
+
+ if (!validate(name))
+ throw new ClassNotFoundException(name);
+
+ String tempPath = name.replace('.', '/');
+ String classPath = tempPath + ".class";
+
+ ResourceEntry entry = null;
+
+ entry = findResourceInternal(name, classPath);
+
+ if (entry == null)
+ throw new ClassNotFoundException(name);
+
+ Class clazz = entry.loadedClass;
+ if (clazz != null)
+ return clazz;
+
+ synchronized (this) {
+ clazz = entry.loadedClass;
+ if (clazz != null)
+ return clazz;
+
+ if (entry.binaryContent == null)
+ throw new ClassNotFoundException(name);
+
+ // Looking up the package
+ String packageName = null;
+ int pos = name.lastIndexOf('.');
+ if (pos != -1)
+ packageName = name.substring(0, pos);
+
+ Package pkg = null;
+
+ if (packageName != null) {
+ pkg = getPackage(packageName);
+ // Define the package (if null)
+ if (pkg == null) {
+ try {
+ if (entry.manifest == null) {
+ definePackage(packageName, null, null, null, null,
+ null, null, null);
+ } else {
+ definePackage(packageName, entry.manifest,
+ entry.codeBase);
+ }
+ } catch (IllegalArgumentException e) {
+ // Ignore: normal error due to dual definition of package
+ }
+ pkg = getPackage(packageName);
+ }
+ }
+
+ if (securityManager != null) {
+
+ // Checking sealing
+ if (pkg != null) {
+ boolean sealCheck = true;
+ if (pkg.isSealed()) {
+ sealCheck = pkg.isSealed(entry.codeBase);
+ } else {
+ sealCheck = (entry.manifest == null)
+ || !isPackageSealed(packageName, entry.manifest);
+ }
+ if (!sealCheck)
+ throw new SecurityException
+ ("Sealing violation loading " + name + " : Package "
+ + packageName + " is sealed.");
+ }
+
+ }
+
+ clazz = defineClass(name, entry.binaryContent, 0,
+ entry.binaryContent.length,
+ new CodeSource(entry.codeBase, entry.certificates));
+ entry.loadedClass = clazz;
+ entry.binaryContent = null;
+ entry.source = null;
+ entry.codeBase = null;
+ entry.manifest = null;
+ entry.certificates = null;
+ }
+
+ return clazz;
+
+ }
+
+ /**
+ * Find specified resource in local repositories. This block
+ * will execute under an AccessControl.doPrivilege block.
+ *
+ * @return the loaded resource, or null if the resource isn't found
+ */
+ protected ResourceEntry findResourceInternal(File file, String path){
+ ResourceEntry entry = new ResourceEntry();
+ try {
+ entry.source = getURI(new File(file, path));
+ entry.codeBase = getURL(new File(file, path), false);
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ return entry;
+ }
+
+
+ /**
+ * Find specified resource in local repositories.
+ *
+ * @return the loaded resource, or null if the resource isn't found
+ */
+ protected ResourceEntry findResourceInternal(String name, String path) {
+
+ if (!started) {
+ log.info(sm.getString("webappClassLoader.stopped", name));
+ return null;
+ }
+
+ if ((name == null) || (path == null))
+ return null;
+
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ if (entry != null)
+ return entry;
+
+ int contentLength = -1;
+ InputStream binaryStream = null;
+
+ int jarFilesLength = jarFiles.length;
+ int repositoriesLength = repositories.length;
+
+ int i;
+
+ Resource resource = null;
+
+ boolean fileNeedConvert = false;
+
+ for (i = 0; (entry == null) && (i < repositoriesLength); i++) {
+ try {
+
+ String fullPath = repositories[i] + path;
+
+ Object lookupResult = resources.lookup(fullPath);
+ if (lookupResult instanceof Resource) {
+ resource = (Resource) lookupResult;
+ }
+
+ // Note : Not getting an exception here means the resource was
+ // found
+ if (securityManager != null) {
+ PrivilegedAction dp =
+ new PrivilegedFindResource(files[i], path);
+ entry = (ResourceEntry)AccessController.doPrivileged(dp);
+ } else {
+ entry = findResourceInternal(files[i], path);
+ }
+
+ ResourceAttributes attributes =
+ (ResourceAttributes) resources.getAttributes(fullPath);
+ contentLength = (int) attributes.getContentLength();
+ entry.lastModified = attributes.getLastModified();
+
+ if (resource != null) {
+
+
+ try {
+ binaryStream = resource.streamContent();
+ } catch (IOException e) {
+ return null;
+ }
+
+ if (needConvert) {
+ if (path.endsWith(".properties")) {
+ fileNeedConvert = true;
+ }
+ }
+
+ // Register the full path for modification checking
+ // Note: Only syncing on a 'constant' object is needed
+ synchronized (allPermission) {
+
+ int j;
+
+ long[] result2 =
+ new long[lastModifiedDates.length + 1];
+ for (j = 0; j < lastModifiedDates.length; j++) {
+ result2[j] = lastModifiedDates[j];
+ }
+ result2[lastModifiedDates.length] = entry.lastModified;
+ lastModifiedDates = result2;
+
+ String[] result = new String[paths.length + 1];
+ for (j = 0; j < paths.length; j++) {
+ result[j] = paths[j];
+ }
+ result[paths.length] = fullPath;
+ paths = result;
+
+ }
+
+ }
+
+ } catch (NamingException e) {
+ }
+ }
+
+ if ((entry == null) && (notFoundResources.containsKey(name)))
+ return null;
+
+ JarEntry jarEntry = null;
+
+ synchronized (jarFiles) {
+
+ if (!openJARs()) {
+ return null;
+ }
+ for (i = 0; (entry == null) && (i < jarFilesLength); i++) {
+
+ jarEntry = jarFiles[i].getJarEntry(path);
+
+ if (jarEntry != null) {
+
+ entry = new ResourceEntry();
+ try {
+ entry.codeBase = getURL(jarRealFiles[i], false);
+ String jarFakeUrl = getURI(jarRealFiles[i]).toString();
+ jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
+ entry.source = new URL(jarFakeUrl);
+ entry.lastModified = jarRealFiles[i].lastModified();
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ contentLength = (int) jarEntry.getSize();
+ try {
+ entry.manifest = jarFiles[i].getManifest();
+ binaryStream = jarFiles[i].getInputStream(jarEntry);
+ } catch (IOException e) {
+ return null;
+ }
+
+ // Extract resources contained in JAR to the workdir
+ if (antiJARLocking && !(path.endsWith(".class"))) {
+ byte[] buf = new byte[1024];
+ File resourceFile = new File
+ (loaderDir, jarEntry.getName());
+ if (!resourceFile.exists()) {
+ Enumeration entries = jarFiles[i].entries();
+ while (entries.hasMoreElements()) {
+ JarEntry jarEntry2 =
+ (JarEntry) entries.nextElement();
+ if (!(jarEntry2.isDirectory())
+ && (!jarEntry2.getName().endsWith
+ (".class"))) {
+ resourceFile = new File
+ (loaderDir, jarEntry2.getName());
+ resourceFile.getParentFile().mkdirs();
+ FileOutputStream os = null;
+ InputStream is = null;
+ try {
+ is = jarFiles[i].getInputStream
+ (jarEntry2);
+ os = new FileOutputStream
+ (resourceFile);
+ while (true) {
+ int n = is.read(buf);
+ if (n <= 0) {
+ break;
+ }
+ os.write(buf, 0, n);
+ }
+ } catch (IOException e) {
+ // Ignore
+ } finally {
+ try {
+ if (is != null) {
+ is.close();
+ }
+ } catch (IOException e) {
+ }
+ try {
+ if (os != null) {
+ os.close();
+ }
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ }
+
+ if (entry == null) {
+ synchronized (notFoundResources) {
+ notFoundResources.put(name, name);
+ }
+ return null;
+ }
+
+ if (binaryStream != null) {
+
+ byte[] binaryContent = new byte[contentLength];
+
+ int pos = 0;
+ try {
+
+ while (true) {
+ int n = binaryStream.read(binaryContent, pos,
+ binaryContent.length - pos);
+ if (n <= 0)
+ break;
+ pos += n;
+ }
+ } catch (IOException e) {
+ log.error(sm.getString("webappClassLoader.readError", name), e);
+ return null;
+ } finally {
+ try {
+ binaryStream.close();
+ } catch (IOException e) {}
+ }
+
+ if (fileNeedConvert) {
+ String str = new String(binaryContent,0,pos);
+ try {
+ binaryContent = str.getBytes("UTF-8");
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ entry.binaryContent = binaryContent;
+
+ // The certificates are only available after the JarEntry
+ // associated input stream has been fully read
+ if (jarEntry != null) {
+ entry.certificates = jarEntry.getCertificates();
+ }
+
+ }
+
+ }
+
+ // Add the entry in the local resource repository
+ synchronized (resourceEntries) {
+ // Ensures that all the threads which may be in a race to load
+ // a particular class all end up with the same ResourceEntry
+ // instance
+ ResourceEntry entry2 = (ResourceEntry) resourceEntries.get(name);
+ if (entry2 == null) {
+ resourceEntries.put(name, entry);
+ } else {
+ entry = entry2;
+ }
+ }
+
+ return entry;
+
+ }
+
+
+ /**
+ * Returns true if the specified package name is sealed according to the
+ * given manifest.
+ */
+ protected boolean isPackageSealed(String name, Manifest man) {
+
+ String path = name.replace('.', '/') + '/';
+ Attributes attr = man.getAttributes(path);
+ String sealed = null;
+ if (attr != null) {
+ sealed = attr.getValue(Name.SEALED);
+ }
+ if (sealed == null) {
+ if ((attr = man.getMainAttributes()) != null) {
+ sealed = attr.getValue(Name.SEALED);
+ }
+ }
+ return "true".equalsIgnoreCase(sealed);
+
+ }
+
+
+ /**
+ * Finds the resource with the given name if it has previously been
+ * loaded and cached by this class loader, and return an input stream
+ * to the resource data. If this resource has not been cached, return
+ * <code>null</code>.
+ *
+ * @param name Name of the resource to return
+ */
+ protected InputStream findLoadedResource(String name) {
+
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ if (entry != null) {
+ if (entry.binaryContent != null)
+ return new ByteArrayInputStream(entry.binaryContent);
+ }
+ return (null);
+
+ }
+
+
+ /**
+ * Finds the class with the given name if it has previously been
+ * loaded and cached by this class loader, and return the Class object.
+ * If this class has not been cached, return <code>null</code>.
+ *
+ * @param name Name of the resource to return
+ */
+ protected Class findLoadedClass0(String name) {
+
+ ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+ if (entry != null) {
+ return entry.loadedClass;
+ }
+ return (null); // FIXME - findLoadedResource()
+
+ }
+
+
+ /**
+ * Refresh the system policy file, to pick up eventual changes.
+ */
+ protected void refreshPolicy() {
+
+ try {
+ // The policy file may have been modified to adjust
+ // permissions, so we're reloading it when loading or
+ // reloading a Context
+ Policy policy = Policy.getPolicy();
+ policy.refresh();
+ } catch (AccessControlException e) {
+ // Some policy files may restrict this, even for the core,
+ // so this exception is ignored
+ }
+
+ }
+
+
+ /**
+ * Filter classes.
+ *
+ * @param name class name
+ * @return true if the class should be filtered
+ */
+ protected boolean filter(String name) {
+
+ if (name == null)
+ return false;
+
+ // Looking up the package
+ String packageName = null;
+ int pos = name.lastIndexOf('.');
+ if (pos != -1)
+ packageName = name.substring(0, pos);
+ else
+ return false;
+
+ for (int i = 0; i < packageTriggers.length; i++) {
+ if (packageName.startsWith(packageTriggers[i]))
+ return true;
+ }
+
+ return false;
+
+ }
+
+
+ /**
+ * Validate a classname. As per SRV.9.7.2, we must restict loading of
+ * classes from J2SE (java.*) and classes of the servlet API
+ * (javax.servlet.*). That should enhance robustness and prevent a number
+ * of user error (where an older version of servlet.jar would be present
+ * in /WEB-INF/lib).
+ *
+ * @param name class name
+ * @return true if the name is valid
+ */
+ protected boolean validate(String name) {
+
+ if (name == null)
+ return false;
+ if (name.startsWith("java."))
+ return false;
+
+ return true;
+
+ }
+
+
+ /**
+ * Check the specified JAR file, and return <code>true</code> if it does
+ * not contain any of the trigger classes.
+ *
+ * @param jarfile The JAR file to be checked
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ protected boolean validateJarFile(File jarfile)
+ throws IOException {
+
+ if (triggers == null)
+ return (true);
+ JarFile jarFile = new JarFile(jarfile);
+ for (int i = 0; i < triggers.length; i++) {
+ Class clazz = null;
+ try {
+ if (parent != null) {
+ clazz = parent.loadClass(triggers[i]);
+ } else {
+ clazz = Class.forName(triggers[i]);
+ }
+ } catch (Throwable t) {
+ clazz = null;
+ }
+ if (clazz == null)
+ continue;
+ String name = triggers[i].replace('.', '/') + ".class";
+ if (log.isDebugEnabled())
+ log.debug(" Checking for " + name);
+ JarEntry jarEntry = jarFile.getJarEntry(name);
+ if (jarEntry != null) {
+ log.info("validateJarFile(" + jarfile +
+ ") - jar not loaded. See Servlet Spec 2.3, "
+ + "section 9.7.2. Offending class: " + name);
+ jarFile.close();
+ return (false);
+ }
+ }
+ jarFile.close();
+ return (true);
+
+ }
+
+
+ /**
+ * Get URL.
+ */
+ protected URL getURL(File file, boolean encoded)
+ throws MalformedURLException {
+
+ File realFile = file;
+ try {
+ realFile = realFile.getCanonicalFile();
+ } catch (IOException e) {
+ // Ignore
+ }
+ if(encoded) {
+ return getURI(realFile);
+ } else {
+ return realFile.toURL();
+ }
+
+ }
+
+
+ /**
+ * Get URL.
+ */
+ protected URL getURI(File file)
+ throws MalformedURLException {
+
+
+ File realFile = file;
+ try {
+ realFile = realFile.getCanonicalFile();
+ } catch (IOException e) {
+ // Ignore
+ }
+ return realFile.toURI().toURL();
+
+ }
+
+
+ /**
+ * Delete the specified directory, including all of its contents and
+ * subdirectories recursively.
+ *
+ * @param dir File object representing the directory to be deleted
+ */
+ protected static void deleteDir(File dir) {
+
+ String files[] = dir.list();
+ if (files == null) {
+ files = new String[0];
+ }
+ for (int i = 0; i < files.length; i++) {
+ File file = new File(dir, files[i]);
+ if (file.isDirectory()) {
+ deleteDir(file);
+ } else {
+ file.delete();
+ }
+ }
+ dir.delete();
+
+ }
+
+
+}
+
Added: trunk/java/org/apache/catalina/loader/LegacyWebappLoader.java
===================================================================
--- trunk/java/org/apache/catalina/loader/LegacyWebappLoader.java (rev 0)
+++ trunk/java/org/apache/catalina/loader/LegacyWebappLoader.java 2009-06-10 22:40:29 UTC (rev 1100)
@@ -0,0 +1,1234 @@
+/*
+ * 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.catalina.loader;
+
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandlerFactory;
+import java.util.ArrayList;
+import java.util.jar.JarFile;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.naming.Binding;
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.servlet.ServletContext;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Loader;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.naming.resources.DirContextURLStreamHandler;
+import org.apache.naming.resources.DirContextURLStreamHandlerFactory;
+import org.apache.naming.resources.Resource;
+import org.apache.tomcat.util.modeler.Registry;
+
+
+/**
+ * Classloader implementation which is specialized for handling web
+ * applications in the most efficient way, while being Catalina aware (all
+ * accesses to resources are made through the DirContext interface).
+ * This class loader supports detection of modified
+ * Java classes, which can be used to implement auto-reload support.
+ * <p>
+ * This class loader is configured by adding the pathnames of directories,
+ * JAR files, and ZIP files with the <code>addRepository()</code> method,
+ * prior to calling <code>start()</code>. When a new class is required,
+ * these repositories will be consulted first to locate the class. If it
+ * is not present, the system class loader will be used instead.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 914 $ $Date: 2009-01-29 17:56:25 +0100 (Thu, 29 Jan 2009) $
+ */
+
+public class LegacyWebappLoader
+ implements Lifecycle, Loader, PropertyChangeListener, MBeanRegistration {
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Construct a new WebappLoader with no defined parent class loader
+ * (so that the actual parent will be the system class loader).
+ */
+ public LegacyWebappLoader() {
+
+ this(null);
+
+ }
+
+
+ /**
+ * Construct a new WebappLoader with the specified class loader
+ * to be defined as the parent of the ClassLoader we ultimately create.
+ *
+ * @param parent The parent class loader
+ */
+ public LegacyWebappLoader(ClassLoader parent) {
+ super();
+ this.parentClassLoader = parent;
+ }
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * First load of the class.
+ */
+ private static boolean first = true;
+
+
+ /**
+ * The class loader being managed by this Loader component.
+ */
+ private LegacyWebappClassLoader classLoader = null;
+
+
+ /**
+ * The Container with which this Loader has been associated.
+ */
+ private Container container = null;
+
+
+ /**
+ * The "follow standard delegation model" flag that will be used to
+ * configure our ClassLoader.
+ */
+ private boolean delegate = false;
+
+
+ /**
+ * The descriptive information about this Loader implementation.
+ */
+ private static final String info =
+ "org.apache.catalina.loader.LegacyWebappLoader/1.0";
+
+
+ /**
+ * The lifecycle event support for this component.
+ */
+ protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+ /**
+ * The Java class name of the ClassLoader implementation to be used.
+ * This class should extend LegacyWebappClassLoader, otherwise, a different
+ * loader implementation must be used.
+ */
+ private String loaderClass =
+ "org.apache.catalina.loader.LegacyWebappClassLoader";
+
+
+ /**
+ * The parent class loader of the class loader we will create.
+ */
+ private ClassLoader parentClassLoader = null;
+
+
+ /**
+ * The reloadable flag for this Loader.
+ */
+ private boolean reloadable = false;
+
+
+ /**
+ * The set of repositories associated with this class loader.
+ */
+ private String repositories[] = new String[0];
+
+
+ /**
+ * The string manager for this package.
+ */
+ protected static final StringManager sm =
+ StringManager.getManager(Constants.Package);
+
+
+ /**
+ * Has this component been started?
+ */
+ private boolean started = false;
+
+
+ /**
+ * The property change support for this component.
+ */
+ protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+
+ /**
+ * Classpath set in the loader.
+ */
+ private String classpath = null;
+
+
+ /**
+ * Repositories that are set in the loader, for JMX.
+ */
+ private ArrayList loaderRepositories = null;
+
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Return the Java class loader to be used by this Container.
+ */
+ public ClassLoader getClassLoader() {
+
+ return ((ClassLoader) classLoader);
+
+ }
+
+
+ /**
+ * Return the Container with which this Logger has been associated.
+ */
+ public Container getContainer() {
+
+ return (container);
+
+ }
+
+
+ /**
+ * Set the Container with which this Logger has been associated.
+ *
+ * @param container The associated Container
+ */
+ public void setContainer(Container container) {
+
+ // Deregister from the old Container (if any)
+ if ((this.container != null) && (this.container instanceof Context))
+ ((Context) this.container).removePropertyChangeListener(this);
+
+ // Process this property change
+ Container oldContainer = this.container;
+ this.container = container;
+ support.firePropertyChange("container", oldContainer, this.container);
+
+ // Register with the new Container (if any)
+ if ((this.container != null) && (this.container instanceof Context)) {
+ setReloadable( ((Context) this.container).getReloadable() );
+ ((Context) this.container).addPropertyChangeListener(this);
+ }
+
+ }
+
+
+ /**
+ * Return the "follow standard delegation model" flag used to configure
+ * our ClassLoader.
+ */
+ public boolean getDelegate() {
+
+ return (this.delegate);
+
+ }
+
+
+ /**
+ * Set the "follow standard delegation model" flag used to configure
+ * our ClassLoader.
+ *
+ * @param delegate The new flag
+ */
+ public void setDelegate(boolean delegate) {
+
+ boolean oldDelegate = this.delegate;
+ this.delegate = delegate;
+ support.firePropertyChange("delegate", new Boolean(oldDelegate),
+ new Boolean(this.delegate));
+
+ }
+
+
+ /**
+ * Return descriptive information about this Loader implementation and
+ * the corresponding version number, in the format
+ * <code><description>/<version></code>.
+ */
+ public String getInfo() {
+
+ return (info);
+
+ }
+
+
+ /**
+ * Return the ClassLoader class name.
+ */
+ public String getLoaderClass() {
+
+ return (this.loaderClass);
+
+ }
+
+
+ /**
+ * Set the ClassLoader class name.
+ *
+ * @param loaderClass The new ClassLoader class name
+ */
+ public void setLoaderClass(String loaderClass) {
+
+ this.loaderClass = loaderClass;
+
+ }
+
+
+ /**
+ * Return the reloadable flag for this Loader.
+ */
+ public boolean getReloadable() {
+
+ return (this.reloadable);
+
+ }
+
+
+ /**
+ * Set the reloadable flag for this Loader.
+ *
+ * @param reloadable The new reloadable flag
+ */
+ public void setReloadable(boolean reloadable) {
+
+ // Process this property change
+ boolean oldReloadable = this.reloadable;
+ this.reloadable = reloadable;
+ support.firePropertyChange("reloadable",
+ new Boolean(oldReloadable),
+ new Boolean(this.reloadable));
+
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Add a property change listener to this component.
+ *
+ * @param listener The listener to add
+ */
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+ support.addPropertyChangeListener(listener);
+
+ }
+
+
+ /**
+ * Add a new repository to the set of repositories for this class loader.
+ *
+ * @param repository Repository to be added
+ */
+ public void addRepository(String repository) {
+
+ if (log.isDebugEnabled())
+ log.debug(sm.getString("webappLoader.addRepository", repository));
+
+ for (int i = 0; i < repositories.length; i++) {
+ if (repository.equals(repositories[i]))
+ return;
+ }
+ String results[] = new String[repositories.length + 1];
+ for (int i = 0; i < repositories.length; i++)
+ results[i] = repositories[i];
+ results[repositories.length] = repository;
+ repositories = results;
+
+ if (started && (classLoader != null)) {
+ classLoader.addRepository(repository);
+ if( loaderRepositories != null ) loaderRepositories.add(repository);
+ setClassPath();
+ }
+
+ }
+
+
+ /**
+ * Execute a periodic task, such as reloading, etc. This method will be
+ * invoked inside the classloading context of this container. Unexpected
+ * throwables will be caught and logged.
+ */
+ public void backgroundProcess() {
+ if (reloadable && modified()) {
+ try {
+ Thread.currentThread().setContextClassLoader
+ (LegacyWebappLoader.class.getClassLoader());
+ if (container instanceof StandardContext) {
+ ((StandardContext) container).reload();
+ }
+ } finally {
+ if (container.getLoader() != null) {
+ Thread.currentThread().setContextClassLoader
+ (container.getLoader().getClassLoader());
+ }
+ }
+ } else {
+ closeJARs(false);
+ }
+ }
+
+
+ /**
+ * Return the set of repositories defined for this class loader.
+ * If none are defined, a zero-length array is returned.
+ * For security reason, returns a clone of the Array (since
+ * String are immutable).
+ */
+ public String[] findRepositories() {
+
+ return ((String[])repositories.clone());
+
+ }
+
+ public String[] getRepositories() {
+ return ((String[])repositories.clone());
+ }
+
+ /** Extra repositories for this loader
+ */
+ public String getRepositoriesString() {
+ StringBuffer sb=new StringBuffer();
+ for( int i=0; i<repositories.length ; i++ ) {
+ sb.append( repositories[i]).append(":");
+ }
+ return sb.toString();
+ }
+
+ public String[] findLoaderRepositories() {
+ return getLoaderRepositories();
+ }
+
+ public String[] getLoaderRepositories() {
+ if( loaderRepositories==null ) return null;
+ String res[]=new String[ loaderRepositories.size()];
+ loaderRepositories.toArray(res);
+ return res;
+ }
+
+ public String getLoaderRepositoriesString() {
+ String repositories[]=getLoaderRepositories();
+ StringBuffer sb=new StringBuffer();
+ for( int i=0; i<repositories.length ; i++ ) {
+ sb.append( repositories[i]).append(":");
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Classpath, as set in org.apache.catalina.jsp_classpath context
+ * property
+ *
+ * @return The classpath
+ */
+ public String getClasspath() {
+ return classpath;
+ }
+
+
+ /**
+ * Has the internal repository associated with this Loader been modified,
+ * such that the loaded classes should be reloaded?
+ */
+ public boolean modified() {
+
+ return (classLoader.modified());
+
+ }
+
+
+ /**
+ * Used to periodically signal to the classloader to release JAR resources.
+ */
+ public void closeJARs(boolean force) {
+ if (classLoader !=null){
+ classLoader.closeJARs(force);
+ }
+ }
+
+
+ /**
+ * Remove a property change listener from this component.
+ *
+ * @param listener The listener to remove
+ */
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+ support.removePropertyChangeListener(listener);
+
+ }
+
+
+ /**
+ * Return a String representation of this component.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("WebappLoader[");
+ if (container != null)
+ sb.append(container.getName());
+ sb.append("]");
+ return (sb.toString());
+
+ }
+
+
+ // ------------------------------------------------------ Lifecycle Methods
+
+
+ /**
+ * Add a lifecycle event listener to this component.
+ *
+ * @param listener The listener to add
+ */
+ public void addLifecycleListener(LifecycleListener listener) {
+
+ lifecycle.addLifecycleListener(listener);
+
+ }
+
+
+ /**
+ * Get the lifecycle listeners associated with this lifecycle. If this
+ * Lifecycle has no listeners registered, a zero-length array is returned.
+ */
+ public LifecycleListener[] findLifecycleListeners() {
+
+ return lifecycle.findLifecycleListeners();
+
+ }
+
+
+ /**
+ * Remove a lifecycle event listener from this component.
+ *
+ * @param listener The listener to remove
+ */
+ public void removeLifecycleListener(LifecycleListener listener) {
+
+ lifecycle.removeLifecycleListener(listener);
+
+ }
+
+ private boolean initialized=false;
+
+ public void init() {
+ initialized=true;
+
+ if( oname==null ) {
+ // not registered yet - standalone or API
+ if( container instanceof StandardContext) {
+ // Register ourself. The container must be a webapp
+ try {
+ StandardContext ctx=(StandardContext)container;
+ Engine eng=(Engine)ctx.getParent().getParent();
+ String path = ctx.getPath();
+ if (path.equals("")) {
+ path = "/";
+ }
+ oname=new ObjectName(ctx.getEngineName() + ":type=Loader,path=" +
+ path + ",host=" + ctx.getParent().getName());
+ Registry.getRegistry(null, null).registerComponent(this, oname, null);
+ controller=oname;
+ } catch (Exception e) {
+ log.error("Error registering loader", e );
+ }
+ }
+ }
+
+ if( container == null ) {
+ // JMX created the loader
+ // TODO
+
+ }
+ }
+
+ public void destroy() {
+ if( controller==oname ) {
+ // Self-registration, undo it
+ Registry.getRegistry(null, null).unregisterComponent(oname);
+ oname = null;
+ }
+ initialized = false;
+
+ }
+
+ /**
+ * Start this component, initializing our associated class loader.
+ *
+ * @exception LifecycleException if a lifecycle error occurs
+ */
+ public void start() throws LifecycleException {
+ // Validate and update our current component state
+ if( ! initialized ) init();
+ if (started)
+ throw new LifecycleException
+ (sm.getString("webappLoader.alreadyStarted"));
+ if (log.isDebugEnabled())
+ log.debug(sm.getString("webappLoader.starting"));
+ lifecycle.fireLifecycleEvent(START_EVENT, null);
+ started = true;
+
+ if (container.getResources() == null) {
+ log.info("No resources for " + container);
+ return;
+ }
+ // Register a stream handler factory for the JNDI protocol
+ URLStreamHandlerFactory streamHandlerFactory =
+ new DirContextURLStreamHandlerFactory();
+ if (first) {
+ first = false;
+ try {
+ URL.setURLStreamHandlerFactory(streamHandlerFactory);
+ } catch (Exception e) {
+ // Log and continue anyway, this is not critical
+ log.error("Error registering jndi stream handler", e);
+ } catch (Throwable t) {
+ // This is likely a dual registration, ignore
+ }
+ }
+
+ // Construct a class loader based on our current repositories list
+ try {
+
+ classLoader = createClassLoader();
+ classLoader.setResources(container.getResources());
+ classLoader.setDelegate(this.delegate);
+ if (container instanceof StandardContext)
+ classLoader.setAntiJARLocking(((StandardContext) container).getAntiJARLocking());
+
+ for (int i = 0; i < repositories.length; i++) {
+ classLoader.addRepository(repositories[i]);
+ }
+
+ // Configure our repositories
+ setRepositories();
+ setClassPath();
+
+ setPermissions();
+
+ if (classLoader instanceof Lifecycle)
+ ((Lifecycle) classLoader).start();
+
+ // Binding the Webapp class loader to the directory context
+ DirContextURLStreamHandler.bind
+ ((ClassLoader) classLoader, this.container.getResources());
+
+ StandardContext ctx=(StandardContext)container;
+ Engine eng=(Engine)ctx.getParent().getParent();
+ String path = ctx.getPath();
+ if (path.equals("")) {
+ path = "/";
+ }
+ ObjectName cloname = new ObjectName
+ (ctx.getEngineName() + ":type=LegacyWebappClassLoader,path="
+ + path + ",host=" + ctx.getParent().getName());
+ Registry.getRegistry(null, null)
+ .registerComponent(classLoader, cloname, null);
+
+ } catch (Throwable t) {
+ log.error( "LifecycleException ", t );
+ throw new LifecycleException("start: ", t);
+ }
+
+ }
+
+
+ /**
+ * Stop this component, finalizing our associated class loader.
+ *
+ * @exception LifecycleException if a lifecycle error occurs
+ */
+ public void stop() throws LifecycleException {
+
+ // Validate and update our current component state
+ if (!started)
+ throw new LifecycleException
+ (sm.getString("webappLoader.notStarted"));
+ if (log.isDebugEnabled())
+ log.debug(sm.getString("webappLoader.stopping"));
+ lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+ started = false;
+
+ // Remove context attributes as appropriate
+ if (container instanceof Context) {
+ ServletContext servletContext =
+ ((Context) container).getServletContext();
+ servletContext.removeAttribute(Globals.CLASS_PATH_ATTR);
+ }
+
+ // Throw away our current class loader
+ if (classLoader instanceof Lifecycle)
+ ((Lifecycle) classLoader).stop();
+ DirContextURLStreamHandler.unbind((ClassLoader) classLoader);
+
+ try {
+ StandardContext ctx=(StandardContext)container;
+ Engine eng=(Engine)ctx.getParent().getParent();
+ String path = ctx.getPath();
+ if (path.equals("")) {
+ path = "/";
+ }
+ ObjectName cloname = new ObjectName
+ (ctx.getEngineName() + ":type=LegacyWebappClassLoader,path="
+ + path + ",host=" + ctx.getParent().getName());
+ Registry.getRegistry(null, null).unregisterComponent(cloname);
+ } catch (Throwable t) {
+ log.error( "LifecycleException ", t );
+ }
+
+ classLoader = null;
+
+ destroy();
+
+ }
+
+
+ // ----------------------------------------- PropertyChangeListener Methods
+
+
+ /**
+ * Process property change events from our associated Context.
+ *
+ * @param event The property change event that has occurred
+ */
+ public void propertyChange(PropertyChangeEvent event) {
+
+ // Validate the source of this event
+ if (!(event.getSource() instanceof Context))
+ return;
+ Context context = (Context) event.getSource();
+
+ // Process a relevant property change
+ if (event.getPropertyName().equals("reloadable")) {
+ try {
+ setReloadable
+ ( ((Boolean) event.getNewValue()).booleanValue() );
+ } catch (NumberFormatException e) {
+ log.error(sm.getString("webappLoader.reloadable",
+ event.getNewValue().toString()));
+ }
+ }
+
+ }
+
+
+ // ------------------------------------------------------- Private Methods
+
+
+ /**
+ * Create associated classLoader.
+ */
+ private LegacyWebappClassLoader createClassLoader()
+ throws Exception {
+
+ Class clazz = Class.forName(loaderClass);
+ LegacyWebappClassLoader classLoader = null;
+
+ if (parentClassLoader == null) {
+ parentClassLoader = container.getParentClassLoader();
+ }
+ Class[] argTypes = { ClassLoader.class };
+ Object[] args = { parentClassLoader };
+ Constructor constr = clazz.getConstructor(argTypes);
+ classLoader = (LegacyWebappClassLoader) constr.newInstance(args);
+
+ return classLoader;
+
+ }
+
+
+ /**
+ * Configure associated class loader permissions.
+ */
+ private void setPermissions() {
+
+ if (!Globals.IS_SECURITY_ENABLED)
+ return;
+ if (!(container instanceof Context))
+ return;
+
+ // Tell the class loader the root of the context
+ ServletContext servletContext =
+ ((Context) container).getServletContext();
+
+ // Assigning permissions for the work directory
+ File workDir =
+ (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
+ if (workDir != null) {
+ try {
+ String workDirPath = workDir.getCanonicalPath();
+ classLoader.addPermission
+ (new FilePermission(workDirPath, "read,write"));
+ classLoader.addPermission
+ (new FilePermission(workDirPath + File.separator + "-",
+ "read,write,delete"));
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+
+ try {
+
+ URL rootURL = servletContext.getResource("/");
+ classLoader.addPermission(rootURL);
+
+ String contextRoot = servletContext.getRealPath("/");
+ if (contextRoot != null) {
+ try {
+ contextRoot = (new File(contextRoot)).getCanonicalPath();
+ classLoader.addPermission(contextRoot);
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+
+ URL classesURL = servletContext.getResource("/WEB-INF/classes/");
+ classLoader.addPermission(classesURL);
+ URL libURL = servletContext.getResource("/WEB-INF/lib/");
+ classLoader.addPermission(libURL);
+
+ if (contextRoot != null) {
+
+ if (libURL != null) {
+ File rootDir = new File(contextRoot);
+ File libDir = new File(rootDir, "WEB-INF/lib/");
+ try {
+ String path = libDir.getCanonicalPath();
+ classLoader.addPermission(path);
+ } catch (IOException e) {
+ }
+ }
+
+ } else {
+
+ if (workDir != null) {
+ if (libURL != null) {
+ File libDir = new File(workDir, "WEB-INF/lib/");
+ try {
+ String path = libDir.getCanonicalPath();
+ classLoader.addPermission(path);
+ } catch (IOException e) {
+ }
+ }
+ if (classesURL != null) {
+ File classesDir = new File(workDir, "WEB-INF/classes/");
+ try {
+ String path = classesDir.getCanonicalPath();
+ classLoader.addPermission(path);
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ }
+
+ } catch (MalformedURLException e) {
+ }
+
+ }
+
+
+ /**
+ * Configure the repositories for our class loader, based on the
+ * associated Context.
+ */
+ private void setRepositories() {
+
+ if (!(container instanceof Context))
+ return;
+ ServletContext servletContext =
+ ((Context) container).getServletContext();
+ if (servletContext == null)
+ return;
+
+ loaderRepositories=new ArrayList();
+ // Loading the work directory
+ File workDir =
+ (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
+ if (workDir == null) {
+ log.info("No work dir for " + servletContext);
+ }
+
+ if( log.isDebugEnabled())
+ log.debug(sm.getString("webappLoader.deploy", workDir.getAbsolutePath()));
+
+ classLoader.setWorkDir(workDir);
+
+ DirContext resources = container.getResources();
+
+ // Setting up the class repository (/WEB-INF/classes), if it exists
+
+ String classesPath = "/WEB-INF/classes";
+ DirContext classes = null;
+
+ try {
+ Object object = resources.lookup(classesPath);
+ if (object instanceof DirContext) {
+ classes = (DirContext) object;
+ }
+ } catch(NamingException e) {
+ // Silent catch: it's valid that no /WEB-INF/classes collection
+ // exists
+ }
+
+ if (classes != null) {
+
+ File classRepository = null;
+
+ String absoluteClassesPath =
+ servletContext.getRealPath(classesPath);
+
+ if (absoluteClassesPath != null) {
+
+ classRepository = new File(absoluteClassesPath);
+
+ } else {
+
+ classRepository = new File(workDir, classesPath);
+ classRepository.mkdirs();
+ copyDir(classes, classRepository);
+
+ }
+
+ if(log.isDebugEnabled())
+ log.debug(sm.getString("webappLoader.classDeploy", classesPath,
+ classRepository.getAbsolutePath()));
+
+
+ // Adding the repository to the class loader
+ classLoader.addRepository(classesPath + "/", classRepository);
+ loaderRepositories.add(classRepository.getAbsolutePath());
+
+ }
+
+ // Setting up the JAR repository (/WEB-INF/lib), if it exists
+
+ String libPath = "/WEB-INF/lib";
+
+ classLoader.setJarPath(libPath);
+
+ DirContext libDir = null;
+ // Looking up directory /WEB-INF/lib in the context
+ try {
+ Object object = resources.lookup(libPath);
+ if (object instanceof DirContext)
+ libDir = (DirContext) object;
+ } catch(NamingException e) {
+ // Silent catch: it's valid that no /WEB-INF/lib collection
+ // exists
+ }
+
+ if (libDir != null) {
+
+ boolean copyJars = false;
+ String absoluteLibPath = servletContext.getRealPath(libPath);
+
+ File destDir = null;
+
+ if (absoluteLibPath != null) {
+ destDir = new File(absoluteLibPath);
+ } else {
+ copyJars = true;
+ destDir = new File(workDir, libPath);
+ destDir.mkdirs();
+ }
+
+ // Looking up directory /WEB-INF/lib in the context
+ try {
+ NamingEnumeration enumeration = resources.listBindings(libPath);
+ while (enumeration.hasMoreElements()) {
+
+ Binding binding = (Binding) enumeration.nextElement();
+ String filename = libPath + "/" + binding.getName();
+ if (!filename.endsWith(".jar"))
+ continue;
+
+ // Copy JAR in the work directory, always (the JAR file
+ // would get locked otherwise, which would make it
+ // impossible to update it or remove it at runtime)
+ File destFile = new File(destDir, binding.getName());
+
+ if( log.isDebugEnabled())
+ log.debug(sm.getString("webappLoader.jarDeploy", filename,
+ destFile.getAbsolutePath()));
+
+ Object obj = binding.getObject();
+ if (!(obj instanceof Resource))
+ continue;
+
+ Resource jarResource = (Resource) obj;
+ if (copyJars) {
+ if (!copy(jarResource.streamContent(),
+ new FileOutputStream(destFile)))
+ continue;
+ }
+
+ try {
+ JarFile jarFile = new JarFile(destFile);
+ classLoader.addJar(filename, jarFile, destFile);
+ } catch (Exception ex) {
+ // Catch the exception if there is an empty jar file
+ // Should ignore and continute loading other jar files
+ // in the dir
+ }
+
+ loaderRepositories.add(destFile.getAbsolutePath());
+
+ }
+ } catch (NamingException e) {
+ // Silent catch: it's valid that no /WEB-INF/lib directory
+ // exists
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ }
+
+
+ /**
+ * Set the appropriate context attribute for our class path. This
+ * is required only because Jasper depends on it.
+ */
+ private void setClassPath() {
+
+ // Validate our current state information
+ if (!(container instanceof Context))
+ return;
+ ServletContext servletContext =
+ ((Context) container).getServletContext();
+ if (servletContext == null)
+ return;
+
+ if (container instanceof StandardContext) {
+ String baseClasspath =
+ ((StandardContext) container).getCompilerClasspath();
+ if (baseClasspath != null) {
+ servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
+ baseClasspath);
+ return;
+ }
+ }
+
+ StringBuffer classpath = new StringBuffer();
+
+ // Assemble the class path information from our class loader chain
+ ClassLoader loader = getClassLoader();
+ int layers = 0;
+ int n = 0;
+ while (loader != null) {
+ if (!(loader instanceof URLClassLoader)) {
+ String cp=getClasspath( loader );
+ if( cp==null ) {
+ log.info( "Unknown loader " + loader + " " + loader.getClass());
+ break;
+ } else {
+ if (n > 0)
+ classpath.append(File.pathSeparator);
+ classpath.append(cp);
+ n++;
+ }
+ break;
+ //continue;
+ }
+ URL repositories[] =
+ ((URLClassLoader) loader).getURLs();
+ for (int i = 0; i < repositories.length; i++) {
+ String repository = repositories[i].toString();
+ if (repository.startsWith("file://"))
+ repository = repository.substring(7);
+ else if (repository.startsWith("file:"))
+ repository = repository.substring(5);
+ else if (repository.startsWith("jndi:"))
+ repository =
+ servletContext.getRealPath(repository.substring(5));
+ else
+ continue;
+ if (repository == null)
+ continue;
+ if (n > 0)
+ classpath.append(File.pathSeparator);
+ classpath.append(repository);
+ n++;
+ }
+ loader = loader.getParent();
+ layers++;
+ }
+
+ this.classpath=classpath.toString();
+
+ // Store the assembled class path as a servlet context attribute
+ servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
+ classpath.toString());
+
+ }
+
+ // try to extract the classpath from a loader that is not URLClassLoader
+ private String getClasspath( ClassLoader loader ) {
+ try {
+ Method m=loader.getClass().getMethod("getClasspath", new Class[] {});
+ if( log.isTraceEnabled())
+ log.trace("getClasspath " + m );
+ if( m==null ) return null;
+ Object o=m.invoke( loader, new Object[] {} );
+ if( log.isDebugEnabled() )
+ log.debug("gotClasspath " + o);
+ if( o instanceof String )
+ return (String)o;
+ return null;
+ } catch( Exception ex ) {
+ if (log.isDebugEnabled())
+ log.debug("getClasspath ", ex);
+ }
+ return null;
+ }
+
+ /**
+ * Copy directory.
+ */
+ private boolean copyDir(DirContext srcDir, File destDir) {
+
+ try {
+
+ NamingEnumeration enumeration = srcDir.list("");
+ while (enumeration.hasMoreElements()) {
+ NameClassPair ncPair =
+ (NameClassPair) enumeration.nextElement();
+ String name = ncPair.getName();
+ Object object = srcDir.lookup(name);
+ File currentFile = new File(destDir, name);
+ if (object instanceof Resource) {
+ InputStream is = ((Resource) object).streamContent();
+ OutputStream os = new FileOutputStream(currentFile);
+ if (!copy(is, os))
+ return false;
+ } else if (object instanceof InputStream) {
+ OutputStream os = new FileOutputStream(currentFile);
+ if (!copy((InputStream) object, os))
+ return false;
+ } else if (object instanceof DirContext) {
+ currentFile.mkdir();
+ copyDir((DirContext) object, currentFile);
+ }
+ }
+
+ } catch (NamingException e) {
+ return false;
+ } catch (IOException e) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * Copy a file to the specified temp directory. This is required only
+ * because Jasper depends on it.
+ */
+ private boolean copy(InputStream is, OutputStream os) {
+
+ try {
+ byte[] buf = new byte[4096];
+ while (true) {
+ int len = is.read(buf);
+ if (len < 0)
+ break;
+ os.write(buf, 0, len);
+ }
+ is.close();
+ os.close();
+ } catch (IOException e) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+
+ private static org.jboss.logging.Logger log=
+ org.jboss.logging.Logger.getLogger( LegacyWebappLoader.class );
+
+ private ObjectName oname;
+ private MBeanServer mserver;
+ private String domain;
+ private ObjectName controller;
+
+ public ObjectName preRegister(MBeanServer server,
+ ObjectName name) throws Exception {
+ oname=name;
+ mserver=server;
+ domain=name.getDomain();
+
+ return name;
+ }
+
+ public void postRegister(Boolean registrationDone) {
+ }
+
+ public void preDeregister() throws Exception {
+ }
+
+ public void postDeregister() {
+ }
+
+ public ObjectName getController() {
+ return controller;
+ }
+
+ public void setController(ObjectName controller) {
+ this.controller = controller;
+ }
+
+}
Modified: trunk/java/org/apache/catalina/loader/WebappClassLoader.java
===================================================================
--- trunk/java/org/apache/catalina/loader/WebappClassLoader.java 2009-06-10 12:42:02 UTC (rev 1099)
+++ trunk/java/org/apache/catalina/loader/WebappClassLoader.java 2009-06-10 22:40:29 UTC (rev 1100)
@@ -1,18 +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
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
- * 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.
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 1999-2009 The Apache Software Foundation
+ *
+ * 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.
*/
@@ -20,6 +48,7 @@
import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilePermission;
import java.io.IOException;
@@ -42,6 +71,7 @@
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.Vector;
import java.util.jar.Attributes;
@@ -50,17 +80,15 @@
import java.util.jar.Manifest;
import java.util.jar.Attributes.Name;
-import javax.naming.NameClassPair;
-import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
+import org.apache.catalina.JarRepository;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.util.StringManager;
import org.apache.naming.JndiPermission;
-import org.apache.naming.resources.Resource;
import org.apache.naming.resources.ResourceAttributes;
import org.apache.tomcat.util.IntrospectionUtils;
@@ -91,8 +119,7 @@
* class is contained inside a JAR.
* <p>
* <strong>IMPLEMENTATION NOTE</strong> - Local repositories are searched in
- * the order they are added via the initial constructor and/or any subsequent
- * calls to <code>addRepository()</code> or <code>addJar()</code>.
+ * the order they are specified in the JarRepository.
* <p>
* <strong>IMPLEMENTATION NOTE</strong> - No check for sealing violations or
* security is made unless a security manager is present.
@@ -154,6 +181,7 @@
* class loader without delegating first.
*/
protected static final String[] packageTriggers = {
+ "javax.servlet."
};
@@ -215,6 +243,12 @@
/**
+ * Associated Jar repository.
+ */
+ protected JarRepository repository = null;
+
+
+ /**
* Associated directory context giving access to the resources in this
* webapp.
*/
@@ -225,13 +259,13 @@
* The cache of ResourceEntry for classes and resources we have loaded,
* keyed by resource name.
*/
- protected HashMap resourceEntries = new HashMap();
+ protected HashMap<String, ResourceEntry> resourceEntries = new HashMap<String, ResourceEntry>();
/**
* The list of not found resources.
*/
- protected HashMap notFoundResources = new HashMap();
+ protected HashSet<String> notFoundResources = new HashSet<String>();
/**
@@ -248,14 +282,14 @@
/**
* Last time a JAR was accessed.
*/
- protected long lastJarAccessed = 0L;
+ //protected long lastJarAccessed = 0L;
/**
* The list of local repositories, in the order they should be searched
* for locally loaded classes or resources.
*/
- protected String[] repositories = new String[0];
+ //protected String[] repositories = new String[0];
/**
@@ -269,34 +303,34 @@
* originally), but which is used to generate fake URLs should getURLs be
* called.
*/
- protected File[] files = new File[0];
+ //protected File[] files = new File[0];
/**
* The list of JARs, in the order they should be searched
* for locally loaded classes or resources.
*/
- protected JarFile[] jarFiles = new JarFile[0];
+ //protected JarFile[] jarFiles = new JarFile[0];
/**
* The list of JARs, in the order they should be searched
* for locally loaded classes or resources.
*/
- protected File[] jarRealFiles = new File[0];
+ //protected File[] jarRealFiles = new File[0];
/**
* The path which will be monitored for added Jar files.
*/
- protected String jarPath = null;
+ //protected String jarPath = null;
/**
* The list of JARs, in the order they should be searched
* for locally loaded classes or resources.
*/
- protected String[] jarNames = new String[0];
+ //protected String[] jarNames = new String[0];
/**
@@ -360,7 +394,7 @@
/**
* Has external repositories.
*/
- protected boolean hasExternalRepositories = false;
+ //protected boolean hasExternalRepositories = false;
/**
* need conversion for properties files
@@ -377,23 +411,23 @@
// ------------------------------------------------------------- Properties
- /**
- * Get associated resources.
- */
- public DirContext getResources() {
+ public JarRepository getRepository() {
+ return repository;
+ }
- return this.resources;
+ public void setRepository(JarRepository repository) {
+ this.repository = repository;
}
- /**
- * Set associated resources.
- */
- public void setResources(DirContext resources) {
+ public DirContext getResources() {
+ return resources;
+ }
- this.resources = resources;
+ public void setResources(DirContext resources) {
+ this.resources = resources;
}
@@ -493,40 +527,21 @@
/**
- * Return the JAR path.
+ * Change the work directory.
*/
- public String getJarPath() {
-
- return this.jarPath;
-
+ public void setWorkDir(File workDir) {
+ this.loaderDir = new File(workDir, "loader");
}
-
/**
- * Change the Jar path.
+ * Utility method for use in subclasses.
+ * Must be called before Lifecycle methods to have any effect.
*/
- public void setJarPath(String jarPath) {
-
- this.jarPath = jarPath;
-
+ protected void setParentClassLoader(ClassLoader pcl) {
+ parent = pcl;
}
- /**
- * Change the work directory.
- */
- public void setWorkDir(File workDir) {
- this.loaderDir = new File(workDir, "loader");
- }
-
- /**
- * Utility method for use in subclasses.
- * Must be called before Lifecycle methods to have any effect.
- */
- protected void setParentClassLoader(ClassLoader pcl) {
- parent = pcl;
- }
-
// ------------------------------------------------------- Reloader Methods
@@ -542,158 +557,24 @@
*/
public void addRepository(String repository) {
+ // FIXME: remove
// Ignore any of the standard repositories, as they are set up using
// either addJar or addRepository
if (repository.startsWith("/WEB-INF/lib")
|| repository.startsWith("/WEB-INF/classes"))
return;
- // Add this repository to our underlying class loader
- try {
- URL url = new URL(repository);
- super.addURL(url);
- hasExternalRepositories = true;
- repositoryURLs = null;
- } catch (MalformedURLException e) {
- IllegalArgumentException iae = new IllegalArgumentException
- ("Invalid repository: " + repository);
- iae.initCause(e);
- throw iae;
- }
-
}
/**
- * Add a new repository to the set of places this ClassLoader can look for
- * classes to be loaded.
- *
- * @param repository Name of a source of classes to be loaded, such as a
- * directory pathname, a JAR file pathname, or a ZIP file pathname
- *
- * @exception IllegalArgumentException if the specified repository is
- * invalid or does not exist
- */
- synchronized void addRepository(String repository, File file) {
-
- // Note : There should be only one (of course), but I think we should
- // keep this a bit generic
-
- if (repository == null)
- return;
-
- if (log.isDebugEnabled())
- log.debug("addRepository(" + repository + ")");
-
- int i;
-
- // Add this repository to our internal list
- String[] result = new String[repositories.length + 1];
- for (i = 0; i < repositories.length; i++) {
- result[i] = repositories[i];
- }
- result[repositories.length] = repository;
- repositories = result;
-
- // Add the file to the list
- File[] result2 = new File[files.length + 1];
- for (i = 0; i < files.length; i++) {
- result2[i] = files[i];
- }
- result2[files.length] = file;
- files = result2;
-
- }
-
-
- synchronized void addJar(String jar, JarFile jarFile, File file)
- throws IOException {
-
- if (jar == null)
- return;
- if (jarFile == null)
- return;
- if (file == null)
- return;
-
- if (log.isDebugEnabled())
- log.debug("addJar(" + jar + ")");
-
- int i;
-
- if ((jarPath != null) && (jar.startsWith(jarPath))) {
-
- String jarName = jar.substring(jarPath.length());
- while (jarName.startsWith("/"))
- jarName = jarName.substring(1);
-
- String[] result = new String[jarNames.length + 1];
- for (i = 0; i < jarNames.length; i++) {
- result[i] = jarNames[i];
- }
- result[jarNames.length] = jarName;
- jarNames = result;
-
- }
-
- try {
-
- // Register the JAR for tracking
-
- long lastModified =
- ((ResourceAttributes) resources.getAttributes(jar))
- .getLastModified();
-
- String[] result = new String[paths.length + 1];
- for (i = 0; i < paths.length; i++) {
- result[i] = paths[i];
- }
- result[paths.length] = jar;
- paths = result;
-
- long[] result3 = new long[lastModifiedDates.length + 1];
- for (i = 0; i < lastModifiedDates.length; i++) {
- result3[i] = lastModifiedDates[i];
- }
- result3[lastModifiedDates.length] = lastModified;
- lastModifiedDates = result3;
-
- } catch (NamingException e) {
- // Ignore
- }
-
- // If the JAR currently contains invalid classes, don't actually use it
- // for classloading
- if (!validateJarFile(file))
- return;
-
- JarFile[] result2 = new JarFile[jarFiles.length + 1];
- for (i = 0; i < jarFiles.length; i++) {
- result2[i] = jarFiles[i];
- }
- result2[jarFiles.length] = jarFile;
- jarFiles = result2;
-
- // Add the file to the list
- File[] result4 = new File[jarRealFiles.length + 1];
- for (i = 0; i < jarRealFiles.length; i++) {
- result4[i] = jarRealFiles[i];
- }
- result4[jarRealFiles.length] = file;
- jarRealFiles = result4;
- }
-
-
- /**
* Return a String array of the current repositories for this class
* loader. If there are no repositories, a zero-length array is
* returned.For security reason, returns a clone of the Array (since
* String are immutable).
*/
public String[] findRepositories() {
-
- return ((String[])repositories.clone());
-
+ return null;
}
@@ -706,16 +587,8 @@
if (log.isDebugEnabled())
log.debug("modified()");
- // Checking for modified loaded resources
- int length = paths.length;
+ int length = lastModifiedDates.length;
- // A rare race condition can occur in the updates of the two arrays
- // It's totally ok if the latest class added is not checked (it will
- // be checked the next time
- int length2 = lastModifiedDates.length;
- if (length > length2)
- length = length2;
-
for (int i = 0; i < length; i++) {
try {
long lastModified =
@@ -735,56 +608,6 @@
}
}
- length = jarNames.length;
-
- // Check if JARs have been added or removed
- if (getJarPath() != null) {
-
- try {
- NamingEnumeration enumeration = resources.list(getJarPath());
- int i = 0;
- while (enumeration.hasMoreElements() && (i < length)) {
- NameClassPair ncPair = (NameClassPair) enumeration.nextElement();
- String name = ncPair.getName();
- // Ignore non JARs present in the lib folder
- if (!name.endsWith(".jar"))
- continue;
- if (!name.equals(jarNames[i])) {
- // Missing JAR
- log.info(" Additional JARs have been added : '"
- + name + "'");
- return (true);
- }
- i++;
- }
- if (enumeration.hasMoreElements()) {
- while (enumeration.hasMoreElements()) {
- NameClassPair ncPair =
- (NameClassPair) enumeration.nextElement();
- String name = ncPair.getName();
- // Additional non-JAR files are allowed
- if (name.endsWith(".jar")) {
- // There was more JARs
- log.info(" Additional JARs have been added");
- return (true);
- }
- }
- } else if (i < jarNames.length) {
- // There was less JARs
- log.info(" Additional JARs have been added");
- return (true);
- }
- } catch (NamingException e) {
- if (log.isDebugEnabled())
- log.debug(" Failed tracking modifications of '"
- + getJarPath() + "'");
- } catch (ClassCastException e) {
- log.error(" Failed tracking modifications of '"
- + getJarPath() + "' : " + e.getMessage());
- }
-
- }
-
// No classes have been modified
return (false);
@@ -800,14 +623,6 @@
sb.append(" delegate: ");
sb.append(delegate);
sb.append("\r\n");
- sb.append(" repositories:\r\n");
- if (repositories != null) {
- for (int i = 0; i < repositories.length; i++) {
- sb.append(" ");
- sb.append(repositories[i]);
- sb.append("\r\n");
- }
- }
if (this.parent != null) {
sb.append("----------> Parent Classloader:\r\n");
sb.append(this.parent.toString());
@@ -821,16 +636,6 @@
// ---------------------------------------------------- ClassLoader Methods
- /**
- * Add the specified URL to the classloader.
- */
- protected void addURL(URL url) {
- super.addURL(url);
- hasExternalRepositories = true;
- repositoryURLs = null;
- }
-
-
/**
* Find the specified class in our local repositories, if possible. If
* not found, throw <code>ClassNotFoundException</code>.
@@ -868,43 +673,17 @@
// Ask our superclass to locate this class, if possible
// (throws ClassNotFoundException if it is not found)
Class clazz = null;
+ if (log.isTraceEnabled())
+ log.trace(" findClassInternal(" + name + ")");
try {
+ clazz = findClassInternal(name);
+ } catch(ClassNotFoundException cnfe) {
+ throw cnfe;
+ } catch(AccessControlException ace) {
+ throw new ClassNotFoundException(name, ace);
+ } catch (RuntimeException e) {
if (log.isTraceEnabled())
- log.trace(" findClassInternal(" + name + ")");
- try {
- clazz = findClassInternal(name);
- } catch(ClassNotFoundException cnfe) {
- if (!hasExternalRepositories) {
- throw cnfe;
- }
- } catch(AccessControlException ace) {
- throw new ClassNotFoundException(name, ace);
- } catch (RuntimeException e) {
- if (log.isTraceEnabled())
- log.trace(" -->RuntimeException Rethrown", e);
- throw e;
- }
- if ((clazz == null) && hasExternalRepositories) {
- try {
- synchronized (this) {
- clazz = super.findClass(name);
- }
- } catch(AccessControlException ace) {
- throw new ClassNotFoundException(name, ace);
- } catch (RuntimeException e) {
- if (log.isTraceEnabled())
- log.trace(" -->RuntimeException Rethrown", e);
- throw e;
- }
- }
- if (clazz == null) {
- if (log.isDebugEnabled())
- log.debug(" --> Returning ClassNotFoundException");
- throw new ClassNotFoundException(name);
- }
- } catch (ClassNotFoundException e) {
- if (log.isTraceEnabled())
- log.trace(" --> Passing on ClassNotFoundException");
+ log.trace(" -->RuntimeException Rethrown", e);
throw e;
}
@@ -940,9 +719,6 @@
url = entry.source;
}
- if ((url == null) && hasExternalRepositories)
- url = super.findResource(name);
-
if (log.isDebugEnabled()) {
if (url != null)
log.debug(" --> Returning '" + url.toString() + "'");
@@ -970,56 +746,32 @@
Vector result = new Vector();
- int jarFilesLength = jarFiles.length;
- int repositoriesLength = repositories.length;
+ File[] repositories = repository.findExplodedJars();
+ JarFile[] jarFiles = repository.findJars();
- int i;
-
// Looking at the repositories
- for (i = 0; i < repositoriesLength; i++) {
- try {
- String fullPath = repositories[i] + name;
- resources.lookup(fullPath);
- // Note : Not getting an exception here means the resource was
- // found
- try {
- result.addElement(getURI(new File(files[i], name)));
- } catch (MalformedURLException e) {
- // Ignore
- }
- } catch (NamingException e) {
+ for (int i = 0; i < repositories.length; i++) {
+ File resource = new File(repositories[i], name);
+ if (resource.exists()) {
+ result.addElement(getURI(resource));
}
}
// Looking at the JAR files
- synchronized (jarFiles) {
- if (openJARs()) {
- for (i = 0; i < jarFilesLength; i++) {
- JarEntry jarEntry = jarFiles[i].getJarEntry(name);
- if (jarEntry != null) {
- try {
- String jarFakeUrl = getURI(jarRealFiles[i]).toString();
- jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
- result.addElement(new URL(jarFakeUrl));
- } catch (MalformedURLException e) {
- // Ignore
- }
- }
+ for (int i = 0; i < jarFiles.length; i++) {
+ JarEntry jarEntry = jarFiles[i].getJarEntry(name);
+ if (jarEntry != null) {
+ File jarFile = new File(jarFiles[i].getName());
+ try {
+ String jarFakeUrl = getURI(jarFile).toString();
+ jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
+ result.addElement(new URL(jarFakeUrl));
+ } catch (MalformedURLException e) {
+ // Ignore
}
}
}
- // Adding the results of a call to the superclass
- if (hasExternalRepositories) {
-
- Enumeration otherResourcePaths = super.findResources(name);
-
- while (otherResourcePaths.hasMoreElements()) {
- result.addElement(otherResourcePaths.nextElement());
- }
-
- }
-
return result.elements();
}
@@ -1161,12 +913,6 @@
if (log.isDebugEnabled())
log.debug(" --> Returning stream from local");
stream = findLoadedResource(name);
- try {
- if (hasExternalRepositories && (stream == null))
- stream = url.openStream();
- } catch (IOException e) {
- ; // Ignore
- }
if (stream != null)
return (stream);
}
@@ -1196,22 +942,6 @@
/**
- * 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>.
@@ -1236,7 +966,7 @@
*
* @exception ClassNotFoundException if the class was not found
*/
- public Class loadClass(String name, boolean resolve)
+ public Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
if (log.isDebugEnabled())
@@ -1410,21 +1140,19 @@
URL[] external = super.getURLs();
- int filesLength = files.length;
- int jarFilesLength = jarRealFiles.length;
- int length = filesLength + jarFilesLength + external.length;
- int i;
+ File[] repositories = repository.findExplodedJars();
+ JarFile[] jarFiles = repository.findJars();
+ int length = repositories.length + jarFiles.length;
+
try {
URL[] urls = new URL[length];
- for (i = 0; i < length; i++) {
- if (i < filesLength) {
- urls[i] = getURL(files[i], true);
- } else if (i < filesLength + jarFilesLength) {
- urls[i] = getURL(jarRealFiles[i - filesLength], true);
+ for (int i = 0; i < length; i++) {
+ if (i < repositories.length) {
+ urls[i] = getURL(repositories[i], true);
} else {
- urls[i] = external[i - filesLength - jarFilesLength];
+ urls[i] = getURL(new File(jarFiles[i - repositories.length].getName()), true);
}
}
@@ -1503,37 +1231,14 @@
started = false;
- int length = files.length;
- for (int i = 0; i < length; i++) {
- files[i] = null;
- }
-
- length = jarFiles.length;
- for (int i = 0; i < length; i++) {
- try {
- if (jarFiles[i] != null) {
- jarFiles[i].close();
- }
- } catch (IOException e) {
- // Ignore
- }
- jarFiles[i] = null;
- }
-
notFoundResources.clear();
resourceEntries.clear();
resources = null;
- repositories = null;
repositoryURLs = null;
- files = null;
- jarFiles = null;
- jarRealFiles = null;
- jarPath = null;
- jarNames = null;
lastModifiedDates = null;
paths = null;
- hasExternalRepositories = false;
parent = null;
+ repository = null;
permissionList.clear();
loaderPC.clear();
@@ -1545,33 +1250,6 @@
}
- /**
- * Used to periodically signal to the classloader to release
- * JAR resources.
- */
- public void closeJARs(boolean force) {
- if (jarFiles.length > 0) {
- synchronized (jarFiles) {
- if (force || (System.currentTimeMillis()
- > (lastJarAccessed + 90000))) {
- for (int i = 0; i < jarFiles.length; i++) {
- try {
- if (jarFiles[i] != null) {
- jarFiles[i].close();
- jarFiles[i] = null;
- }
- } catch (IOException e) {
- if (log.isDebugEnabled()) {
- log.debug("Failed to close JAR", e);
- }
- }
- }
- }
- }
- }
- }
-
-
// ------------------------------------------------------ Protected Methods
@@ -1720,29 +1398,6 @@
/**
- * Used to periodically signal to the classloader to release JAR resources.
- */
- protected boolean openJARs() {
- if (started && (jarFiles.length > 0)) {
- lastJarAccessed = System.currentTimeMillis();
- if (jarFiles[0] == null) {
- for (int i = 0; i < jarFiles.length; i++) {
- try {
- jarFiles[i] = new JarFile(jarRealFiles[i]);
- } catch (IOException e) {
- if (log.isDebugEnabled()) {
- log.debug("Failed to open JAR", e);
- }
- return false;
- }
- }
- }
- }
- return true;
- }
-
-
- /**
* Find specified class in local repositories.
*
* @return the loaded class, or null if the class isn't found
@@ -1876,219 +1531,198 @@
int contentLength = -1;
InputStream binaryStream = null;
- int jarFilesLength = jarFiles.length;
- int repositoriesLength = repositories.length;
+ File[] repositories = repository.findExplodedJars();
+ JarFile[] jarFiles = repository.findJars();
int i;
- Resource resource = null;
+ //Resource resource = null;
boolean fileNeedConvert = false;
- for (i = 0; (entry == null) && (i < repositoriesLength); i++) {
- try {
+ for (i = 0; (entry == null) && (i < repositories.length); i++) {
- String fullPath = repositories[i] + path;
+ File resource = new File(repositories[i], path);
+ if (!resource.exists()) {
+ continue;
+ }
- Object lookupResult = resources.lookup(fullPath);
- if (lookupResult instanceof Resource) {
- resource = (Resource) lookupResult;
- }
+ // Note : Not getting an exception here means the resource was
+ // found
+ if (securityManager != null) {
+ PrivilegedAction dp =
+ new PrivilegedFindResource(repositories[i], path);
+ entry = (ResourceEntry)AccessController.doPrivileged(dp);
+ } else {
+ entry = findResourceInternal(repositories[i], path);
+ }
- // Note : Not getting an exception here means the resource was
- // found
- if (securityManager != null) {
- PrivilegedAction dp =
- new PrivilegedFindResource(files[i], path);
- entry = (ResourceEntry)AccessController.doPrivileged(dp);
- } else {
- entry = findResourceInternal(files[i], path);
- }
+ contentLength = (int) resource.length();
+ entry.lastModified = resource.lastModified();
- ResourceAttributes attributes =
- (ResourceAttributes) resources.getAttributes(fullPath);
- contentLength = (int) attributes.getContentLength();
- entry.lastModified = attributes.getLastModified();
+ try {
+ binaryStream = new FileInputStream(resource);
+ } catch (IOException e) {
+ return null;
+ }
- if (resource != null) {
+ if (needConvert) {
+ if (path.endsWith(".properties")) {
+ fileNeedConvert = true;
+ }
+ }
+ // Register the full path for modification checking
+ // Note: Only syncing on a 'constant' object is needed
+ synchronized (allPermission) {
- try {
- binaryStream = resource.streamContent();
- } catch (IOException e) {
- return null;
- }
+ int j;
- if (needConvert) {
- if (path.endsWith(".properties")) {
- fileNeedConvert = true;
- }
- }
+ long[] result2 =
+ new long[lastModifiedDates.length + 1];
+ for (j = 0; j < lastModifiedDates.length; j++) {
+ result2[j] = lastModifiedDates[j];
+ }
+ result2[lastModifiedDates.length] = entry.lastModified;
+ lastModifiedDates = result2;
- // Register the full path for modification checking
- // Note: Only syncing on a 'constant' object is needed
- synchronized (allPermission) {
-
- int j;
-
- long[] result2 =
- new long[lastModifiedDates.length + 1];
- for (j = 0; j < lastModifiedDates.length; j++) {
- result2[j] = lastModifiedDates[j];
- }
- result2[lastModifiedDates.length] = entry.lastModified;
- lastModifiedDates = result2;
-
- String[] result = new String[paths.length + 1];
- for (j = 0; j < paths.length; j++) {
- result[j] = paths[j];
- }
- result[paths.length] = fullPath;
- paths = result;
-
- }
-
+ String[] result = new String[paths.length + 1];
+ for (j = 0; j < paths.length; j++) {
+ result[j] = paths[j];
}
+ result[paths.length] = resource.getPath();
+ paths = result;
- } catch (NamingException e) {
}
+
}
- if ((entry == null) && (notFoundResources.containsKey(name)))
+ if ((entry == null) && (notFoundResources.contains(name)))
return null;
JarEntry jarEntry = null;
- synchronized (jarFiles) {
+ for (i = 0; (entry == null) && (i < jarFiles.length); i++) {
- if (!openJARs()) {
- return null;
- }
- for (i = 0; (entry == null) && (i < jarFilesLength); i++) {
+ jarEntry = jarFiles[i].getJarEntry(path);
- jarEntry = jarFiles[i].getJarEntry(path);
+ if (jarEntry != null) {
- if (jarEntry != null) {
+ entry = new ResourceEntry();
+ try {
+ File jarFile = new File(jarFiles[i].getName());
+ entry.codeBase = getURL(jarFile, false);
+ String jarFakeUrl = getURI(jarFile).toString();
+ jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
+ entry.source = new URL(jarFakeUrl);
+ entry.lastModified = jarFile.lastModified();
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ contentLength = (int) jarEntry.getSize();
+ try {
+ entry.manifest = jarFiles[i].getManifest();
+ binaryStream = jarFiles[i].getInputStream(jarEntry);
+ } catch (IOException e) {
+ return null;
+ }
- entry = new ResourceEntry();
- try {
- entry.codeBase = getURL(jarRealFiles[i], false);
- String jarFakeUrl = getURI(jarRealFiles[i]).toString();
- jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
- entry.source = new URL(jarFakeUrl);
- entry.lastModified = jarRealFiles[i].lastModified();
- } catch (MalformedURLException e) {
- return null;
- }
- contentLength = (int) jarEntry.getSize();
- try {
- entry.manifest = jarFiles[i].getManifest();
- binaryStream = jarFiles[i].getInputStream(jarEntry);
- } catch (IOException e) {
- return null;
- }
-
- // Extract resources contained in JAR to the workdir
- if (antiJARLocking && !(path.endsWith(".class"))) {
- byte[] buf = new byte[1024];
- File resourceFile = new File
- (loaderDir, jarEntry.getName());
- if (!resourceFile.exists()) {
- Enumeration entries = jarFiles[i].entries();
- while (entries.hasMoreElements()) {
- JarEntry jarEntry2 =
- (JarEntry) entries.nextElement();
- if (!(jarEntry2.isDirectory())
- && (!jarEntry2.getName().endsWith
- (".class"))) {
- resourceFile = new File
- (loaderDir, jarEntry2.getName());
- resourceFile.getParentFile().mkdirs();
- FileOutputStream os = null;
- InputStream is = null;
+ // Extract resources contained in JAR to the workdir
+ if (antiJARLocking && !(path.endsWith(".class"))) {
+ byte[] buf = new byte[1024];
+ File resourceFile = new File
+ (loaderDir, jarEntry.getName());
+ if (!resourceFile.exists()) {
+ Enumeration entries = jarFiles[i].entries();
+ while (entries.hasMoreElements()) {
+ JarEntry jarEntry2 =
+ (JarEntry) entries.nextElement();
+ if (!(jarEntry2.isDirectory())
+ && (!jarEntry2.getName().endsWith(".class"))) {
+ resourceFile = new File
+ (loaderDir, jarEntry2.getName());
+ resourceFile.getParentFile().mkdirs();
+ FileOutputStream os = null;
+ InputStream is = null;
+ try {
+ is = jarFiles[i].getInputStream(jarEntry2);
+ os = new FileOutputStream(resourceFile);
+ while (true) {
+ int n = is.read(buf);
+ if (n <= 0) {
+ break;
+ }
+ os.write(buf, 0, n);
+ }
+ } catch (IOException e) {
+ // Ignore
+ } finally {
try {
- is = jarFiles[i].getInputStream
- (jarEntry2);
- os = new FileOutputStream
- (resourceFile);
- while (true) {
- int n = is.read(buf);
- if (n <= 0) {
- break;
- }
- os.write(buf, 0, n);
+ if (is != null) {
+ is.close();
}
} catch (IOException e) {
- // Ignore
- } finally {
- try {
- if (is != null) {
- is.close();
- }
- } catch (IOException e) {
+ }
+ try {
+ if (os != null) {
+ os.close();
}
- try {
- if (os != null) {
- os.close();
- }
- } catch (IOException e) {
- }
+ } catch (IOException e) {
}
}
}
}
}
-
}
}
+
+ }
- if (entry == null) {
- synchronized (notFoundResources) {
- notFoundResources.put(name, name);
- }
- return null;
+ if (entry == null) {
+ synchronized (notFoundResources) {
+ notFoundResources.add(name);
}
+ return null;
+ }
- if (binaryStream != null) {
+ if (binaryStream != null) {
- byte[] binaryContent = new byte[contentLength];
+ byte[] binaryContent = new byte[contentLength];
- int pos = 0;
+ int pos = 0;
+ try {
+
+ while (true) {
+ int n = binaryStream.read(binaryContent, pos,
+ binaryContent.length - pos);
+ if (n <= 0)
+ break;
+ pos += n;
+ }
+ } catch (IOException e) {
+ log.error(sm.getString("webappClassLoader.readError", name), e);
+ return null;
+ } finally {
try {
+ binaryStream.close();
+ } catch (IOException e) {}
+ }
- while (true) {
- int n = binaryStream.read(binaryContent, pos,
- binaryContent.length - pos);
- if (n <= 0)
- break;
- pos += n;
- }
- } catch (IOException e) {
- log.error(sm.getString("webappClassLoader.readError", name), e);
+ if (fileNeedConvert) {
+ String str = new String(binaryContent,0,pos);
+ try {
+ binaryContent = str.getBytes("UTF-8");
+ } catch (Exception e) {
return null;
- } finally {
- try {
- binaryStream.close();
- } catch (IOException e) {}
}
+ }
+ entry.binaryContent = binaryContent;
- if (fileNeedConvert) {
- String str = new String(binaryContent,0,pos);
- try {
- binaryContent = str.getBytes("UTF-8");
- } catch (Exception e) {
- return null;
- }
- }
- entry.binaryContent = binaryContent;
-
- // The certificates are only available after the JarEntry
- // associated input stream has been fully read
- if (jarEntry != null) {
- entry.certificates = jarEntry.getCertificates();
- }
-
+ // The certificates are only available after the JarEntry
+ // associated input stream has been fully read
+ if (jarEntry != null) {
+ entry.certificates = jarEntry.getCertificates();
}
}
Modified: trunk/java/org/apache/catalina/loader/WebappLoader.java
===================================================================
--- trunk/java/org/apache/catalina/loader/WebappLoader.java 2009-06-10 12:42:02 UTC (rev 1099)
+++ trunk/java/org/apache/catalina/loader/WebappLoader.java 2009-06-10 22:40:29 UTC (rev 1100)
@@ -1,18 +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
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
- * 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.
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 1999-2009 The Apache Software Foundation
+ *
+ * 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.
*/
@@ -23,28 +51,16 @@
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.FilePermission;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
-import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
-import java.util.ArrayList;
-import java.util.jar.JarFile;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
-import javax.naming.Binding;
-import javax.naming.NameClassPair;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.DirContext;
import javax.servlet.ServletContext;
import org.apache.catalina.Container;
@@ -60,7 +76,6 @@
import org.apache.catalina.util.StringManager;
import org.apache.naming.resources.DirContextURLStreamHandler;
import org.apache.naming.resources.DirContextURLStreamHandlerFactory;
-import org.apache.naming.resources.Resource;
import org.apache.tomcat.util.modeler.Registry;
@@ -85,6 +100,13 @@
public class WebappLoader
implements Lifecycle, Loader, PropertyChangeListener, MBeanRegistration {
+ /**
+ * The string manager for this package.
+ */
+ protected static final StringManager sm =
+ StringManager.getManager(Constants.Package);
+
+
// ----------------------------------------------------------- Constructors
@@ -174,19 +196,6 @@
/**
- * The set of repositories associated with this class loader.
- */
- private String repositories[] = new String[0];
-
-
- /**
- * The string manager for this package.
- */
- protected static final StringManager sm =
- StringManager.getManager(Constants.Package);
-
-
- /**
* Has this component been started?
*/
private boolean started = false;
@@ -198,18 +207,6 @@
protected PropertyChangeSupport support = new PropertyChangeSupport(this);
- /**
- * Classpath set in the loader.
- */
- private String classpath = null;
-
-
- /**
- * Repositories that are set in the loader, for JMX.
- */
- private ArrayList loaderRepositories = null;
-
-
// ------------------------------------------------------------- Properties
@@ -371,22 +368,6 @@
if (log.isDebugEnabled())
log.debug(sm.getString("webappLoader.addRepository", repository));
- for (int i = 0; i < repositories.length; i++) {
- if (repository.equals(repositories[i]))
- return;
- }
- String results[] = new String[repositories.length + 1];
- for (int i = 0; i < repositories.length; i++)
- results[i] = repositories[i];
- results[repositories.length] = repository;
- repositories = results;
-
- if (started && (classLoader != null)) {
- classLoader.addRepository(repository);
- if( loaderRepositories != null ) loaderRepositories.add(repository);
- setClassPath();
- }
-
}
@@ -409,8 +390,6 @@
(container.getLoader().getClassLoader());
}
}
- } else {
- closeJARs(false);
}
}
@@ -422,87 +401,31 @@
* String are immutable).
*/
public String[] findRepositories() {
-
- return ((String[])repositories.clone());
-
+ return null;
}
- public String[] getRepositories() {
- return ((String[])repositories.clone());
- }
- /** Extra repositories for this loader
- */
- public String getRepositoriesString() {
- StringBuffer sb=new StringBuffer();
- for( int i=0; i<repositories.length ; i++ ) {
- sb.append( repositories[i]).append(":");
- }
- return sb.toString();
- }
-
public String[] findLoaderRepositories() {
- return getLoaderRepositories();
+ return null;
}
-
- public String[] getLoaderRepositories() {
- if( loaderRepositories==null ) return null;
- String res[]=new String[ loaderRepositories.size()];
- loaderRepositories.toArray(res);
- return res;
- }
- public String getLoaderRepositoriesString() {
- String repositories[]=getLoaderRepositories();
- StringBuffer sb=new StringBuffer();
- for( int i=0; i<repositories.length ; i++ ) {
- sb.append( repositories[i]).append(":");
- }
- return sb.toString();
- }
-
- /**
- * Classpath, as set in org.apache.catalina.jsp_classpath context
- * property
- *
- * @return The classpath
- */
- public String getClasspath() {
- return classpath;
- }
-
-
/**
* Has the internal repository associated with this Loader been modified,
* such that the loaded classes should be reloaded?
*/
public boolean modified() {
-
return (classLoader.modified());
-
}
-
+
/**
- * Used to periodically signal to the classloader to release JAR resources.
- */
- public void closeJARs(boolean force) {
- if (classLoader !=null){
- classLoader.closeJARs(force);
- }
- }
-
-
- /**
* Remove a property change listener from this component.
*
* @param listener The listener to remove
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
-
support.removePropertyChangeListener(listener);
-
}
@@ -644,14 +567,25 @@
if (container instanceof StandardContext)
classLoader.setAntiJARLocking(((StandardContext) container).getAntiJARLocking());
- for (int i = 0; i < repositories.length; i++) {
- classLoader.addRepository(repositories[i]);
+ // Configure our repositories
+ if (!(container instanceof Context))
+ throw new IllegalStateException("This loader only supports a Context");
+ ServletContext servletContext = ((Context) container).getServletContext();
+ if (servletContext == null)
+ throw new IllegalStateException("No servlet context available");
+
+ File workDir =
+ (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
+ if (workDir == null) {
+ log.info("No work dir for " + servletContext);
}
- // Configure our repositories
- setRepositories();
- setClassPath();
+ if( log.isDebugEnabled())
+ log.debug(sm.getString("webappLoader.deploy", workDir.getAbsolutePath()));
+ classLoader.setWorkDir(workDir);
+ classLoader.setRepository(container.getJarRepository());
+
setPermissions();
if (classLoader instanceof Lifecycle)
@@ -666,7 +600,7 @@
String path = ctx.getPath();
if (path.equals("")) {
path = "/";
- }
+ }
ObjectName cloname = new ObjectName
(ctx.getEngineName() + ":type=WebappClassLoader,path="
+ path + ",host=" + ctx.getParent().getName());
@@ -876,327 +810,6 @@
}
- /**
- * Configure the repositories for our class loader, based on the
- * associated Context.
- */
- private void setRepositories() {
-
- if (!(container instanceof Context))
- return;
- ServletContext servletContext =
- ((Context) container).getServletContext();
- if (servletContext == null)
- return;
-
- loaderRepositories=new ArrayList();
- // Loading the work directory
- File workDir =
- (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
- if (workDir == null) {
- log.info("No work dir for " + servletContext);
- }
-
- if( log.isDebugEnabled())
- log.debug(sm.getString("webappLoader.deploy", workDir.getAbsolutePath()));
-
- classLoader.setWorkDir(workDir);
-
- DirContext resources = container.getResources();
-
- // Setting up the class repository (/WEB-INF/classes), if it exists
-
- String classesPath = "/WEB-INF/classes";
- DirContext classes = null;
-
- try {
- Object object = resources.lookup(classesPath);
- if (object instanceof DirContext) {
- classes = (DirContext) object;
- }
- } catch(NamingException e) {
- // Silent catch: it's valid that no /WEB-INF/classes collection
- // exists
- }
-
- if (classes != null) {
-
- File classRepository = null;
-
- String absoluteClassesPath =
- servletContext.getRealPath(classesPath);
-
- if (absoluteClassesPath != null) {
-
- classRepository = new File(absoluteClassesPath);
-
- } else {
-
- classRepository = new File(workDir, classesPath);
- classRepository.mkdirs();
- copyDir(classes, classRepository);
-
- }
-
- if(log.isDebugEnabled())
- log.debug(sm.getString("webappLoader.classDeploy", classesPath,
- classRepository.getAbsolutePath()));
-
-
- // Adding the repository to the class loader
- classLoader.addRepository(classesPath + "/", classRepository);
- loaderRepositories.add(classRepository.getAbsolutePath());
-
- }
-
- // Setting up the JAR repository (/WEB-INF/lib), if it exists
-
- String libPath = "/WEB-INF/lib";
-
- classLoader.setJarPath(libPath);
-
- DirContext libDir = null;
- // Looking up directory /WEB-INF/lib in the context
- try {
- Object object = resources.lookup(libPath);
- if (object instanceof DirContext)
- libDir = (DirContext) object;
- } catch(NamingException e) {
- // Silent catch: it's valid that no /WEB-INF/lib collection
- // exists
- }
-
- if (libDir != null) {
-
- boolean copyJars = false;
- String absoluteLibPath = servletContext.getRealPath(libPath);
-
- File destDir = null;
-
- if (absoluteLibPath != null) {
- destDir = new File(absoluteLibPath);
- } else {
- copyJars = true;
- destDir = new File(workDir, libPath);
- destDir.mkdirs();
- }
-
- // Looking up directory /WEB-INF/lib in the context
- try {
- NamingEnumeration enumeration = resources.listBindings(libPath);
- while (enumeration.hasMoreElements()) {
-
- Binding binding = (Binding) enumeration.nextElement();
- String filename = libPath + "/" + binding.getName();
- if (!filename.endsWith(".jar"))
- continue;
-
- // Copy JAR in the work directory, always (the JAR file
- // would get locked otherwise, which would make it
- // impossible to update it or remove it at runtime)
- File destFile = new File(destDir, binding.getName());
-
- if( log.isDebugEnabled())
- log.debug(sm.getString("webappLoader.jarDeploy", filename,
- destFile.getAbsolutePath()));
-
- Object obj = binding.getObject();
- if (!(obj instanceof Resource))
- continue;
-
- Resource jarResource = (Resource) obj;
- if (copyJars) {
- if (!copy(jarResource.streamContent(),
- new FileOutputStream(destFile)))
- continue;
- }
-
- try {
- JarFile jarFile = new JarFile(destFile);
- classLoader.addJar(filename, jarFile, destFile);
- } catch (Exception ex) {
- // Catch the exception if there is an empty jar file
- // Should ignore and continute loading other jar files
- // in the dir
- }
-
- loaderRepositories.add(destFile.getAbsolutePath());
-
- }
- } catch (NamingException e) {
- // Silent catch: it's valid that no /WEB-INF/lib directory
- // exists
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- }
-
-
- /**
- * Set the appropriate context attribute for our class path. This
- * is required only because Jasper depends on it.
- */
- private void setClassPath() {
-
- // Validate our current state information
- if (!(container instanceof Context))
- return;
- ServletContext servletContext =
- ((Context) container).getServletContext();
- if (servletContext == null)
- return;
-
- if (container instanceof StandardContext) {
- String baseClasspath =
- ((StandardContext) container).getCompilerClasspath();
- if (baseClasspath != null) {
- servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
- baseClasspath);
- return;
- }
- }
-
- StringBuffer classpath = new StringBuffer();
-
- // Assemble the class path information from our class loader chain
- ClassLoader loader = getClassLoader();
- int layers = 0;
- int n = 0;
- while (loader != null) {
- if (!(loader instanceof URLClassLoader)) {
- String cp=getClasspath( loader );
- if( cp==null ) {
- log.info( "Unknown loader " + loader + " " + loader.getClass());
- break;
- } else {
- if (n > 0)
- classpath.append(File.pathSeparator);
- classpath.append(cp);
- n++;
- }
- break;
- //continue;
- }
- URL repositories[] =
- ((URLClassLoader) loader).getURLs();
- for (int i = 0; i < repositories.length; i++) {
- String repository = repositories[i].toString();
- if (repository.startsWith("file://"))
- repository = repository.substring(7);
- else if (repository.startsWith("file:"))
- repository = repository.substring(5);
- else if (repository.startsWith("jndi:"))
- repository =
- servletContext.getRealPath(repository.substring(5));
- else
- continue;
- if (repository == null)
- continue;
- if (n > 0)
- classpath.append(File.pathSeparator);
- classpath.append(repository);
- n++;
- }
- loader = loader.getParent();
- layers++;
- }
-
- this.classpath=classpath.toString();
-
- // Store the assembled class path as a servlet context attribute
- servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
- classpath.toString());
-
- }
-
- // try to extract the classpath from a loader that is not URLClassLoader
- private String getClasspath( ClassLoader loader ) {
- try {
- Method m=loader.getClass().getMethod("getClasspath", new Class[] {});
- if( log.isTraceEnabled())
- log.trace("getClasspath " + m );
- if( m==null ) return null;
- Object o=m.invoke( loader, new Object[] {} );
- if( log.isDebugEnabled() )
- log.debug("gotClasspath " + o);
- if( o instanceof String )
- return (String)o;
- return null;
- } catch( Exception ex ) {
- if (log.isDebugEnabled())
- log.debug("getClasspath ", ex);
- }
- return null;
- }
-
- /**
- * Copy directory.
- */
- private boolean copyDir(DirContext srcDir, File destDir) {
-
- try {
-
- NamingEnumeration enumeration = srcDir.list("");
- while (enumeration.hasMoreElements()) {
- NameClassPair ncPair =
- (NameClassPair) enumeration.nextElement();
- String name = ncPair.getName();
- Object object = srcDir.lookup(name);
- File currentFile = new File(destDir, name);
- if (object instanceof Resource) {
- InputStream is = ((Resource) object).streamContent();
- OutputStream os = new FileOutputStream(currentFile);
- if (!copy(is, os))
- return false;
- } else if (object instanceof InputStream) {
- OutputStream os = new FileOutputStream(currentFile);
- if (!copy((InputStream) object, os))
- return false;
- } else if (object instanceof DirContext) {
- currentFile.mkdir();
- copyDir((DirContext) object, currentFile);
- }
- }
-
- } catch (NamingException e) {
- return false;
- } catch (IOException e) {
- return false;
- }
-
- return true;
-
- }
-
-
- /**
- * Copy a file to the specified temp directory. This is required only
- * because Jasper depends on it.
- */
- private boolean copy(InputStream is, OutputStream os) {
-
- try {
- byte[] buf = new byte[4096];
- while (true) {
- int len = is.read(buf);
- if (len < 0)
- break;
- os.write(buf, 0, len);
- }
- is.close();
- os.close();
- } catch (IOException e) {
- return false;
- }
-
- return true;
-
- }
-
-
private static org.jboss.logging.Logger log=
org.jboss.logging.Logger.getLogger( WebappLoader.class );
15 years, 9 months
JBossWeb SVN: r1099 - branches/2.1.x/java/org/apache/jasper/compiler.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2009-06-10 08:42:02 -0400 (Wed, 10 Jun 2009)
New Revision: 1099
Modified:
branches/2.1.x/java/org/apache/jasper/compiler/Parser.java
Log:
- Fix the include fix.
Modified: branches/2.1.x/java/org/apache/jasper/compiler/Parser.java
===================================================================
--- branches/2.1.x/java/org/apache/jasper/compiler/Parser.java 2009-06-10 12:41:52 UTC (rev 1098)
+++ branches/2.1.x/java/org/apache/jasper/compiler/Parser.java 2009-06-10 12:42:02 UTC (rev 1099)
@@ -125,21 +125,22 @@
// For the Top level page, add include-prelude and include-coda
PageInfo pageInfo = pc.getCompiler().getPageInfo();
- if (parent == null) {
+ if (parent == null && !isTagFile) {
parser.addInclude(root, pageInfo.getIncludePrelude());
}
if (directivesOnly) {
- parser.parseTagFileDirectives(root);
+ parser.parseFileDirectives(root);
} else {
while (reader.hasMoreInput()) {
parser.parseElements(root);
}
}
- if (parent == null) {
+ if (parent == null && !isTagFile) {
parser.addInclude(root, pageInfo.getIncludeCoda());
}
- return new Node.Nodes(root);
+ Node.Nodes page = new Node.Nodes(root);
+ return page;
}
/**
@@ -1770,7 +1771,7 @@
return JAVAX_BODY_CONTENT_TEMPLATE_TEXT;
}
- private void parseTagFileDirectives(Node parent) throws JasperException {
+ private void parseFileDirectives(Node parent) throws JasperException {
reader.setSingleFile(true);
reader.skipUntil("<");
while (reader.hasMoreInput()) {
15 years, 9 months