Codebase list tomcat9 / 10c36ee
Imported Upstream version 8.0.14 Emmanuel Bourg 9 years ago
207 changed file(s) with 7164 addition(s) and 7506 deletion(s). Raw diff Collapse all Expand all
192192 if not exist "%CATALINA_BASE%\conf\logging.properties" goto noJuliConfig
193193 set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties"
194194 :noJuliConfig
195 set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%
195 set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%"
196196
197197 if not "%LOGGING_MANAGER%" == "" goto noJuliManager
198198 set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
199199 :noJuliManager
200 set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%
200 set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%"
201201
202202 rem ----- Execute The Requested Command ---------------------------------------
203203
2424 # ----- Version Control Flags -----
2525 version.major=8
2626 version.minor=0
27 version.build=12
27 version.build=14
2828 version.patch=0
2929 version.suffix=
3030
5252 codesigning.user=request-via-pmc
5353 codesigning.pwd=request-via-pmc
5454 codesigning.partnercode=request-via-pmc
55 codesigning.service=Microsoft Signing
5556
5657 # ----- Settings to use when downloading files -----
5758 trydownload.httpusecaches=true
174175 commons-daemon.native.win.home=${commons-daemon.home}/windows
175176 commons-daemon.native.win.mgr.exe=${commons-daemon.native.win.home}/prunmgr.exe
176177 commons-daemon.native.src.tgz=${commons-daemon.home}/commons-daemon-${commons-daemon.version}-native-src.tar.gz
177 commons-daemon.native.win.zip=${commons-daemon.home}/commons-daemon-${commons-daemon.version}-bin-windows.zip
178 commons-daemon.native.win.zip=${commons-daemon.home}/commons-daemon-${commons-daemon.version}-bin-windows-signed.zip
178179 commons-daemon.bin.loc.1=${base-commons.loc.1}/daemon/binaries/commons-daemon-${commons-daemon.version}-bin.tar.gz
179180 commons-daemon.bin.loc.2=${base-commons.loc.2}/daemon/binaries/commons-daemon-${commons-daemon.version}-bin.tar.gz
180181 commons-daemon.native.src.loc.1=${base-commons.loc.1}/daemon/source/commons-daemon-${commons-daemon.version}-native-src.tar.gz
181182 commons-daemon.native.src.loc.2=${base-commons.loc.2}/daemon/source/commons-daemon-${commons-daemon.version}-native-src.tar.gz
182 commons-daemon.native.win.loc.1=${base-commons.loc.1}/daemon/binaries/windows/commons-daemon-${commons-daemon.version}-bin-windows.zip
183 commons-daemon.native.win.loc.2=${base-commons.loc.2}/daemon/binaries/windows/commons-daemon-${commons-daemon.version}-bin-windows.zip
183 commons-daemon.native.win.loc.1=${base-commons.loc.1}/daemon/binaries/windows/commons-daemon-${commons-daemon.version}-bin-windows-signed.zip
184 commons-daemon.native.win.loc.2=${base-commons.loc.2}/daemon/binaries/windows/commons-daemon-${commons-daemon.version}-bin-windows-signed.zip
184185
185186 # ----- JUnit Unit Test Suite, version 4.11 or later -----
186187 junit.version=4.11
337337 <patternset id="files.tomcat-api">
338338 <include name="org/apache/tomcat/*" />
339339 <exclude name="org/apache/tomcat/buildutil" />
340 <exclude name="org/apache/tomcat/dbcp" />
340341 <exclude name="org/apache/tomcat/jni" />
341342 <exclude name="org/apache/tomcat/spdy" />
342343 <exclude name="org/apache/tomcat/util" />
10931094 <!-- build the jdbc-pool jar and source jar-->
10941095 <echo message="Building Tomcat JDBC pool libraries"/>
10951096 <ant antfile="${tomcat.jdbc.dir}/build.xml" dir="${tomcat.jdbc.dir}"
1096 inheritall="false" target="build">
1097 inheritAll="false" target="build">
10971098 <property name="tomcat.pool" value="${tomcat.pool}" />
10981099 <property name="tomcat.juli.jar" value="${tomcat-juli.jar}" />
10991100 <property name="skip.download" value="set"/>
11051106 <!-- build the jdbc-pool source jar-->
11061107 <echo message="Building Tomcat JDBC pool src JAR"/>
11071108 <ant antfile="${tomcat.jdbc.dir}/build.xml" dir="${tomcat.jdbc.dir}"
1108 inheritall="false" target="build-src">
1109 inheritAll="false" target="build-src">
11091110 <property name="tomcat.pool" value="${tomcat.pool}" />
11101111 <property name="tomcat.juli.jar" value="${tomcat-juli.jar}" />
11111112 <property name="skip.download" value="set"/>
15851586
15861587 <ant antfile="${tomcat.extras}/logging/commons-logging-${commons-logging.version}-src/build2.xml"
15871588 dir="${tomcat.extras}/logging/commons-logging-${commons-logging.version}-src"
1588 target="compile" />
1589 inheritAll="false" target="compile" />
15891590
15901591 <jar jarfile="${tomcat-juli-extras.jar}"
15911592 manifest="${tomcat.manifests}/default.manifest">
21282129 partnerCode="${codesigning.partnercode}"
21292130 applicationName="Apache Tomcat ${version.major.minor}"
21302131 applicationversion="${version}"
2131 signingService="Microsoft Signing">
2132 signingService="${codesigning.service}">
21322133 <fileset dir="${tomcat.release}">
21332134 <filename name="v${version}/bin/${final.name}.exe"/>
21342135 </fileset>
21352136 </signcode>
2137
2138 <!-- .exe has changed so need to redo MD5 and OpenPGP signature -->
2139 <delete file="${tomcat.release}/v${version}/bin/${final.name}.exe.md5" />
2140 <delete file="${tomcat.release}/v${version}/bin/${final.name}.exe.asc" />
2141 <antcall target="md5sum">
2142 <param name="file" value="${tomcat.release}/v${version}/bin/${final.name}.exe" />
2143 </antcall>
21362144
21372145 </target>
21382146
26422650 <delete dir="${tomcat.output}" />
26432651 <!-- Remove the copied catalina.properties -->
26442652 <delete file="java/org/apache/catalina/startup/catalina.properties" />
2645 <ant antfile="${tomcat.jdbc.dir}/build.xml" dir="${tomcat.jdbc.dir}" inheritall="false" target="clean">
2653 <ant antfile="${tomcat.jdbc.dir}/build.xml" dir="${tomcat.jdbc.dir}" inheritAll="false" target="clean">
26462654 <property name="tomcat.pool" value="${tomcat.pool}" />
26472655 </ant>
26482656 <!-- remove jdbc-pool documentation -->
28862894
28872895 <!-- ============================ Eclipse ================================ -->
28882896
2889 <target name="ide-eclipse" depends="deploy, extras-webservices-prepare"
2897 <target name="ide-eclipse"
2898 depends="download-compile, extras-webservices-prepare, download-test-compile"
28902899 description="Prepares the source tree to be built in Eclipse">
28912900
28922901 <!-- Copy the sample project files into the root directory -->
1919 Documentation at /docs/config/server.html
2020 -->
2121 <Server port="8005" shutdown="SHUTDOWN">
22 <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
2223 <!-- Security listener. Documentation at /docs/config/listeners.html
2324 <Listener className="org.apache.catalina.security.SecurityListener" />
2425 -->
184184 }
185185
186186 context.setPropertyResolved(base, property);
187 return this.readOnly
188 || this.property(context, base, property).isReadOnly();
187 return this.readOnly || this.property(context, base, property).isReadOnly();
189188 }
190189
191190 @Override
280279 }
281280
282281 public boolean isReadOnly() {
283 return this.write == null
284 && (null == (this.write = Util.getMethod(this.owner, descriptor.getWriteMethod())));
282 return this.write == null &&
283 (null == (this.write = Util.getMethod(this.owner, descriptor.getWriteMethod())));
285284 }
286285
287286 public Method getWriteMethod() {
153153 Class<?> commonType = null, type = null;
154154 for (int i = 0; i < sz; i++) {
155155 type = this.resolvers[i].getCommonPropertyType(context, base);
156 if (type != null
157 && (commonType == null || commonType.isAssignableFrom(type))) {
156 if (type != null &&
157 (commonType == null || commonType.isAssignableFrom(type))) {
158158 commonType = type;
159159 }
160160 }
7373 }
7474 return template;
7575 } catch (MissingResourceException e) {
76 return "Missing Resource: '" + name + "' for Locale "
77 + locale.getDisplayName();
76 return "Missing Resource: '" + name + "' for Locale " + locale.getDisplayName();
7877 }
7978 }
8079
266266 url.append (scheme); // http, https
267267 url.append ("://");
268268 url.append (req.getServerName ());
269 if ((scheme.equals ("http") && port != 80)
270 || (scheme.equals ("https") && port != 443)) {
269 if ((scheme.equals ("http") && port != 80) || (scheme.equals ("https") && port != 443)) {
271270 url.append (':');
272271 url.append (req.getServerPort ());
273272 }
183183 {
184184 boolean isInterface = false;
185185
186 if (from == null || klass == null
187 || (!JspTag.class.isAssignableFrom(klass)
188 && !(isInterface = klass.isInterface()))) {
186 if (from == null || klass == null || (!JspTag.class.isAssignableFrom(klass) &&
187 !(isInterface = klass.isInterface()))) {
189188 return null;
190189 }
191190
205204 parent = ((TagAdapter) parent).getAdaptee();
206205 }
207206
208 if ((isInterface && klass.isInstance(parent))
209 || klass.isAssignableFrom(parent.getClass())) {
207 if ((isInterface && klass.isInstance(parent)) ||
208 klass.isAssignableFrom(parent.getClass())) {
210209 return parent;
211210 }
212211
3030 */
3131 WebSocketContainer getContainer();
3232
33 void addMessageHandler(MessageHandler listener)
34 throws IllegalStateException;
33 /**
34 * Registers a {@link MessageHandler} for incoming messages. Only one
35 * {@link MessageHandler} may be registered for each message type (text,
36 * binary, pong). The message type will be derived at runtime from the
37 * provided {@link MessageHandler} instance. It is not always possible to do
38 * this so it is better to use
39 * {@link #addMessageHandler(Class, javax.websocket.MessageHandler.Partial)}
40 * or
41 * {@link #addMessageHandler(Class, javax.websocket.MessageHandler.Whole)}.
42 *
43 * @param listener The message handler for a incoming message
44 *
45 * @throws IllegalStateException If a message handler has already been
46 * registered for the associated message type
47 */
48 void addMessageHandler(MessageHandler listener) throws IllegalStateException;
3549
3650 Set<MessageHandler> getMessageHandlers();
3751
125139 * this session is associated with.
126140 */
127141 Set<Session> getOpenSessions();
142
143 /**
144 * Registers a {@link MessageHandler} for partial incoming messages. Only
145 * one {@link MessageHandler} may be registered for each message type (text
146 * or binary, pong messages are never presented as partial messages).
147 *
148 * @param clazz The type of message that the given handler is intended
149 * for
150 * @param listener The message handler for a incoming message
151 *
152 * @throws IllegalStateException If a message handler has already been
153 * registered for the associated message type
154 */
155 <T> void addMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler)
156 throws IllegalStateException;
157
158 /**
159 * Registers a {@link MessageHandler} for whole incoming messages. Only
160 * one {@link MessageHandler} may be registered for each message type (text,
161 * binary, pong).
162 *
163 * @param clazz The type of message that the given handler is intended
164 * for
165 * @param listener The message handler for a incoming message
166 *
167 * @throws IllegalStateException If a message handler has already been
168 * registered for the associated message type
169 */
170 <T> void addMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler)
171 throws IllegalStateException;
128172 }
1616 package org.apache.catalina;
1717
1818 import java.net.URL;
19 import java.nio.charset.Charset;
1920 import java.util.Locale;
2021 import java.util.Map;
2122 import java.util.Set;
16361637 * context.
16371638 */
16381639 public Object getNamingToken();
1640
1641 /**
1642 * Should this context use the new RFC6265 based cookie parser for
1643 * processing HTTP cookies? The default value is currently false but that
1644 * may change in a future point release.
1645 */
1646 public void setUseRfc6265(boolean useRfc6265);
1647
1648 /**
1649 * Does this context use the new RFC6265 based cookie parser for
1650 * processing HTTP cookies? The default value is currently false but that
1651 * may change in a future point release.
1652 */
1653 public boolean getUseRfc6265();
1654
1655 /**
1656 * Specifies the name of the character encoding to use to convert bytes into
1657 * characters when processing cookies using the RFC6265 based cookie parser.
1658 * It has no effect if the RFC6265 parser is not used.
1659 * If an unrecognised character encoding is specified, a warning will be
1660 * logged and the default value of UTF-8 will be used.
1661 */
1662 public void setCookieEncoding(String encoding);
1663
1664 /**
1665 * Returns the name of the character encoding used to convert bytes into
1666 * characters when processing cookies using the RFC6265 based cookie parser.
1667 * The default value is UTF-8.
1668 */
1669 public String getCookieEncoding();
1670
1671 /**
1672 * Returns the character set used to convert bytes into characters when
1673 * processing cookies using the RFC6265 based cookie parser.
1674 */
1675 public Charset getCookieEncodingCharset();
16391676 }
1313 * See the License for the specific language governing permissions and
1414 * limitations under the License.
1515 */
16
17
1816 package org.apache.catalina;
1917
2018 import java.beans.PropertyChangeListener;
2624 import org.apache.catalina.connector.Response;
2725 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
2826 import org.ietf.jgss.GSSContext;
27
2928 /**
3029 * A <b>Realm</b> is a read-only facade for an underlying security realm
3130 * used to authenticate individual users, and identify the security roles
3938
4039
4140 // ------------------------------------------------------------- Properties
42
4341
4442 /**
4543 * Return the Container with which this Realm has been associated.
5654
5755
5856 // --------------------------------------------------------- Public Methods
57
5958 /**
6059 * Add a property change listener to this component.
6160 *
163162 */
164163 public boolean hasRole(Wrapper wrapper, Principal principal, String role);
165164
166 /**
165
166 /**
167167 * Enforce any user data constraint required by the security constraint
168168 * guarding this request URI. Return <code>true</code> if this constraint
169169 * was not violated and processing should continue, or <code>false</code>
180180 SecurityConstraint []constraint)
181181 throws IOException;
182182
183
183184 /**
184185 * Remove a property change listener from this component.
185186 *
186187 * @param listener The listener to remove
187188 */
188189 public void removePropertyChangeListener(PropertyChangeListener listener);
189
190
191190 }
1313 * See the License for the specific language governing permissions and
1414 * limitations under the License.
1515 */
16
1716 package org.apache.catalina.ant.jmx;
1817
19 import java.io.IOException;
20 import java.net.MalformedURLException;
21
22 import javax.management.MBeanServerConnection;
23 import javax.management.ObjectName;
24
2518 import org.apache.tools.ant.BuildException;
26 import org.apache.tools.ant.ProjectComponent;
27 import org.apache.tools.ant.taskdefs.condition.Condition;
2819
2920 /**
3021 *
8677 * @author Peter Rossbach
8778 * @since 5.5.10
8879 */
89 public class JMXAccessorCondition extends ProjectComponent implements Condition {
80 public class JMXAccessorCondition extends JMXAccessorConditionBase {
9081
9182 // ----------------------------------------------------- Instance Variables
9283
93 private String url = null;
94 private String host = "localhost";
95 private String port = "8050";
96 private String password = null;
97 private String username = null;
98 private String name = null;
99 private String attribute;
100 private String value;
10184 private String operation = "==" ;
10285 private String type = "long" ;
103 private String ref = "jmx.server";
10486 private String unlessCondition;
10587 private String ifCondition;
10688
89
10790 // ----------------------------------------------------- Properties
10891
10992 /**
131114 public void setType(String type) {
132115 this.type = type;
133116 }
134 /**
135 * @return Returns the attribute.
136 */
137 public String getAttribute() {
138 return attribute;
139 }
140 /**
141 * @param attribute The attribute to set.
142 */
143 public void setAttribute(String attribute) {
144 this.attribute = attribute;
145 }
146 /**
147 * @return Returns the host.
148 */
149 public String getHost() {
150 return host;
151 }
152 /**
153 * @param host The host to set.
154 */
155 public void setHost(String host) {
156 this.host = host;
157 }
158 /**
159 * @return Returns the name.
160 */
161 public String getName() {
162 return name;
163 }
164 /**
165 * @param objectName The name to set.
166 */
167 public void setName(String objectName) {
168 this.name = objectName;
169 }
170 /**
171 * @return Returns the password.
172 */
173 public String getPassword() {
174 return password;
175 }
176 /**
177 * @param password The password to set.
178 */
179 public void setPassword(String password) {
180 this.password = password;
181 }
182 /**
183 * @return Returns the port.
184 */
185 public String getPort() {
186 return port;
187 }
188 /**
189 * @param port The port to set.
190 */
191 public void setPort(String port) {
192 this.port = port;
193 }
194 /**
195 * @return Returns the url.
196 */
197 public String getUrl() {
198 return url;
199 }
200 /**
201 * @param url The url to set.
202 */
203 public void setUrl(String url) {
204 this.url = url;
205 }
206 /**
207 * @return Returns the username.
208 */
209 public String getUsername() {
210 return username;
211 }
212 /**
213 * @param username The username to set.
214 */
215 public void setUsername(String username) {
216 this.username = username;
217 }
218 /**
219 * @return Returns the value.
220 */
221 public String getValue() {
222 return value;
223 }
224 // The setter for the "value" attribute
225 public void setValue(String value) {
226 this.value = value;
227 }
228
229 /**
230 * @return Returns the ref.
231 */
232 public String getRef() {
233 return ref;
234 }
235 /**
236 * @param refId The ref to set.
237 */
238 public void setRef(String refId) {
239 this.ref = refId;
240 }
117
241118 /**
242119 * @return Returns the ifCondition.
243120 */
251128 public void setIf(String c) {
252129 ifCondition = c;
253130 }
131
254132 /**
255133 * @return Returns the unlessCondition.
256134 */
257135 public String getUnless() {
258136 return unlessCondition;
259137 }
260
261138 /**
262139 * Only execute if a property of the given name does not
263140 * exist in the current project.
268145 }
269146
270147 /**
271 * Get JMXConnection (default look at <em>jmx.server</em> project reference from jmxOpen Task)
272 * @return active JMXConnection
273 * @throws MalformedURLException
274 * @throws IOException
275 */
276 protected MBeanServerConnection getJMXConnection()
277 throws MalformedURLException, IOException {
278 return JMXAccessorTask.accessJMXConnection(
279 getProject(),
280 getUrl(), getHost(),
281 getPort(), getUsername(), getPassword(), ref);
282 }
283
284 /**
285 * Get value from MBeans attribute
286 * @return The value
287 */
288 protected String accessJMXValue() {
289 try {
290 Object result = getJMXConnection().getAttribute(
291 new ObjectName(name), attribute);
292 if(result != null)
293 return result.toString();
294 } catch (Exception e) {
295 // ignore access or connection open errors
296 }
297 return null;
298 }
299
300 /**
301148 * test the if condition
302149 * @return true if there is no if condition, or the named property exists
303150 */
327174 */
328175 @Override
329176 public boolean eval() {
177 String value = getValue();
330178 if (operation == null) {
331179 throw new BuildException("operation attribute is not set");
332180 }
333181 if (value == null) {
334182 throw new BuildException("value attribute is not set");
335183 }
336 if ((name == null || attribute == null)) {
184 if ((getName() == null || getAttribute() == null)) {
337185 throw new BuildException(
338 "Must specify a 'attribute', name for equals condition");
186 "Must specify an MBean name and attribute for condition");
339187 }
340188 if (testIfCondition() && testUnlessCondition()) {
341189 String jmxValue = accessJMXValue();
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.catalina.ant.jmx;
17
18 import java.io.IOException;
19 import java.net.MalformedURLException;
20
21 import javax.management.MBeanServerConnection;
22 import javax.management.ObjectName;
23
24 import org.apache.tools.ant.ProjectComponent;
25 import org.apache.tools.ant.taskdefs.condition.Condition;
26
27 public abstract class JMXAccessorConditionBase extends ProjectComponent implements Condition {
28
29 private String url = null;
30 private String host = "localhost";
31 private String port = "8050";
32 private String password = null;
33 private String username = null;
34 private String name = null;
35 private String attribute;
36 private String value;
37 private String ref = "jmx.server" ;
38
39 /**
40 * @return Returns the attribute.
41 */
42 public String getAttribute() {
43 return attribute;
44 }
45 /**
46 * @param attribute The attribute to set.
47 */
48 public void setAttribute(String attribute) {
49 this.attribute = attribute;
50 }
51 /**
52 * @return Returns the host.
53 */
54 public String getHost() {
55 return host;
56 }
57 /**
58 * @param host The host to set.
59 */
60 public void setHost(String host) {
61 this.host = host;
62 }
63 /**
64 * @return Returns the name.
65 */
66 public String getName() {
67 return name;
68 }
69 /**
70 * @param objectName The name to set.
71 */
72 public void setName(String objectName) {
73 this.name = objectName;
74 }
75 /**
76 * @return Returns the password.
77 */
78 public String getPassword() {
79 return password;
80 }
81 /**
82 * @param password The password to set.
83 */
84 public void setPassword(String password) {
85 this.password = password;
86 }
87 /**
88 * @return Returns the port.
89 */
90 public String getPort() {
91 return port;
92 }
93 /**
94 * @param port The port to set.
95 */
96 public void setPort(String port) {
97 this.port = port;
98 }
99 /**
100 * @return Returns the url.
101 */
102 public String getUrl() {
103 return url;
104 }
105 /**
106 * @param url The url to set.
107 */
108 public void setUrl(String url) {
109 this.url = url;
110 }
111 /**
112 * @return Returns the username.
113 */
114 public String getUsername() {
115 return username;
116 }
117 /**
118 * @param username The username to set.
119 */
120 public void setUsername(String username) {
121 this.username = username;
122 }
123 /**
124 * @return Returns the value.
125 */
126 public String getValue() {
127 return value;
128 }
129 // The setter for the "value" attribute
130 public void setValue(String value) {
131 this.value = value;
132 }
133
134 /**
135 * @return Returns the ref.
136 */
137 public String getRef() {
138 return ref;
139 }
140 /**
141 * @param refId The ref to set.
142 */
143 public void setRef(String refId) {
144 this.ref = refId;
145 }
146
147 /**
148 * Get JMXConnection (default look at <em>jmx.server</em> project reference
149 * from jmxOpen Task).
150 *
151 * @return active JMXConnection
152 * @throws MalformedURLException
153 * @throws IOException
154 */
155 protected MBeanServerConnection getJMXConnection()
156 throws MalformedURLException, IOException {
157 return JMXAccessorTask.accessJMXConnection(
158 getProject(),
159 getUrl(), getHost(),
160 getPort(), getUsername(), getPassword(), ref);
161 }
162
163 /**
164 * Get value from MBeans attribute.
165 *
166 * @return The value
167 */
168 protected String accessJMXValue() {
169 try {
170 Object result = getJMXConnection().getAttribute(
171 new ObjectName(name), attribute);
172 if(result != null)
173 return result.toString();
174 } catch (Exception e) {
175 // ignore access or connection open errors
176 }
177 return null;
178 }
179 }
180
1313 * See the License for the specific language governing permissions and
1414 * limitations under the License.
1515 */
16
1716 package org.apache.catalina.ant.jmx;
1817
19 import java.io.IOException;
20 import java.net.MalformedURLException;
21
22 import javax.management.MBeanServerConnection;
23 import javax.management.ObjectName;
24
2518 import org.apache.tools.ant.BuildException;
26 import org.apache.tools.ant.ProjectComponent;
27 import org.apache.tools.ant.taskdefs.condition.Condition;
2819
2920 /**
3021 *
6556 * @author Peter Rossbach
6657 * @since 5.5.10
6758 */
68 public class JMXAccessorEqualsCondition extends ProjectComponent implements Condition {
59 public class JMXAccessorEqualsCondition extends JMXAccessorConditionBase {
6960
70 // ----------------------------------------------------- Instance Variables
71
72 private String url = null;
73 private String host = "localhost";
74 private String port = "8050";
75 private String password = null;
76 private String username = null;
77 private String name = null;
78 private String attribute;
79 private String value;
80 private String ref = "jmx.server" ;
81
82 // ----------------------------------------------------- Properties
83
84 /**
85 * @return Returns the attribute.
86 */
87 public String getAttribute() {
88 return attribute;
89 }
90 /**
91 * @param attribute The attribute to set.
92 */
93 public void setAttribute(String attribute) {
94 this.attribute = attribute;
95 }
96 /**
97 * @return Returns the host.
98 */
99 public String getHost() {
100 return host;
101 }
102 /**
103 * @param host The host to set.
104 */
105 public void setHost(String host) {
106 this.host = host;
107 }
108 /**
109 * @return Returns the name.
110 */
111 public String getName() {
112 return name;
113 }
114 /**
115 * @param objectName The name to set.
116 */
117 public void setName(String objectName) {
118 this.name = objectName;
119 }
120 /**
121 * @return Returns the password.
122 */
123 public String getPassword() {
124 return password;
125 }
126 /**
127 * @param password The password to set.
128 */
129 public void setPassword(String password) {
130 this.password = password;
131 }
132 /**
133 * @return Returns the port.
134 */
135 public String getPort() {
136 return port;
137 }
138 /**
139 * @param port The port to set.
140 */
141 public void setPort(String port) {
142 this.port = port;
143 }
144 /**
145 * @return Returns the url.
146 */
147 public String getUrl() {
148 return url;
149 }
150 /**
151 * @param url The url to set.
152 */
153 public void setUrl(String url) {
154 this.url = url;
155 }
156 /**
157 * @return Returns the username.
158 */
159 public String getUsername() {
160 return username;
161 }
162 /**
163 * @param username The username to set.
164 */
165 public void setUsername(String username) {
166 this.username = username;
167 }
168 /**
169 * @return Returns the value.
170 */
171 public String getValue() {
172 return value;
173 }
174 // The setter for the "value" attribute
175 public void setValue(String value) {
176 this.value = value;
177 }
178
179 /**
180 * @return Returns the ref.
181 */
182 public String getRef() {
183 return ref;
184 }
185 /**
186 * @param refId The ref to set.
187 */
188 public void setRef(String refId) {
189 this.ref = refId;
190 }
191
192 protected MBeanServerConnection getJMXConnection()
193 throws MalformedURLException, IOException {
194 return JMXAccessorTask.accessJMXConnection(
195 getProject(),
196 getUrl(), getHost(),
197 getPort(), getUsername(), getPassword(), ref);
198 }
199
200 /**
201 * @return The value
202 */
203 protected String accessJMXValue() {
204 try {
205 Object result = getJMXConnection().getAttribute(
206 new ObjectName(name), attribute);
207 if(result != null)
208 return result.toString();
209 } catch (Exception e) {
210 // ignore access or connection open errors
211 }
212 return null;
213 }
214
215 // This method evaluates the condition
21661 @Override
21762 public boolean eval() {
63 String value = getValue();
64
21865 if (value == null) {
21966 throw new BuildException("value attribute is not set");
22067 }
221 if ((name == null || attribute == null)) {
68 if (getName() == null || getAttribute() == null) {
22269 throw new BuildException(
223 "Must specify a 'attribute', name for equals condition");
70 "Must specify an MBean name and attribute for equals condition");
22471 }
22572 //FIXME check url or host/parameter
22673 String jmxValue = accessJMXValue();
227 if(jmxValue != null)
74 if (jmxValue != null) {
22875 return jmxValue.equals(value);
76 }
22977 return false;
23078 }
23179 }
2424
2525 import javax.servlet.ServletException;
2626 import javax.servlet.http.Cookie;
27 import javax.servlet.http.HttpServletRequest;
2728 import javax.servlet.http.HttpServletResponse;
2829
2930 import org.apache.catalina.Authenticator;
566567 "authorization") != null;
567568 }
568569
569 if (!authRequired && context.getPreemptiveAuthentication()) {
570 X509Certificate[] certs = getRequestCertificates(request, false);
570 if (!authRequired && context.getPreemptiveAuthentication() &&
571 HttpServletRequest.CLIENT_CERT_AUTH.equals(getAuthMethod())) {
572 X509Certificate[] certs = getRequestCertificates(request);
571573 authRequired = certs != null && certs.length > 0;
572574 }
573575
625627 * extracting the certificate chain from the Coyote request.
626628 *
627629 * @param request Request to be processed
628 * @param force Should a renegotiation be forced to request certificates
629 * from the user agent if none have been provided
630630 *
631631 * @return The X509 certificate chain if found, <code>null</code>
632632 * otherwise.
633633 */
634 protected X509Certificate[] getRequestCertificates(final Request request, boolean force)
634 protected X509Certificate[] getRequestCertificates(final Request request)
635635 throws IllegalStateException {
636636
637637 X509Certificate certs[] =
639639
640640 if ((certs == null) || (certs.length < 1)) {
641641 try {
642 request.getCoyoteRequest().action(ActionCode.REQ_SSL_CERTIFICATE, Boolean.valueOf(force));
642 request.getCoyoteRequest().action(ActionCode.REQ_SSL_CERTIFICATE, null);
643643 certs = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR);
644644 } catch (IllegalStateException ise) {
645645 // Request body was too large for save buffer
1818 import java.io.IOException;
1919 import java.io.StringReader;
2020 import java.nio.charset.StandardCharsets;
21 import java.security.MessageDigest;
22 import java.security.NoSuchAlgorithmException;
2321 import java.security.Principal;
2422 import java.util.LinkedHashMap;
2523 import java.util.Map;
3028 import org.apache.catalina.LifecycleException;
3129 import org.apache.catalina.Realm;
3230 import org.apache.catalina.connector.Request;
33 import org.apache.catalina.util.ConcurrentMessageDigest;
34 import org.apache.catalina.util.MD5Encoder;
3531 import org.apache.juli.logging.Log;
3632 import org.apache.juli.logging.LogFactory;
3733 import org.apache.tomcat.util.http.parser.Authorization;
34 import org.apache.tomcat.util.security.ConcurrentMessageDigest;
35 import org.apache.tomcat.util.security.MD5Encoder;
3836
3937
4038 /**
5654 */
5755 protected static final String QOP = "auth";
5856
57
5958 // ----------------------------------------------------------- Constructors
60
6159
6260 public DigestAuthenticator() {
6361 super();
6462 setCache(false);
65 try {
66 if (md5Helper == null) {
67 md5Helper = MessageDigest.getInstance("MD5");
68 }
69 } catch (NoSuchAlgorithmException e) {
70 throw new IllegalStateException(e);
71 }
7263 }
7364
7465
7566 // ----------------------------------------------------- Instance Variables
76
77
78 /**
79 * MD5 message digest provider.
80 * @deprecated Unused - will be removed in Tomcat 8.0.x onwards
81 */
82 @Deprecated
83 protected static volatile MessageDigest md5Helper;
84
8567
8668 /**
8769 * List of server nonce values currently being tracked
9494 containerLog.debug(" Looking up certificates");
9595 }
9696
97 X509Certificate certs[] = getRequestCertificates(request, true);
97 X509Certificate certs[] = getRequestCertificates(request);
9898
9999 if ((certs == null) || (certs.length < 1)) {
100100 if (containerLog.isDebugEnabled()) {
305305 }
306306
307307 if (status==SocketStatus.TIMEOUT) {
308 success = true;
309308 if (!asyncConImpl.timeout()) {
310309 asyncConImpl.setErrorState(null, false);
311310 }
372371 } finally {
373372 request.getContext().unbind(false, oldCL);
374373 }
375 success = true;
376374 } else if (readListener != null && status == SocketStatus.OPEN_READ) {
377375 ClassLoader oldCL = null;
378376 try {
395393 } finally {
396394 request.getContext().unbind(false, oldCL);
397395 }
398 success = true;
399396 }
400397 }
401398
408405 }
409406
410407 if (request.isAsyncDispatching()) {
411 success = true;
412408 connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
413409 Throwable t = (Throwable) request.getAttribute(
414410 RequestDispatcher.ERROR_EXCEPTION);
449445 }
450446 }
451447
448 // Check to see if the processor is in an error state. If it is,
449 // bail out now.
450 AtomicBoolean error = new AtomicBoolean(false);
451 res.action(ActionCode.IS_ERROR, error);
452 if (error.get()) {
453 success = false;
454 }
452455 } catch (IOException e) {
453456 success = false;
454457 // Ignore
898901 request.setRequestedSessionURL(true);
899902 }
900903 }
904
905 if (request.getContext().getUseRfc6265()) {
906 req.getCookies().setUseRfc6265(true);
907 } else {
908 req.getCookies().setUseRfc6265(false);
909 }
910
901911
902912 // Look for session ID in cookies and SSL session
903913 parseSessionCookiesId(req, request);
930940 // Reset mapping
931941 request.getMappingData().recycle();
932942 mapRequired = true;
943 // Recycle cookies in case correct context is
944 // configured with different settings
945 req.getCookies().recycle();
933946 }
934947 break;
935948 }
28642864 Cookie cookie = new Cookie(scookie.getName().toString(),null);
28652865 int version = scookie.getVersion();
28662866 cookie.setVersion(version);
2867 if (getContext().getUseRfc6265()) {
2868 scookie.getValue().getByteChunk().setCharset(
2869 getContext().getCookieEncodingCharset());
2870 }
28672871 cookie.setValue(unescape(scookie.getValue().toString()));
28682872 cookie.setPath(unescape(scookie.getPath().toString()));
28692873 String domain = scookie.getDomain().toString();
4848 import org.apache.catalina.Globals;
4949 import org.apache.catalina.security.SecurityUtil;
5050 import org.apache.catalina.util.Introspection;
51 import org.apache.juli.logging.Log;
5152 import org.apache.tomcat.InstanceManager;
5253 import org.apache.tomcat.util.ExceptionUtils;
5354 import org.apache.tomcat.util.res.StringManager;
7071 protected final ClassLoader containerClassLoader;
7172 protected final boolean privileged;
7273 protected final boolean ignoreAnnotations;
73 private final Properties restrictedFilters = new Properties();
74 private final Properties restrictedListeners = new Properties();
75 private final Properties restrictedServlets = new Properties();
74 private final Properties restrictedFilters;
75 private final Properties restrictedListeners;
76 private final Properties restrictedServlets;
7677 private final Map<Class<?>, AnnotationCacheEntry[]> annotationCache =
7778 new WeakHashMap<>();
7879 private final Map<String, String> postConstructMethods;
8788 this.containerClassLoader = containerClassLoader;
8889 ignoreAnnotations = catalinaContext.getIgnoreAnnotations();
8990 StringManager sm = StringManager.getManager(Constants.Package);
90 try {
91 InputStream is =
92 this.getClass().getClassLoader().getResourceAsStream
93 ("org/apache/catalina/core/RestrictedServlets.properties");
94 if (is != null) {
95 restrictedServlets.load(is);
96 } else {
97 catalinaContext.getLogger().error(sm.getString(
98 "defaultInstanceManager.restrictedServletsResource"));
99 }
100 } catch (IOException e) {
101 catalinaContext.getLogger().error(sm.getString(
102 "defaultInstanceManager.restrictedServletsResource"), e);
103 }
104
105 try {
106 InputStream is =
107 this.getClass().getClassLoader().getResourceAsStream
108 ("org/apache/catalina/core/RestrictedListeners.properties");
109 if (is != null) {
110 restrictedListeners.load(is);
111 } else {
112 catalinaContext.getLogger().error(sm.getString(
113 "defaultInstanceManager.restrictedListenersResources"));
114 }
115 } catch (IOException e) {
116 catalinaContext.getLogger().error(sm.getString(
117 "defaultInstanceManager.restrictedListenersResources"), e);
118 }
119 try {
120 InputStream is =
121 this.getClass().getClassLoader().getResourceAsStream
122 ("org/apache/catalina/core/RestrictedFilters.properties");
123 if (is != null) {
124 restrictedFilters.load(is);
125 } else {
126 catalinaContext.getLogger().error(sm.getString(
127 "defaultInstanceManager.restrictedFiltersResource"));
128 }
129 } catch (IOException e) {
130 catalinaContext.getLogger().error(sm.getString(
131 "defaultInstanceManager.restrictedServletsResources"), e);
132 }
91 restrictedServlets = loadProperties(
92 "org/apache/catalina/core/RestrictedServlets.properties",
93 sm.getString("defaultInstanceManager.restrictedServletsResource"),
94 catalinaContext.getLogger());
95 restrictedListeners = loadProperties(
96 "org/apache/catalina/core/RestrictedListeners.properties",
97 "defaultInstanceManager.restrictedListenersResources",
98 catalinaContext.getLogger());
99 restrictedFilters = loadProperties(
100 "org/apache/catalina/core/RestrictedFilters.properties",
101 "defaultInstanceManager.restrictedFiltersResource",
102 catalinaContext.getLogger());
133103 this.context = context;
134104 this.injectionMap = injectionMap;
135105 this.postConstructMethods = catalinaContext.findPostConstructMethods();
653623 }
654624 }
655625
626 private static Properties loadProperties(String resourceName, String errorString, Log log) {
627 Properties result = new Properties();
628 ClassLoader cl = DefaultInstanceManager.class.getClassLoader();
629 try (InputStream is = cl.getResourceAsStream(resourceName)) {
630 if (is ==null) {
631 log.error(errorString);
632 } else {
633 result.load(is);
634 }
635 } catch (IOException ioe) {
636 log.error(errorString, ioe);
637 }
638 return result;
639 }
640
656641 private static String normalize(String jndiName){
657642 if(jndiName != null && jndiName.startsWith("java:comp/env/")){
658643 return jndiName.substring(14);
147147 standardContext.startingContext=Exception starting Context with name [{0}]
148148 standardContext.stoppingContext=Exception stopping Context with name [{0}]
149149 standardContext.threadBindingListenerError=An error occurred in the thread binding listener configured for Context [{0}]
150 standardContext.unknownCookieEncoding=The unknown encoding [{0}] was specified for setCookieEncoding(String) so the default of UTF-8 will be used instead
150151 standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a ''/'' in Servlet 2.4
151152 standardContext.webappClassLoader.missingProperty=Unable to set the web application class loader property [{0}] to [{1}] as the property does not exist.
152153 standardContext.workPath=Exception obtaining work path for context [{0}]
2020 import java.io.IOException;
2121 import java.io.InputStream;
2222 import java.io.InputStreamReader;
23 import java.io.UnsupportedEncodingException;
2324 import java.net.MalformedURLException;
2425 import java.net.URL;
26 import java.nio.charset.Charset;
27 import java.nio.charset.StandardCharsets;
2528 import java.security.AccessController;
2629 import java.security.PrivilegedAction;
2730 import java.util.ArrayList;
114117 import org.apache.tomcat.JarScanner;
115118 import org.apache.tomcat.util.ExceptionUtils;
116119 import org.apache.tomcat.util.IntrospectionUtils;
120 import org.apache.tomcat.util.buf.B2CConverter;
117121 import org.apache.tomcat.util.buf.UDecoder;
118122 import org.apache.tomcat.util.descriptor.XmlIdentifiers;
119123 import org.apache.tomcat.util.descriptor.web.ApplicationParameter;
757761 /**
758762 * If an HttpClient keep-alive timer thread has been started by this web
759763 * application and is still running, should Tomcat change the context class
760 * loader from the current {@link WebappClassLoader} to
761 * {@link WebappClassLoader#parent} to prevent a memory leak? Note that the
764 * loader from the current {@link ClassLoader} to
765 * {@link ClassLoader#getParent()} to prevent a memory leak? Note that the
762766 * keep-alive timer thread will stop on its own once the keep-alives all
763767 * expire however, on a busy system that might not happen for some time.
764768 */
820824
821825 private final Object namingToken = new Object();
822826
827 private boolean useRfc6265 = false;
828 private Charset cookieEncoding = StandardCharsets.UTF_8;
829
823830
824831 // ----------------------------------------------------- Context Properties
832
833
834 @Override
835 public void setUseRfc6265(boolean useRfc6265) {
836 this.useRfc6265 = useRfc6265;
837 }
838
839
840 @Override
841 public boolean getUseRfc6265() {
842 return useRfc6265;
843 }
844
845
846 @Override
847 public void setCookieEncoding(String encoding) {
848 try {
849 Charset charset = B2CConverter.getCharset(encoding);
850 cookieEncoding = charset;
851 } catch (UnsupportedEncodingException uee) {
852 cookieEncoding = StandardCharsets.UTF_8;
853 log.warn(sm.getString("standardContext.unknownCookieEncoding"), uee);
854 }
855 }
856
857
858 @Override
859 public String getCookieEncoding() {
860 return cookieEncoding.name();
861 }
862
863
864 @Override
865 public Charset getCookieEncodingCharset() {
866 return cookieEncoding;
867 }
868
825869
826870 @Override
827871 public Object getNamingToken() {
917961 StringBuilder result = new StringBuilder();
918962 boolean first = true;
919963 for (String servletName : resourceOnlyServlets) {
920 if (!first) {
964 if (first) {
965 first = false;
966 } else {
921967 result.append(',');
922968 }
923969 result.append(servletName);
3838 import org.apache.catalina.LifecycleException;
3939 import org.apache.catalina.LifecycleListener;
4040 import org.apache.catalina.Valve;
41 import org.apache.catalina.loader.WebappClassLoader;
41 import org.apache.catalina.loader.WebappClassLoaderBase;
4242 import org.apache.tomcat.util.ExceptionUtils;
4343
4444 /**
748748 for (Map.Entry<ClassLoader, String> entry :
749749 childClassLoaders.entrySet()) {
750750 ClassLoader cl = entry.getKey();
751 if (cl instanceof WebappClassLoader) {
752 if (!((WebappClassLoader) cl).getState().isAvailable()) {
751 if (cl instanceof WebappClassLoaderBase) {
752 if (!((WebappClassLoaderBase) cl).getState().isAvailable()) {
753753 result.add(entry.getValue());
754754 }
755755 }
102102 type="boolean"
103103 writeable="false" />
104104
105 <attribute name="cookieEncoding"
106 description="If the new cookie parser is used, which encoding should be used to decode the cookie values?"
107 type="java.lang.String"/>
108
105109 <attribute name="cookies"
106110 description="Should we attempt to use cookies for session id communication?"
107111 type="boolean"/>
328332 <attribute name="useNaming"
329333 description="Create a JNDI naming context for this application?"
330334 is="true"
335 type="boolean"/>
336
337 <attribute name="useNewCookieParser"
338 description="Use the new RFC6265 based cookie parser"
339 is="false"
331340 type="boolean"/>
332341
333342 <attribute name="webappVersion"
2626 import java.util.List;
2727
2828 /**
29 * This class is loaded by the {@link WebappClassLoader} to enable it to
29 * This class is loaded by {@link WebappClassLoaderBase} to enable it to
3030 * deregister JDBC drivers forgotten by the web application. There are some
31 * classloading hacks involved - see {@link WebappClassLoader#clearReferences()}
32 * for details - but the short version is do not just create a new instance of
33 * this class with the new keyword.
31 * classloading hacks involved - see
32 * {@link WebappClassLoaderBase#clearReferences()} for details - but the short
33 * version is do not just create a new instance of this class with the new
34 * keyword.
3435 *
35 * Since this class is loaded by {@link WebappClassLoader}, it can not refer to
36 * any internal Tomcat classes as that will cause the security manager to
36 * Since this class is loaded by {@link WebappClassLoaderBase}, it can not refer
37 * to any internal Tomcat classes as that will cause the security manager to
3738 * complain.
3839 */
3940 public class JdbcLeakPrevention {
5050 webappClassLoader.addTransformer=Added class file transformer [{0}] to web application [{1}].
5151 webappClassLoader.removeTransformer=Removed class file transformer [{0}] from web application [{1}].
5252 webappClassLoader.transformError=Instrumentation error: could not transform class [{0}] because its class file format is not legal.
53
54 webappClassLoaderParallel.registrationFailed=Registration of org.apache.catalina.loader.ParallelWebappClassLoader as capable of loading classes in parallel failed
55
5356 webappLoader.addRepository=Adding repository {0}
5457 webappLoader.deploy=Deploying class repositories to work directory {0}
5558 webappLoader.jarDeploy=Deploy JAR {0} to {1}
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.catalina.loader;
17
18 import org.apache.catalina.LifecycleException;
19
20 public class ParallelWebappClassLoader extends WebappClassLoaderBase {
21
22 private static final org.apache.juli.logging.Log log =
23 org.apache.juli.logging.LogFactory.getLog(ParallelWebappClassLoader.class);
24
25 static {
26 boolean result = ClassLoader.registerAsParallelCapable();
27 if (!result) {
28 log.warn(sm.getString("webappClassLoaderParallel.registrationFailed"));
29 }
30 }
31
32 public ParallelWebappClassLoader() {
33 super();
34 }
35
36
37 public ParallelWebappClassLoader(ClassLoader parent) {
38 super(parent);
39 }
40
41
42 /**
43 * Returns a copy of this class loader without any class file
44 * transformers. This is a tool often used by Java Persistence API
45 * providers to inspect entity classes in the absence of any
46 * instrumentation, something that can't be guaranteed within the
47 * context of a {@link java.lang.instrument.ClassFileTransformer}'s
48 * {@link java.lang.instrument.ClassFileTransformer#transform(ClassLoader,
49 * String, Class, java.security.ProtectionDomain, byte[]) transform} method.
50 * <p>
51 * The returned class loader's resource cache will have been cleared
52 * so that classes already instrumented will not be retained or
53 * returned.
54 *
55 * @return the transformer-free copy of this class loader.
56 */
57 @Override
58 public ParallelWebappClassLoader copyWithoutTransformers() {
59
60 ParallelWebappClassLoader result = new ParallelWebappClassLoader(getParent());
61
62 super.copyStateWithoutTransformers(result);
63
64 try {
65 result.start();
66 } catch (LifecycleException e) {
67 throw new IllegalStateException(e);
68 }
69
70 return result;
71 }
72 }
1515 */
1616 package org.apache.catalina.loader;
1717
18 import java.io.ByteArrayInputStream;
19 import java.io.File;
20 import java.io.FilePermission;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.lang.instrument.ClassFileTransformer;
24 import java.lang.instrument.IllegalClassFormatException;
25 import java.lang.ref.Reference;
26 import java.lang.ref.WeakReference;
27 import java.lang.reflect.Field;
28 import java.lang.reflect.Method;
29 import java.lang.reflect.Modifier;
30 import java.net.URI;
31 import java.net.URISyntaxException;
32 import java.net.URL;
33 import java.net.URLClassLoader;
34 import java.nio.charset.StandardCharsets;
35 import java.security.AccessControlException;
36 import java.security.AccessController;
37 import java.security.CodeSource;
38 import java.security.Permission;
39 import java.security.PermissionCollection;
40 import java.security.Policy;
41 import java.security.PrivilegedAction;
42 import java.security.ProtectionDomain;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.ConcurrentModificationException;
48 import java.util.Date;
49 import java.util.Enumeration;
50 import java.util.HashMap;
51 import java.util.Iterator;
52 import java.util.LinkedHashSet;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Map.Entry;
56 import java.util.ResourceBundle;
57 import java.util.Set;
58 import java.util.concurrent.ConcurrentHashMap;
59 import java.util.concurrent.CopyOnWriteArrayList;
60 import java.util.concurrent.ThreadPoolExecutor;
61 import java.util.jar.Attributes;
62 import java.util.jar.Attributes.Name;
63 import java.util.jar.Manifest;
64 import java.util.regex.Matcher;
65 import java.util.regex.Pattern;
18 import org.apache.catalina.LifecycleException;
6619
67 import org.apache.catalina.Globals;
68 import org.apache.catalina.Lifecycle;
69 import org.apache.catalina.LifecycleException;
70 import org.apache.catalina.LifecycleListener;
71 import org.apache.catalina.LifecycleState;
72 import org.apache.catalina.WebResource;
73 import org.apache.catalina.WebResourceRoot;
74 import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
75 import org.apache.tomcat.InstrumentableClassLoader;
76 import org.apache.tomcat.util.ExceptionUtils;
77 import org.apache.tomcat.util.IntrospectionUtils;
78 import org.apache.tomcat.util.res.StringManager;
20 public class WebappClassLoader extends WebappClassLoaderBase {
7921
80 /**
81 * Specialized web application class loader.
82 * <p>
83 * This class loader is a full reimplementation of the
84 * <code>URLClassLoader</code> from the JDK. It is designed to be fully
85 * compatible with a normal <code>URLClassLoader</code>, although its internal
86 * behavior may be completely different.
87 * <p>
88 * <strong>IMPLEMENTATION NOTE</strong> - By default, this class loader follows
89 * the delegation model required by the specification. The system class
90 * loader will be queried first, then the local repositories, and only then
91 * delegation to the parent class loader will occur. This allows the web
92 * application to override any shared class except the classes from J2SE.
93 * Special handling is provided from the JAXP XML parser interfaces, the JNDI
94 * interfaces, and the classes from the servlet API, which are never loaded
95 * from the webapp repositories. The <code>delegate</code> property
96 * allows an application to modify this behavior to move the parent class loader
97 * ahead of the local repositories.
98 * <p>
99 * <strong>IMPLEMENTATION NOTE</strong> - Due to limitations in Jasper
100 * compilation technology, any repository which contains classes from
101 * the servlet API will be ignored by the class loader.
102 * <p>
103 * <strong>IMPLEMENTATION NOTE</strong> - The class loader generates source
104 * URLs which include the full JAR URL when a class is loaded from a JAR file,
105 * which allows setting security permission at the class level, even when a
106 * class is contained inside a JAR.
107 * <p>
108 * <strong>IMPLEMENTATION NOTE</strong> - Local repositories are searched in
109 * the order they are added via the initial constructor and/or any subsequent
110 * calls to <code>addRepository()</code> or <code>addJar()</code>.
111 * <p>
112 * <strong>IMPLEMENTATION NOTE</strong> - No check for sealing violations or
113 * security is made unless a security manager is present.
114 * <p>
115 * <strong>IMPLEMENTATION NOTE</strong> - As of 8.0, this class
116 * loader implements {@link InstrumentableClassLoader}, permitting web
117 * application classes to instrument other classes in the same web
118 * application. It does not permit instrumentation of system or container
119 * classes or classes in other web apps.
120 *
121 * @author Remy Maucherat
122 * @author Craig R. McClanahan
123 */
124 public class WebappClassLoader extends URLClassLoader
125 implements Lifecycle, InstrumentableClassLoader {
126
127 private static final org.apache.juli.logging.Log log=
128 org.apache.juli.logging.LogFactory.getLog( WebappClassLoader.class );
129
130 /**
131 * List of ThreadGroup names to ignore when scanning for web application
132 * started threads that need to be shut down.
133 */
134 private static final List<String> JVM_THREAD_GROUP_NAMES = new ArrayList<>();
135
136 private static final String JVM_THREAD_GROUP_SYSTEM = "system";
137
138 private static final String CLASS_FILE_SUFFIX = ".class";
139 private static final String SERVICES_PREFIX = "/META-INF/services/";
140
141 static {
142 JVM_THREAD_GROUP_NAMES.add(JVM_THREAD_GROUP_SYSTEM);
143 JVM_THREAD_GROUP_NAMES.add("RMI Runtime");
144 }
145
146 protected class PrivilegedFindResourceByName
147 implements PrivilegedAction<ResourceEntry> {
148
149 protected final String name;
150 protected final String path;
151
152 PrivilegedFindResourceByName(String name, String path) {
153 this.name = name;
154 this.path = path;
155 }
156
157 @Override
158 public ResourceEntry run() {
159 return findResourceInternal(name, path);
160 }
161
22 public WebappClassLoader() {
23 super();
16224 }
16325
16426
165 protected static final class PrivilegedGetClassLoader
166 implements PrivilegedAction<ClassLoader> {
167
168 public final Class<?> clazz;
169
170 public PrivilegedGetClassLoader(Class<?> clazz){
171 this.clazz = clazz;
172 }
173
174 @Override
175 public ClassLoader run() {
176 return clazz.getClassLoader();
177 }
27 public WebappClassLoader(ClassLoader parent) {
28 super(parent);
17829 }
17930
180
181 // ------------------------------------------------------- Static Variables
182
183 /**
184 * Regular expression of package names which are not allowed to be loaded
185 * from a webapp class loader without delegating first.
186 */
187 protected final Matcher packageTriggersDeny = Pattern.compile(
188 "^javax\\.el\\.|" +
189 "^javax\\.servlet\\.|" +
190 "^org\\.apache\\.(catalina|coyote|el|jasper|juli|naming|tomcat)\\."
191 ).matcher("");
192
193
194 /**
195 * Regular expression of package names which are allowed to be loaded from a
196 * webapp class loader without delegating first and override any set by
197 * {@link #packageTriggersDeny}.
198 */
199 protected final Matcher packageTriggersPermit =
200 Pattern.compile("^javax\\.servlet\\.jsp\\.jstl\\.|" +
201 "^org\\.apache\\.tomcat\\.jdbc\\.").matcher("");
202
203
204 /**
205 * The string manager for this package.
206 */
207 protected static final StringManager sm =
208 StringManager.getManager(Constants.Package);
209
210
211 // ----------------------------------------------------------- Constructors
212
213 /**
214 * Construct a new ClassLoader with no defined repositories and no
215 * parent ClassLoader.
216 */
217 public WebappClassLoader() {
218
219 super(new URL[0]);
220
221 ClassLoader p = getParent();
222 if (p == null) {
223 p = getSystemClassLoader();
224 }
225 this.parent = p;
226
227 ClassLoader j = String.class.getClassLoader();
228 if (j == null) {
229 j = getSystemClassLoader();
230 while (j.getParent() != null) {
231 j = j.getParent();
232 }
233 }
234 this.javaseClassLoader = j;
235
236 securityManager = System.getSecurityManager();
237 if (securityManager != null) {
238 refreshPolicy();
239 }
240 }
241
242
243 /**
244 * Construct a new ClassLoader with no defined repositories and the given
245 * parent ClassLoader.
246 * <p>
247 * Method is used via reflection -
248 * see {@link WebappLoader#createClassLoader()}
249 *
250 * @param parent Our parent class loader
251 */
252 public WebappClassLoader(ClassLoader parent) {
253
254 super(new URL[0], parent);
255
256 ClassLoader p = getParent();
257 if (p == null) {
258 p = getSystemClassLoader();
259 }
260 this.parent = p;
261
262 ClassLoader j = String.class.getClassLoader();
263 if (j == null) {
264 j = getSystemClassLoader();
265 while (j.getParent() != null) {
266 j = j.getParent();
267 }
268 }
269 this.javaseClassLoader = j;
270
271 securityManager = System.getSecurityManager();
272 if (securityManager != null) {
273 refreshPolicy();
274 }
275 }
276
277
278 // ----------------------------------------------------- Instance Variables
279
280 /**
281 * Associated web resources for this webapp.
282 */
283 protected WebResourceRoot resources = null;
284
285
286 /**
287 * The cache of ResourceEntry for classes and resources we have loaded,
288 * keyed by resource path, not binary name. Path is used as the key since
289 * resources may be requested by binary name (classes) or path (other
290 * resources such as property files) and the mapping from binary name to
291 * path is unambiguous but the reverse mapping is ambiguous.
292 */
293 protected final Map<String, ResourceEntry> resourceEntries =
294 new ConcurrentHashMap<>();
295
296
297 /**
298 * Should this class loader delegate to the parent class loader
299 * <strong>before</strong> searching its own repositories (i.e. the
300 * usual Java2 delegation model)? If set to <code>false</code>,
301 * this class loader will search its own repositories first, and
302 * delegate to the parent only if the class or resource is not
303 * found locally. Note that the default, <code>false</code>, is
304 * the behavior called for by the servlet specification.
305 */
306 protected boolean delegate = false;
307
308
309 private final HashMap<String,Long> jarModificationTimes = new HashMap<>();
310
311
312 /**
313 * A list of read File and Jndi Permission's required if this loader
314 * is for a web application context.
315 */
316 protected final ArrayList<Permission> permissionList = new ArrayList<>();
317
318
319 /**
320 * The PermissionCollection for each CodeSource for a web
321 * application context.
322 */
323 protected final HashMap<String, PermissionCollection> loaderPC = new HashMap<>();
324
325
326 /**
327 * Instance of the SecurityManager installed.
328 */
329 protected final SecurityManager securityManager;
330
331
332 /**
333 * The parent class loader.
334 */
335 protected final ClassLoader parent;
336
337
338 /**
339 * The bootstrap class loader used to load the JavaSE classes. In some
340 * implementations this class loader is always <code>null</null> and in
341 * those cases {@link ClassLoader#getParent()} will be called recursively on
342 * the system class loader and the last non-null result used.
343 */
344 private ClassLoader javaseClassLoader;
345
346
347 /**
348 * need conversion for properties files
349 */
350 protected boolean needConvert = false;
351
352
353 /**
354 * All permission.
355 */
356 protected final Permission allPermission = new java.security.AllPermission();
357
358
359 /**
360 * Should Tomcat attempt to null out any static or final fields from loaded
361 * classes when a web application is stopped as a work around for apparent
362 * garbage collection bugs and application coding errors? There have been
363 * some issues reported with log4j when this option is true. Applications
364 * without memory leaks using recent JVMs should operate correctly with this
365 * option set to <code>false</code>. If not specified, the default value of
366 * <code>false</code> will be used.
367 */
368 private boolean clearReferencesStatic = false;
369
370 /**
371 * Should Tomcat attempt to terminate threads that have been started by the
372 * web application? Stopping threads is performed via the deprecated (for
373 * good reason) <code>Thread.stop()</code> method and is likely to result in
374 * instability. As such, enabling this should be viewed as an option of last
375 * resort in a development environment and is not recommended in a
376 * production environment. If not specified, the default value of
377 * <code>false</code> will be used.
378 */
379 private boolean clearReferencesStopThreads = false;
380
381 /**
382 * Should Tomcat attempt to terminate any {@link java.util.TimerThread}s
383 * that have been started by the web application? If not specified, the
384 * default value of <code>false</code> will be used.
385 */
386 private boolean clearReferencesStopTimerThreads = false;
387
388 /**
389 * Should Tomcat call {@link org.apache.juli.logging.LogFactory#release()}
390 * when the class loader is stopped? If not specified, the default value
391 * of <code>true</code> is used. Changing the default setting is likely to
392 * lead to memory leaks and other issues.
393 */
394 private boolean clearReferencesLogFactoryRelease = true;
395
396 /**
397 * If an HttpClient keep-alive timer thread has been started by this web
398 * application and is still running, should Tomcat change the context class
399 * loader from the current {@link WebappClassLoader} to
400 * {@link WebappClassLoader#parent} to prevent a memory leak? Note that the
401 * keep-alive timer thread will stop on its own once the keep-alives all
402 * expire however, on a busy system that might not happen for some time.
403 */
404 private boolean clearReferencesHttpClientKeepAliveThread = true;
405
406 /**
407 * Holds the class file transformers decorating this class loader. The
408 * CopyOnWriteArrayList is thread safe. It is expensive on writes, but
409 * those should be rare. It is very fast on reads, since synchronization
410 * is not actually used. Importantly, the ClassLoader will never block
411 * iterating over the transformers while loading a class.
412 */
413 private final List<ClassFileTransformer> transformers = new CopyOnWriteArrayList<>();
414
415
416 /**
417 * Flag that indicates that {@link #addURL(URL)} has been called which
418 * creates a requirement to check the super class when searching for
419 * resources.
420 */
421 private boolean hasExternalRepositories = false;
422
423
424 /**
425 * Repositories managed by this class rather than the super class.
426 */
427 private List<URL> localRepositories = new ArrayList<>();
428
429
430 private volatile LifecycleState state = LifecycleState.NEW;
431
432
433 // ------------------------------------------------------------- Properties
434
435 /**
436 * Get associated resources.
437 */
438 public WebResourceRoot getResources() {
439 return this.resources;
440 }
441
442
443 /**
444 * Set associated resources.
445 */
446 public void setResources(WebResourceRoot resources) {
447 this.resources = resources;
448 }
449
450
451 /**
452 * Return the context name for this class loader.
453 */
454 public String getContextName() {
455 if (resources == null) {
456 return "Unknown";
457 } else {
458 return resources.getContext().getName();
459 }
460 }
461
462
463 /**
464 * Return the "delegate first" flag for this class loader.
465 */
466 public boolean getDelegate() {
467
468 return (this.delegate);
469
470 }
471
472
473 /**
474 * Set the "delegate first" flag for this class loader.
475 * If this flag is true, this class loader delegates
476 * to the parent class loader
477 * <strong>before</strong> searching its own repositories, as
478 * in an ordinary (non-servlet) chain of Java class loaders.
479 * If set to <code>false</code> (the default),
480 * this class loader will search its own repositories first, and
481 * delegate to the parent only if the class or resource is not
482 * found locally, as per the servlet specification.
483 *
484 * @param delegate The new "delegate first" flag
485 */
486 public void setDelegate(boolean delegate) {
487 this.delegate = delegate;
488 }
489
490
491 /**
492 * If there is a Java SecurityManager create a read permission for the
493 * target of the given URL as appropriate.
494 *
495 * @param url URL for a file or directory on local system
496 */
497 void addPermission(URL url) {
498 if (url == null) {
499 return;
500 }
501 if (securityManager != null) {
502 String protocol = url.getProtocol();
503 if ("file".equalsIgnoreCase(protocol)) {
504 URI uri;
505 File f;
506 String path;
507 try {
508 uri = url.toURI();
509 f = new File(uri);
510 path = f.getCanonicalPath();
511 } catch (IOException | URISyntaxException e) {
512 log.warn(sm.getString(
513 "webappClassLoader.addPermisionNoCanonicalFile",
514 url.toExternalForm()));
515 return;
516 }
517 if (f.isFile()) {
518 // Allow the file to be read
519 addPermission(new FilePermission(path, "read"));
520 } else if (f.isDirectory()) {
521 addPermission(new FilePermission(path, "read"));
522 addPermission(new FilePermission(
523 path + File.separator + "-", "read"));
524 } else {
525 // File does not exist - ignore (shouldn't happen)
526 }
527 } else {
528 // Unsupported URL protocol
529 log.warn(sm.getString(
530 "webappClassLoader.addPermisionNoProtocol",
531 protocol, url.toExternalForm()));
532 }
533 }
534 }
535
536
537 /**
538 * If there is a Java SecurityManager create a Permission.
539 *
540 * @param permission The permission
541 */
542 void addPermission(Permission permission) {
543 if ((securityManager != null) && (permission != null)) {
544 permissionList.add(permission);
545 }
546 }
547
548
549 /**
550 * Return the clearReferencesStatic flag for this Context.
551 */
552 public boolean getClearReferencesStatic() {
553 return (this.clearReferencesStatic);
554 }
555
556
557 /**
558 * Set the clearReferencesStatic feature for this Context.
559 *
560 * @param clearReferencesStatic The new flag value
561 */
562 public void setClearReferencesStatic(boolean clearReferencesStatic) {
563 this.clearReferencesStatic = clearReferencesStatic;
564 }
565
566
567 /**
568 * Return the clearReferencesStopThreads flag for this Context.
569 */
570 public boolean getClearReferencesStopThreads() {
571 return (this.clearReferencesStopThreads);
572 }
573
574
575 /**
576 * Set the clearReferencesStopThreads feature for this Context.
577 *
578 * @param clearReferencesStopThreads The new flag value
579 */
580 public void setClearReferencesStopThreads(
581 boolean clearReferencesStopThreads) {
582 this.clearReferencesStopThreads = clearReferencesStopThreads;
583 }
584
585
586 /**
587 * Return the clearReferencesStopTimerThreads flag for this Context.
588 */
589 public boolean getClearReferencesStopTimerThreads() {
590 return (this.clearReferencesStopTimerThreads);
591 }
592
593
594 /**
595 * Set the clearReferencesStopTimerThreads feature for this Context.
596 *
597 * @param clearReferencesStopTimerThreads The new flag value
598 */
599 public void setClearReferencesStopTimerThreads(
600 boolean clearReferencesStopTimerThreads) {
601 this.clearReferencesStopTimerThreads = clearReferencesStopTimerThreads;
602 }
603
604
605 /**
606 * Return the clearReferencesLogFactoryRelease flag for this Context.
607 */
608 public boolean getClearReferencesLogFactoryRelease() {
609 return (this.clearReferencesLogFactoryRelease);
610 }
611
612
613 /**
614 * Set the clearReferencesLogFactoryRelease feature for this Context.
615 *
616 * @param clearReferencesLogFactoryRelease The new flag value
617 */
618 public void setClearReferencesLogFactoryRelease(
619 boolean clearReferencesLogFactoryRelease) {
620 this.clearReferencesLogFactoryRelease =
621 clearReferencesLogFactoryRelease;
622 }
623
624
625 /**
626 * Return the clearReferencesHttpClientKeepAliveThread flag for this
627 * Context.
628 */
629 public boolean getClearReferencesHttpClientKeepAliveThread() {
630 return (this.clearReferencesHttpClientKeepAliveThread);
631 }
632
633
634 /**
635 * Set the clearReferencesHttpClientKeepAliveThread feature for this
636 * Context.
637 *
638 * @param clearReferencesHttpClientKeepAliveThread The new flag value
639 */
640 public void setClearReferencesHttpClientKeepAliveThread(
641 boolean clearReferencesHttpClientKeepAliveThread) {
642 this.clearReferencesHttpClientKeepAliveThread =
643 clearReferencesHttpClientKeepAliveThread;
644 }
645
646
647 // ------------------------------------------------------- Reloader Methods
648
649 /**
650 * Adds the specified class file transformer to this class loader. The
651 * transformer will then be able to modify the bytecode of any classes
652 * loaded by this class loader after the invocation of this method.
653 *
654 * @param transformer The transformer to add to the class loader
655 */
656 @Override
657 public void addTransformer(ClassFileTransformer transformer) {
658
659 if (transformer == null) {
660 throw new IllegalArgumentException(sm.getString(
661 "webappClassLoader.addTransformer.illegalArgument", getContextName()));
662 }
663
664 if (this.transformers.contains(transformer)) {
665 // if the same instance of this transformer was already added, bail out
666 log.warn(sm.getString("webappClassLoader.addTransformer.duplicate",
667 transformer, getContextName()));
668 return;
669 }
670 this.transformers.add(transformer);
671
672 log.info(sm.getString("webappClassLoader.addTransformer", transformer, getContextName()));
673 }
674
675 /**
676 * Removes the specified class file transformer from this class loader.
677 * It will no longer be able to modify the byte code of any classes
678 * loaded by the class loader after the invocation of this method.
679 * However, any classes already modified by this transformer will
680 * remain transformed.
681 *
682 * @param transformer The transformer to remove
683 */
684 @Override
685 public void removeTransformer(ClassFileTransformer transformer) {
686
687 if (transformer == null) {
688 return;
689 }
690
691 if (this.transformers.remove(transformer)) {
692 log.info(sm.getString("webappClassLoader.removeTransformer",
693 transformer, getContextName()));
694 return;
695 }
696
697 }
69831
69932 /**
70033 * Returns a copy of this class loader without any class file
70134 * transformers. This is a tool often used by Java Persistence API
70235 * providers to inspect entity classes in the absence of any
70336 * instrumentation, something that can't be guaranteed within the
704 * context of a {@link ClassFileTransformer}'s
705 * {@link ClassFileTransformer#transform(ClassLoader, String, Class,
706 * ProtectionDomain, byte[]) transform} method.
37 * context of a {@link java.lang.instrument.ClassFileTransformer}'s
38 * {@link java.lang.instrument.ClassFileTransformer#transform(ClassLoader,
39 * String, Class, java.security.ProtectionDomain, byte[]) transform} method.
70740 * <p>
70841 * The returned class loader's resource cache will have been cleared
70942 * so that classes already instrumented will not be retained or
71649
71750 WebappClassLoader result = new WebappClassLoader(getParent());
71851
719 result.resources = this.resources;
720 result.delegate = this.delegate;
721 result.state = this.state;
722 result.needConvert = this.needConvert;
723 result.clearReferencesStatic = this.clearReferencesStatic;
724 result.clearReferencesStopThreads = this.clearReferencesStopThreads;
725 result.clearReferencesStopTimerThreads = this.clearReferencesStopTimerThreads;
726 result.clearReferencesLogFactoryRelease = this.clearReferencesLogFactoryRelease;
727 result.clearReferencesHttpClientKeepAliveThread = this.clearReferencesHttpClientKeepAliveThread;
728 result.jarModificationTimes.putAll(this.jarModificationTimes);
729 result.permissionList.addAll(this.permissionList);
730 result.loaderPC.putAll(this.loaderPC);
52 super.copyStateWithoutTransformers(result);
73153
73254 try {
73355 result.start();
73860 return result;
73961 }
74062
741 /**
742 * Have one or more classes or resources been modified so that a reload
743 * is appropriate?
744 */
745 public boolean modified() {
746
747 if (log.isDebugEnabled())
748 log.debug("modified()");
749
750 for (Entry<String,ResourceEntry> entry : resourceEntries.entrySet()) {
751 long cachedLastModified = entry.getValue().lastModified;
752 long lastModified = resources.getClassLoaderResource(
753 entry.getKey()).getLastModified();
754 if (lastModified != cachedLastModified) {
755 if( log.isDebugEnabled() )
756 log.debug(sm.getString("webappClassLoader.resourceModified",
757 entry.getKey(),
758 new Date(cachedLastModified),
759 new Date(lastModified)));
760 return true;
761 }
762 }
763
764 // Check if JARs have been added or removed
765 WebResource[] jars = resources.listResources("/WEB-INF/lib");
766 // Filter out non-JAR resources
767
768 int jarCount = 0;
769 for (WebResource jar : jars) {
770 if (jar.getName().endsWith(".jar") && jar.isFile() && jar.canRead()) {
771 jarCount++;
772 Long recordedLastModified = jarModificationTimes.get(jar.getName());
773 if (recordedLastModified == null) {
774 // Jar has been added
775 log.info(sm.getString("webappClassLoader.jarsAdded",
776 resources.getContext().getName()));
777 return true;
778 }
779 if (recordedLastModified.longValue() != jar.getLastModified()) {
780 // Jar has been changed
781 log.info(sm.getString("webappClassLoader.jarsModified",
782 resources.getContext().getName()));
783 return true;
784 }
785 }
786 }
787
788 if (jarCount < jarModificationTimes.size()){
789 log.info(sm.getString("webappClassLoader.jarsRemoved",
790 resources.getContext().getName()));
791 return true;
792 }
793
794
795 // No classes have been modified
796 return false;
797 }
798
79963
80064 /**
801 * Render a String representation of this object.
65 * This class loader is not parallel capable so lock on the class loader
66 * rather than a per-class lock.
80267 */
80368 @Override
804 public String toString() {
805
806 StringBuilder sb = new StringBuilder("WebappClassLoader\r\n");
807 sb.append(" context: ");
808 sb.append(getContextName());
809 sb.append("\r\n");
810 sb.append(" delegate: ");
811 sb.append(delegate);
812 sb.append("\r\n");
813 if (this.parent != null) {
814 sb.append("----------> Parent Classloader:\r\n");
815 sb.append(this.parent.toString());
816 sb.append("\r\n");
817 }
818 if (this.transformers.size() > 0) {
819 sb.append("----------> Class file transformers:\r\n");
820 for (ClassFileTransformer transformer : this.transformers) {
821 sb.append(transformer).append("\r\n");
822 }
823 }
824 return (sb.toString());
825
826 }
827
828
829 // ---------------------------------------------------- ClassLoader Methods
830
831
832 /**
833 * Expose this method for use by the unit tests.
834 */
835 protected final Class<?> doDefineClass(String name, byte[] b, int off, int len,
836 ProtectionDomain protectionDomain) {
837 return super.defineClass(name, b, off, len, protectionDomain);
838 }
839
840 /**
841 * Find the specified class in our local repositories, if possible. If
842 * not found, throw <code>ClassNotFoundException</code>.
843 *
844 * @param name The binary name of the class to be loaded
845 *
846 * @exception ClassNotFoundException if the class was not found
847 */
848 @Override
849 public Class<?> findClass(String name) throws ClassNotFoundException {
850
851 if (log.isDebugEnabled())
852 log.debug(" findClass(" + name + ")");
853
854 checkStateForClassLoading(name);
855
856 // (1) Permission to define this class when using a SecurityManager
857 if (securityManager != null) {
858 int i = name.lastIndexOf('.');
859 if (i >= 0) {
860 try {
861 if (log.isTraceEnabled())
862 log.trace(" securityManager.checkPackageDefinition");
863 securityManager.checkPackageDefinition(name.substring(0,i));
864 } catch (Exception se) {
865 if (log.isTraceEnabled())
866 log.trace(" -->Exception-->ClassNotFoundException", se);
867 throw new ClassNotFoundException(name, se);
868 }
869 }
870 }
871
872 // Ask our superclass to locate this class, if possible
873 // (throws ClassNotFoundException if it is not found)
874 Class<?> clazz = null;
875 try {
876 if (log.isTraceEnabled())
877 log.trace(" findClassInternal(" + name + ")");
878 try {
879 clazz = findClassInternal(name);
880 } catch(AccessControlException ace) {
881 log.warn("WebappClassLoader.findClassInternal(" + name
882 + ") security exception: " + ace.getMessage(), ace);
883 throw new ClassNotFoundException(name, ace);
884 } catch (RuntimeException e) {
885 if (log.isTraceEnabled())
886 log.trace(" -->RuntimeException Rethrown", e);
887 throw e;
888 }
889 if ((clazz == null) && hasExternalRepositories) {
890 try {
891 clazz = super.findClass(name);
892 } catch(AccessControlException ace) {
893 log.warn("WebappClassLoader.findClassInternal(" + name
894 + ") security exception: " + ace.getMessage(), ace);
895 throw new ClassNotFoundException(name, ace);
896 } catch (RuntimeException e) {
897 if (log.isTraceEnabled())
898 log.trace(" -->RuntimeException Rethrown", e);
899 throw e;
900 }
901 }
902 if (clazz == null) {
903 if (log.isDebugEnabled())
904 log.debug(" --> Returning ClassNotFoundException");
905 throw new ClassNotFoundException(name);
906 }
907 } catch (ClassNotFoundException e) {
908 if (log.isTraceEnabled())
909 log.trace(" --> Passing on ClassNotFoundException");
910 throw e;
911 }
912
913 // Return the class we have located
914 if (log.isTraceEnabled())
915 log.debug(" Returning class " + clazz);
916
917 if (log.isTraceEnabled()) {
918 ClassLoader cl;
919 if (Globals.IS_SECURITY_ENABLED){
920 cl = AccessController.doPrivileged(
921 new PrivilegedGetClassLoader(clazz));
922 } else {
923 cl = clazz.getClassLoader();
924 }
925 log.debug(" Loaded by " + cl.toString());
926 }
927 return (clazz);
928
929 }
930
931
932 /**
933 * Find the specified resource in our local repository, and return a
934 * <code>URL</code> referring to it, or <code>null</code> if this resource
935 * cannot be found.
936 *
937 * @param name Name of the resource to be found
938 */
939 @Override
940 public URL findResource(final String name) {
941
942 if (log.isDebugEnabled())
943 log.debug(" findResource(" + name + ")");
944
945 URL url = null;
946
947 String path = nameToPath(name);
948
949 ResourceEntry entry = resourceEntries.get(path);
950 if (entry == null) {
951 if (securityManager != null) {
952 PrivilegedAction<ResourceEntry> dp =
953 new PrivilegedFindResourceByName(name, path);
954 entry = AccessController.doPrivileged(dp);
955 } else {
956 entry = findResourceInternal(name, path);
957 }
958 }
959 if (entry != null) {
960 url = entry.source;
961 }
962
963 if ((url == null) && hasExternalRepositories) {
964 url = super.findResource(name);
965 }
966
967 if (log.isDebugEnabled()) {
968 if (url != null)
969 log.debug(" --> Returning '" + url.toString() + "'");
970 else
971 log.debug(" --> Resource not found, returning null");
972 }
973 return (url);
974
975 }
976
977
978 /**
979 * Return an enumeration of <code>URLs</code> representing all of the
980 * resources with the given name. If no resources with this name are
981 * found, return an empty enumeration.
982 *
983 * @param name Name of the resources to be found
984 *
985 * @exception IOException if an input/output error occurs
986 */
987 @Override
988 public Enumeration<URL> findResources(String name) throws IOException {
989
990 if (log.isDebugEnabled())
991 log.debug(" findResources(" + name + ")");
992
993 LinkedHashSet<URL> result = new LinkedHashSet<>();
994
995 String path = nameToPath(name);
996
997 WebResource[] webResources = resources.getClassLoaderResources(path);
998 for (WebResource webResource : webResources) {
999 if (webResource.exists()) {
1000 result.add(webResource.getURL());
1001 }
1002 }
1003
1004 // Adding the results of a call to the superclass
1005 if (hasExternalRepositories) {
1006 Enumeration<URL> otherResourcePaths = super.findResources(name);
1007 while (otherResourcePaths.hasMoreElements()) {
1008 result.add(otherResourcePaths.nextElement());
1009 }
1010 }
1011
1012 return Collections.enumeration(result);
1013 }
1014
1015
1016 /**
1017 * Find the resource with the given name. A resource is some data
1018 * (images, audio, text, etc.) that can be accessed by class code in a
1019 * way that is independent of the location of the code. The name of a
1020 * resource is a "/"-separated path name that identifies the resource.
1021 * If the resource cannot be found, return <code>null</code>.
1022 * <p>
1023 * This method searches according to the following algorithm, returning
1024 * as soon as it finds the appropriate URL. If the resource cannot be
1025 * found, returns <code>null</code>.
1026 * <ul>
1027 * <li>If the <code>delegate</code> property is set to <code>true</code>,
1028 * call the <code>getResource()</code> method of the parent class
1029 * loader, if any.</li>
1030 * <li>Call <code>findResource()</code> to find this resource in our
1031 * locally defined repositories.</li>
1032 * <li>Call the <code>getResource()</code> method of the parent class
1033 * loader, if any.</li>
1034 * </ul>
1035 *
1036 * @param name Name of the resource to return a URL for
1037 */
1038 @Override
1039 public URL getResource(String name) {
1040
1041 if (log.isDebugEnabled())
1042 log.debug("getResource(" + name + ")");
1043 URL url = null;
1044
1045 // (1) Delegate to parent if requested
1046 if (delegate) {
1047 if (log.isDebugEnabled())
1048 log.debug(" Delegating to parent classloader " + parent);
1049 url = parent.getResource(name);
1050 if (url != null) {
1051 if (log.isDebugEnabled())
1052 log.debug(" --> Returning '" + url.toString() + "'");
1053 return (url);
1054 }
1055 }
1056
1057 // (2) Search local repositories
1058 url = findResource(name);
1059 if (url != null) {
1060 if (log.isDebugEnabled())
1061 log.debug(" --> Returning '" + url.toString() + "'");
1062 return (url);
1063 }
1064
1065 // (3) Delegate to parent unconditionally if not already attempted
1066 if( !delegate ) {
1067 url = parent.getResource(name);
1068 if (url != null) {
1069 if (log.isDebugEnabled())
1070 log.debug(" --> Returning '" + url.toString() + "'");
1071 return (url);
1072 }
1073 }
1074
1075 // (4) Resource was not found
1076 if (log.isDebugEnabled())
1077 log.debug(" --> Resource not found, returning null");
1078 return (null);
1079
1080 }
1081
1082
1083 /**
1084 * Find the resource with the given name, and return an input stream
1085 * that can be used for reading it. The search order is as described
1086 * for <code>getResource()</code>, after checking to see if the resource
1087 * data has been previously cached. If the resource cannot be found,
1088 * return <code>null</code>.
1089 *
1090 * @param name Name of the resource to return an input stream for
1091 */
1092 @Override
1093 public InputStream getResourceAsStream(String name) {
1094
1095 if (log.isDebugEnabled())
1096 log.debug("getResourceAsStream(" + name + ")");
1097 InputStream stream = null;
1098
1099 // (0) Check for a cached copy of this resource
1100 stream = findLoadedResource(name);
1101 if (stream != null) {
1102 if (log.isDebugEnabled())
1103 log.debug(" --> Returning stream from cache");
1104 return (stream);
1105 }
1106
1107 // (1) Delegate to parent if requested
1108 if (delegate) {
1109 if (log.isDebugEnabled())
1110 log.debug(" Delegating to parent classloader " + parent);
1111 stream = parent.getResourceAsStream(name);
1112 if (stream != null) {
1113 // FIXME - cache???
1114 if (log.isDebugEnabled())
1115 log.debug(" --> Returning stream from parent");
1116 return (stream);
1117 }
1118 }
1119
1120 // (2) Search local repositories
1121 if (log.isDebugEnabled())
1122 log.debug(" Searching local repositories");
1123 URL url = findResource(name);
1124 if (url != null) {
1125 // FIXME - cache???
1126 if (log.isDebugEnabled())
1127 log.debug(" --> Returning stream from local");
1128 stream = findLoadedResource(name);
1129 try {
1130 if (hasExternalRepositories && (stream == null))
1131 stream = url.openStream();
1132 } catch (IOException e) {
1133 // Ignore
1134 }
1135 if (stream != null)
1136 return (stream);
1137 }
1138
1139 // (3) Delegate to parent unconditionally
1140 if (!delegate) {
1141 if (log.isDebugEnabled())
1142 log.debug(" Delegating to parent classloader unconditionally " + parent);
1143 stream = parent.getResourceAsStream(name);
1144 if (stream != null) {
1145 // FIXME - cache???
1146 if (log.isDebugEnabled())
1147 log.debug(" --> Returning stream from parent");
1148 return (stream);
1149 }
1150 }
1151
1152 // (4) Resource was not found
1153 if (log.isDebugEnabled())
1154 log.debug(" --> Resource not found, returning null");
1155 return (null);
1156
1157 }
1158
1159
1160 /**
1161 * Load the class with the specified name. This method searches for
1162 * classes in the same manner as <code>loadClass(String, boolean)</code>
1163 * with <code>false</code> as the second argument.
1164 *
1165 * @param name The binary name of the class to be loaded
1166 *
1167 * @exception ClassNotFoundException if the class was not found
1168 */
1169 @Override
1170 public Class<?> loadClass(String name) throws ClassNotFoundException {
1171
1172 return (loadClass(name, false));
1173
1174 }
1175
1176
1177 /**
1178 * Load the class with the specified name, searching using the following
1179 * algorithm until it finds and returns the class. If the class cannot
1180 * be found, returns <code>ClassNotFoundException</code>.
1181 * <ul>
1182 * <li>Call <code>findLoadedClass(String)</code> to check if the
1183 * class has already been loaded. If it has, the same
1184 * <code>Class</code> object is returned.</li>
1185 * <li>If the <code>delegate</code> property is set to <code>true</code>,
1186 * call the <code>loadClass()</code> method of the parent class
1187 * loader, if any.</li>
1188 * <li>Call <code>findClass()</code> to find this class in our locally
1189 * defined repositories.</li>
1190 * <li>Call the <code>loadClass()</code> method of our parent
1191 * class loader, if any.</li>
1192 * </ul>
1193 * If the class was found using the above steps, and the
1194 * <code>resolve</code> flag is <code>true</code>, this method will then
1195 * call <code>resolveClass(Class)</code> on the resulting Class object.
1196 *
1197 * @param name The binary name of the class to be loaded
1198 * @param resolve If <code>true</code> then resolve the class
1199 *
1200 * @exception ClassNotFoundException if the class was not found
1201 */
1202 @Override
1203 public synchronized Class<?> loadClass(String name, boolean resolve)
1204 throws ClassNotFoundException {
1205
1206 if (log.isDebugEnabled())
1207 log.debug("loadClass(" + name + ", " + resolve + ")");
1208 Class<?> clazz = null;
1209
1210 // Log access to stopped class loader
1211 checkStateForClassLoading(name);
1212
1213 // (0) Check our previously loaded local class cache
1214 clazz = findLoadedClass0(name);
1215 if (clazz != null) {
1216 if (log.isDebugEnabled())
1217 log.debug(" Returning class from cache");
1218 if (resolve)
1219 resolveClass(clazz);
1220 return (clazz);
1221 }
1222
1223 // (0.1) Check our previously loaded class cache
1224 clazz = findLoadedClass(name);
1225 if (clazz != null) {
1226 if (log.isDebugEnabled())
1227 log.debug(" Returning class from cache");
1228 if (resolve)
1229 resolveClass(clazz);
1230 return (clazz);
1231 }
1232
1233 // (0.2) Try loading the class with the system class loader, to prevent
1234 // the webapp from overriding J2SE classes
1235 String resourceName = binaryNameToPath(name, false);
1236 ClassLoader javaseLoader = getJavaseClassLoader();
1237 if (javaseLoader.getResource(resourceName) != null) {
1238 try {
1239 clazz = javaseLoader.loadClass(name);
1240 if (clazz != null) {
1241 if (resolve)
1242 resolveClass(clazz);
1243 return (clazz);
1244 }
1245 } catch (ClassNotFoundException e) {
1246 // Ignore
1247 }
1248 }
1249
1250 // (0.5) Permission to access this class when using a SecurityManager
1251 if (securityManager != null) {
1252 int i = name.lastIndexOf('.');
1253 if (i >= 0) {
1254 try {
1255 securityManager.checkPackageAccess(name.substring(0,i));
1256 } catch (SecurityException se) {
1257 String error = "Security Violation, attempt to use " +
1258 "Restricted Class: " + name;
1259 log.info(error, se);
1260 throw new ClassNotFoundException(error, se);
1261 }
1262 }
1263 }
1264
1265 boolean delegateLoad = delegate || filter(name);
1266
1267 // (1) Delegate to our parent if requested
1268 if (delegateLoad) {
1269 if (log.isDebugEnabled())
1270 log.debug(" Delegating to parent classloader1 " + parent);
1271 try {
1272 clazz = Class.forName(name, false, parent);
1273 if (clazz != null) {
1274 if (log.isDebugEnabled())
1275 log.debug(" Loading class from parent");
1276 if (resolve)
1277 resolveClass(clazz);
1278 return (clazz);
1279 }
1280 } catch (ClassNotFoundException e) {
1281 // Ignore
1282 }
1283 }
1284
1285 // (2) Search local repositories
1286 if (log.isDebugEnabled())
1287 log.debug(" Searching local repositories");
1288 try {
1289 clazz = findClass(name);
1290 if (clazz != null) {
1291 if (log.isDebugEnabled())
1292 log.debug(" Loading class from local repository");
1293 if (resolve)
1294 resolveClass(clazz);
1295 return (clazz);
1296 }
1297 } catch (ClassNotFoundException e) {
1298 // Ignore
1299 }
1300
1301 // (3) Delegate to parent unconditionally
1302 if (!delegateLoad) {
1303 if (log.isDebugEnabled())
1304 log.debug(" Delegating to parent classloader at end: " + parent);
1305 try {
1306 clazz = Class.forName(name, false, parent);
1307 if (clazz != null) {
1308 if (log.isDebugEnabled())
1309 log.debug(" Loading class from parent");
1310 if (resolve)
1311 resolveClass(clazz);
1312 return (clazz);
1313 }
1314 } catch (ClassNotFoundException e) {
1315 // Ignore
1316 }
1317 }
1318
1319 throw new ClassNotFoundException(name);
1320 }
1321
1322
1323 protected void checkStateForClassLoading(String className) throws ClassNotFoundException {
1324 // It is not permitted to load new classes once the web application has
1325 // been stopped.
1326 if (!state.isAvailable()) {
1327 String msg = sm.getString("webappClassLoader.stopped", className);
1328 IllegalStateException cause = new IllegalStateException(msg);
1329 ClassNotFoundException cnfe = new ClassNotFoundException();
1330 cnfe.initCause(cause);
1331 log.info(msg, cnfe);
1332 throw cnfe;
1333 }
1334 }
1335
1336
1337 /**
1338 * Get the Permissions for a CodeSource. If this instance
1339 * of WebappClassLoader is for a web application context,
1340 * add read FilePermission or JndiPermissions for the base
1341 * directory (if unpacked),
1342 * the context URL, and jar file resources.
1343 *
1344 * @param codeSource where the code was loaded from
1345 * @return PermissionCollection for CodeSource
1346 */
1347 @Override
1348 protected PermissionCollection getPermissions(CodeSource codeSource) {
1349
1350 String codeUrl = codeSource.getLocation().toString();
1351 PermissionCollection pc;
1352 if ((pc = loaderPC.get(codeUrl)) == null) {
1353 pc = super.getPermissions(codeSource);
1354 if (pc != null) {
1355 Iterator<Permission> perms = permissionList.iterator();
1356 while (perms.hasNext()) {
1357 Permission p = perms.next();
1358 pc.add(p);
1359 }
1360 loaderPC.put(codeUrl,pc);
1361 }
1362 }
1363 return (pc);
1364
1365 }
1366
1367
1368 /**
1369 * {@inheritDoc}
1370 * <p>
1371 * Note that list of URLs returned by this method may not be complete. The
1372 * web application class loader accesses class loader resources via the
1373 * {@link WebResourceRoot} which supports the arbitrary mapping of
1374 * additional files, directories and contents of JAR files under
1375 * WEB-INF/classes. Any such resources will not be included in the URLs
1376 * returned here.
1377 */
1378 @Override
1379 public URL[] getURLs() {
1380 ArrayList<URL> result = new ArrayList<>();
1381 result.addAll(localRepositories);
1382 result.addAll(Arrays.asList(super.getURLs()));
1383 return result.toArray(new URL[result.size()]);
1384 }
1385
1386
1387 // ------------------------------------------------------ Lifecycle Methods
1388
1389
1390 /**
1391 * Add a lifecycle event listener to this component.
1392 *
1393 * @param listener The listener to add
1394 */
1395 @Override
1396 public void addLifecycleListener(LifecycleListener listener) {
1397 // NOOP
1398 }
1399
1400
1401 /**
1402 * Get the lifecycle listeners associated with this lifecycle. If this
1403 * Lifecycle has no listeners registered, a zero-length array is returned.
1404 */
1405 @Override
1406 public LifecycleListener[] findLifecycleListeners() {
1407 return new LifecycleListener[0];
1408 }
1409
1410
1411 /**
1412 * Remove a lifecycle event listener from this component.
1413 *
1414 * @param listener The listener to remove
1415 */
1416 @Override
1417 public void removeLifecycleListener(LifecycleListener listener) {
1418 // NOOP
1419 }
1420
1421
1422 /**
1423 * Obtain the current state of the source component.
1424 *
1425 * @return The current state of the source component.
1426 */
1427 @Override
1428 public LifecycleState getState() {
1429 return state;
1430 }
1431
1432
1433 /**
1434 * {@inheritDoc}
1435 */
1436 @Override
1437 public String getStateName() {
1438 return getState().toString();
1439 }
1440
1441
1442 @Override
1443 public void init() {
1444 state = LifecycleState.INITIALIZED;
1445 }
1446
1447
1448 /**
1449 * Start the class loader.
1450 *
1451 * @exception LifecycleException if a lifecycle error occurs
1452 */
1453 @Override
1454 public void start() throws LifecycleException {
1455
1456 state = LifecycleState.STARTING_PREP;
1457
1458 WebResource classes = resources.getResource("/WEB-INF/classes");
1459 if (classes.isDirectory() && classes.canRead()) {
1460 localRepositories.add(classes.getURL());
1461 }
1462 WebResource[] jars = resources.listResources("/WEB-INF/lib");
1463 for (WebResource jar : jars) {
1464 if (jar.getName().endsWith(".jar") && jar.isFile() && jar.canRead()) {
1465 localRepositories.add(jar.getURL());
1466 jarModificationTimes.put(
1467 jar.getName(), Long.valueOf(jar.getLastModified()));
1468 }
1469 }
1470
1471 state = LifecycleState.STARTING;
1472
1473 String encoding = null;
1474 try {
1475 encoding = System.getProperty("file.encoding");
1476 } catch (SecurityException e) {
1477 return;
1478 }
1479 if (encoding.indexOf("EBCDIC")!=-1) {
1480 needConvert = true;
1481 }
1482
1483 state = LifecycleState.STARTED;
1484 }
1485
1486
1487 /**
1488 * Stop the class loader.
1489 *
1490 * @exception LifecycleException if a lifecycle error occurs
1491 */
1492 @Override
1493 public void stop() throws LifecycleException {
1494
1495 state = LifecycleState.STOPPING_PREP;
1496
1497 // Clearing references should be done before setting started to
1498 // false, due to possible side effects
1499 clearReferences();
1500
1501 state = LifecycleState.STOPPING;
1502
1503 resourceEntries.clear();
1504 jarModificationTimes.clear();
1505 resources = null;
1506
1507 permissionList.clear();
1508 loaderPC.clear();
1509
1510 state = LifecycleState.STOPPED;
1511 }
1512
1513
1514 @Override
1515 public void destroy() {
1516 state = LifecycleState.DESTROYING;
1517
1518 try {
1519 super.close();
1520 } catch (IOException ioe) {
1521 log.warn(sm.getString("webappClassLoader.superCloseFail"), ioe);
1522 }
1523 state = LifecycleState.DESTROYED;
1524 }
1525
1526
1527 // ------------------------------------------------------ Protected Methods
1528
1529 protected ClassLoader getJavaseClassLoader() {
1530 return javaseClassLoader;
1531 }
1532
1533 protected void setJavaseClassLoader(ClassLoader classLoader) {
1534 if (classLoader == null) {
1535 throw new IllegalArgumentException(
1536 sm.getString("webappClassLoader.javaseClassLoaderNull"));
1537 }
1538 javaseClassLoader = classLoader;
1539 }
1540
1541 /**
1542 * Clear references.
1543 */
1544 protected void clearReferences() {
1545
1546 // De-register any remaining JDBC drivers
1547 clearReferencesJdbc();
1548
1549 // Stop any threads the web application started
1550 clearReferencesThreads();
1551
1552 // Check for leaks triggered by ThreadLocals loaded by this class loader
1553 checkThreadLocalsForLeaks();
1554
1555 // Clear RMI Targets loaded by this class loader
1556 clearReferencesRmiTargets();
1557
1558 // Null out any static or final fields from loaded classes,
1559 // as a workaround for apparent garbage collection bugs
1560 if (clearReferencesStatic) {
1561 clearReferencesStaticFinal();
1562 }
1563
1564 // Clear the IntrospectionUtils cache.
1565 IntrospectionUtils.clear();
1566
1567 // Clear the classloader reference in common-logging
1568 if (clearReferencesLogFactoryRelease) {
1569 org.apache.juli.logging.LogFactory.release(this);
1570 }
1571
1572 // Clear the resource bundle cache
1573 // This shouldn't be necessary, the cache uses weak references but
1574 // it has caused leaks. Oddly, using the leak detection code in
1575 // standard host allows the class loader to be GC'd. This has been seen
1576 // on Sun but not IBM JREs. Maybe a bug in Sun's GC impl?
1577 clearReferencesResourceBundles();
1578
1579 // Clear the classloader reference in the VM's bean introspector
1580 java.beans.Introspector.flushCaches();
1581
1582 // Clear any custom URLStreamHandlers
1583 TomcatURLStreamHandlerFactory.release(this);
1584 }
1585
1586
1587 /**
1588 * Deregister any JDBC drivers registered by the webapp that the webapp
1589 * forgot. This is made unnecessary complex because a) DriverManager
1590 * checks the class loader of the calling class (it would be much easier
1591 * if it checked the context class loader) b) using reflection would
1592 * create a dependency on the DriverManager implementation which can,
1593 * and has, changed.
1594 *
1595 * We can't just create an instance of JdbcLeakPrevention as it will be
1596 * loaded by the common class loader (since it's .class file is in the
1597 * $CATALINA_HOME/lib directory). This would fail DriverManager's check
1598 * on the class loader of the calling class. So, we load the bytes via
1599 * our parent class loader but define the class with this class loader
1600 * so the JdbcLeakPrevention looks like a webapp class to the
1601 * DriverManager.
1602 *
1603 * If only apps cleaned up after themselves...
1604 */
1605 private final void clearReferencesJdbc() {
1606 // We know roughly how big the class will be (~ 1K) so allow 2k as a
1607 // starting point
1608 byte[] classBytes = new byte[2048];
1609 int offset = 0;
1610 try (InputStream is = getResourceAsStream(
1611 "org/apache/catalina/loader/JdbcLeakPrevention.class")) {
1612 int read = is.read(classBytes, offset, classBytes.length-offset);
1613 while (read > -1) {
1614 offset += read;
1615 if (offset == classBytes.length) {
1616 // Buffer full - double size
1617 byte[] tmp = new byte[classBytes.length * 2];
1618 System.arraycopy(classBytes, 0, tmp, 0, classBytes.length);
1619 classBytes = tmp;
1620 }
1621 read = is.read(classBytes, offset, classBytes.length-offset);
1622 }
1623 Class<?> lpClass =
1624 defineClass("org.apache.catalina.loader.JdbcLeakPrevention",
1625 classBytes, 0, offset, this.getClass().getProtectionDomain());
1626 Object obj = lpClass.newInstance();
1627 @SuppressWarnings("unchecked")
1628 List<String> driverNames = (List<String>) obj.getClass().getMethod(
1629 "clearJdbcDriverRegistrations").invoke(obj);
1630 for (String name : driverNames) {
1631 log.warn(sm.getString("webappClassLoader.clearJdbc",
1632 getContextName(), name));
1633 }
1634 } catch (Exception e) {
1635 // So many things to go wrong above...
1636 Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
1637 ExceptionUtils.handleThrowable(t);
1638 log.warn(sm.getString(
1639 "webappClassLoader.jdbcRemoveFailed", getContextName()), t);
1640 }
1641 }
1642
1643
1644 private final void clearReferencesStaticFinal() {
1645
1646 Collection<ResourceEntry> values = resourceEntries.values();
1647 Iterator<ResourceEntry> loadedClasses = values.iterator();
1648 //
1649 // walk through all loaded class to trigger initialization for
1650 // any uninitialized classes, otherwise initialization of
1651 // one class may call a previously cleared class.
1652 while(loadedClasses.hasNext()) {
1653 ResourceEntry entry = loadedClasses.next();
1654 if (entry.loadedClass != null) {
1655 Class<?> clazz = entry.loadedClass;
1656 try {
1657 Field[] fields = clazz.getDeclaredFields();
1658 for (int i = 0; i < fields.length; i++) {
1659 if(Modifier.isStatic(fields[i].getModifiers())) {
1660 fields[i].get(null);
1661 break;
1662 }
1663 }
1664 } catch(Throwable t) {
1665 // Ignore
1666 }
1667 }
1668 }
1669 loadedClasses = values.iterator();
1670 while (loadedClasses.hasNext()) {
1671 ResourceEntry entry = loadedClasses.next();
1672 if (entry.loadedClass != null) {
1673 Class<?> clazz = entry.loadedClass;
1674 try {
1675 Field[] fields = clazz.getDeclaredFields();
1676 for (int i = 0; i < fields.length; i++) {
1677 Field field = fields[i];
1678 int mods = field.getModifiers();
1679 if (field.getType().isPrimitive()
1680 || (field.getName().indexOf("$") != -1)) {
1681 continue;
1682 }
1683 if (Modifier.isStatic(mods)) {
1684 try {
1685 field.setAccessible(true);
1686 if (Modifier.isFinal(mods)) {
1687 if (!((field.getType().getName().startsWith("java."))
1688 || (field.getType().getName().startsWith("javax.")))) {
1689 nullInstance(field.get(null));
1690 }
1691 } else {
1692 field.set(null, null);
1693 if (log.isDebugEnabled()) {
1694 log.debug("Set field " + field.getName()
1695 + " to null in class " + clazz.getName());
1696 }
1697 }
1698 } catch (Throwable t) {
1699 ExceptionUtils.handleThrowable(t);
1700 if (log.isDebugEnabled()) {
1701 log.debug("Could not set field " + field.getName()
1702 + " to null in class " + clazz.getName(), t);
1703 }
1704 }
1705 }
1706 }
1707 } catch (Throwable t) {
1708 ExceptionUtils.handleThrowable(t);
1709 if (log.isDebugEnabled()) {
1710 log.debug("Could not clean fields for class " + clazz.getName(), t);
1711 }
1712 }
1713 }
1714 }
1715
1716 }
1717
1718
1719 private void nullInstance(Object instance) {
1720 if (instance == null) {
1721 return;
1722 }
1723 Field[] fields = instance.getClass().getDeclaredFields();
1724 for (int i = 0; i < fields.length; i++) {
1725 Field field = fields[i];
1726 int mods = field.getModifiers();
1727 if (field.getType().isPrimitive()
1728 || (field.getName().indexOf("$") != -1)) {
1729 continue;
1730 }
1731 try {
1732 field.setAccessible(true);
1733 if (Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
1734 // Doing something recursively is too risky
1735 continue;
1736 }
1737 Object value = field.get(instance);
1738 if (null != value) {
1739 Class<? extends Object> valueClass = value.getClass();
1740 if (!loadedByThisOrChild(valueClass)) {
1741 if (log.isDebugEnabled()) {
1742 log.debug("Not setting field " + field.getName() +
1743 " to null in object of class " +
1744 instance.getClass().getName() +
1745 " because the referenced object was of type " +
1746 valueClass.getName() +
1747 " which was not loaded by this WebappClassLoader.");
1748 }
1749 } else {
1750 field.set(instance, null);
1751 if (log.isDebugEnabled()) {
1752 log.debug("Set field " + field.getName()
1753 + " to null in class " + instance.getClass().getName());
1754 }
1755 }
1756 }
1757 } catch (Throwable t) {
1758 ExceptionUtils.handleThrowable(t);
1759 if (log.isDebugEnabled()) {
1760 log.debug("Could not set field " + field.getName()
1761 + " to null in object instance of class "
1762 + instance.getClass().getName(), t);
1763 }
1764 }
1765 }
1766 }
1767
1768
1769 @SuppressWarnings("deprecation") // thread.stop()
1770 private void clearReferencesThreads() {
1771 Thread[] threads = getThreads();
1772 List<Thread> executorThreadsToStop = new ArrayList<>();
1773
1774 // Iterate over the set of threads
1775 for (Thread thread : threads) {
1776 if (thread != null) {
1777 ClassLoader ccl = thread.getContextClassLoader();
1778 if (ccl == this) {
1779 // Don't warn about this thread
1780 if (thread == Thread.currentThread()) {
1781 continue;
1782 }
1783
1784 final String threadName = thread.getName();
1785
1786 // JVM controlled threads
1787 ThreadGroup tg = thread.getThreadGroup();
1788 if (tg != null &&
1789 JVM_THREAD_GROUP_NAMES.contains(tg.getName())) {
1790
1791 // HttpClient keep-alive threads
1792 if (clearReferencesHttpClientKeepAliveThread &&
1793 threadName.equals("Keep-Alive-Timer")) {
1794 thread.setContextClassLoader(parent);
1795 log.debug(sm.getString(
1796 "webappClassLoader.checkThreadsHttpClient"));
1797 }
1798
1799 // Don't warn about remaining JVM controlled threads
1800 continue;
1801 }
1802
1803 // Skip threads that have already died
1804 if (!thread.isAlive()) {
1805 continue;
1806 }
1807
1808 // TimerThread can be stopped safely so treat separately
1809 // "java.util.TimerThread" in Sun/Oracle JDK
1810 // "java.util.Timer$TimerImpl" in Apache Harmony and in IBM JDK
1811 if (thread.getClass().getName().startsWith("java.util.Timer") &&
1812 clearReferencesStopTimerThreads) {
1813 clearReferencesStopTimerThread(thread);
1814 continue;
1815 }
1816
1817 if (isRequestThread(thread)) {
1818 log.warn(sm.getString("webappClassLoader.stackTraceRequestThread",
1819 getContextName(), threadName, getStackTrace(thread)));
1820 } else {
1821 log.warn(sm.getString("webappClassLoader.stackTrace",
1822 getContextName(), threadName, getStackTrace(thread)));
1823 }
1824
1825 // Don't try an stop the threads unless explicitly
1826 // configured to do so
1827 if (!clearReferencesStopThreads) {
1828 continue;
1829 }
1830
1831 // If the thread has been started via an executor, try
1832 // shutting down the executor
1833 boolean usingExecutor = false;
1834 try {
1835
1836 // Runnable wrapped by Thread
1837 // "target" in Sun/Oracle JDK
1838 // "runnable" in IBM JDK
1839 // "action" in Apache Harmony
1840 Object target = null;
1841 for (String fieldName : new String[] { "target",
1842 "runnable", "action" }) {
1843 try {
1844 Field targetField = thread.getClass()
1845 .getDeclaredField(fieldName);
1846 targetField.setAccessible(true);
1847 target = targetField.get(thread);
1848 break;
1849 } catch (NoSuchFieldException nfe) {
1850 continue;
1851 }
1852 }
1853
1854 // "java.util.concurrent" code is in public domain,
1855 // so all implementations are similar
1856 if (target != null &&
1857 target.getClass().getCanonicalName() != null
1858 && target.getClass().getCanonicalName().equals(
1859 "java.util.concurrent.ThreadPoolExecutor.Worker")) {
1860 Field executorField =
1861 target.getClass().getDeclaredField("this$0");
1862 executorField.setAccessible(true);
1863 Object executor = executorField.get(target);
1864 if (executor instanceof ThreadPoolExecutor) {
1865 ((ThreadPoolExecutor) executor).shutdownNow();
1866 usingExecutor = true;
1867 }
1868 }
1869 } catch (SecurityException e) {
1870 log.warn(sm.getString(
1871 "webappClassLoader.stopThreadFail",
1872 thread.getName(), getContextName()), e);
1873 } catch (NoSuchFieldException e) {
1874 log.warn(sm.getString(
1875 "webappClassLoader.stopThreadFail",
1876 thread.getName(), getContextName()), e);
1877 } catch (IllegalArgumentException e) {
1878 log.warn(sm.getString(
1879 "webappClassLoader.stopThreadFail",
1880 thread.getName(), getContextName()), e);
1881 } catch (IllegalAccessException e) {
1882 log.warn(sm.getString(
1883 "webappClassLoader.stopThreadFail",
1884 thread.getName(), getContextName()), e);
1885 }
1886
1887 if (usingExecutor) {
1888 // Executor may take a short time to stop all the
1889 // threads. Make a note of threads that should be
1890 // stopped and check them at the end of the method.
1891 executorThreadsToStop.add(thread);
1892 } else {
1893 // This method is deprecated and for good reason. This
1894 // is very risky code but is the only option at this
1895 // point. A *very* good reason for apps to do this
1896 // clean-up themselves.
1897 thread.stop();
1898 }
1899 }
1900 }
1901 }
1902
1903 // If thread stopping is enabled, executor threads should have been
1904 // stopped above when the executor was shut down but that depends on the
1905 // thread correctly handling the interrupt. Give all the executor
1906 // threads a few seconds shutdown and if they are still running
1907 // Give threads up to 2 seconds to shutdown
1908 int count = 0;
1909 for (Thread t : executorThreadsToStop) {
1910 while (t.isAlive() && count < 100) {
1911 try {
1912 Thread.sleep(20);
1913 } catch (InterruptedException e) {
1914 // Quit the while loop
1915 break;
1916 }
1917 count++;
1918 }
1919 if (t.isAlive()) {
1920 // This method is deprecated and for good reason. This is
1921 // very risky code but is the only option at this point.
1922 // A *very* good reason for apps to do this clean-up
1923 // themselves.
1924 t.stop();
1925 }
1926 }
1927 }
1928
1929
1930 /*
1931 * Look at a threads stack trace to see if it is a request thread or not. It
1932 * isn't perfect, but it should be good-enough for most cases.
1933 */
1934 private boolean isRequestThread(Thread thread) {
1935
1936 StackTraceElement[] elements = thread.getStackTrace();
1937
1938 if (elements == null || elements.length == 0) {
1939 // Must have stopped already. Too late to ignore it. Assume not a
1940 // request processing thread.
1941 return false;
1942 }
1943
1944 // Step through the methods in reverse order looking for calls to any
1945 // CoyoteAdapter method. All request threads will have this unless
1946 // Tomcat has been heavily modified - in which case there isn't much we
1947 // can do.
1948 for (int i = 0; i < elements.length; i++) {
1949 StackTraceElement element = elements[elements.length - (i+1)];
1950 if ("org.apache.catalina.connector.CoyoteAdapter".equals(
1951 element.getClassName())) {
1952 return true;
1953 }
1954 }
1955 return false;
1956 }
1957
1958
1959 private void clearReferencesStopTimerThread(Thread thread) {
1960
1961 // Need to get references to:
1962 // in Sun/Oracle JDK:
1963 // - newTasksMayBeScheduled field (in java.util.TimerThread)
1964 // - queue field
1965 // - queue.clear()
1966 // in IBM JDK, Apache Harmony:
1967 // - cancel() method (in java.util.Timer$TimerImpl)
1968
1969 try {
1970
1971 try {
1972 Field newTasksMayBeScheduledField =
1973 thread.getClass().getDeclaredField("newTasksMayBeScheduled");
1974 newTasksMayBeScheduledField.setAccessible(true);
1975 Field queueField = thread.getClass().getDeclaredField("queue");
1976 queueField.setAccessible(true);
1977
1978 Object queue = queueField.get(thread);
1979
1980 Method clearMethod = queue.getClass().getDeclaredMethod("clear");
1981 clearMethod.setAccessible(true);
1982
1983 synchronized(queue) {
1984 newTasksMayBeScheduledField.setBoolean(thread, false);
1985 clearMethod.invoke(queue);
1986 queue.notify(); // In case queue was already empty.
1987 }
1988
1989 }catch (NoSuchFieldException nfe){
1990 Method cancelMethod = thread.getClass().getDeclaredMethod("cancel");
1991 synchronized(thread) {
1992 cancelMethod.setAccessible(true);
1993 cancelMethod.invoke(thread);
1994 }
1995 }
1996
1997 log.warn(sm.getString("webappClassLoader.warnTimerThread",
1998 getContextName(), thread.getName()));
1999
2000 } catch (Exception e) {
2001 // So many things to go wrong above...
2002 Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
2003 ExceptionUtils.handleThrowable(t);
2004 log.warn(sm.getString(
2005 "webappClassLoader.stopTimerThreadFail",
2006 thread.getName(), getContextName()), t);
2007 }
2008 }
2009
2010 private void checkThreadLocalsForLeaks() {
2011 Thread[] threads = getThreads();
2012
2013 try {
2014 // Make the fields in the Thread class that store ThreadLocals
2015 // accessible
2016 Field threadLocalsField =
2017 Thread.class.getDeclaredField("threadLocals");
2018 threadLocalsField.setAccessible(true);
2019 Field inheritableThreadLocalsField =
2020 Thread.class.getDeclaredField("inheritableThreadLocals");
2021 inheritableThreadLocalsField.setAccessible(true);
2022 // Make the underlying array of ThreadLoad.ThreadLocalMap.Entry objects
2023 // accessible
2024 Class<?> tlmClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
2025 Field tableField = tlmClass.getDeclaredField("table");
2026 tableField.setAccessible(true);
2027 Method expungeStaleEntriesMethod = tlmClass.getDeclaredMethod("expungeStaleEntries");
2028 expungeStaleEntriesMethod.setAccessible(true);
2029
2030 for (int i = 0; i < threads.length; i++) {
2031 Object threadLocalMap;
2032 if (threads[i] != null) {
2033
2034 // Clear the first map
2035 threadLocalMap = threadLocalsField.get(threads[i]);
2036 if (null != threadLocalMap){
2037 expungeStaleEntriesMethod.invoke(threadLocalMap);
2038 checkThreadLocalMapForLeaks(threadLocalMap, tableField);
2039 }
2040
2041 // Clear the second map
2042 threadLocalMap =inheritableThreadLocalsField.get(threads[i]);
2043 if (null != threadLocalMap){
2044 expungeStaleEntriesMethod.invoke(threadLocalMap);
2045 checkThreadLocalMapForLeaks(threadLocalMap, tableField);
2046 }
2047 }
2048 }
2049 } catch (Throwable t) {
2050 ExceptionUtils.handleThrowable(t);
2051 log.warn(sm.getString(
2052 "webappClassLoader.checkThreadLocalsForLeaksFail",
2053 getContextName()), t);
2054 }
2055 }
2056
2057
2058 /**
2059 * Analyzes the given thread local map object. Also pass in the field that
2060 * points to the internal table to save re-calculating it on every
2061 * call to this method.
2062 */
2063 private void checkThreadLocalMapForLeaks(Object map,
2064 Field internalTableField) throws IllegalAccessException,
2065 NoSuchFieldException {
2066 if (map != null) {
2067 Object[] table = (Object[]) internalTableField.get(map);
2068 if (table != null) {
2069 for (int j =0; j < table.length; j++) {
2070 Object obj = table[j];
2071 if (obj != null) {
2072 boolean potentialLeak = false;
2073 // Check the key
2074 Object key = ((Reference<?>) obj).get();
2075 if (this.equals(key) || loadedByThisOrChild(key)) {
2076 potentialLeak = true;
2077 }
2078 // Check the value
2079 Field valueField =
2080 obj.getClass().getDeclaredField("value");
2081 valueField.setAccessible(true);
2082 Object value = valueField.get(obj);
2083 if (this.equals(value) || loadedByThisOrChild(value)) {
2084 potentialLeak = true;
2085 }
2086 if (potentialLeak) {
2087 Object[] args = new Object[5];
2088 args[0] = getContextName();
2089 if (key != null) {
2090 args[1] = getPrettyClassName(key.getClass());
2091 try {
2092 args[2] = key.toString();
2093 } catch (Exception e) {
2094 log.warn(sm.getString(
2095 "webappClassLoader.checkThreadLocalsForLeaks.badKey",
2096 args[1]), e);
2097 args[2] = sm.getString(
2098 "webappClassLoader.checkThreadLocalsForLeaks.unknown");
2099 }
2100 }
2101 if (value != null) {
2102 args[3] = getPrettyClassName(value.getClass());
2103 try {
2104 args[4] = value.toString();
2105 } catch (Exception e) {
2106 log.warn(sm.getString(
2107 "webappClassLoader.checkThreadLocalsForLeaks.badValue",
2108 args[3]), e);
2109 args[4] = sm.getString(
2110 "webappClassLoader.checkThreadLocalsForLeaks.unknown");
2111 }
2112 }
2113 if (value == null) {
2114 if (log.isDebugEnabled()) {
2115 log.debug(sm.getString(
2116 "webappClassLoader.checkThreadLocalsForLeaksDebug",
2117 args));
2118 }
2119 } else {
2120 log.error(sm.getString(
2121 "webappClassLoader.checkThreadLocalsForLeaks",
2122 args));
2123 }
2124 }
2125 }
2126 }
2127 }
2128 }
2129 }
2130
2131 private String getPrettyClassName(Class<?> clazz) {
2132 String name = clazz.getCanonicalName();
2133 if (name==null){
2134 name = clazz.getName();
2135 }
2136 return name;
2137 }
2138
2139 private String getStackTrace(Thread thread) {
2140 StringBuilder builder = new StringBuilder();
2141 for (StackTraceElement ste : thread.getStackTrace()) {
2142 builder.append("\n ").append(ste);
2143 }
2144 return builder.toString();
2145 }
2146
2147 /**
2148 * @param o object to test, may be null
2149 * @return <code>true</code> if o has been loaded by the current classloader
2150 * or one of its descendants.
2151 */
2152 private boolean loadedByThisOrChild(Object o) {
2153 if (o == null) {
2154 return false;
2155 }
2156
2157 Class<?> clazz;
2158 if (o instanceof Class) {
2159 clazz = (Class<?>) o;
2160 } else {
2161 clazz = o.getClass();
2162 }
2163
2164 ClassLoader cl = clazz.getClassLoader();
2165 while (cl != null) {
2166 if (cl == this) {
2167 return true;
2168 }
2169 cl = cl.getParent();
2170 }
2171
2172 if (o instanceof Collection<?>) {
2173 Iterator<?> iter = ((Collection<?>) o).iterator();
2174 try {
2175 while (iter.hasNext()) {
2176 Object entry = iter.next();
2177 if (loadedByThisOrChild(entry)) {
2178 return true;
2179 }
2180 }
2181 } catch (ConcurrentModificationException e) {
2182 log.warn(sm.getString(
2183 "webappClassLoader", clazz.getName(), getContextName()),
2184 e);
2185 }
2186 }
2187 return false;
2188 }
2189
2190 /*
2191 * Get the set of current threads as an array.
2192 */
2193 private Thread[] getThreads() {
2194 // Get the current thread group
2195 ThreadGroup tg = Thread.currentThread().getThreadGroup();
2196 // Find the root thread group
2197 try {
2198 while (tg.getParent() != null) {
2199 tg = tg.getParent();
2200 }
2201 } catch (SecurityException se) {
2202 String msg = sm.getString(
2203 "webappClassLoader.getThreadGroupError", tg.getName());
2204 if (log.isDebugEnabled()) {
2205 log.debug(msg, se);
2206 } else {
2207 log.warn(msg);
2208 }
2209 }
2210
2211 int threadCountGuess = tg.activeCount() + 50;
2212 Thread[] threads = new Thread[threadCountGuess];
2213 int threadCountActual = tg.enumerate(threads);
2214 // Make sure we don't miss any threads
2215 while (threadCountActual == threadCountGuess) {
2216 threadCountGuess *=2;
2217 threads = new Thread[threadCountGuess];
2218 // Note tg.enumerate(Thread[]) silently ignores any threads that
2219 // can't fit into the array
2220 threadCountActual = tg.enumerate(threads);
2221 }
2222
2223 return threads;
2224 }
2225
2226
2227 /**
2228 * This depends on the internals of the Sun JVM so it does everything by
2229 * reflection.
2230 */
2231 private void clearReferencesRmiTargets() {
2232 try {
2233 // Need access to the ccl field of sun.rmi.transport.Target
2234 Class<?> objectTargetClass =
2235 Class.forName("sun.rmi.transport.Target");
2236 Field cclField = objectTargetClass.getDeclaredField("ccl");
2237 cclField.setAccessible(true);
2238
2239 // Clear the objTable map
2240 Class<?> objectTableClass =
2241 Class.forName("sun.rmi.transport.ObjectTable");
2242 Field objTableField = objectTableClass.getDeclaredField("objTable");
2243 objTableField.setAccessible(true);
2244 Object objTable = objTableField.get(null);
2245 if (objTable == null) {
2246 return;
2247 }
2248
2249 // Iterate over the values in the table
2250 if (objTable instanceof Map<?,?>) {
2251 Iterator<?> iter = ((Map<?,?>) objTable).values().iterator();
2252 while (iter.hasNext()) {
2253 Object obj = iter.next();
2254 Object cclObject = cclField.get(obj);
2255 if (this == cclObject) {
2256 iter.remove();
2257 }
2258 }
2259 }
2260
2261 // Clear the implTable map
2262 Field implTableField = objectTableClass.getDeclaredField("implTable");
2263 implTableField.setAccessible(true);
2264 Object implTable = implTableField.get(null);
2265 if (implTable == null) {
2266 return;
2267 }
2268
2269 // Iterate over the values in the table
2270 if (implTable instanceof Map<?,?>) {
2271 Iterator<?> iter = ((Map<?,?>) implTable).values().iterator();
2272 while (iter.hasNext()) {
2273 Object obj = iter.next();
2274 Object cclObject = cclField.get(obj);
2275 if (this == cclObject) {
2276 iter.remove();
2277 }
2278 }
2279 }
2280 } catch (ClassNotFoundException e) {
2281 log.info(sm.getString("webappClassLoader.clearRmiInfo",
2282 getContextName()), e);
2283 } catch (SecurityException e) {
2284 log.warn(sm.getString("webappClassLoader.clearRmiFail",
2285 getContextName()), e);
2286 } catch (NoSuchFieldException e) {
2287 log.warn(sm.getString("webappClassLoader.clearRmiFail",
2288 getContextName()), e);
2289 } catch (IllegalArgumentException e) {
2290 log.warn(sm.getString("webappClassLoader.clearRmiFail",
2291 getContextName()), e);
2292 } catch (IllegalAccessException e) {
2293 log.warn(sm.getString("webappClassLoader.clearRmiFail",
2294 getContextName()), e);
2295 }
2296 }
2297
2298
2299 /**
2300 * Clear the {@link ResourceBundle} cache of any bundles loaded by this
2301 * class loader or any class loader where this loader is a parent class
2302 * loader. Whilst {@link ResourceBundle#clearCache()} could be used there
2303 * are complications around the
2304 * {@link org.apache.jasper.servlet.JasperLoader} that mean a reflection
2305 * based approach is more likely to be complete.
2306 *
2307 * The ResourceBundle is using WeakReferences so it shouldn't be pinning the
2308 * class loader in memory. However, it is. Therefore clear ou the
2309 * references.
2310 */
2311 private void clearReferencesResourceBundles() {
2312 // Get a reference to the cache
2313 try {
2314 Field cacheListField =
2315 ResourceBundle.class.getDeclaredField("cacheList");
2316 cacheListField.setAccessible(true);
2317
2318 // Java 6 uses ConcurrentMap
2319 // Java 5 uses SoftCache extends Abstract Map
2320 // So use Map and it *should* work with both
2321 Map<?,?> cacheList = (Map<?,?>) cacheListField.get(null);
2322
2323 // Get the keys (loader references are in the key)
2324 Set<?> keys = cacheList.keySet();
2325
2326 Field loaderRefField = null;
2327
2328 // Iterate over the keys looking at the loader instances
2329 Iterator<?> keysIter = keys.iterator();
2330
2331 int countRemoved = 0;
2332
2333 while (keysIter.hasNext()) {
2334 Object key = keysIter.next();
2335
2336 if (loaderRefField == null) {
2337 loaderRefField =
2338 key.getClass().getDeclaredField("loaderRef");
2339 loaderRefField.setAccessible(true);
2340 }
2341 WeakReference<?> loaderRef =
2342 (WeakReference<?>) loaderRefField.get(key);
2343
2344 ClassLoader loader = (ClassLoader) loaderRef.get();
2345
2346 while (loader != null && loader != this) {
2347 loader = loader.getParent();
2348 }
2349
2350 if (loader != null) {
2351 keysIter.remove();
2352 countRemoved++;
2353 }
2354 }
2355
2356 if (countRemoved > 0 && log.isDebugEnabled()) {
2357 log.debug(sm.getString(
2358 "webappClassLoader.clearReferencesResourceBundlesCount",
2359 Integer.valueOf(countRemoved), getContextName()));
2360 }
2361 } catch (SecurityException e) {
2362 log.warn(sm.getString(
2363 "webappClassLoader.clearReferencesResourceBundlesFail",
2364 getContextName()), e);
2365 } catch (NoSuchFieldException e) {
2366 if (Globals.IS_ORACLE_JVM) {
2367 log.warn(sm.getString(
2368 "webappClassLoader.clearReferencesResourceBundlesFail",
2369 getContextName()), e);
2370 } else {
2371 log.debug(sm.getString(
2372 "webappClassLoader.clearReferencesResourceBundlesFail",
2373 getContextName()), e);
2374 }
2375 } catch (IllegalArgumentException e) {
2376 log.warn(sm.getString(
2377 "webappClassLoader.clearReferencesResourceBundlesFail",
2378 getContextName()), e);
2379 } catch (IllegalAccessException e) {
2380 log.warn(sm.getString(
2381 "webappClassLoader.clearReferencesResourceBundlesFail",
2382 getContextName()), e);
2383 }
2384 }
2385
2386
2387 /**
2388 * Find specified class in local repositories.
2389 *
2390 * @param name The binary name of the class to be loaded
2391 *
2392 * @return the loaded class, or null if the class isn't found
2393 */
2394 protected Class<?> findClassInternal(String name) {
2395
2396 if (!validate(name)) {
2397 return null;
2398 }
2399
2400 String path = binaryNameToPath(name, true);
2401
2402 ResourceEntry entry = null;
2403
2404 if (securityManager != null) {
2405 PrivilegedAction<ResourceEntry> dp =
2406 new PrivilegedFindResourceByName(name, path);
2407 entry = AccessController.doPrivileged(dp);
2408 } else {
2409 entry = findResourceInternal(name, path);
2410 }
2411
2412 if (entry == null) {
2413 return null;
2414 }
2415
2416 Class<?> clazz = entry.loadedClass;
2417 if (clazz != null)
2418 return clazz;
2419
2420 synchronized (this) {
2421 clazz = entry.loadedClass;
2422 if (clazz != null)
2423 return clazz;
2424
2425 if (entry.binaryContent == null) {
2426 return null;
2427 }
2428
2429 // Looking up the package
2430 String packageName = null;
2431 int pos = name.lastIndexOf('.');
2432 if (pos != -1)
2433 packageName = name.substring(0, pos);
2434
2435 Package pkg = null;
2436
2437 if (packageName != null) {
2438 pkg = getPackage(packageName);
2439 // Define the package (if null)
2440 if (pkg == null) {
2441 try {
2442 if (entry.manifest == null) {
2443 definePackage(packageName, null, null, null, null,
2444 null, null, null);
2445 } else {
2446 definePackage(packageName, entry.manifest,
2447 entry.codeBase);
2448 }
2449 } catch (IllegalArgumentException e) {
2450 // Ignore: normal error due to dual definition of package
2451 }
2452 pkg = getPackage(packageName);
2453 }
2454 }
2455
2456 if (securityManager != null) {
2457
2458 // Checking sealing
2459 if (pkg != null) {
2460 boolean sealCheck = true;
2461 if (pkg.isSealed()) {
2462 sealCheck = pkg.isSealed(entry.codeBase);
2463 } else {
2464 sealCheck = (entry.manifest == null)
2465 || !isPackageSealed(packageName, entry.manifest);
2466 }
2467 if (!sealCheck)
2468 throw new SecurityException
2469 ("Sealing violation loading " + name + " : Package "
2470 + packageName + " is sealed.");
2471 }
2472
2473 }
2474
2475 try {
2476 clazz = defineClass(name, entry.binaryContent, 0,
2477 entry.binaryContent.length,
2478 new CodeSource(entry.codeBase, entry.certificates));
2479 } catch (UnsupportedClassVersionError ucve) {
2480 throw new UnsupportedClassVersionError(
2481 ucve.getLocalizedMessage() + " " +
2482 sm.getString("webappClassLoader.wrongVersion",
2483 name));
2484 }
2485 // Now the class has been defined, clear the elements of the local
2486 // resource cache that are no longer required.
2487 entry.loadedClass = clazz;
2488 entry.binaryContent = null;
2489 entry.codeBase = null;
2490 entry.manifest = null;
2491 entry.certificates = null;
2492 // Retain entry.source in case of a getResourceAsStream() call on
2493 // the class file after the class has been defined.
2494 }
2495
2496 return clazz;
2497 }
2498
2499
2500 private String binaryNameToPath(String binaryName, boolean withLeadingSlash) {
2501 // 1 for leading '/', 6 for ".class"
2502 StringBuilder path = new StringBuilder(7 + binaryName.length());
2503 if (withLeadingSlash) {
2504 path.append('/');
2505 }
2506 path.append(binaryName.replace('.', '/'));
2507 path.append(CLASS_FILE_SUFFIX);
2508 return path.toString();
2509 }
2510
2511
2512 private String nameToPath(String name) {
2513 if (name.startsWith("/")) {
2514 return name;
2515 }
2516 StringBuilder path = new StringBuilder(
2517 1 + name.length());
2518 path.append('/');
2519 path.append(name);
2520 return path.toString();
2521 }
2522
2523
2524 /**
2525 * Find specified resource in local repositories.
2526 *
2527 * @return the loaded resource, or null if the resource isn't found
2528 */
2529 protected ResourceEntry findResourceInternal(final String name, final String path) {
2530
2531 if (!state.isAvailable()) {
2532 log.info(sm.getString("webappClassLoader.stopped", name));
2533 return null;
2534 }
2535
2536 if (name == null || path == null) {
2537 return null;
2538 }
2539
2540 ResourceEntry entry = resourceEntries.get(path);
2541 if (entry != null) {
2542 return entry;
2543 }
2544
2545 boolean isClassResource = path.endsWith(CLASS_FILE_SUFFIX);
2546 boolean isCacheable = isClassResource;
2547 if (!isCacheable) {
2548 isCacheable = path.startsWith(SERVICES_PREFIX);
2549 }
2550
2551 WebResource resource = null;
2552
2553 boolean fileNeedConvert = false;
2554
2555 resource = resources.getClassLoaderResource(path);
2556
2557 if (!resource.exists()) {
2558 return null;
2559 }
2560
2561 entry = new ResourceEntry();
2562 entry.source = resource.getURL();
2563 entry.codeBase = entry.source;
2564 entry.lastModified = resource.getLastModified();
2565
2566 if (needConvert && path.endsWith(".properties")) {
2567 fileNeedConvert = true;
2568 }
2569
2570 /* Only cache the binary content if there is some content
2571 * available one of the following is true:
2572 * a) It is a class file since the binary content is only cached
2573 * until the class has been loaded
2574 * or
2575 * b) The file needs conversion to address encoding issues (see
2576 * below)
2577 * or
2578 * c) The resource is a service provider configuration file located
2579 * under META=INF/services
2580 *
2581 * In all other cases do not cache the content to prevent
2582 * excessive memory usage if large resources are present (see
2583 * https://issues.apache.org/bugzilla/show_bug.cgi?id=53081).
2584 */
2585 if (isCacheable || fileNeedConvert) {
2586 byte[] binaryContent = resource.getContent();
2587 if (binaryContent != null) {
2588 if (fileNeedConvert) {
2589 // Workaround for certain files on platforms that use
2590 // EBCDIC encoding, when they are read through FileInputStream.
2591 // See commit message of rev.303915 for details
2592 // http://svn.apache.org/viewvc?view=revision&revision=303915
2593 String str = new String(binaryContent);
2594 try {
2595 binaryContent = str.getBytes(StandardCharsets.UTF_8);
2596 } catch (Exception e) {
2597 return null;
2598 }
2599 }
2600 entry.binaryContent = binaryContent;
2601 // The certificates and manifest are made available as a side
2602 // effect of reading the binary content
2603 entry.certificates = resource.getCertificates();
2604 }
2605 }
2606 entry.manifest = resource.getManifest();
2607
2608 if (isClassResource && entry.binaryContent != null &&
2609 this.transformers.size() > 0) {
2610 // If the resource is a class just being loaded, decorate it
2611 // with any attached transformers
2612 String className = name.endsWith(CLASS_FILE_SUFFIX) ?
2613 name.substring(0, name.length() - CLASS_FILE_SUFFIX.length()) : name;
2614 String internalName = className.replace(".", "/");
2615
2616 for (ClassFileTransformer transformer : this.transformers) {
2617 try {
2618 byte[] transformed = transformer.transform(
2619 this, internalName, null, null, entry.binaryContent
2620 );
2621 if (transformed != null) {
2622 entry.binaryContent = transformed;
2623 }
2624 } catch (IllegalClassFormatException e) {
2625 log.error(sm.getString("webappClassLoader.transformError", name), e);
2626 return null;
2627 }
2628 }
2629 }
2630
2631 // Add the entry in the local resource repository
2632 synchronized (resourceEntries) {
2633 // Ensures that all the threads which may be in a race to load
2634 // a particular class all end up with the same ResourceEntry
2635 // instance
2636 ResourceEntry entry2 = resourceEntries.get(path);
2637 if (entry2 == null) {
2638 resourceEntries.put(path, entry);
2639 } else {
2640 entry = entry2;
2641 }
2642 }
2643
2644 return entry;
2645 }
2646
2647
2648 /**
2649 * Returns true if the specified package name is sealed according to the
2650 * given manifest.
2651 */
2652 protected boolean isPackageSealed(String name, Manifest man) {
2653
2654 String path = name.replace('.', '/') + '/';
2655 Attributes attr = man.getAttributes(path);
2656 String sealed = null;
2657 if (attr != null) {
2658 sealed = attr.getValue(Name.SEALED);
2659 }
2660 if (sealed == null) {
2661 if ((attr = man.getMainAttributes()) != null) {
2662 sealed = attr.getValue(Name.SEALED);
2663 }
2664 }
2665 return "true".equalsIgnoreCase(sealed);
2666
2667 }
2668
2669
2670 /**
2671 * Finds the resource with the given name if it has previously been
2672 * loaded and cached by this class loader, and return an input stream
2673 * to the resource data. If this resource has not been cached, return
2674 * <code>null</code>.
2675 *
2676 * @param name Name of the resource to return
2677 */
2678 protected InputStream findLoadedResource(String name) {
2679
2680 String path = nameToPath(name);
2681
2682 ResourceEntry entry = resourceEntries.get(path);
2683 if (entry != null) {
2684 if (entry.binaryContent != null)
2685 return new ByteArrayInputStream(entry.binaryContent);
2686 else {
2687 try {
2688 return entry.source.openStream();
2689 } catch (IOException ioe) {
2690 // Ignore
2691 }
2692 }
2693 }
2694 return null;
2695 }
2696
2697
2698 /**
2699 * Finds the class with the given name if it has previously been
2700 * loaded and cached by this class loader, and return the Class object.
2701 * If this class has not been cached, return <code>null</code>.
2702 *
2703 * @param name The binary name of the resource to return
2704 */
2705 protected Class<?> findLoadedClass0(String name) {
2706
2707 String path = binaryNameToPath(name, true);
2708
2709 ResourceEntry entry = resourceEntries.get(path);
2710 if (entry != null) {
2711 return entry.loadedClass;
2712 }
2713 return null;
2714 }
2715
2716
2717 /**
2718 * Refresh the system policy file, to pick up eventual changes.
2719 */
2720 protected void refreshPolicy() {
2721
2722 try {
2723 // The policy file may have been modified to adjust
2724 // permissions, so we're reloading it when loading or
2725 // reloading a Context
2726 Policy policy = Policy.getPolicy();
2727 policy.refresh();
2728 } catch (AccessControlException e) {
2729 // Some policy files may restrict this, even for the core,
2730 // so this exception is ignored
2731 }
2732
2733 }
2734
2735
2736 /**
2737 * Filter classes.
2738 *
2739 * @param name class name
2740 * @return true if the class should be filtered
2741 */
2742 protected synchronized boolean filter(String name) {
2743
2744 if (name == null)
2745 return false;
2746
2747 // Looking up the package
2748 String packageName = null;
2749 int pos = name.lastIndexOf('.');
2750 if (pos != -1)
2751 packageName = name.substring(0, pos);
2752 else
2753 return false;
2754
2755 packageTriggersPermit.reset(packageName);
2756 if (packageTriggersPermit.lookingAt()) {
2757 return false;
2758 }
2759
2760 packageTriggersDeny.reset(packageName);
2761 if (packageTriggersDeny.lookingAt()) {
2762 return true;
2763 }
2764
2765 return false;
2766 }
2767
2768
2769 /**
2770 * Validate a classname. As per SRV.9.7.2, we must restrict loading of
2771 * classes from J2SE (java.*) and most classes of the servlet API
2772 * (javax.servlet.*). That should enhance robustness and prevent a number
2773 * of user error (where an older version of servlet.jar would be present
2774 * in /WEB-INF/lib).
2775 *
2776 * @param name class name
2777 * @return true if the name is valid
2778 */
2779 protected boolean validate(String name) {
2780
2781 // Need to be careful with order here
2782 if (name == null) {
2783 // Can't load a class without a name
2784 return false;
2785 }
2786 if (name.startsWith("java.")) {
2787 // Must never load java.* classes
2788 return false;
2789 }
2790 if (name.startsWith("javax.servlet.jsp.jstl")) {
2791 // OK for web apps to package JSTL
2792 return true;
2793 }
2794 if (name.startsWith("javax.servlet.")) {
2795 // Web apps should never package any other Servlet or JSP classes
2796 return false;
2797 }
2798 if (name.startsWith("javax.el")) {
2799 // Must never load javax.el.* classes
2800 return false;
2801 }
2802
2803 // Assume everything else is OK
2804 return true;
2805
2806 }
2807
2808
2809 @Override
2810 protected void addURL(URL url) {
2811 super.addURL(url);
2812 hasExternalRepositories = true;
69 protected Object getClassLoadingLock(String className) {
70 return this;
281371 }
281472 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.catalina.loader;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.File;
20 import java.io.FilePermission;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.lang.instrument.ClassFileTransformer;
24 import java.lang.instrument.IllegalClassFormatException;
25 import java.lang.ref.Reference;
26 import java.lang.ref.WeakReference;
27 import java.lang.reflect.Field;
28 import java.lang.reflect.Method;
29 import java.lang.reflect.Modifier;
30 import java.net.URI;
31 import java.net.URISyntaxException;
32 import java.net.URL;
33 import java.net.URLClassLoader;
34 import java.nio.charset.StandardCharsets;
35 import java.security.AccessControlException;
36 import java.security.AccessController;
37 import java.security.CodeSource;
38 import java.security.Permission;
39 import java.security.PermissionCollection;
40 import java.security.Policy;
41 import java.security.PrivilegedAction;
42 import java.security.ProtectionDomain;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.ConcurrentModificationException;
48 import java.util.Date;
49 import java.util.Enumeration;
50 import java.util.HashMap;
51 import java.util.Iterator;
52 import java.util.LinkedHashSet;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Map.Entry;
56 import java.util.ResourceBundle;
57 import java.util.Set;
58 import java.util.concurrent.ConcurrentHashMap;
59 import java.util.concurrent.CopyOnWriteArrayList;
60 import java.util.concurrent.ThreadPoolExecutor;
61 import java.util.jar.Attributes;
62 import java.util.jar.Attributes.Name;
63 import java.util.jar.Manifest;
64 import java.util.regex.Matcher;
65 import java.util.regex.Pattern;
66
67 import org.apache.catalina.Globals;
68 import org.apache.catalina.Lifecycle;
69 import org.apache.catalina.LifecycleException;
70 import org.apache.catalina.LifecycleListener;
71 import org.apache.catalina.LifecycleState;
72 import org.apache.catalina.WebResource;
73 import org.apache.catalina.WebResourceRoot;
74 import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
75 import org.apache.tomcat.InstrumentableClassLoader;
76 import org.apache.tomcat.util.ExceptionUtils;
77 import org.apache.tomcat.util.IntrospectionUtils;
78 import org.apache.tomcat.util.res.StringManager;
79
80 /**
81 * Specialized web application class loader.
82 * <p>
83 * This class loader is a full reimplementation of the
84 * <code>URLClassLoader</code> from the JDK. It is designed to be fully
85 * compatible with a normal <code>URLClassLoader</code>, although its internal
86 * behavior may be completely different.
87 * <p>
88 * <strong>IMPLEMENTATION NOTE</strong> - By default, this class loader follows
89 * the delegation model required by the specification. The system class
90 * loader will be queried first, then the local repositories, and only then
91 * delegation to the parent class loader will occur. This allows the web
92 * application to override any shared class except the classes from J2SE.
93 * Special handling is provided from the JAXP XML parser interfaces, the JNDI
94 * interfaces, and the classes from the servlet API, which are never loaded
95 * from the webapp repositories. The <code>delegate</code> property
96 * allows an application to modify this behavior to move the parent class loader
97 * ahead of the local repositories.
98 * <p>
99 * <strong>IMPLEMENTATION NOTE</strong> - Due to limitations in Jasper
100 * compilation technology, any repository which contains classes from
101 * the servlet API will be ignored by the class loader.
102 * <p>
103 * <strong>IMPLEMENTATION NOTE</strong> - The class loader generates source
104 * URLs which include the full JAR URL when a class is loaded from a JAR file,
105 * which allows setting security permission at the class level, even when a
106 * class is contained inside a JAR.
107 * <p>
108 * <strong>IMPLEMENTATION NOTE</strong> - Local repositories are searched in
109 * the order they are added via the initial constructor and/or any subsequent
110 * calls to <code>addRepository()</code> or <code>addJar()</code>.
111 * <p>
112 * <strong>IMPLEMENTATION NOTE</strong> - No check for sealing violations or
113 * security is made unless a security manager is present.
114 * <p>
115 * <strong>IMPLEMENTATION NOTE</strong> - As of 8.0, this class
116 * loader implements {@link InstrumentableClassLoader}, permitting web
117 * application classes to instrument other classes in the same web
118 * application. It does not permit instrumentation of system or container
119 * classes or classes in other web apps.
120 *
121 * @author Remy Maucherat
122 * @author Craig R. McClanahan
123 */
124 public abstract class WebappClassLoaderBase extends URLClassLoader
125 implements Lifecycle, InstrumentableClassLoader {
126
127 private static final org.apache.juli.logging.Log log =
128 org.apache.juli.logging.LogFactory.getLog(WebappClassLoaderBase.class);
129
130 /**
131 * List of ThreadGroup names to ignore when scanning for web application
132 * started threads that need to be shut down.
133 */
134 private static final List<String> JVM_THREAD_GROUP_NAMES = new ArrayList<>();
135
136 private static final String JVM_THREAD_GROUP_SYSTEM = "system";
137
138 private static final String CLASS_FILE_SUFFIX = ".class";
139 private static final String SERVICES_PREFIX = "/META-INF/services/";
140
141 static {
142 ClassLoader.registerAsParallelCapable();
143 JVM_THREAD_GROUP_NAMES.add(JVM_THREAD_GROUP_SYSTEM);
144 JVM_THREAD_GROUP_NAMES.add("RMI Runtime");
145 }
146
147 protected class PrivilegedFindResourceByName
148 implements PrivilegedAction<ResourceEntry> {
149
150 protected final String name;
151 protected final String path;
152
153 PrivilegedFindResourceByName(String name, String path) {
154 this.name = name;
155 this.path = path;
156 }
157
158 @Override
159 public ResourceEntry run() {
160 return findResourceInternal(name, path);
161 }
162
163 }
164
165
166 protected static final class PrivilegedGetClassLoader
167 implements PrivilegedAction<ClassLoader> {
168
169 public final Class<?> clazz;
170
171 public PrivilegedGetClassLoader(Class<?> clazz){
172 this.clazz = clazz;
173 }
174
175 @Override
176 public ClassLoader run() {
177 return clazz.getClassLoader();
178 }
179 }
180
181
182 // ------------------------------------------------------- Static Variables
183
184 /**
185 * Regular expression of package names which are not allowed to be loaded
186 * from a webapp class loader without delegating first.
187 */
188 protected final Matcher packageTriggersDeny = Pattern.compile(
189 "^javax\\.el\\.|" +
190 "^javax\\.servlet\\.|" +
191 "^org\\.apache\\.(catalina|coyote|el|jasper|juli|naming|tomcat)\\."
192 ).matcher("");
193
194
195 /**
196 * Regular expression of package names which are allowed to be loaded from a
197 * webapp class loader without delegating first and override any set by
198 * {@link #packageTriggersDeny}.
199 */
200 protected final Matcher packageTriggersPermit =
201 Pattern.compile("^javax\\.servlet\\.jsp\\.jstl\\.|" +
202 "^org\\.apache\\.tomcat\\.jdbc\\.").matcher("");
203
204
205 /**
206 * The string manager for this package.
207 */
208 protected static final StringManager sm =
209 StringManager.getManager(Constants.Package);
210
211
212 // ----------------------------------------------------------- Constructors
213
214 /**
215 * Construct a new ClassLoader with no defined repositories and no
216 * parent ClassLoader.
217 */
218 protected WebappClassLoaderBase() {
219
220 super(new URL[0]);
221
222 ClassLoader p = getParent();
223 if (p == null) {
224 p = getSystemClassLoader();
225 }
226 this.parent = p;
227
228 ClassLoader j = String.class.getClassLoader();
229 if (j == null) {
230 j = getSystemClassLoader();
231 while (j.getParent() != null) {
232 j = j.getParent();
233 }
234 }
235 this.javaseClassLoader = j;
236
237 securityManager = System.getSecurityManager();
238 if (securityManager != null) {
239 refreshPolicy();
240 }
241 }
242
243
244 /**
245 * Construct a new ClassLoader with no defined repositories and the given
246 * parent ClassLoader.
247 * <p>
248 * Method is used via reflection -
249 * see {@link WebappLoader#createClassLoader()}
250 *
251 * @param parent Our parent class loader
252 */
253 protected WebappClassLoaderBase(ClassLoader parent) {
254
255 super(new URL[0], parent);
256
257 ClassLoader p = getParent();
258 if (p == null) {
259 p = getSystemClassLoader();
260 }
261 this.parent = p;
262
263 ClassLoader j = String.class.getClassLoader();
264 if (j == null) {
265 j = getSystemClassLoader();
266 while (j.getParent() != null) {
267 j = j.getParent();
268 }
269 }
270 this.javaseClassLoader = j;
271
272 securityManager = System.getSecurityManager();
273 if (securityManager != null) {
274 refreshPolicy();
275 }
276 }
277
278
279 // ----------------------------------------------------- Instance Variables
280
281 /**
282 * Associated web resources for this webapp.
283 */
284 protected WebResourceRoot resources = null;
285
286
287 /**
288 * The cache of ResourceEntry for classes and resources we have loaded,
289 * keyed by resource path, not binary name. Path is used as the key since
290 * resources may be requested by binary name (classes) or path (other
291 * resources such as property files) and the mapping from binary name to
292 * path is unambiguous but the reverse mapping is ambiguous.
293 */
294 protected final Map<String, ResourceEntry> resourceEntries =
295 new ConcurrentHashMap<>();
296
297
298 /**
299 * Should this class loader delegate to the parent class loader
300 * <strong>before</strong> searching its own repositories (i.e. the
301 * usual Java2 delegation model)? If set to <code>false</code>,
302 * this class loader will search its own repositories first, and
303 * delegate to the parent only if the class or resource is not
304 * found locally. Note that the default, <code>false</code>, is
305 * the behavior called for by the servlet specification.
306 */
307 protected boolean delegate = false;
308
309
310 private final HashMap<String,Long> jarModificationTimes = new HashMap<>();
311
312
313 /**
314 * A list of read File and Jndi Permission's required if this loader
315 * is for a web application context.
316 */
317 protected final ArrayList<Permission> permissionList = new ArrayList<>();
318
319
320 /**
321 * The PermissionCollection for each CodeSource for a web
322 * application context.
323 */
324 protected final HashMap<String, PermissionCollection> loaderPC = new HashMap<>();
325
326
327 /**
328 * Instance of the SecurityManager installed.
329 */
330 protected final SecurityManager securityManager;
331
332
333 /**
334 * The parent class loader.
335 */
336 protected final ClassLoader parent;
337
338
339 /**
340 * The bootstrap class loader used to load the JavaSE classes. In some
341 * implementations this class loader is always <code>null</null> and in
342 * those cases {@link ClassLoader#getParent()} will be called recursively on
343 * the system class loader and the last non-null result used.
344 */
345 private ClassLoader javaseClassLoader;
346
347
348 /**
349 * need conversion for properties files
350 */
351 protected boolean needConvert = false;
352
353
354 /**
355 * All permission.
356 */
357 protected final Permission allPermission = new java.security.AllPermission();
358
359
360 /**
361 * Should Tomcat attempt to null out any static or final fields from loaded
362 * classes when a web application is stopped as a work around for apparent
363 * garbage collection bugs and application coding errors? There have been
364 * some issues reported with log4j when this option is true. Applications
365 * without memory leaks using recent JVMs should operate correctly with this
366 * option set to <code>false</code>. If not specified, the default value of
367 * <code>false</code> will be used.
368 */
369 private boolean clearReferencesStatic = false;
370
371 /**
372 * Should Tomcat attempt to terminate threads that have been started by the
373 * web application? Stopping threads is performed via the deprecated (for
374 * good reason) <code>Thread.stop()</code> method and is likely to result in
375 * instability. As such, enabling this should be viewed as an option of last
376 * resort in a development environment and is not recommended in a
377 * production environment. If not specified, the default value of
378 * <code>false</code> will be used.
379 */
380 private boolean clearReferencesStopThreads = false;
381
382 /**
383 * Should Tomcat attempt to terminate any {@link java.util.TimerThread}s
384 * that have been started by the web application? If not specified, the
385 * default value of <code>false</code> will be used.
386 */
387 private boolean clearReferencesStopTimerThreads = false;
388
389 /**
390 * Should Tomcat call {@link org.apache.juli.logging.LogFactory#release()}
391 * when the class loader is stopped? If not specified, the default value
392 * of <code>true</code> is used. Changing the default setting is likely to
393 * lead to memory leaks and other issues.
394 */
395 private boolean clearReferencesLogFactoryRelease = true;
396
397 /**
398 * If an HttpClient keep-alive timer thread has been started by this web
399 * application and is still running, should Tomcat change the context class
400 * loader from the current {@link ClassLoader} to
401 * {@link ClassLoader#getParent()} to prevent a memory leak? Note that the
402 * keep-alive timer thread will stop on its own once the keep-alives all
403 * expire however, on a busy system that might not happen for some time.
404 */
405 private boolean clearReferencesHttpClientKeepAliveThread = true;
406
407 /**
408 * Holds the class file transformers decorating this class loader. The
409 * CopyOnWriteArrayList is thread safe. It is expensive on writes, but
410 * those should be rare. It is very fast on reads, since synchronization
411 * is not actually used. Importantly, the ClassLoader will never block
412 * iterating over the transformers while loading a class.
413 */
414 private final List<ClassFileTransformer> transformers = new CopyOnWriteArrayList<>();
415
416
417 /**
418 * Flag that indicates that {@link #addURL(URL)} has been called which
419 * creates a requirement to check the super class when searching for
420 * resources.
421 */
422 private boolean hasExternalRepositories = false;
423
424
425 /**
426 * Repositories managed by this class rather than the super class.
427 */
428 private List<URL> localRepositories = new ArrayList<>();
429
430
431 private volatile LifecycleState state = LifecycleState.NEW;
432
433
434 // ------------------------------------------------------------- Properties
435
436 /**
437 * Get associated resources.
438 */
439 public WebResourceRoot getResources() {
440 return this.resources;
441 }
442
443
444 /**
445 * Set associated resources.
446 */
447 public void setResources(WebResourceRoot resources) {
448 this.resources = resources;
449 }
450
451
452 /**
453 * Return the context name for this class loader.
454 */
455 public String getContextName() {
456 if (resources == null) {
457 return "Unknown";
458 } else {
459 return resources.getContext().getName();
460 }
461 }
462
463
464 /**
465 * Return the "delegate first" flag for this class loader.
466 */
467 public boolean getDelegate() {
468
469 return (this.delegate);
470
471 }
472
473
474 /**
475 * Set the "delegate first" flag for this class loader.
476 * If this flag is true, this class loader delegates
477 * to the parent class loader
478 * <strong>before</strong> searching its own repositories, as
479 * in an ordinary (non-servlet) chain of Java class loaders.
480 * If set to <code>false</code> (the default),
481 * this class loader will search its own repositories first, and
482 * delegate to the parent only if the class or resource is not
483 * found locally, as per the servlet specification.
484 *
485 * @param delegate The new "delegate first" flag
486 */
487 public void setDelegate(boolean delegate) {
488 this.delegate = delegate;
489 }
490
491
492 /**
493 * If there is a Java SecurityManager create a read permission for the
494 * target of the given URL as appropriate.
495 *
496 * @param url URL for a file or directory on local system
497 */
498 void addPermission(URL url) {
499 if (url == null) {
500 return;
501 }
502 if (securityManager != null) {
503 String protocol = url.getProtocol();
504 if ("file".equalsIgnoreCase(protocol)) {
505 URI uri;
506 File f;
507 String path;
508 try {
509 uri = url.toURI();
510 f = new File(uri);
511 path = f.getCanonicalPath();
512 } catch (IOException | URISyntaxException e) {
513 log.warn(sm.getString(
514 "webappClassLoader.addPermisionNoCanonicalFile",
515 url.toExternalForm()));
516 return;
517 }
518 if (f.isFile()) {
519 // Allow the file to be read
520 addPermission(new FilePermission(path, "read"));
521 } else if (f.isDirectory()) {
522 addPermission(new FilePermission(path, "read"));
523 addPermission(new FilePermission(
524 path + File.separator + "-", "read"));
525 } else {
526 // File does not exist - ignore (shouldn't happen)
527 }
528 } else {
529 // Unsupported URL protocol
530 log.warn(sm.getString(
531 "webappClassLoader.addPermisionNoProtocol",
532 protocol, url.toExternalForm()));
533 }
534 }
535 }
536
537
538 /**
539 * If there is a Java SecurityManager create a Permission.
540 *
541 * @param permission The permission
542 */
543 void addPermission(Permission permission) {
544 if ((securityManager != null) && (permission != null)) {
545 permissionList.add(permission);
546 }
547 }
548
549
550 /**
551 * Return the clearReferencesStatic flag for this Context.
552 */
553 public boolean getClearReferencesStatic() {
554 return (this.clearReferencesStatic);
555 }
556
557
558 /**
559 * Set the clearReferencesStatic feature for this Context.
560 *
561 * @param clearReferencesStatic The new flag value
562 */
563 public void setClearReferencesStatic(boolean clearReferencesStatic) {
564 this.clearReferencesStatic = clearReferencesStatic;
565 }
566
567
568 /**
569 * Return the clearReferencesStopThreads flag for this Context.
570 */
571 public boolean getClearReferencesStopThreads() {
572 return (this.clearReferencesStopThreads);
573 }
574
575
576 /**
577 * Set the clearReferencesStopThreads feature for this Context.
578 *
579 * @param clearReferencesStopThreads The new flag value
580 */
581 public void setClearReferencesStopThreads(
582 boolean clearReferencesStopThreads) {
583 this.clearReferencesStopThreads = clearReferencesStopThreads;
584 }
585
586
587 /**
588 * Return the clearReferencesStopTimerThreads flag for this Context.
589 */
590 public boolean getClearReferencesStopTimerThreads() {
591 return (this.clearReferencesStopTimerThreads);
592 }
593
594
595 /**
596 * Set the clearReferencesStopTimerThreads feature for this Context.
597 *
598 * @param clearReferencesStopTimerThreads The new flag value
599 */
600 public void setClearReferencesStopTimerThreads(
601 boolean clearReferencesStopTimerThreads) {
602 this.clearReferencesStopTimerThreads = clearReferencesStopTimerThreads;
603 }
604
605
606 /**
607 * Return the clearReferencesLogFactoryRelease flag for this Context.
608 */
609 public boolean getClearReferencesLogFactoryRelease() {
610 return (this.clearReferencesLogFactoryRelease);
611 }
612
613
614 /**
615 * Set the clearReferencesLogFactoryRelease feature for this Context.
616 *
617 * @param clearReferencesLogFactoryRelease The new flag value
618 */
619 public void setClearReferencesLogFactoryRelease(
620 boolean clearReferencesLogFactoryRelease) {
621 this.clearReferencesLogFactoryRelease =
622 clearReferencesLogFactoryRelease;
623 }
624
625
626 /**
627 * Return the clearReferencesHttpClientKeepAliveThread flag for this
628 * Context.
629 */
630 public boolean getClearReferencesHttpClientKeepAliveThread() {
631 return (this.clearReferencesHttpClientKeepAliveThread);
632 }
633
634
635 /**
636 * Set the clearReferencesHttpClientKeepAliveThread feature for this
637 * Context.
638 *
639 * @param clearReferencesHttpClientKeepAliveThread The new flag value
640 */
641 public void setClearReferencesHttpClientKeepAliveThread(
642 boolean clearReferencesHttpClientKeepAliveThread) {
643 this.clearReferencesHttpClientKeepAliveThread =
644 clearReferencesHttpClientKeepAliveThread;
645 }
646
647
648 // ------------------------------------------------------- Reloader Methods
649
650 /**
651 * Adds the specified class file transformer to this class loader. The
652 * transformer will then be able to modify the bytecode of any classes
653 * loaded by this class loader after the invocation of this method.
654 *
655 * @param transformer The transformer to add to the class loader
656 */
657 @Override
658 public void addTransformer(ClassFileTransformer transformer) {
659
660 if (transformer == null) {
661 throw new IllegalArgumentException(sm.getString(
662 "webappClassLoader.addTransformer.illegalArgument", getContextName()));
663 }
664
665 if (this.transformers.contains(transformer)) {
666 // if the same instance of this transformer was already added, bail out
667 log.warn(sm.getString("webappClassLoader.addTransformer.duplicate",
668 transformer, getContextName()));
669 return;
670 }
671 this.transformers.add(transformer);
672
673 log.info(sm.getString("webappClassLoader.addTransformer", transformer, getContextName()));
674 }
675
676 /**
677 * Removes the specified class file transformer from this class loader.
678 * It will no longer be able to modify the byte code of any classes
679 * loaded by the class loader after the invocation of this method.
680 * However, any classes already modified by this transformer will
681 * remain transformed.
682 *
683 * @param transformer The transformer to remove
684 */
685 @Override
686 public void removeTransformer(ClassFileTransformer transformer) {
687
688 if (transformer == null) {
689 return;
690 }
691
692 if (this.transformers.remove(transformer)) {
693 log.info(sm.getString("webappClassLoader.removeTransformer",
694 transformer, getContextName()));
695 return;
696 }
697
698 }
699
700 protected void copyStateWithoutTransformers(WebappClassLoaderBase base) {
701 base.resources = this.resources;
702 base.delegate = this.delegate;
703 base.state = LifecycleState.NEW;
704 base.needConvert = this.needConvert;
705 base.clearReferencesStatic = this.clearReferencesStatic;
706 base.clearReferencesStopThreads = this.clearReferencesStopThreads;
707 base.clearReferencesStopTimerThreads = this.clearReferencesStopTimerThreads;
708 base.clearReferencesLogFactoryRelease = this.clearReferencesLogFactoryRelease;
709 base.clearReferencesHttpClientKeepAliveThread = this.clearReferencesHttpClientKeepAliveThread;
710 base.jarModificationTimes.putAll(this.jarModificationTimes);
711 base.permissionList.addAll(this.permissionList);
712 base.loaderPC.putAll(this.loaderPC);
713 }
714
715 /**
716 * Have one or more classes or resources been modified so that a reload
717 * is appropriate?
718 */
719 public boolean modified() {
720
721 if (log.isDebugEnabled())
722 log.debug("modified()");
723
724 for (Entry<String,ResourceEntry> entry : resourceEntries.entrySet()) {
725 long cachedLastModified = entry.getValue().lastModified;
726 long lastModified = resources.getClassLoaderResource(
727 entry.getKey()).getLastModified();
728 if (lastModified != cachedLastModified) {
729 if( log.isDebugEnabled() )
730 log.debug(sm.getString("webappClassLoader.resourceModified",
731 entry.getKey(),
732 new Date(cachedLastModified),
733 new Date(lastModified)));
734 return true;
735 }
736 }
737
738 // Check if JARs have been added or removed
739 WebResource[] jars = resources.listResources("/WEB-INF/lib");
740 // Filter out non-JAR resources
741
742 int jarCount = 0;
743 for (WebResource jar : jars) {
744 if (jar.getName().endsWith(".jar") && jar.isFile() && jar.canRead()) {
745 jarCount++;
746 Long recordedLastModified = jarModificationTimes.get(jar.getName());
747 if (recordedLastModified == null) {
748 // Jar has been added
749 log.info(sm.getString("webappClassLoader.jarsAdded",
750 resources.getContext().getName()));
751 return true;
752 }
753 if (recordedLastModified.longValue() != jar.getLastModified()) {
754 // Jar has been changed
755 log.info(sm.getString("webappClassLoader.jarsModified",
756 resources.getContext().getName()));
757 return true;
758 }
759 }
760 }
761
762 if (jarCount < jarModificationTimes.size()){
763 log.info(sm.getString("webappClassLoader.jarsRemoved",
764 resources.getContext().getName()));
765 return true;
766 }
767
768
769 // No classes have been modified
770 return false;
771 }
772
773
774 /**
775 * Render a String representation of this object.
776 */
777 @Override
778 public String toString() {
779
780 StringBuilder sb = new StringBuilder(this.getClass().getSimpleName());
781 sb.append("\r\n context: ");
782 sb.append(getContextName());
783 sb.append("\r\n delegate: ");
784 sb.append(delegate);
785 sb.append("\r\n");
786 if (this.parent != null) {
787 sb.append("----------> Parent Classloader:\r\n");
788 sb.append(this.parent.toString());
789 sb.append("\r\n");
790 }
791 if (this.transformers.size() > 0) {
792 sb.append("----------> Class file transformers:\r\n");
793 for (ClassFileTransformer transformer : this.transformers) {
794 sb.append(transformer).append("\r\n");
795 }
796 }
797 return (sb.toString());
798 }
799
800
801 // ---------------------------------------------------- ClassLoader Methods
802
803
804 /**
805 * Expose this method for use by the unit tests.
806 */
807 protected final Class<?> doDefineClass(String name, byte[] b, int off, int len,
808 ProtectionDomain protectionDomain) {
809 return super.defineClass(name, b, off, len, protectionDomain);
810 }
811
812 /**
813 * Find the specified class in our local repositories, if possible. If
814 * not found, throw <code>ClassNotFoundException</code>.
815 *
816 * @param name The binary name of the class to be loaded
817 *
818 * @exception ClassNotFoundException if the class was not found
819 */
820 @Override
821 public Class<?> findClass(String name) throws ClassNotFoundException {
822
823 if (log.isDebugEnabled())
824 log.debug(" findClass(" + name + ")");
825
826 checkStateForClassLoading(name);
827
828 // (1) Permission to define this class when using a SecurityManager
829 if (securityManager != null) {
830 int i = name.lastIndexOf('.');
831 if (i >= 0) {
832 try {
833 if (log.isTraceEnabled())
834 log.trace(" securityManager.checkPackageDefinition");
835 securityManager.checkPackageDefinition(name.substring(0,i));
836 } catch (Exception se) {
837 if (log.isTraceEnabled())
838 log.trace(" -->Exception-->ClassNotFoundException", se);
839 throw new ClassNotFoundException(name, se);
840 }
841 }
842 }
843
844 // Ask our superclass to locate this class, if possible
845 // (throws ClassNotFoundException if it is not found)
846 Class<?> clazz = null;
847 try {
848 if (log.isTraceEnabled())
849 log.trace(" findClassInternal(" + name + ")");
850 try {
851 clazz = findClassInternal(name);
852 } catch(AccessControlException ace) {
853 log.warn("WebappClassLoader.findClassInternal(" + name
854 + ") security exception: " + ace.getMessage(), ace);
855 throw new ClassNotFoundException(name, ace);
856 } catch (RuntimeException e) {
857 if (log.isTraceEnabled())
858 log.trace(" -->RuntimeException Rethrown", e);
859 throw e;
860 }
861 if ((clazz == null) && hasExternalRepositories) {
862 try {
863 clazz = super.findClass(name);
864 } catch(AccessControlException ace) {
865 log.warn("WebappClassLoader.findClassInternal(" + name
866 + ") security exception: " + ace.getMessage(), ace);
867 throw new ClassNotFoundException(name, ace);
868 } catch (RuntimeException e) {
869 if (log.isTraceEnabled())
870 log.trace(" -->RuntimeException Rethrown", e);
871 throw e;
872 }
873 }
874 if (clazz == null) {
875 if (log.isDebugEnabled())
876 log.debug(" --> Returning ClassNotFoundException");
877 throw new ClassNotFoundException(name);
878 }
879 } catch (ClassNotFoundException e) {
880 if (log.isTraceEnabled())
881 log.trace(" --> Passing on ClassNotFoundException");
882 throw e;
883 }
884
885 // Return the class we have located
886 if (log.isTraceEnabled())
887 log.debug(" Returning class " + clazz);
888
889 if (log.isTraceEnabled()) {
890 ClassLoader cl;
891 if (Globals.IS_SECURITY_ENABLED){
892 cl = AccessController.doPrivileged(
893 new PrivilegedGetClassLoader(clazz));
894 } else {
895 cl = clazz.getClassLoader();
896 }
897 log.debug(" Loaded by " + cl.toString());
898 }
899 return (clazz);
900
901 }
902
903
904 /**
905 * Find the specified resource in our local repository, and return a
906 * <code>URL</code> referring to it, or <code>null</code> if this resource
907 * cannot be found.
908 *
909 * @param name Name of the resource to be found
910 */
911 @Override
912 public URL findResource(final String name) {
913
914 if (log.isDebugEnabled())
915 log.debug(" findResource(" + name + ")");
916
917 URL url = null;
918
919 String path = nameToPath(name);
920
921 ResourceEntry entry = resourceEntries.get(path);
922 if (entry == null) {
923 if (securityManager != null) {
924 PrivilegedAction<ResourceEntry> dp =
925 new PrivilegedFindResourceByName(name, path);
926 entry = AccessController.doPrivileged(dp);
927 } else {
928 entry = findResourceInternal(name, path);
929 }
930 }
931 if (entry != null) {
932 url = entry.source;
933 }
934
935 if ((url == null) && hasExternalRepositories) {
936 url = super.findResource(name);
937 }
938
939 if (log.isDebugEnabled()) {
940 if (url != null)
941 log.debug(" --> Returning '" + url.toString() + "'");
942 else
943 log.debug(" --> Resource not found, returning null");
944 }
945 return (url);
946
947 }
948
949
950 /**
951 * Return an enumeration of <code>URLs</code> representing all of the
952 * resources with the given name. If no resources with this name are
953 * found, return an empty enumeration.
954 *
955 * @param name Name of the resources to be found
956 *
957 * @exception IOException if an input/output error occurs
958 */
959 @Override
960 public Enumeration<URL> findResources(String name) throws IOException {
961
962 if (log.isDebugEnabled())
963 log.debug(" findResources(" + name + ")");
964
965 LinkedHashSet<URL> result = new LinkedHashSet<>();
966
967 String path = nameToPath(name);
968
969 WebResource[] webResources = resources.getClassLoaderResources(path);
970 for (WebResource webResource : webResources) {
971 if (webResource.exists()) {
972 result.add(webResource.getURL());
973 }
974 }
975
976 // Adding the results of a call to the superclass
977 if (hasExternalRepositories) {
978 Enumeration<URL> otherResourcePaths = super.findResources(name);
979 while (otherResourcePaths.hasMoreElements()) {
980 result.add(otherResourcePaths.nextElement());
981 }
982 }
983
984 return Collections.enumeration(result);
985 }
986
987
988 /**
989 * Find the resource with the given name. A resource is some data
990 * (images, audio, text, etc.) that can be accessed by class code in a
991 * way that is independent of the location of the code. The name of a
992 * resource is a "/"-separated path name that identifies the resource.
993 * If the resource cannot be found, return <code>null</code>.
994 * <p>
995 * This method searches according to the following algorithm, returning
996 * as soon as it finds the appropriate URL. If the resource cannot be
997 * found, returns <code>null</code>.
998 * <ul>
999 * <li>If the <code>delegate</code> property is set to <code>true</code>,
1000 * call the <code>getResource()</code> method of the parent class
1001 * loader, if any.</li>
1002 * <li>Call <code>findResource()</code> to find this resource in our
1003 * locally defined repositories.</li>
1004 * <li>Call the <code>getResource()</code> method of the parent class
1005 * loader, if any.</li>
1006 * </ul>
1007 *
1008 * @param name Name of the resource to return a URL for
1009 */
1010 @Override
1011 public URL getResource(String name) {
1012
1013 if (log.isDebugEnabled())
1014 log.debug("getResource(" + name + ")");
1015 URL url = null;
1016
1017 // (1) Delegate to parent if requested
1018 if (delegate) {
1019 if (log.isDebugEnabled())
1020 log.debug(" Delegating to parent classloader " + parent);
1021 url = parent.getResource(name);
1022 if (url != null) {
1023 if (log.isDebugEnabled())
1024 log.debug(" --> Returning '" + url.toString() + "'");
1025 return (url);
1026 }
1027 }
1028
1029 // (2) Search local repositories
1030 url = findResource(name);
1031 if (url != null) {
1032 if (log.isDebugEnabled())
1033 log.debug(" --> Returning '" + url.toString() + "'");
1034 return (url);
1035 }
1036
1037 // (3) Delegate to parent unconditionally if not already attempted
1038 if( !delegate ) {
1039 url = parent.getResource(name);
1040 if (url != null) {
1041 if (log.isDebugEnabled())
1042 log.debug(" --> Returning '" + url.toString() + "'");
1043 return (url);
1044 }
1045 }
1046
1047 // (4) Resource was not found
1048 if (log.isDebugEnabled())
1049 log.debug(" --> Resource not found, returning null");
1050 return (null);
1051
1052 }
1053
1054
1055 /**
1056 * Find the resource with the given name, and return an input stream
1057 * that can be used for reading it. The search order is as described
1058 * for <code>getResource()</code>, after checking to see if the resource
1059 * data has been previously cached. If the resource cannot be found,
1060 * return <code>null</code>.
1061 *
1062 * @param name Name of the resource to return an input stream for
1063 */
1064 @Override
1065 public InputStream getResourceAsStream(String name) {
1066
1067 if (log.isDebugEnabled())
1068 log.debug("getResourceAsStream(" + name + ")");
1069 InputStream stream = null;
1070
1071 // (0) Check for a cached copy of this resource
1072 stream = findLoadedResource(name);
1073 if (stream != null) {
1074 if (log.isDebugEnabled())
1075 log.debug(" --> Returning stream from cache");
1076 return (stream);
1077 }
1078
1079 // (1) Delegate to parent if requested
1080 if (delegate) {
1081 if (log.isDebugEnabled())
1082 log.debug(" Delegating to parent classloader " + parent);
1083 stream = parent.getResourceAsStream(name);
1084 if (stream != null) {
1085 // FIXME - cache???
1086 if (log.isDebugEnabled())
1087 log.debug(" --> Returning stream from parent");
1088 return (stream);
1089 }
1090 }
1091
1092 // (2) Search local repositories
1093 if (log.isDebugEnabled())
1094 log.debug(" Searching local repositories");
1095 URL url = findResource(name);
1096 if (url != null) {
1097 // FIXME - cache???
1098 if (log.isDebugEnabled())
1099 log.debug(" --> Returning stream from local");
1100 stream = findLoadedResource(name);
1101 try {
1102 if (hasExternalRepositories && (stream == null))
1103 stream = url.openStream();
1104 } catch (IOException e) {
1105 // Ignore
1106 }
1107 if (stream != null)
1108 return (stream);
1109 }
1110
1111 // (3) Delegate to parent unconditionally
1112 if (!delegate) {
1113 if (log.isDebugEnabled())
1114 log.debug(" Delegating to parent classloader unconditionally " + parent);
1115 stream = parent.getResourceAsStream(name);
1116 if (stream != null) {
1117 // FIXME - cache???
1118 if (log.isDebugEnabled())
1119 log.debug(" --> Returning stream from parent");
1120 return (stream);
1121 }
1122 }
1123
1124 // (4) Resource was not found
1125 if (log.isDebugEnabled())
1126 log.debug(" --> Resource not found, returning null");
1127 return (null);
1128
1129 }
1130
1131
1132 /**
1133 * Load the class with the specified name. This method searches for
1134 * classes in the same manner as <code>loadClass(String, boolean)</code>
1135 * with <code>false</code> as the second argument.
1136 *
1137 * @param name The binary name of the class to be loaded
1138 *
1139 * @exception ClassNotFoundException if the class was not found
1140 */
1141 @Override
1142 public Class<?> loadClass(String name) throws ClassNotFoundException {
1143
1144 return (loadClass(name, false));
1145
1146 }
1147
1148
1149 /**
1150 * Load the class with the specified name, searching using the following
1151 * algorithm until it finds and returns the class. If the class cannot
1152 * be found, returns <code>ClassNotFoundException</code>.
1153 * <ul>
1154 * <li>Call <code>findLoadedClass(String)</code> to check if the
1155 * class has already been loaded. If it has, the same
1156 * <code>Class</code> object is returned.</li>
1157 * <li>If the <code>delegate</code> property is set to <code>true</code>,
1158 * call the <code>loadClass()</code> method of the parent class
1159 * loader, if any.</li>
1160 * <li>Call <code>findClass()</code> to find this class in our locally
1161 * defined repositories.</li>
1162 * <li>Call the <code>loadClass()</code> method of our parent
1163 * class loader, if any.</li>
1164 * </ul>
1165 * If the class was found using the above steps, and the
1166 * <code>resolve</code> flag is <code>true</code>, this method will then
1167 * call <code>resolveClass(Class)</code> on the resulting Class object.
1168 *
1169 * @param name The binary name of the class to be loaded
1170 * @param resolve If <code>true</code> then resolve the class
1171 *
1172 * @exception ClassNotFoundException if the class was not found
1173 */
1174 @Override
1175 public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
1176
1177 synchronized (getClassLoadingLock(name)) {
1178 if (log.isDebugEnabled())
1179 log.debug("loadClass(" + name + ", " + resolve + ")");
1180 Class<?> clazz = null;
1181
1182 // Log access to stopped class loader
1183 checkStateForClassLoading(name);
1184
1185 // (0) Check our previously loaded local class cache
1186 clazz = findLoadedClass0(name);
1187 if (clazz != null) {
1188 if (log.isDebugEnabled())
1189 log.debug(" Returning class from cache");
1190 if (resolve)
1191 resolveClass(clazz);
1192 return (clazz);
1193 }
1194
1195 // (0.1) Check our previously loaded class cache
1196 clazz = findLoadedClass(name);
1197 if (clazz != null) {
1198 if (log.isDebugEnabled())
1199 log.debug(" Returning class from cache");
1200 if (resolve)
1201 resolveClass(clazz);
1202 return (clazz);
1203 }
1204
1205 // (0.2) Try loading the class with the system class loader, to prevent
1206 // the webapp from overriding J2SE classes
1207 String resourceName = binaryNameToPath(name, false);
1208 ClassLoader javaseLoader = getJavaseClassLoader();
1209 if (javaseLoader.getResource(resourceName) != null) {
1210 try {
1211 clazz = javaseLoader.loadClass(name);
1212 if (clazz != null) {
1213 if (resolve)
1214 resolveClass(clazz);
1215 return (clazz);
1216 }
1217 } catch (ClassNotFoundException e) {
1218 // Ignore
1219 }
1220 }
1221
1222 // (0.5) Permission to access this class when using a SecurityManager
1223 if (securityManager != null) {
1224 int i = name.lastIndexOf('.');
1225 if (i >= 0) {
1226 try {
1227 securityManager.checkPackageAccess(name.substring(0,i));
1228 } catch (SecurityException se) {
1229 String error = "Security Violation, attempt to use " +
1230 "Restricted Class: " + name;
1231 log.info(error, se);
1232 throw new ClassNotFoundException(error, se);
1233 }
1234 }
1235 }
1236
1237 boolean delegateLoad = delegate || filter(name);
1238
1239 // (1) Delegate to our parent if requested
1240 if (delegateLoad) {
1241 if (log.isDebugEnabled())
1242 log.debug(" Delegating to parent classloader1 " + parent);
1243 try {
1244 clazz = Class.forName(name, false, parent);
1245 if (clazz != null) {
1246 if (log.isDebugEnabled())
1247 log.debug(" Loading class from parent");
1248 if (resolve)
1249 resolveClass(clazz);
1250 return (clazz);
1251 }
1252 } catch (ClassNotFoundException e) {
1253 // Ignore
1254 }
1255 }
1256
1257 // (2) Search local repositories
1258 if (log.isDebugEnabled())
1259 log.debug(" Searching local repositories");
1260 try {
1261 clazz = findClass(name);
1262 if (clazz != null) {
1263 if (log.isDebugEnabled())
1264 log.debug(" Loading class from local repository");
1265 if (resolve)
1266 resolveClass(clazz);
1267 return (clazz);
1268 }
1269 } catch (ClassNotFoundException e) {
1270 // Ignore
1271 }
1272
1273 // (3) Delegate to parent unconditionally
1274 if (!delegateLoad) {
1275 if (log.isDebugEnabled())
1276 log.debug(" Delegating to parent classloader at end: " + parent);
1277 try {
1278 clazz = Class.forName(name, false, parent);
1279 if (clazz != null) {
1280 if (log.isDebugEnabled())
1281 log.debug(" Loading class from parent");
1282 if (resolve)
1283 resolveClass(clazz);
1284 return (clazz);
1285 }
1286 } catch (ClassNotFoundException e) {
1287 // Ignore
1288 }
1289 }
1290 }
1291
1292 throw new ClassNotFoundException(name);
1293 }
1294
1295
1296 protected void checkStateForClassLoading(String className) throws ClassNotFoundException {
1297 // It is not permitted to load new classes once the web application has
1298 // been stopped.
1299 if (!state.isAvailable()) {
1300 String msg = sm.getString("webappClassLoader.stopped", className);
1301 IllegalStateException cause = new IllegalStateException(msg);
1302 ClassNotFoundException cnfe = new ClassNotFoundException();
1303 cnfe.initCause(cause);
1304 log.info(msg, cnfe);
1305 throw cnfe;
1306 }
1307 }
1308
1309
1310 /**
1311 * Get the Permissions for a CodeSource. If this instance
1312 * of WebappClassLoaderBase is for a web application context,
1313 * add read FilePermission or JndiPermissions for the base
1314 * directory (if unpacked),
1315 * the context URL, and jar file resources.
1316 *
1317 * @param codeSource where the code was loaded from
1318 * @return PermissionCollection for CodeSource
1319 */
1320 @Override
1321 protected PermissionCollection getPermissions(CodeSource codeSource) {
1322
1323 String codeUrl = codeSource.getLocation().toString();
1324 PermissionCollection pc;
1325 if ((pc = loaderPC.get(codeUrl)) == null) {
1326 pc = super.getPermissions(codeSource);
1327 if (pc != null) {
1328 Iterator<Permission> perms = permissionList.iterator();
1329 while (perms.hasNext()) {
1330 Permission p = perms.next();
1331 pc.add(p);
1332 }
1333 loaderPC.put(codeUrl,pc);
1334 }
1335 }
1336 return (pc);
1337
1338 }
1339
1340
1341 /**
1342 * {@inheritDoc}
1343 * <p>
1344 * Note that list of URLs returned by this method may not be complete. The
1345 * web application class loader accesses class loader resources via the
1346 * {@link WebResourceRoot} which supports the arbitrary mapping of
1347 * additional files, directories and contents of JAR files under
1348 * WEB-INF/classes. Any such resources will not be included in the URLs
1349 * returned here.
1350 */
1351 @Override
1352 public URL[] getURLs() {
1353 ArrayList<URL> result = new ArrayList<>();
1354 result.addAll(localRepositories);
1355 result.addAll(Arrays.asList(super.getURLs()));
1356 return result.toArray(new URL[result.size()]);
1357 }
1358
1359
1360 // ------------------------------------------------------ Lifecycle Methods
1361
1362
1363 /**
1364 * Add a lifecycle event listener to this component.
1365 *
1366 * @param listener The listener to add
1367 */
1368 @Override
1369 public void addLifecycleListener(LifecycleListener listener) {
1370 // NOOP
1371 }
1372
1373
1374 /**
1375 * Get the lifecycle listeners associated with this lifecycle. If this
1376 * Lifecycle has no listeners registered, a zero-length array is returned.
1377 */
1378 @Override
1379 public LifecycleListener[] findLifecycleListeners() {
1380 return new LifecycleListener[0];
1381 }
1382
1383
1384 /**
1385 * Remove a lifecycle event listener from this component.
1386 *
1387 * @param listener The listener to remove
1388 */
1389 @Override
1390 public void removeLifecycleListener(LifecycleListener listener) {
1391 // NOOP
1392 }
1393
1394
1395 /**
1396 * Obtain the current state of the source component.
1397 *
1398 * @return The current state of the source component.
1399 */
1400 @Override
1401 public LifecycleState getState() {
1402 return state;
1403 }
1404
1405
1406 /**
1407 * {@inheritDoc}
1408 */
1409 @Override
1410 public String getStateName() {
1411 return getState().toString();
1412 }
1413
1414
1415 @Override
1416 public void init() {
1417 state = LifecycleState.INITIALIZED;
1418 }
1419
1420
1421 /**
1422 * Start the class loader.
1423 *
1424 * @exception LifecycleException if a lifecycle error occurs
1425 */
1426 @Override
1427 public void start() throws LifecycleException {
1428
1429 state = LifecycleState.STARTING_PREP;
1430
1431 WebResource classes = resources.getResource("/WEB-INF/classes");
1432 if (classes.isDirectory() && classes.canRead()) {
1433 localRepositories.add(classes.getURL());
1434 }
1435 WebResource[] jars = resources.listResources("/WEB-INF/lib");
1436 for (WebResource jar : jars) {
1437 if (jar.getName().endsWith(".jar") && jar.isFile() && jar.canRead()) {
1438 localRepositories.add(jar.getURL());
1439 jarModificationTimes.put(
1440 jar.getName(), Long.valueOf(jar.getLastModified()));
1441 }
1442 }
1443
1444 state = LifecycleState.STARTING;
1445
1446 String encoding = null;
1447 try {
1448 encoding = System.getProperty("file.encoding");
1449 } catch (SecurityException e) {
1450 return;
1451 }
1452 if (encoding.indexOf("EBCDIC")!=-1) {
1453 needConvert = true;
1454 }
1455
1456 state = LifecycleState.STARTED;
1457 }
1458
1459
1460 /**
1461 * Stop the class loader.
1462 *
1463 * @exception LifecycleException if a lifecycle error occurs
1464 */
1465 @Override
1466 public void stop() throws LifecycleException {
1467
1468 state = LifecycleState.STOPPING_PREP;
1469
1470 // Clearing references should be done before setting started to
1471 // false, due to possible side effects
1472 clearReferences();
1473
1474 state = LifecycleState.STOPPING;
1475
1476 resourceEntries.clear();
1477 jarModificationTimes.clear();
1478 resources = null;
1479
1480 permissionList.clear();
1481 loaderPC.clear();
1482
1483 state = LifecycleState.STOPPED;
1484 }
1485
1486
1487 @Override
1488 public void destroy() {
1489 state = LifecycleState.DESTROYING;
1490
1491 try {
1492 super.close();
1493 } catch (IOException ioe) {
1494 log.warn(sm.getString("webappClassLoader.superCloseFail"), ioe);
1495 }
1496 state = LifecycleState.DESTROYED;
1497 }
1498
1499
1500 // ------------------------------------------------------ Protected Methods
1501
1502 protected ClassLoader getJavaseClassLoader() {
1503 return javaseClassLoader;
1504 }
1505
1506 protected void setJavaseClassLoader(ClassLoader classLoader) {
1507 if (classLoader == null) {
1508 throw new IllegalArgumentException(
1509 sm.getString("webappClassLoader.javaseClassLoaderNull"));
1510 }
1511 javaseClassLoader = classLoader;
1512 }
1513
1514 /**
1515 * Clear references.
1516 */
1517 protected void clearReferences() {
1518
1519 // De-register any remaining JDBC drivers
1520 clearReferencesJdbc();
1521
1522 // Stop any threads the web application started
1523 clearReferencesThreads();
1524
1525 // Check for leaks triggered by ThreadLocals loaded by this class loader
1526 checkThreadLocalsForLeaks();
1527
1528 // Clear RMI Targets loaded by this class loader
1529 clearReferencesRmiTargets();
1530
1531 // Null out any static or final fields from loaded classes,
1532 // as a workaround for apparent garbage collection bugs
1533 if (clearReferencesStatic) {
1534 clearReferencesStaticFinal();
1535 }
1536
1537 // Clear the IntrospectionUtils cache.
1538 IntrospectionUtils.clear();
1539
1540 // Clear the classloader reference in common-logging
1541 if (clearReferencesLogFactoryRelease) {
1542 org.apache.juli.logging.LogFactory.release(this);
1543 }
1544
1545 // Clear the resource bundle cache
1546 // This shouldn't be necessary, the cache uses weak references but
1547 // it has caused leaks. Oddly, using the leak detection code in
1548 // standard host allows the class loader to be GC'd. This has been seen
1549 // on Sun but not IBM JREs. Maybe a bug in Sun's GC impl?
1550 clearReferencesResourceBundles();
1551
1552 // Clear the classloader reference in the VM's bean introspector
1553 java.beans.Introspector.flushCaches();
1554
1555 // Clear any custom URLStreamHandlers
1556 TomcatURLStreamHandlerFactory.release(this);
1557 }
1558
1559
1560 /**
1561 * Deregister any JDBC drivers registered by the webapp that the webapp
1562 * forgot. This is made unnecessary complex because a) DriverManager
1563 * checks the class loader of the calling class (it would be much easier
1564 * if it checked the context class loader) b) using reflection would
1565 * create a dependency on the DriverManager implementation which can,
1566 * and has, changed.
1567 *
1568 * We can't just create an instance of JdbcLeakPrevention as it will be
1569 * loaded by the common class loader (since it's .class file is in the
1570 * $CATALINA_HOME/lib directory). This would fail DriverManager's check
1571 * on the class loader of the calling class. So, we load the bytes via
1572 * our parent class loader but define the class with this class loader
1573 * so the JdbcLeakPrevention looks like a webapp class to the
1574 * DriverManager.
1575 *
1576 * If only apps cleaned up after themselves...
1577 */
1578 private final void clearReferencesJdbc() {
1579 // We know roughly how big the class will be (~ 1K) so allow 2k as a
1580 // starting point
1581 byte[] classBytes = new byte[2048];
1582 int offset = 0;
1583 try (InputStream is = getResourceAsStream(
1584 "org/apache/catalina/loader/JdbcLeakPrevention.class")) {
1585 int read = is.read(classBytes, offset, classBytes.length-offset);
1586 while (read > -1) {
1587 offset += read;
1588 if (offset == classBytes.length) {
1589 // Buffer full - double size
1590 byte[] tmp = new byte[classBytes.length * 2];
1591 System.arraycopy(classBytes, 0, tmp, 0, classBytes.length);
1592 classBytes = tmp;
1593 }
1594 read = is.read(classBytes, offset, classBytes.length-offset);
1595 }
1596 Class<?> lpClass =
1597 defineClass("org.apache.catalina.loader.JdbcLeakPrevention",
1598 classBytes, 0, offset, this.getClass().getProtectionDomain());
1599 Object obj = lpClass.newInstance();
1600 @SuppressWarnings("unchecked")
1601 List<String> driverNames = (List<String>) obj.getClass().getMethod(
1602 "clearJdbcDriverRegistrations").invoke(obj);
1603 for (String name : driverNames) {
1604 log.warn(sm.getString("webappClassLoader.clearJdbc",
1605 getContextName(), name));
1606 }
1607 } catch (Exception e) {
1608 // So many things to go wrong above...
1609 Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
1610 ExceptionUtils.handleThrowable(t);
1611 log.warn(sm.getString(
1612 "webappClassLoader.jdbcRemoveFailed", getContextName()), t);
1613 }
1614 }
1615
1616
1617 private final void clearReferencesStaticFinal() {
1618
1619 Collection<ResourceEntry> values = resourceEntries.values();
1620 Iterator<ResourceEntry> loadedClasses = values.iterator();
1621 //
1622 // walk through all loaded class to trigger initialization for
1623 // any uninitialized classes, otherwise initialization of
1624 // one class may call a previously cleared class.
1625 while(loadedClasses.hasNext()) {
1626 ResourceEntry entry = loadedClasses.next();
1627 if (entry.loadedClass != null) {
1628 Class<?> clazz = entry.loadedClass;
1629 try {
1630 Field[] fields = clazz.getDeclaredFields();
1631 for (int i = 0; i < fields.length; i++) {
1632 if(Modifier.isStatic(fields[i].getModifiers())) {
1633 fields[i].get(null);
1634 break;
1635 }
1636 }
1637 } catch(Throwable t) {
1638 // Ignore
1639 }
1640 }
1641 }
1642 loadedClasses = values.iterator();
1643 while (loadedClasses.hasNext()) {
1644 ResourceEntry entry = loadedClasses.next();
1645 if (entry.loadedClass != null) {
1646 Class<?> clazz = entry.loadedClass;
1647 try {
1648 Field[] fields = clazz.getDeclaredFields();
1649 for (int i = 0; i < fields.length; i++) {
1650 Field field = fields[i];
1651 int mods = field.getModifiers();
1652 if (field.getType().isPrimitive()
1653 || (field.getName().indexOf("$") != -1)) {
1654 continue;
1655 }
1656 if (Modifier.isStatic(mods)) {
1657 try {
1658 field.setAccessible(true);
1659 if (Modifier.isFinal(mods)) {
1660 if (!((field.getType().getName().startsWith("java."))
1661 || (field.getType().getName().startsWith("javax.")))) {
1662 nullInstance(field.get(null));
1663 }
1664 } else {
1665 field.set(null, null);
1666 if (log.isDebugEnabled()) {
1667 log.debug("Set field " + field.getName()
1668 + " to null in class " + clazz.getName());
1669 }
1670 }
1671 } catch (Throwable t) {
1672 ExceptionUtils.handleThrowable(t);
1673 if (log.isDebugEnabled()) {
1674 log.debug("Could not set field " + field.getName()
1675 + " to null in class " + clazz.getName(), t);
1676 }
1677 }
1678 }
1679 }
1680 } catch (Throwable t) {
1681 ExceptionUtils.handleThrowable(t);
1682 if (log.isDebugEnabled()) {
1683 log.debug("Could not clean fields for class " + clazz.getName(), t);
1684 }
1685 }
1686 }
1687 }
1688
1689 }
1690
1691
1692 private void nullInstance(Object instance) {
1693 if (instance == null) {
1694 return;
1695 }
1696 Field[] fields = instance.getClass().getDeclaredFields();
1697 for (int i = 0; i < fields.length; i++) {
1698 Field field = fields[i];
1699 int mods = field.getModifiers();
1700 if (field.getType().isPrimitive()
1701 || (field.getName().indexOf("$") != -1)) {
1702 continue;
1703 }
1704 try {
1705 field.setAccessible(true);
1706 if (Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
1707 // Doing something recursively is too risky
1708 continue;
1709 }
1710 Object value = field.get(instance);
1711 if (null != value) {
1712 Class<? extends Object> valueClass = value.getClass();
1713 if (!loadedByThisOrChild(valueClass)) {
1714 if (log.isDebugEnabled()) {
1715 log.debug("Not setting field " + field.getName() +
1716 " to null in object of class " +
1717 instance.getClass().getName() +
1718 " because the referenced object was of type " +
1719 valueClass.getName() +
1720 " which was not loaded by this web application class loader.");
1721 }
1722 } else {
1723 field.set(instance, null);
1724 if (log.isDebugEnabled()) {
1725 log.debug("Set field " + field.getName()
1726 + " to null in class " + instance.getClass().getName());
1727 }
1728 }
1729 }
1730 } catch (Throwable t) {
1731 ExceptionUtils.handleThrowable(t);
1732 if (log.isDebugEnabled()) {
1733 log.debug("Could not set field " + field.getName()
1734 + " to null in object instance of class "
1735 + instance.getClass().getName(), t);
1736 }
1737 }
1738 }
1739 }
1740
1741
1742 @SuppressWarnings("deprecation") // thread.stop()
1743 private void clearReferencesThreads() {
1744 Thread[] threads = getThreads();
1745 List<Thread> executorThreadsToStop = new ArrayList<>();
1746
1747 // Iterate over the set of threads
1748 for (Thread thread : threads) {
1749 if (thread != null) {
1750 ClassLoader ccl = thread.getContextClassLoader();
1751 if (ccl == this) {
1752 // Don't warn about this thread
1753 if (thread == Thread.currentThread()) {
1754 continue;
1755 }
1756
1757 final String threadName = thread.getName();
1758
1759 // JVM controlled threads
1760 ThreadGroup tg = thread.getThreadGroup();
1761 if (tg != null &&
1762 JVM_THREAD_GROUP_NAMES.contains(tg.getName())) {
1763
1764 // HttpClient keep-alive threads
1765 if (clearReferencesHttpClientKeepAliveThread &&
1766 threadName.equals("Keep-Alive-Timer")) {
1767 thread.setContextClassLoader(parent);
1768 log.debug(sm.getString(
1769 "webappClassLoader.checkThreadsHttpClient"));
1770 }
1771
1772 // Don't warn about remaining JVM controlled threads
1773 continue;
1774 }
1775
1776 // Skip threads that have already died
1777 if (!thread.isAlive()) {
1778 continue;
1779 }
1780
1781 // TimerThread can be stopped safely so treat separately
1782 // "java.util.TimerThread" in Sun/Oracle JDK
1783 // "java.util.Timer$TimerImpl" in Apache Harmony and in IBM JDK
1784 if (thread.getClass().getName().startsWith("java.util.Timer") &&
1785 clearReferencesStopTimerThreads) {
1786 clearReferencesStopTimerThread(thread);
1787 continue;
1788 }
1789
1790 if (isRequestThread(thread)) {
1791 log.warn(sm.getString("webappClassLoader.stackTraceRequestThread",
1792 getContextName(), threadName, getStackTrace(thread)));
1793 } else {
1794 log.warn(sm.getString("webappClassLoader.stackTrace",
1795 getContextName(), threadName, getStackTrace(thread)));
1796 }
1797
1798 // Don't try an stop the threads unless explicitly
1799 // configured to do so
1800 if (!clearReferencesStopThreads) {
1801 continue;
1802 }
1803
1804 // If the thread has been started via an executor, try
1805 // shutting down the executor
1806 boolean usingExecutor = false;
1807 try {
1808
1809 // Runnable wrapped by Thread
1810 // "target" in Sun/Oracle JDK
1811 // "runnable" in IBM JDK
1812 // "action" in Apache Harmony
1813 Object target = null;
1814 for (String fieldName : new String[] { "target",
1815 "runnable", "action" }) {
1816 try {
1817 Field targetField = thread.getClass()
1818 .getDeclaredField(fieldName);
1819 targetField.setAccessible(true);
1820 target = targetField.get(thread);
1821 break;
1822 } catch (NoSuchFieldException nfe) {
1823 continue;
1824 }
1825 }
1826
1827 // "java.util.concurrent" code is in public domain,
1828 // so all implementations are similar
1829 if (target != null &&
1830 target.getClass().getCanonicalName() != null
1831 && target.getClass().getCanonicalName().equals(
1832 "java.util.concurrent.ThreadPoolExecutor.Worker")) {
1833 Field executorField =
1834 target.getClass().getDeclaredField("this$0");
1835 executorField.setAccessible(true);
1836 Object executor = executorField.get(target);
1837 if (executor instanceof ThreadPoolExecutor) {
1838 ((ThreadPoolExecutor) executor).shutdownNow();
1839 usingExecutor = true;
1840 }
1841 }
1842 } catch (SecurityException e) {
1843 log.warn(sm.getString(
1844 "webappClassLoader.stopThreadFail",
1845 thread.getName(), getContextName()), e);
1846 } catch (NoSuchFieldException e) {
1847 log.warn(sm.getString(
1848 "webappClassLoader.stopThreadFail",
1849 thread.getName(), getContextName()), e);
1850 } catch (IllegalArgumentException e) {
1851 log.warn(sm.getString(
1852 "webappClassLoader.stopThreadFail",
1853 thread.getName(), getContextName()), e);
1854 } catch (IllegalAccessException e) {
1855 log.warn(sm.getString(
1856 "webappClassLoader.stopThreadFail",
1857 thread.getName(), getContextName()), e);
1858 }
1859
1860 if (usingExecutor) {
1861 // Executor may take a short time to stop all the
1862 // threads. Make a note of threads that should be
1863 // stopped and check them at the end of the method.
1864 executorThreadsToStop.add(thread);
1865 } else {
1866 // This method is deprecated and for good reason. This
1867 // is very risky code but is the only option at this
1868 // point. A *very* good reason for apps to do this
1869 // clean-up themselves.
1870 thread.stop();
1871 }
1872 }
1873 }
1874 }
1875
1876 // If thread stopping is enabled, executor threads should have been
1877 // stopped above when the executor was shut down but that depends on the
1878 // thread correctly handling the interrupt. Give all the executor
1879 // threads a few seconds shutdown and if they are still running
1880 // Give threads up to 2 seconds to shutdown
1881 int count = 0;
1882 for (Thread t : executorThreadsToStop) {
1883 while (t.isAlive() && count < 100) {
1884 try {
1885 Thread.sleep(20);
1886 } catch (InterruptedException e) {
1887 // Quit the while loop
1888 break;
1889 }
1890 count++;
1891 }
1892 if (t.isAlive()) {
1893 // This method is deprecated and for good reason. This is
1894 // very risky code but is the only option at this point.
1895 // A *very* good reason for apps to do this clean-up
1896 // themselves.
1897 t.stop();
1898 }
1899 }
1900 }
1901
1902
1903 /*
1904 * Look at a threads stack trace to see if it is a request thread or not. It
1905 * isn't perfect, but it should be good-enough for most cases.
1906 */
1907 private boolean isRequestThread(Thread thread) {
1908
1909 StackTraceElement[] elements = thread.getStackTrace();
1910
1911 if (elements == null || elements.length == 0) {
1912 // Must have stopped already. Too late to ignore it. Assume not a
1913 // request processing thread.
1914 return false;
1915 }
1916
1917 // Step through the methods in reverse order looking for calls to any
1918 // CoyoteAdapter method. All request threads will have this unless
1919 // Tomcat has been heavily modified - in which case there isn't much we
1920 // can do.
1921 for (int i = 0; i < elements.length; i++) {
1922 StackTraceElement element = elements[elements.length - (i+1)];
1923 if ("org.apache.catalina.connector.CoyoteAdapter".equals(
1924 element.getClassName())) {
1925 return true;
1926 }
1927 }
1928 return false;
1929 }
1930
1931
1932 private void clearReferencesStopTimerThread(Thread thread) {
1933
1934 // Need to get references to:
1935 // in Sun/Oracle JDK:
1936 // - newTasksMayBeScheduled field (in java.util.TimerThread)
1937 // - queue field
1938 // - queue.clear()
1939 // in IBM JDK, Apache Harmony:
1940 // - cancel() method (in java.util.Timer$TimerImpl)
1941
1942 try {
1943
1944 try {
1945 Field newTasksMayBeScheduledField =
1946 thread.getClass().getDeclaredField("newTasksMayBeScheduled");
1947 newTasksMayBeScheduledField.setAccessible(true);
1948 Field queueField = thread.getClass().getDeclaredField("queue");
1949 queueField.setAccessible(true);
1950
1951 Object queue = queueField.get(thread);
1952
1953 Method clearMethod = queue.getClass().getDeclaredMethod("clear");
1954 clearMethod.setAccessible(true);
1955
1956 synchronized(queue) {
1957 newTasksMayBeScheduledField.setBoolean(thread, false);
1958 clearMethod.invoke(queue);
1959 queue.notify(); // In case queue was already empty.
1960 }
1961
1962 }catch (NoSuchFieldException nfe){
1963 Method cancelMethod = thread.getClass().getDeclaredMethod("cancel");
1964 synchronized(thread) {
1965 cancelMethod.setAccessible(true);
1966 cancelMethod.invoke(thread);
1967 }
1968 }
1969
1970 log.warn(sm.getString("webappClassLoader.warnTimerThread",
1971 getContextName(), thread.getName()));
1972
1973 } catch (Exception e) {
1974 // So many things to go wrong above...
1975 Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
1976 ExceptionUtils.handleThrowable(t);
1977 log.warn(sm.getString(
1978 "webappClassLoader.stopTimerThreadFail",
1979 thread.getName(), getContextName()), t);
1980 }
1981 }
1982
1983 private void checkThreadLocalsForLeaks() {
1984 Thread[] threads = getThreads();
1985
1986 try {
1987 // Make the fields in the Thread class that store ThreadLocals
1988 // accessible
1989 Field threadLocalsField =
1990 Thread.class.getDeclaredField("threadLocals");
1991 threadLocalsField.setAccessible(true);
1992 Field inheritableThreadLocalsField =
1993 Thread.class.getDeclaredField("inheritableThreadLocals");
1994 inheritableThreadLocalsField.setAccessible(true);
1995 // Make the underlying array of ThreadLoad.ThreadLocalMap.Entry objects
1996 // accessible
1997 Class<?> tlmClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
1998 Field tableField = tlmClass.getDeclaredField("table");
1999 tableField.setAccessible(true);
2000 Method expungeStaleEntriesMethod = tlmClass.getDeclaredMethod("expungeStaleEntries");
2001 expungeStaleEntriesMethod.setAccessible(true);
2002
2003 for (int i = 0; i < threads.length; i++) {
2004 Object threadLocalMap;
2005 if (threads[i] != null) {
2006
2007 // Clear the first map
2008 threadLocalMap = threadLocalsField.get(threads[i]);
2009 if (null != threadLocalMap){
2010 expungeStaleEntriesMethod.invoke(threadLocalMap);
2011 checkThreadLocalMapForLeaks(threadLocalMap, tableField);
2012 }
2013
2014 // Clear the second map
2015 threadLocalMap =inheritableThreadLocalsField.get(threads[i]);
2016 if (null != threadLocalMap){
2017 expungeStaleEntriesMethod.invoke(threadLocalMap);
2018 checkThreadLocalMapForLeaks(threadLocalMap, tableField);
2019 }
2020 }
2021 }
2022 } catch (Throwable t) {
2023 ExceptionUtils.handleThrowable(t);
2024 log.warn(sm.getString(
2025 "webappClassLoader.checkThreadLocalsForLeaksFail",
2026 getContextName()), t);
2027 }
2028 }
2029
2030
2031 /**
2032 * Analyzes the given thread local map object. Also pass in the field that
2033 * points to the internal table to save re-calculating it on every
2034 * call to this method.
2035 */
2036 private void checkThreadLocalMapForLeaks(Object map,
2037 Field internalTableField) throws IllegalAccessException,
2038 NoSuchFieldException {
2039 if (map != null) {
2040 Object[] table = (Object[]) internalTableField.get(map);
2041 if (table != null) {
2042 for (int j =0; j < table.length; j++) {
2043 Object obj = table[j];
2044 if (obj != null) {
2045 boolean potentialLeak = false;
2046 // Check the key
2047 Object key = ((Reference<?>) obj).get();
2048 if (this.equals(key) || loadedByThisOrChild(key)) {
2049 potentialLeak = true;
2050 }
2051 // Check the value
2052 Field valueField =
2053 obj.getClass().getDeclaredField("value");
2054 valueField.setAccessible(true);
2055 Object value = valueField.get(obj);
2056 if (this.equals(value) || loadedByThisOrChild(value)) {
2057 potentialLeak = true;
2058 }
2059 if (potentialLeak) {
2060 Object[] args = new Object[5];
2061 args[0] = getContextName();
2062 if (key != null) {
2063 args[1] = getPrettyClassName(key.getClass());
2064 try {
2065 args[2] = key.toString();
2066 } catch (Exception e) {
2067 log.warn(sm.getString(
2068 "webappClassLoader.checkThreadLocalsForLeaks.badKey",
2069 args[1]), e);
2070 args[2] = sm.getString(
2071 "webappClassLoader.checkThreadLocalsForLeaks.unknown");
2072 }
2073 }
2074 if (value != null) {
2075 args[3] = getPrettyClassName(value.getClass());
2076 try {
2077 args[4] = value.toString();
2078 } catch (Exception e) {
2079 log.warn(sm.getString(
2080 "webappClassLoader.checkThreadLocalsForLeaks.badValue",
2081 args[3]), e);
2082 args[4] = sm.getString(
2083 "webappClassLoader.checkThreadLocalsForLeaks.unknown");
2084 }
2085 }
2086 if (value == null) {
2087 if (log.isDebugEnabled()) {
2088 log.debug(sm.getString(
2089 "webappClassLoader.checkThreadLocalsForLeaksDebug",
2090 args));
2091 }
2092 } else {
2093 log.error(sm.getString(
2094 "webappClassLoader.checkThreadLocalsForLeaks",
2095 args));
2096 }
2097 }
2098 }
2099 }
2100 }
2101 }
2102 }
2103
2104 private String getPrettyClassName(Class<?> clazz) {
2105 String name = clazz.getCanonicalName();
2106 if (name==null){
2107 name = clazz.getName();
2108 }
2109 return name;
2110 }
2111
2112 private String getStackTrace(Thread thread) {
2113 StringBuilder builder = new StringBuilder();
2114 for (StackTraceElement ste : thread.getStackTrace()) {
2115 builder.append("\n ").append(ste);
2116 }
2117 return builder.toString();
2118 }
2119
2120 /**
2121 * @param o object to test, may be null
2122 * @return <code>true</code> if o has been loaded by the current classloader
2123 * or one of its descendants.
2124 */
2125 private boolean loadedByThisOrChild(Object o) {
2126 if (o == null) {
2127 return false;
2128 }
2129
2130 Class<?> clazz;
2131 if (o instanceof Class) {
2132 clazz = (Class<?>) o;
2133 } else {
2134 clazz = o.getClass();
2135 }
2136
2137 ClassLoader cl = clazz.getClassLoader();
2138 while (cl != null) {
2139 if (cl == this) {
2140 return true;
2141 }
2142 cl = cl.getParent();
2143 }
2144
2145 if (o instanceof Collection<?>) {
2146 Iterator<?> iter = ((Collection<?>) o).iterator();
2147 try {
2148 while (iter.hasNext()) {
2149 Object entry = iter.next();
2150 if (loadedByThisOrChild(entry)) {
2151 return true;
2152 }
2153 }
2154 } catch (ConcurrentModificationException e) {
2155 log.warn(sm.getString(
2156 "webappClassLoader.loadedByThisOrChildFail", clazz.getName(), getContextName()),
2157 e);
2158 }
2159 }
2160 return false;
2161 }
2162
2163 /*
2164 * Get the set of current threads as an array.
2165 */
2166 private Thread[] getThreads() {
2167 // Get the current thread group
2168 ThreadGroup tg = Thread.currentThread().getThreadGroup();
2169 // Find the root thread group
2170 try {
2171 while (tg.getParent() != null) {
2172 tg = tg.getParent();
2173 }
2174 } catch (SecurityException se) {
2175 String msg = sm.getString(
2176 "webappClassLoader.getThreadGroupError", tg.getName());
2177 if (log.isDebugEnabled()) {
2178 log.debug(msg, se);
2179 } else {
2180 log.warn(msg);
2181 }
2182 }
2183
2184 int threadCountGuess = tg.activeCount() + 50;
2185 Thread[] threads = new Thread[threadCountGuess];
2186 int threadCountActual = tg.enumerate(threads);
2187 // Make sure we don't miss any threads
2188 while (threadCountActual == threadCountGuess) {
2189 threadCountGuess *=2;
2190 threads = new Thread[threadCountGuess];
2191 // Note tg.enumerate(Thread[]) silently ignores any threads that
2192 // can't fit into the array
2193 threadCountActual = tg.enumerate(threads);
2194 }
2195
2196 return threads;
2197 }
2198
2199
2200 /**
2201 * This depends on the internals of the Sun JVM so it does everything by
2202 * reflection.
2203 */
2204 private void clearReferencesRmiTargets() {
2205 try {
2206 // Need access to the ccl field of sun.rmi.transport.Target
2207 Class<?> objectTargetClass =
2208 Class.forName("sun.rmi.transport.Target");
2209 Field cclField = objectTargetClass.getDeclaredField("ccl");
2210 cclField.setAccessible(true);
2211
2212 // Clear the objTable map
2213 Class<?> objectTableClass =
2214 Class.forName("sun.rmi.transport.ObjectTable");
2215 Field objTableField = objectTableClass.getDeclaredField("objTable");
2216 objTableField.setAccessible(true);
2217 Object objTable = objTableField.get(null);
2218 if (objTable == null) {
2219 return;
2220 }
2221
2222 // Iterate over the values in the table
2223 if (objTable instanceof Map<?,?>) {
2224 Iterator<?> iter = ((Map<?,?>) objTable).values().iterator();
2225 while (iter.hasNext()) {
2226 Object obj = iter.next();
2227 Object cclObject = cclField.get(obj);
2228 if (this == cclObject) {
2229 iter.remove();
2230 }
2231 }
2232 }
2233
2234 // Clear the implTable map
2235 Field implTableField = objectTableClass.getDeclaredField("implTable");
2236 implTableField.setAccessible(true);
2237 Object implTable = implTableField.get(null);
2238 if (implTable == null) {
2239 return;
2240 }
2241
2242 // Iterate over the values in the table
2243 if (implTable instanceof Map<?,?>) {
2244 Iterator<?> iter = ((Map<?,?>) implTable).values().iterator();
2245 while (iter.hasNext()) {
2246 Object obj = iter.next();
2247 Object cclObject = cclField.get(obj);
2248 if (this == cclObject) {
2249 iter.remove();
2250 }
2251 }
2252 }
2253 } catch (ClassNotFoundException e) {
2254 log.info(sm.getString("webappClassLoader.clearRmiInfo",
2255 getContextName()), e);
2256 } catch (SecurityException e) {
2257 log.warn(sm.getString("webappClassLoader.clearRmiFail",
2258 getContextName()), e);
2259 } catch (NoSuchFieldException e) {
2260 log.warn(sm.getString("webappClassLoader.clearRmiFail",
2261 getContextName()), e);
2262 } catch (IllegalArgumentException e) {
2263 log.warn(sm.getString("webappClassLoader.clearRmiFail",
2264 getContextName()), e);
2265 } catch (IllegalAccessException e) {
2266 log.warn(sm.getString("webappClassLoader.clearRmiFail",
2267 getContextName()), e);
2268 }
2269 }
2270
2271
2272 /**
2273 * Clear the {@link ResourceBundle} cache of any bundles loaded by this
2274 * class loader or any class loader where this loader is a parent class
2275 * loader. Whilst {@link ResourceBundle#clearCache()} could be used there
2276 * are complications around the
2277 * {@link org.apache.jasper.servlet.JasperLoader} that mean a reflection
2278 * based approach is more likely to be complete.
2279 *
2280 * The ResourceBundle is using WeakReferences so it shouldn't be pinning the
2281 * class loader in memory. However, it is. Therefore clear ou the
2282 * references.
2283 */
2284 private void clearReferencesResourceBundles() {
2285 // Get a reference to the cache
2286 try {
2287 Field cacheListField =
2288 ResourceBundle.class.getDeclaredField("cacheList");
2289 cacheListField.setAccessible(true);
2290
2291 // Java 6 uses ConcurrentMap
2292 // Java 5 uses SoftCache extends Abstract Map
2293 // So use Map and it *should* work with both
2294 Map<?,?> cacheList = (Map<?,?>) cacheListField.get(null);
2295
2296 // Get the keys (loader references are in the key)
2297 Set<?> keys = cacheList.keySet();
2298
2299 Field loaderRefField = null;
2300
2301 // Iterate over the keys looking at the loader instances
2302 Iterator<?> keysIter = keys.iterator();
2303
2304 int countRemoved = 0;
2305
2306 while (keysIter.hasNext()) {
2307 Object key = keysIter.next();
2308
2309 if (loaderRefField == null) {
2310 loaderRefField =
2311 key.getClass().getDeclaredField("loaderRef");
2312 loaderRefField.setAccessible(true);
2313 }
2314 WeakReference<?> loaderRef =
2315 (WeakReference<?>) loaderRefField.get(key);
2316
2317 ClassLoader loader = (ClassLoader) loaderRef.get();
2318
2319 while (loader != null && loader != this) {
2320 loader = loader.getParent();
2321 }
2322
2323 if (loader != null) {
2324 keysIter.remove();
2325 countRemoved++;
2326 }
2327 }
2328
2329 if (countRemoved > 0 && log.isDebugEnabled()) {
2330 log.debug(sm.getString(
2331 "webappClassLoader.clearReferencesResourceBundlesCount",
2332 Integer.valueOf(countRemoved), getContextName()));
2333 }
2334 } catch (SecurityException e) {
2335 log.warn(sm.getString(
2336 "webappClassLoader.clearReferencesResourceBundlesFail",
2337 getContextName()), e);
2338 } catch (NoSuchFieldException e) {
2339 if (Globals.IS_ORACLE_JVM) {
2340 log.warn(sm.getString(
2341 "webappClassLoader.clearReferencesResourceBundlesFail",
2342 getContextName()), e);
2343 } else {
2344 log.debug(sm.getString(
2345 "webappClassLoader.clearReferencesResourceBundlesFail",
2346 getContextName()), e);
2347 }
2348 } catch (IllegalArgumentException e) {
2349 log.warn(sm.getString(
2350 "webappClassLoader.clearReferencesResourceBundlesFail",
2351 getContextName()), e);
2352 } catch (IllegalAccessException e) {
2353 log.warn(sm.getString(
2354 "webappClassLoader.clearReferencesResourceBundlesFail",
2355 getContextName()), e);
2356 }
2357 }
2358
2359
2360 /**
2361 * Find specified class in local repositories.
2362 *
2363 * @param name The binary name of the class to be loaded
2364 *
2365 * @return the loaded class, or null if the class isn't found
2366 */
2367 protected Class<?> findClassInternal(String name) {
2368
2369 if (!validate(name)) {
2370 return null;
2371 }
2372
2373 String path = binaryNameToPath(name, true);
2374
2375 ResourceEntry entry = null;
2376
2377 if (securityManager != null) {
2378 PrivilegedAction<ResourceEntry> dp =
2379 new PrivilegedFindResourceByName(name, path);
2380 entry = AccessController.doPrivileged(dp);
2381 } else {
2382 entry = findResourceInternal(name, path);
2383 }
2384
2385 if (entry == null) {
2386 return null;
2387 }
2388
2389 Class<?> clazz = entry.loadedClass;
2390 if (clazz != null)
2391 return clazz;
2392
2393 synchronized (getClassLoadingLock(name)) {
2394 clazz = entry.loadedClass;
2395 if (clazz != null)
2396 return clazz;
2397
2398 if (entry.binaryContent == null) {
2399 return null;
2400 }
2401
2402 // Looking up the package
2403 String packageName = null;
2404 int pos = name.lastIndexOf('.');
2405 if (pos != -1)
2406 packageName = name.substring(0, pos);
2407
2408 Package pkg = null;
2409
2410 if (packageName != null) {
2411 pkg = getPackage(packageName);
2412 // Define the package (if null)
2413 if (pkg == null) {
2414 try {
2415 if (entry.manifest == null) {
2416 definePackage(packageName, null, null, null, null,
2417 null, null, null);
2418 } else {
2419 definePackage(packageName, entry.manifest,
2420 entry.codeBase);
2421 }
2422 } catch (IllegalArgumentException e) {
2423 // Ignore: normal error due to dual definition of package
2424 }
2425 pkg = getPackage(packageName);
2426 }
2427 }
2428
2429 if (securityManager != null) {
2430
2431 // Checking sealing
2432 if (pkg != null) {
2433 boolean sealCheck = true;
2434 if (pkg.isSealed()) {
2435 sealCheck = pkg.isSealed(entry.codeBase);
2436 } else {
2437 sealCheck = (entry.manifest == null)
2438 || !isPackageSealed(packageName, entry.manifest);
2439 }
2440 if (!sealCheck)
2441 throw new SecurityException
2442 ("Sealing violation loading " + name + " : Package "
2443 + packageName + " is sealed.");
2444 }
2445
2446 }
2447
2448 try {
2449 clazz = defineClass(name, entry.binaryContent, 0,
2450 entry.binaryContent.length,
2451 new CodeSource(entry.codeBase, entry.certificates));
2452 } catch (UnsupportedClassVersionError ucve) {
2453 throw new UnsupportedClassVersionError(
2454 ucve.getLocalizedMessage() + " " +
2455 sm.getString("webappClassLoader.wrongVersion",
2456 name));
2457 }
2458 // Now the class has been defined, clear the elements of the local
2459 // resource cache that are no longer required.
2460 entry.loadedClass = clazz;
2461 entry.binaryContent = null;
2462 entry.codeBase = null;
2463 entry.manifest = null;
2464 entry.certificates = null;
2465 // Retain entry.source in case of a getResourceAsStream() call on
2466 // the class file after the class has been defined.
2467 }
2468
2469 return clazz;
2470 }
2471
2472
2473 private String binaryNameToPath(String binaryName, boolean withLeadingSlash) {
2474 // 1 for leading '/', 6 for ".class"
2475 StringBuilder path = new StringBuilder(7 + binaryName.length());
2476 if (withLeadingSlash) {
2477 path.append('/');
2478 }
2479 path.append(binaryName.replace('.', '/'));
2480 path.append(CLASS_FILE_SUFFIX);
2481 return path.toString();
2482 }
2483
2484
2485 private String nameToPath(String name) {
2486 if (name.startsWith("/")) {
2487 return name;
2488 }
2489 StringBuilder path = new StringBuilder(
2490 1 + name.length());
2491 path.append('/');
2492 path.append(name);
2493 return path.toString();
2494 }
2495
2496
2497 /**
2498 * Find specified resource in local repositories.
2499 *
2500 * @return the loaded resource, or null if the resource isn't found
2501 */
2502 protected ResourceEntry findResourceInternal(final String name, final String path) {
2503
2504 if (!state.isAvailable()) {
2505 log.info(sm.getString("webappClassLoader.stopped", name));
2506 return null;
2507 }
2508
2509 if (name == null || path == null) {
2510 return null;
2511 }
2512
2513 ResourceEntry entry = resourceEntries.get(path);
2514 if (entry != null) {
2515 return entry;
2516 }
2517
2518 boolean isClassResource = path.endsWith(CLASS_FILE_SUFFIX);
2519 boolean isCacheable = isClassResource;
2520 if (!isCacheable) {
2521 isCacheable = path.startsWith(SERVICES_PREFIX);
2522 }
2523
2524 WebResource resource = null;
2525
2526 boolean fileNeedConvert = false;
2527
2528 resource = resources.getClassLoaderResource(path);
2529
2530 if (!resource.exists()) {
2531 return null;
2532 }
2533
2534 entry = new ResourceEntry();
2535 entry.source = resource.getURL();
2536 entry.codeBase = entry.source;
2537 entry.lastModified = resource.getLastModified();
2538
2539 if (needConvert && path.endsWith(".properties")) {
2540 fileNeedConvert = true;
2541 }
2542
2543 /* Only cache the binary content if there is some content
2544 * available one of the following is true:
2545 * a) It is a class file since the binary content is only cached
2546 * until the class has been loaded
2547 * or
2548 * b) The file needs conversion to address encoding issues (see
2549 * below)
2550 * or
2551 * c) The resource is a service provider configuration file located
2552 * under META=INF/services
2553 *
2554 * In all other cases do not cache the content to prevent
2555 * excessive memory usage if large resources are present (see
2556 * https://issues.apache.org/bugzilla/show_bug.cgi?id=53081).
2557 */
2558 if (isCacheable || fileNeedConvert) {
2559 byte[] binaryContent = resource.getContent();
2560 if (binaryContent != null) {
2561 if (fileNeedConvert) {
2562 // Workaround for certain files on platforms that use
2563 // EBCDIC encoding, when they are read through FileInputStream.
2564 // See commit message of rev.303915 for details
2565 // http://svn.apache.org/viewvc?view=revision&revision=303915
2566 String str = new String(binaryContent);
2567 try {
2568 binaryContent = str.getBytes(StandardCharsets.UTF_8);
2569 } catch (Exception e) {
2570 return null;
2571 }
2572 }
2573 entry.binaryContent = binaryContent;
2574 // The certificates and manifest are made available as a side
2575 // effect of reading the binary content
2576 entry.certificates = resource.getCertificates();
2577 }
2578 }
2579 entry.manifest = resource.getManifest();
2580
2581 if (isClassResource && entry.binaryContent != null &&
2582 this.transformers.size() > 0) {
2583 // If the resource is a class just being loaded, decorate it
2584 // with any attached transformers
2585 String className = name.endsWith(CLASS_FILE_SUFFIX) ?
2586 name.substring(0, name.length() - CLASS_FILE_SUFFIX.length()) : name;
2587 String internalName = className.replace(".", "/");
2588
2589 for (ClassFileTransformer transformer : this.transformers) {
2590 try {
2591 byte[] transformed = transformer.transform(
2592 this, internalName, null, null, entry.binaryContent
2593 );
2594 if (transformed != null) {
2595 entry.binaryContent = transformed;
2596 }
2597 } catch (IllegalClassFormatException e) {
2598 log.error(sm.getString("webappClassLoader.transformError", name), e);
2599 return null;
2600 }
2601 }
2602 }
2603
2604 // Add the entry in the local resource repository
2605 synchronized (resourceEntries) {
2606 // Ensures that all the threads which may be in a race to load
2607 // a particular class all end up with the same ResourceEntry
2608 // instance
2609 ResourceEntry entry2 = resourceEntries.get(path);
2610 if (entry2 == null) {
2611 resourceEntries.put(path, entry);
2612 } else {
2613 entry = entry2;
2614 }
2615 }
2616
2617 return entry;
2618 }
2619
2620
2621 /**
2622 * Returns true if the specified package name is sealed according to the
2623 * given manifest.
2624 */
2625 protected boolean isPackageSealed(String name, Manifest man) {
2626
2627 String path = name.replace('.', '/') + '/';
2628 Attributes attr = man.getAttributes(path);
2629 String sealed = null;
2630 if (attr != null) {
2631 sealed = attr.getValue(Name.SEALED);
2632 }
2633 if (sealed == null) {
2634 if ((attr = man.getMainAttributes()) != null) {
2635 sealed = attr.getValue(Name.SEALED);
2636 }
2637 }
2638 return "true".equalsIgnoreCase(sealed);
2639
2640 }
2641
2642
2643 /**
2644 * Finds the resource with the given name if it has previously been
2645 * loaded and cached by this class loader, and return an input stream
2646 * to the resource data. If this resource has not been cached, return
2647 * <code>null</code>.
2648 *
2649 * @param name Name of the resource to return
2650 */
2651 protected InputStream findLoadedResource(String name) {
2652
2653 String path = nameToPath(name);
2654
2655 ResourceEntry entry = resourceEntries.get(path);
2656 if (entry != null) {
2657 if (entry.binaryContent != null)
2658 return new ByteArrayInputStream(entry.binaryContent);
2659 else {
2660 try {
2661 return entry.source.openStream();
2662 } catch (IOException ioe) {
2663 // Ignore
2664 }
2665 }
2666 }
2667 return null;
2668 }
2669
2670
2671 /**
2672 * Finds the class with the given name if it has previously been
2673 * loaded and cached by this class loader, and return the Class object.
2674 * If this class has not been cached, return <code>null</code>.
2675 *
2676 * @param name The binary name of the resource to return
2677 */
2678 protected Class<?> findLoadedClass0(String name) {
2679
2680 String path = binaryNameToPath(name, true);
2681
2682 ResourceEntry entry = resourceEntries.get(path);
2683 if (entry != null) {
2684 return entry.loadedClass;
2685 }
2686 return null;
2687 }
2688
2689
2690 /**
2691 * Refresh the system policy file, to pick up eventual changes.
2692 */
2693 protected void refreshPolicy() {
2694
2695 try {
2696 // The policy file may have been modified to adjust
2697 // permissions, so we're reloading it when loading or
2698 // reloading a Context
2699 Policy policy = Policy.getPolicy();
2700 policy.refresh();
2701 } catch (AccessControlException e) {
2702 // Some policy files may restrict this, even for the core,
2703 // so this exception is ignored
2704 }
2705
2706 }
2707
2708
2709 /**
2710 * Filter classes.
2711 *
2712 * @param name class name
2713 * @return true if the class should be filtered
2714 */
2715 protected synchronized boolean filter(String name) {
2716
2717 if (name == null)
2718 return false;
2719
2720 // Looking up the package
2721 String packageName = null;
2722 int pos = name.lastIndexOf('.');
2723 if (pos != -1)
2724 packageName = name.substring(0, pos);
2725 else
2726 return false;
2727
2728 packageTriggersPermit.reset(packageName);
2729 if (packageTriggersPermit.lookingAt()) {
2730 return false;
2731 }
2732
2733 packageTriggersDeny.reset(packageName);
2734 if (packageTriggersDeny.lookingAt()) {
2735 return true;
2736 }
2737
2738 return false;
2739 }
2740
2741
2742 /**
2743 * Validate a classname. As per SRV.9.7.2, we must restrict loading of
2744 * classes from J2SE (java.*) and most classes of the servlet API
2745 * (javax.servlet.*). That should enhance robustness and prevent a number
2746 * of user error (where an older version of servlet.jar would be present
2747 * in /WEB-INF/lib).
2748 *
2749 * @param name class name
2750 * @return true if the name is valid
2751 */
2752 protected boolean validate(String name) {
2753
2754 // Need to be careful with order here
2755 if (name == null) {
2756 // Can't load a class without a name
2757 return false;
2758 }
2759 if (name.startsWith("java.")) {
2760 // Must never load java.* classes
2761 return false;
2762 }
2763 if (name.startsWith("javax.servlet.jsp.jstl")) {
2764 // OK for web apps to package JSTL
2765 return true;
2766 }
2767 if (name.startsWith("javax.servlet.")) {
2768 // Web apps should never package any other Servlet or JSP classes
2769 return false;
2770 }
2771 if (name.startsWith("javax.el")) {
2772 // Must never load javax.el.* classes
2773 return false;
2774 }
2775
2776 // Assume everything else is OK
2777 return true;
2778
2779 }
2780
2781
2782 @Override
2783 protected void addURL(URL url) {
2784 super.addURL(url);
2785 hasExternalRepositories = true;
2786 }
2787 }
9191 /**
9292 * The class loader being managed by this Loader component.
9393 */
94 private WebappClassLoader classLoader = null;
94 private WebappClassLoaderBase classLoader = null;
9595
9696
9797 /**
109109
110110 /**
111111 * The Java class name of the ClassLoader implementation to be used.
112 * This class should extend WebappClassLoader, otherwise, a different
112 * This class should extend WebappClassLoaderBase, otherwise, a different
113113 * loader implementation must be used.
114114 */
115 private String loaderClass =
116 "org.apache.catalina.loader.WebappClassLoader";
115 private String loaderClass = WebappClassLoader.class.getName();
117116
118117
119118 /**
405404 if (!contextName.startsWith("/")) {
406405 contextName = "/" + contextName;
407406 }
408 ObjectName cloname = new ObjectName(context.getDomain() +
409 ":type=WebappClassLoader,host=" + context.getParent().getName() +
410 ",context=" + contextName);
407 ObjectName cloname = new ObjectName(context.getDomain() + ":type=" +
408 classLoader.getClass().getSimpleName() + ",host=" +
409 context.getParent().getName() + ",context=" + contextName);
411410 Registry.getRegistry(null, null)
412411 .registerComponent(classLoader, cloname, null);
413412
455454 if (!contextName.startsWith("/")) {
456455 contextName = "/" + contextName;
457456 }
458 ObjectName cloname = new ObjectName(context.getDomain() +
459 ":type=WebappClassLoader,host=" + context.getParent().getName() +
460 ",context=" + contextName);
457 ObjectName cloname = new ObjectName(context.getDomain() + ":type=" +
458 classLoader.getClass().getSimpleName() + ",host=" +
459 context.getParent().getName() + ",context=" + contextName);
461460 Registry.getRegistry(null, null).unregisterComponent(cloname);
462461 } catch (Exception e) {
463462 log.error("LifecycleException ", e);
500499 /**
501500 * Create associated classLoader.
502501 */
503 private WebappClassLoader createClassLoader()
502 private WebappClassLoaderBase createClassLoader()
504503 throws Exception {
505504
506505 Class<?> clazz = Class.forName(loaderClass);
507 WebappClassLoader classLoader = null;
506 WebappClassLoaderBase classLoader = null;
508507
509508 if (parentClassLoader == null) {
510509 parentClassLoader = context.getParentClassLoader();
512511 Class<?>[] argTypes = { ClassLoader.class };
513512 Object[] args = { parentClassLoader };
514513 Constructor<?> constr = clazz.getConstructor(argTypes);
515 classLoader = (WebappClassLoader) constr.newInstance(args);
514 classLoader = (WebappClassLoaderBase) constr.newInstance(args);
516515
517516 return classLoader;
518517 }
8989
9090 </mbean>
9191
92
93 <mbean name="ParallelWebappClassLoader"
94 description="Classloader implementation which is specialized for handling web applications and is capable of loading classes in parallel"
95 domain="Catalina"
96 group="Loader"
97 type="org.apache.catalina.loader.ParallelWebappClassLoader">
98
99 <attribute name="className"
100 description="Fully qualified class name of the managed object"
101 type="java.lang.String"
102 writeable="false"/>
103
104 <attribute name="contextName"
105 description="Name of the webapp context"
106 type="java.lang.String"
107 writeable="false"/>
108
109 <attribute name="delegate"
110 description="The 'follow standard delegation model' flag that will be used to configure our ClassLoader"
111 type="boolean"/>
112
113 <attribute name="stateName"
114 description="The name of the LifecycleState that this component is currently in"
115 type="java.lang.String"
116 writeable="false"/>
117
118 <attribute name="URLs"
119 description="The URLs of this loader"
120 type="[Ljava.net.URL;"/>
121
122 </mbean>
92123 </mbeans-descriptors>
4545 import org.apache.catalina.connector.Request;
4646 import org.apache.catalina.connector.Response;
4747 import org.apache.catalina.util.LifecycleMBeanBase;
48 import org.apache.catalina.util.MD5Encoder;
4948 import org.apache.catalina.util.SessionConfig;
5049 import org.apache.juli.logging.Log;
5150 import org.apache.juli.logging.LogFactory;
5554 import org.apache.tomcat.util.descriptor.web.SecurityCollection;
5655 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
5756 import org.apache.tomcat.util.res.StringManager;
57 import org.apache.tomcat.util.security.ConcurrentMessageDigest;
58 import org.apache.tomcat.util.security.MD5Encoder;
5859 import org.ietf.jgss.GSSContext;
5960 import org.ietf.jgss.GSSCredential;
6061 import org.ietf.jgss.GSSException;
102103
103104 /**
104105 * The MessageDigest object for digesting user credentials (passwords).
105 */
106 *
107 * @deprecated Unused. Will be removed in Tomcat 9.0.x onwards.
108 */
109 @Deprecated
106110 protected volatile MessageDigest md = null;
107111
108112
109113 /**
110114 * MD5 message digest provider.
111 */
115 *
116 * @deprecated Unused. Will be removed in Tomcat 9.0.x onwards.
117 */
118 @Deprecated
112119 protected static volatile MessageDigest md5Helper;
113120
114121
389396 throw new IllegalArgumentException(uee.getMessage());
390397 }
391398
392 String serverDigest = null;
393 // Bugzilla 32137
394 synchronized(md5Helper) {
395 serverDigest = MD5Encoder.encode(md5Helper.digest(valueBytes));
396 }
399 String serverDigest = MD5Encoder.encode(ConcurrentMessageDigest.digestMD5(valueBytes));
397400
398401 if (log.isDebugEnabled()) {
399402 log.debug("Digest : " + clientDigest + " Username:" + username
508511 // Server is storing digested passwords with a prefix indicating
509512 // the digest type
510513 String serverDigest = serverCredentials.substring(5);
511 String userDigest;
512 synchronized (this) {
513 md.reset();
514 md.update(userCredentials.getBytes(StandardCharsets.ISO_8859_1));
515 userDigest = Base64.encodeBase64String(md.digest());
516 }
514 String userDigest = Base64.encodeBase64String(ConcurrentMessageDigest.digest(
515 getDigest(), userCredentials.getBytes(StandardCharsets.ISO_8859_1)));
517516 return userDigest.equals(serverDigest);
518517
519518 } else if (serverCredentials.startsWith("{SSHA}")) {
530529 byte[] serverDigestBytes = new byte[saltPos];
531530 System.arraycopy(serverDigestPlusSaltBytes, 0,
532531 serverDigestBytes, 0, saltPos);
532 final int saltLength = serverDigestPlusSaltBytes.length - saltPos;
533 byte[] serverSaltBytes = new byte[saltLength];
534 System.arraycopy(serverDigestPlusSaltBytes, saltPos,
535 serverSaltBytes, 0, saltLength);
533536
534537 // Generate the digested form of the user provided password
535538 // using the salt
536 byte[] userDigestBytes;
537 synchronized (this) {
538 md.reset();
539 // User provided password
540 md.update(userCredentials.getBytes(StandardCharsets.ISO_8859_1));
541 // Add the salt
542 md.update(serverDigestPlusSaltBytes, saltPos,
543 serverDigestPlusSaltBytes.length - saltPos);
544 userDigestBytes = md.digest();
545 }
539 byte[] userDigestBytes = ConcurrentMessageDigest.digest(getDigest(),
540 userCredentials.getBytes(StandardCharsets.ISO_8859_1),
541 serverSaltBytes);
546542
547543 return Arrays.equals(userDigestBytes, serverDigestBytes);
548544
11191115 protected void startInternal() throws LifecycleException {
11201116
11211117 // Create a MessageDigest instance for credentials, if desired
1122 if (digest != null) {
1118
1119 if (getDigest() != null) {
11231120 try {
1124 md = MessageDigest.getInstance(digest);
1121 md = MessageDigest.getInstance(getDigest());
1122 ConcurrentMessageDigest.init(getDigest());
11251123 } catch (NoSuchAlgorithmException e) {
11261124 throw new LifecycleException
1127 (sm.getString("realmBase.algorithm", digest), e);
1128 }
1125 (sm.getString("realmBase.algorithm", getDigest()), e);
1126 }
1127
11291128 }
11301129
11311130 setState(LifecycleState.STARTING);
11821181 // Digest the user credentials and return as hexadecimal
11831182 synchronized (this) {
11841183 try {
1185 md.reset();
1186
11871184 byte[] bytes = null;
11881185 try {
11891186 bytes = credentials.getBytes(getDigestCharset());
11911188 log.error("Illegal digestEncoding: " + getDigestEncoding(), uee);
11921189 throw new IllegalArgumentException(uee.getMessage());
11931190 }
1194 md.update(bytes);
1195
1196 return (HexUtils.toHexString(md.digest()));
1191
1192 return (HexUtils.toHexString(ConcurrentMessageDigest.digest(getDigest(), bytes)));
11971193 } catch (Exception e) {
11981194 log.error(sm.getString("realmBase.digest"), e);
11991195 return (credentials);
12031199 }
12041200
12051201 protected boolean hasMessageDigest() {
1206 return !(md == null);
1202 return getDigest() != null;
12071203 }
12081204
12091205 /**
12101206 * Return the digest associated with given principal's user name.
12111207 */
12121208 protected String getDigest(String username, String realmName) {
1213 if (md5Helper == null) {
1214 try {
1215 md5Helper = MessageDigest.getInstance("MD5");
1216 } catch (NoSuchAlgorithmException e) {
1217 log.error("Couldn't get MD5 digest: ", e);
1218 throw new IllegalStateException(e.getMessage());
1219 }
1220 }
1221
12221209 if (hasMessageDigest()) {
12231210 // Use pre-generated digest
12241211 return getPassword(username);
12351222 throw new IllegalArgumentException(uee.getMessage());
12361223 }
12371224
1238 byte[] digest;
1239 // Bugzilla 32137
1240 synchronized(md5Helper) {
1241 digest = md5Helper.digest(valueBytes);
1242 }
1243
1244 return MD5Encoder.encode(digest);
1225 return MD5Encoder.encode(ConcurrentMessageDigest.digestMD5(valueBytes));
12451226 }
12461227
12471228
108108 final String basePackage = "org.apache.catalina.loader.";
109109 loader.loadClass
110110 (basePackage +
111 "WebappClassLoader$PrivilegedFindResourceByName");
111 "WebappClassLoaderBase$PrivilegedFindResourceByName");
112112 }
113113
114114
275275 clazz.newInstance();
276276 loader.loadClass(basePackage + "util.http.HttpMessages");
277277 loader.loadClass(basePackage + "util.http.parser.HttpParser");
278 loader.loadClass(basePackage + "util.http.parser.HttpParser$SkipResult");
279278 loader.loadClass(basePackage + "util.http.parser.MediaType");
280279 loader.loadClass(basePackage + "util.http.parser.MediaTypeCache");
280 loader.loadClass(basePackage + "util.http.parser.SkipResult");
281281 // net
282282 loader.loadClass(basePackage + "util.net.Constants");
283283 loader.loadClass(basePackage + "util.net.DispatchType");
20312031 while ( (exception == null) && (ranges.hasNext()) ) {
20322032
20332033 InputStream resourceInputStream = resource.getInputStream();
2034 InputStream istream =
2035 new BufferedInputStream(resourceInputStream, input);
2036
2037 Range currentRange = ranges.next();
2038
2039 // Writing MIME header.
2040 ostream.println();
2041 ostream.println("--" + mimeSeparation);
2042 if (contentType != null)
2043 ostream.println("Content-Type: " + contentType);
2044 ostream.println("Content-Range: bytes " + currentRange.start
2045 + "-" + currentRange.end + "/"
2046 + currentRange.length);
2047 ostream.println();
2048
2049 // Printing content
2050 exception = copyRange(istream, ostream, currentRange.start,
2051 currentRange.end);
2052
2053 istream.close();
2054
2034 try (InputStream istream = new BufferedInputStream(resourceInputStream, input)) {
2035
2036 Range currentRange = ranges.next();
2037
2038 // Writing MIME header.
2039 ostream.println();
2040 ostream.println("--" + mimeSeparation);
2041 if (contentType != null)
2042 ostream.println("Content-Type: " + contentType);
2043 ostream.println("Content-Range: bytes " + currentRange.start
2044 + "-" + currentRange.end + "/"
2045 + currentRange.length);
2046 ostream.println();
2047
2048 // Printing content
2049 exception = copyRange(istream, ostream, currentRange.start,
2050 currentRange.end);
2051 }
20552052 }
20562053
20572054 ostream.println();
2020 import java.io.StringWriter;
2121 import java.io.Writer;
2222 import java.nio.charset.StandardCharsets;
23 import java.security.MessageDigest;
24 import java.security.NoSuchAlgorithmException;
2523 import java.util.Date;
2624 import java.util.Enumeration;
2725 import java.util.Hashtable;
3331 import javax.servlet.RequestDispatcher;
3432 import javax.servlet.ServletContext;
3533 import javax.servlet.ServletException;
36 import javax.servlet.UnavailableException;
3734 import javax.servlet.http.HttpServletRequest;
3835 import javax.servlet.http.HttpServletResponse;
3936 import javax.xml.parsers.DocumentBuilder;
4340 import org.apache.catalina.WebResource;
4441 import org.apache.catalina.util.ConcurrentDateFormat;
4542 import org.apache.catalina.util.DOMWriter;
46 import org.apache.catalina.util.MD5Encoder;
4743 import org.apache.catalina.util.XMLWriter;
4844 import org.apache.tomcat.util.buf.UDecoder;
4945 import org.apache.tomcat.util.http.FastHttpDateFormat;
5046 import org.apache.tomcat.util.http.RequestUtil;
47 import org.apache.tomcat.util.security.ConcurrentMessageDigest;
48 import org.apache.tomcat.util.security.MD5Encoder;
5149 import org.w3c.dom.Document;
5250 import org.w3c.dom.Element;
5351 import org.w3c.dom.Node;
190188 TimeZone.getTimeZone("GMT"));
191189
192190
193 /**
194 * MD5 message digest provider.
195 */
196 protected static MessageDigest md5Helper;
197
198
199191 // ----------------------------------------------------- Instance Variables
200192
201193 /**
270262 if (getServletConfig().getInitParameter("allowSpecialPaths") != null)
271263 allowSpecialPaths = Boolean.parseBoolean(
272264 getServletConfig().getInitParameter("allowSpecialPaths"));
273
274 // Load the MD5 helper used to calculate signatures.
275 try {
276 md5Helper = MessageDigest.getInstance("MD5");
277 } catch (NoSuchAlgorithmException e) {
278 throw new UnavailableException("No MD5");
279 }
280
281265 }
282266
283267
10751059 + lock.depth + "-" + lock.owner + "-" + lock.tokens + "-"
10761060 + lock.expiresAt + "-" + System.currentTimeMillis() + "-"
10771061 + secret;
1078 String lockToken = MD5Encoder.encode(md5Helper.digest(
1062 String lockToken = MD5Encoder.encode(ConcurrentMessageDigest.digestMD5(
10791063 lockTokenStr.getBytes(StandardCharsets.ISO_8859_1)));
10801064
10811065 if (resource.isDirectory() && lock.depth == maxDepth) {
137137
138138 static {
139139 // Load our mapping properties for the standard authenticators
140 InputStream is =
141 ContextConfig.class.getClassLoader().getResourceAsStream(
142 "org/apache/catalina/startup/Authenticators.properties");
143 Properties props = null;
144 props = new Properties();
145 if (is != null) {
146 try {
140 Properties props = new Properties();
141 try (InputStream is = ContextConfig.class.getClassLoader().getResourceAsStream(
142 "org/apache/catalina/startup/Authenticators.properties");) {
143 if (is != null) {
147144 props.load(is);
148 } catch (IOException e) {
149 props = null;
150 }
145 }
146 } catch (IOException ioe) {
147 props = null;
151148 }
152149 authenticators = props;
153
154150 }
155151
156152 /**
164160 */
165161 protected static final Map<Host,DefaultWebXmlCacheEntry> hostWebXmlCache =
166162 new ConcurrentHashMap<>();
163
164
165 /**
166 * Set used as the value for {@code JavaClassCacheEntry.sciSet} when there
167 * are no SCIs associated with a class.
168 */
169 private static final Set<ServletContainerInitializer> EMPTY_SCI_SET = Collections.emptySet();
167170
168171
169172 // ----------------------------------------------------- Instance Variables
608611 }
609612 }
610613
611 if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory() && unpackWARs) {
612 URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");
613 docBase = ExpandWar.expand(host, war, pathName);
614 file = new File(docBase);
615 docBase = file.getCanonicalPath();
616 if (context instanceof StandardContext) {
617 ((StandardContext) context).setOriginalDocBase(origDocBase);
618 }
619 } else if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") &&
620 !file.isDirectory() && !unpackWARs) {
621 URL war =
622 new URL("jar:" + (new File (docBase)).toURI().toURL() + "!/");
623 ExpandWar.validate(host, war, pathName);
614 if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory()) {
615 if (unpackWARs) {
616 URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");
617 docBase = ExpandWar.expand(host, war, pathName);
618 file = new File(docBase);
619 docBase = file.getCanonicalPath();
620 if (context instanceof StandardContext) {
621 ((StandardContext) context).setOriginalDocBase(origDocBase);
622 }
623 } else {
624 URL war =
625 new URL("jar:" + (new File (docBase)).toURI().toURL() + "!/");
626 ExpandWar.validate(host, war, pathName);
627 }
624628 } else {
625629 File docDir = new File(docBase);
626630 if (!docDir.exists()) {
19851989 boolean handlesTypesOnly)
19861990 throws ClassFormatException, IOException {
19871991
1988 ClassParser parser = new ClassParser(is, null);
1992 ClassParser parser = new ClassParser(is);
19891993 JavaClass clazz = parser.parse();
19901994 checkHandlesTypes(clazz);
19911995
19931997 return;
19941998 }
19951999
1996 String className = clazz.getClassName();
1997
19982000 AnnotationEntry[] annotationsEntries = clazz.getAnnotationEntries();
1999
2000 for (AnnotationEntry ae : annotationsEntries) {
2001 String type = ae.getAnnotationType();
2002 if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) {
2003 processAnnotationWebServlet(className, ae, fragment);
2004 }else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) {
2005 processAnnotationWebFilter(className, ae, fragment);
2006 }else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) {
2007 fragment.addListener(className);
2008 } else {
2009 // Unknown annotation - ignore
2001 if (annotationsEntries != null) {
2002 String className = clazz.getClassName();
2003 for (AnnotationEntry ae : annotationsEntries) {
2004 String type = ae.getAnnotationType();
2005 if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) {
2006 processAnnotationWebServlet(className, ae, fragment);
2007 }else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) {
2008 processAnnotationWebFilter(className, ae, fragment);
2009 }else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) {
2010 fragment.addListener(className);
2011 } else {
2012 // Unknown annotation - ignore
2013 }
20102014 }
20112015 }
20122016 }
20472051 classHierarchyToString(className, entry)));
20482052 }
20492053 }
2050 if (entry.getSciSet().size() > 0) {
2054 if (!entry.getSciSet().isEmpty()) {
20512055 // Need to try and load the class
20522056 clazz = Introspection.loadClass(context, className);
20532057 if (clazz == null) {
20552059 return;
20562060 }
20572061
2058 for (ServletContainerInitializer sci :
2059 entry.getSciSet()) {
2062 for (ServletContainerInitializer sci : entry.getSciSet()) {
20602063 Set<Class<?>> classes = initializerClassMap.get(sci);
20612064 if (classes == null) {
20622065 classes = new HashSet<>();
20682071 }
20692072
20702073 if (handlesTypesAnnotations) {
2071 for (Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry :
2072 typeInitializerMap.entrySet()) {
2073 if (entry.getKey().isAnnotation()) {
2074 AnnotationEntry[] annotationEntries =
2075 javaClass.getAnnotationEntries();
2076 for (AnnotationEntry annotationEntry : annotationEntries) {
2077 if (entry.getKey().getName().equals(
2078 getClassName(annotationEntry.getAnnotationType()))) {
2079 if (clazz == null) {
2080 clazz = Introspection.loadClass(
2081 context, className);
2074 AnnotationEntry[] annotationEntries = javaClass.getAnnotationEntries();
2075 if (annotationEntries != null) {
2076 for (Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry :
2077 typeInitializerMap.entrySet()) {
2078 if (entry.getKey().isAnnotation()) {
2079 String entryClassName = entry.getKey().getName();
2080 for (AnnotationEntry annotationEntry : annotationEntries) {
2081 if (entryClassName.equals(
2082 getClassName(annotationEntry.getAnnotationType()))) {
20822083 if (clazz == null) {
2083 // Can't load the class so no point
2084 // continuing
2085 return;
2084 clazz = Introspection.loadClass(
2085 context, className);
2086 if (clazz == null) {
2087 // Can't load the class so no point
2088 // continuing
2089 return;
2090 }
20862091 }
2092 for (ServletContainerInitializer sci : entry.getValue()) {
2093 initializerClassMap.get(sci).add(clazz);
2094 }
2095 break;
20872096 }
2088 for (ServletContainerInitializer sci : entry.getValue()) {
2089 initializerClassMap.get(sci).add(clazz);
2090 }
2091 break;
20922097 }
20932098 }
20942099 }
21432148 if (is == null) {
21442149 return;
21452150 }
2146 ClassParser parser = new ClassParser(is, null);
2151 ClassParser parser = new ClassParser(is);
21472152 JavaClass clazz = parser.parse();
21482153 populateJavaClassCache(clazz.getClassName(), clazz);
21492154 } catch (ClassFormatException e) {
21662171
21672172 // Avoid an infinite loop with java.lang.Object
21682173 if (cacheEntry.equals(superClassCacheEntry)) {
2169 cacheEntry.setSciSet(new HashSet<ServletContainerInitializer>());
2174 cacheEntry.setSciSet(EMPTY_SCI_SET);
21702175 return;
21712176 }
21722177
21952200 result.addAll(getSCIsForClass(interfaceName));
21962201 }
21972202
2198 cacheEntry.setSciSet(result);
2203 cacheEntry.setSciSet(result.isEmpty() ? EMPTY_SCI_SET : result);
21992204 }
22002205
22012206 private Set<ServletContainerInitializer> getSCIsForClass(String className) {
22082213 }
22092214 }
22102215 }
2211 return Collections.emptySet();
2216 return EMPTY_SCI_SET;
22122217 }
22132218
22142219 private static final String getClassName(String internalForm) {
22252230 AnnotationEntry ae, WebXml fragment) {
22262231 String servletName = null;
22272232 // must search for name s. Spec Servlet API 3.0 - 8.2.3.3.n.ii page 81
2228 ElementValuePair[] evps = ae.getElementValuePairs();
2233 List<ElementValuePair> evps = ae.getElementValuePairs();
22292234 for (ElementValuePair evp : evps) {
22302235 String name = evp.getNameString();
22312236 if ("name".equals(name)) {
22522257 boolean urlPatternsSet = false;
22532258 String[] urlPatterns = null;
22542259
2255 // ElementValuePair[] evps = ae.getElementValuePairs();
2260 // List<ElementValuePair> evps = ae.getElementValuePairs();
22562261 for (ElementValuePair evp : evps) {
22572262 String name = evp.getNameString();
22582263 if ("value".equals(name) || "urlPatterns".equals(name)) {
23352340 AnnotationEntry ae, WebXml fragment) {
23362341 String filterName = null;
23372342 // must search for name s. Spec Servlet API 3.0 - 8.2.3.3.n.ii page 81
2338 ElementValuePair[] evps = ae.getElementValuePairs();
2343 List<ElementValuePair> evps = ae.getElementValuePairs();
23392344 for (ElementValuePair evp : evps) {
23402345 String name = evp.getNameString();
23412346 if ("filterName".equals(name)) {
24942499 ((ArrayElementValue) ev).getElementValuesArray();
24952500 for (ElementValue value : arrayValues) {
24962501 if (value instanceof AnnotationElementValue) {
2497 ElementValuePair[] evps = ((AnnotationElementValue)
2498 value).getAnnotationEntry().getElementValuePairs();
2502 List<ElementValuePair> evps = ((AnnotationElementValue) value)
2503 .getAnnotationEntry().getElementValuePairs();
24992504 String initParamName = null;
25002505 String initParamValue = null;
25012506 for (ElementValuePair evp : evps) {
1818 import java.beans.PropertyChangeListener;
1919 import java.io.File;
2020 import java.net.URL;
21 import java.nio.charset.Charset;
22 import java.nio.charset.StandardCharsets;
2123 import java.util.Locale;
2224 import java.util.Map;
2325 import java.util.Set;
752754 }
753755
754756 @Override
755 public Object getNamingToken() {
756 return null;
757 }
757 public Object getNamingToken() { return null; }
758
759 @Override
760 public void setUseRfc6265(boolean useRfc6265) { /* NO-OP */ }
761
762 @Override
763 public boolean getUseRfc6265() {return false; }
764
765 @Override
766 public void setCookieEncoding(String encoding) { /* NO-OP */ }
767
768 @Override
769 public String getCookieEncoding() { return "UTF-8"; }
770
771 @Override
772 public Charset getCookieEncodingCharset() { return StandardCharsets.UTF_8; }
758773 }
898898 if (deployXML && xml.exists() && copyThisXml) {
899899 deployedApp.redeployResources.put(xml.getAbsolutePath(),
900900 Long.valueOf(xml.lastModified()));
901 } else if (!copyThisXml ) {
901 } else {
902902 // In case an XML file is added to the config base later
903903 deployedApp.redeployResources.put(
904904 (new File(host.getConfigBaseFile(),
12221222 // expanded WAR (if any)
12231223 Context context = (Context) host.findChild(app.name);
12241224 String docBase = context.getDocBase();
1225 docBase = docBase.toLowerCase(Locale.ENGLISH);
1226 if (!docBase.endsWith(".war")) {
1225 if (!docBase.toLowerCase(Locale.ENGLISH).endsWith(".war")) {
12271226 // This is an expanded directory
12281227 File docBaseFile = new File(docBase);
12291228 if (!docBaseFile.isAbsolute()) {
15191518 Context previousContext =
15201519 (Context) host.findChild(previous.getName());
15211520 Context currentContext =
1522 (Context) host.findChild(previous.getName());
1521 (Context) host.findChild(current.getName());
15231522 if (previousContext != null && currentContext != null &&
15241523 currentContext.getState().isAvailable() &&
15251524 !isServiced(previous.getName())) {
120120 userConfig.start=UserConfig: Processing START
121121 userConfig.stop=UserConfig: Processing STOP
122122 userConfig.deploy.threaded.error=Error waiting for multi-thread deployment of user directories to complete
123 versionLoggerListener.serverInfo.server.version=Server version: {0}
124 versionLoggerListener.serverInfo.server.built =Server built: {0}
125 versionLoggerListener.serverInfo.server.number =Server number: {0}
126 versionLoggerListener.serverInfo.os.name =OS Name: {0}
127 versionLoggerListener.serverInfo.os.version =OS Version: {0}
128 versionLoggerListener.serverInfo.os.arch =Architecture: {0}
129 versionLoggerListener.serverInfo.vm.version =JVM Version: {0}
130 versionLoggerListener.serverInfo.vm.vendor =JVM Vendor: {0}
123131 webAnnotationSet.invalidInjection=Invalid method resource injection annotation.
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.catalina.startup;
17
18 import org.apache.catalina.LifecycleEvent;
19 import org.apache.catalina.LifecycleListener;
20 import org.apache.catalina.util.ServerInfo;
21 import org.apache.juli.logging.Log;
22 import org.apache.juli.logging.LogFactory;
23 import org.apache.tomcat.util.res.StringManager;
24
25 /**
26 * Logs version information on startup.
27 */
28 public class VersionLoggerListener implements LifecycleListener {
29
30 private static final Log log = LogFactory.getLog(VersionLoggerListener.class);
31
32 /**
33 * The string manager for this package.
34 */
35 protected static final StringManager sm = StringManager.getManager(Constants.Package);
36
37
38 public VersionLoggerListener() {
39 // The log message is generated here to ensure that it appears before
40 // any log messages from the APRLifecycleListener. This won't be logged
41 // on shutdown because only the Server element in server.xml is
42 // processed on shutdown.
43 log();
44 }
45
46
47 @Override
48 public void lifecycleEvent(LifecycleEvent event) {
49 // NO-OP
50 }
51
52
53 private void log() {
54 log.info(sm.getString("versionLoggerListener.serverInfo.server.version",
55 ServerInfo.getServerInfo()));
56 log.info(sm.getString("versionLoggerListener.serverInfo.server.built",
57 ServerInfo.getServerBuilt()));
58 log.info(sm.getString("versionLoggerListener.serverInfo.server.number",
59 ServerInfo.getServerNumber()));
60 log.info(sm.getString("versionLoggerListener.serverInfo.os.name",
61 System.getProperty("os.name")));
62 log.info(sm.getString("versionLoggerListener.serverInfo.os.version",
63 System.getProperty("os.version")));
64 log.info(sm.getString("versionLoggerListener.serverInfo.os.arch",
65 System.getProperty("os.arch")));
66 log.info(sm.getString("versionLoggerListener.serverInfo.vm.version",
67 System.getProperty("java.runtime.version")));
68 log.info(sm.getString("versionLoggerListener.serverInfo.vm.vendor",
69 System.getProperty("java.vm.vendor")));
70 }
71 }
153153 /* Process Resource annotation.
154154 * Ref JSR 250
155155 */
156 {
157 Resource annotation = classClass.getAnnotation(Resource.class);
158 if (annotation != null) {
159 addResource(context, annotation);
160 }
156 Resource resourceAnnotation = classClass.getAnnotation(Resource.class);
157 if (resourceAnnotation != null) {
158 addResource(context, resourceAnnotation);
161159 }
162160 /* Process Resources annotation.
163161 * Ref JSR 250
164162 */
165 {
166 Resources annotation = classClass.getAnnotation(Resources.class);
167 if (annotation != null && annotation.value() != null) {
168 for (Resource resource : annotation.value()) {
169 addResource(context, resource);
170 }
163 Resources resourcesAnnotation = classClass.getAnnotation(Resources.class);
164 if (resourcesAnnotation != null && resourcesAnnotation.value() != null) {
165 for (Resource resource : resourcesAnnotation.value()) {
166 addResource(context, resource);
171167 }
172168 }
173169 /* Process EJB annotation.
243239 * Ref JSR 250, equivalent to the security-role element in
244240 * the deployment descriptor
245241 */
246 {
247 DeclareRoles annotation = classClass
248 .getAnnotation(DeclareRoles.class);
249 if (annotation != null && annotation.value() != null) {
250 for (String role : annotation.value()) {
251 context.addSecurityRole(role);
252 }
242 DeclareRoles declareRolesAnnotation = classClass
243 .getAnnotation(DeclareRoles.class);
244 if (declareRolesAnnotation != null && declareRolesAnnotation.value() != null) {
245 for (String role : declareRolesAnnotation.value()) {
246 context.addSecurityRole(role);
253247 }
254248 }
255249 }
6868 * resource could not be loaded for any reason.
6969 */
7070 public CharsetMapper(String name) {
71 try {
72 InputStream stream =
73 this.getClass().getResourceAsStream(name);
71 try (InputStream stream = this.getClass().getResourceAsStream(name)) {
7472 map.load(stream);
75 stream.close();
7673 } catch (Throwable t) {
7774 ExceptionUtils.handleThrowable(t);
7875 throw new IllegalArgumentException(t.toString());
+0
-102
java/org/apache/catalina/util/ConcurrentMessageDigest.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.catalina.util;
17
18 import java.security.MessageDigest;
19 import java.security.NoSuchAlgorithmException;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Queue;
23 import java.util.concurrent.ConcurrentLinkedQueue;
24
25 /**
26 * A thread safe wrapper around {@link MessageDigest} that does not make use
27 * of ThreadLocal and - broadly - only creates enough MessageDigest objects
28 * to satisfy the concurrency requirements.
29 */
30 public class ConcurrentMessageDigest {
31
32 private static final String MD5 = "MD5";
33
34 private static final Map<String,Queue<MessageDigest>> queues =
35 new HashMap<>();
36
37
38 private ConcurrentMessageDigest() {
39 // Hide default constructor for this utility class
40 }
41
42 static {
43 try {
44 // Init commonly used algorithms
45 init(MD5);
46 } catch (NoSuchAlgorithmException e) {
47 throw new IllegalArgumentException(e);
48 }
49 }
50
51 public static byte[] digestMD5(byte[] input) {
52 return digest(MD5, input);
53 }
54
55 public static byte[] digest(String algorithm, byte[] input) {
56
57 Queue<MessageDigest> queue = queues.get(algorithm);
58 if (queue == null) {
59 throw new IllegalStateException("Must call init() first");
60 }
61
62 MessageDigest md = queue.poll();
63 if (md == null) {
64 try {
65 md = MessageDigest.getInstance(algorithm);
66 } catch (NoSuchAlgorithmException e) {
67 // Ignore. Impossible if init() has been successfully called
68 // first.
69 throw new IllegalStateException("Must call init() first");
70 }
71 }
72
73 byte[] result = md.digest(input);
74
75 queue.add(md);
76
77 return result;
78 }
79
80
81 /**
82 * Ensures that {@link #digest(String, byte[])} will support the specified
83 * algorithm. This method <b>must</b> be called and return successfully
84 * before using {@link #digest(String, byte[])}.
85 *
86 * @param algorithm The message digest algorithm to be supported
87 *
88 * @throws NoSuchAlgorithmException If the algorithm is not supported by the
89 * JVM
90 */
91 public static void init(String algorithm) throws NoSuchAlgorithmException {
92 synchronized (queues) {
93 if (!queues.containsKey(algorithm)) {
94 MessageDigest md = MessageDigest.getInstance(algorithm);
95 Queue<MessageDigest> queue = new ConcurrentLinkedQueue<>();
96 queue.add(md);
97 queues.put(algorithm, queue);
98 }
99 }
100 }
101 }
168168 * @param jarFile The system JAR whose manifest to add
169169 */
170170 public static void addSystemResource(File jarFile) throws IOException {
171 Manifest manifest = getManifest(new FileInputStream(jarFile));
172 if (manifest != null) {
173 ManifestResource mre
174 = new ManifestResource(jarFile.getAbsolutePath(),
175 manifest,
176 ManifestResource.SYSTEM);
177 containerManifestResources.add(mre);
171 try (InputStream is = new FileInputStream(jarFile)) {
172 Manifest manifest = getManifest(is);
173 if (manifest != null) {
174 ManifestResource mre = new ManifestResource(jarFile.getAbsolutePath(), manifest,
175 ManifestResource.SYSTEM);
176 containerManifestResources.add(mre);
177 }
178178 }
179179 }
180180
+0
-64
java/org/apache/catalina/util/MD5Encoder.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.catalina.util;
17
18 /**
19 * Encode an MD5 digest into a String.
20 * <p>
21 * The 128 bit MD5 hash is converted into a 32 character long String.
22 * Each character of the String is the hexadecimal representation of 4 bits
23 * of the digest.
24 *
25 * @author Remy Maucherat
26 */
27 public final class MD5Encoder {
28
29
30 private MD5Encoder() {
31 // Hide default constructor for utility class
32 }
33
34
35 private static final char[] hexadecimal = {'0', '1', '2', '3', '4', '5',
36 '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
37
38
39 /**
40 * Encodes the 128 bit (16 bytes) MD5 into a 32 character String.
41 *
42 * @param binaryData Array containing the digest
43 *
44 * @return Encoded MD5, or null if encoding failed
45 */
46 public static String encode(byte[] binaryData) {
47
48 if (binaryData.length != 16)
49 return null;
50
51 char[] buffer = new char[32];
52
53 for (int i=0; i<16; i++) {
54 int low = binaryData[i] & 0x0f;
55 int high = (binaryData[i] & 0xf0) >> 4;
56 buffer[i*2] = hexadecimal[high];
57 buffer[i*2 + 1] = hexadecimal[low];
58 }
59
60 return new String(buffer);
61 }
62 }
63
5757 String built = null;
5858 String number = null;
5959
60 try {
61 InputStream is = ServerInfo.class.getResourceAsStream
62 ("/org/apache/catalina/util/ServerInfo.properties");
63 Properties props = new Properties();
60 Properties props = new Properties();
61 try (InputStream is = ServerInfo.class.getResourceAsStream
62 ("/org/apache/catalina/util/ServerInfo.properties")) {
6463 props.load(is);
65 is.close();
6664 info = props.getProperty("server.info");
6765 built = props.getProperty("server.built");
6866 number = props.getProperty("server.number");
338338 StringBuilder buffer = new StringBuilder();
339339 boolean first = true;
340340 while (iter.hasNext()) {
341 if (!first) {
341 if (first) {
342 first = false;
343 } else {
342344 buffer.append(",");
343345 }
344346 buffer.append(iter.next());
244244 int numStuckThreads = stuckCount.decrementAndGet();
245245 notifyStuckThreadCompleted(completedStuckThread, numStuckThreads);
246246 }
247 }
248
249 public int getStuckThreadCount() {
250 return stuckCount.get();
247251 }
248252
249253 public long[] getStuckThreadIds() {
516516 type="java.lang.String"
517517 writeable="false"/>
518518
519 <attribute name="stuckThreadCount"
520 description="Count of the threads currently considered stuck"
521 type="int"
522 writeable="false"/>
523
519524 <attribute name="stuckThreadIds"
520525 description="IDs of the threads currently considered stuck. Each ID can then be used with the Threading MBean to retrieve data about it."
521526 type="long[]"
7474 }
7575 }
7676
77 protected void configureProcessor(AbstractAjpProcessor<S> processor) {
78 processor.setAdapter(getAdapter());
79 processor.setTomcatAuthentication(getTomcatAuthentication());
80 processor.setRequiredSecret(requiredSecret);
81 processor.setKeepAliveTimeout(getKeepAliveTimeout());
82 processor.setClientCertProvider(getClientCertProvider());
83 }
84
7785 protected abstract static class AbstractAjpConnectionHandler<S,P extends AbstractAjpProcessor<S>>
7886 extends AbstractConnectionHandler<S, P> {
7987
142142 @Override
143143 protected AjpAprProcessor createProcessor() {
144144 AjpAprProcessor processor = new AjpAprProcessor(proto.packetSize, (AprEndpoint)proto.endpoint);
145 processor.setAdapter(proto.getAdapter());
146 processor.setTomcatAuthentication(proto.tomcatAuthentication);
147 processor.setRequiredSecret(proto.requiredSecret);
148 processor.setClientCertProvider(proto.getClientCertProvider());
145 proto.configureProcessor(processor);
149146 register(processor);
150147 return processor;
151148 }
143143 @Override
144144 protected AjpNio2Processor createProcessor() {
145145 AjpNio2Processor processor = new AjpNio2Processor(proto.packetSize, (Nio2Endpoint) proto.endpoint);
146 processor.setAdapter(proto.getAdapter());
147 processor.setTomcatAuthentication(proto.tomcatAuthentication);
148 processor.setRequiredSecret(proto.requiredSecret);
149 processor.setClientCertProvider(proto.getClientCertProvider());
146 proto.configureProcessor(processor);
150147 register(processor);
151148 return processor;
152149 }
172172 @Override
173173 protected AjpNioProcessor createProcessor() {
174174 AjpNioProcessor processor = new AjpNioProcessor(proto.packetSize, (NioEndpoint)proto.endpoint);
175 processor.setAdapter(proto.getAdapter());
176 processor.setTomcatAuthentication(proto.tomcatAuthentication);
177 processor.setRequiredSecret(proto.requiredSecret);
178 processor.setClientCertProvider(proto.getClientCertProvider());
175 proto.configureProcessor(processor);
179176 register(processor);
180177 return processor;
181178 }
131131 @Override
132132 protected AjpProcessor createProcessor() {
133133 AjpProcessor processor = new AjpProcessor(proto.packetSize, (JIoEndpoint)proto.endpoint);
134 processor.setAdapter(proto.getAdapter());
135 processor.setTomcatAuthentication(proto.tomcatAuthentication);
136 processor.setRequiredSecret(proto.requiredSecret);
137 processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
138 processor.setClientCertProvider(proto.getClientCertProvider());
134 proto.configureProcessor(processor);
139135 register(processor);
140136 return processor;
141137 }
217217 }
218218 }
219219
220
221 // ------------------------------------------------------------- Common code
222
223 // Common configuration required for all new HTTP11 processors
224 protected void configureProcessor(AbstractHttp11Processor<S> processor) {
225 processor.setAdapter(getAdapter());
226 processor.setMaxKeepAliveRequests(getMaxKeepAliveRequests());
227 processor.setKeepAliveTimeout(getKeepAliveTimeout());
228 processor.setConnectionUploadTimeout(getConnectionUploadTimeout());
229 processor.setDisableUploadTimeout(getDisableUploadTimeout());
230 processor.setCompressionMinSize(getCompressionMinSize());
231 processor.setCompression(getCompression());
232 processor.setNoCompressionUserAgents(getNoCompressionUserAgents());
233 processor.setCompressableMimeTypes(getCompressableMimeTypes());
234 processor.setRestrictedUserAgents(getRestrictedUserAgents());
235 processor.setSocketBuffer(getSocketBuffer());
236 processor.setMaxSavePostSize(getMaxSavePostSize());
237 processor.setServer(getServer());
238 }
220239 }
418418 }
419419 case REQ_SSL_CERTIFICATE: {
420420 if (endpoint.isSSLEnabled() && (socketRef != 0)) {
421 boolean force = ((Boolean) param).booleanValue();
422 if (force) {
423 /* Forced triggers a handshake so consume and buffer the
424 * request body, so that it does not interfere with the
425 * client's handshake messages
426 */
427 InputFilter[] inputFilters = inputBuffer.getFilters();
428 ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
429 .setLimit(maxSavePostSize);
430 inputBuffer.addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]);
431 }
421 // Consume and buffer the request body, so that it does not
422 // interfere with the client's handshake messages
423 InputFilter[] inputFilters = inputBuffer.getFilters();
424 ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]).setLimit(maxSavePostSize);
425 inputBuffer.addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]);
432426 try {
433 if (force) {
434 // Configure connection to require a certificate
435 SSLSocket.setVerify(socketRef, SSL.SSL_CVERIFY_REQUIRE,
436 ((AprEndpoint)endpoint).getSSLVerifyDepth());
437 }
438 if (!force || SSLSocket.renegotiate(socketRef) == 0) {
439 // Only look for certs if not forcing a renegotiation or
440 // if we know renegotiation worked.
427 // Configure connection to require a certificate
428 SSLSocket.setVerify(socketRef, SSL.SSL_CVERIFY_REQUIRE,
429 ((AprEndpoint)endpoint).getSSLVerifyDepth());
430 // Renegotiate certificates
431 if (SSLSocket.renegotiate(socketRef) == 0) {
432 // Don't look for certs unless we know renegotiation worked.
441433 // Get client certificate and the certificate chain if present
442434 // certLength == -1 indicates an error
443435 int certLength = SSLSocket.getInfoI(socketRef,SSL.SSL_INFO_CLIENT_CERT_CHAIN);
320320 proto.getMaxHttpHeaderSize(), (AprEndpoint)proto.endpoint,
321321 proto.getMaxTrailerSize(), proto.getMaxExtensionSize(),
322322 proto.getMaxSwallowSize());
323 processor.setAdapter(proto.getAdapter());
324 processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
325 processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
326 processor.setConnectionUploadTimeout(
327 proto.getConnectionUploadTimeout());
328 processor.setDisableUploadTimeout(proto.getDisableUploadTimeout());
329 processor.setCompressionMinSize(proto.getCompressionMinSize());
330 processor.setCompression(proto.getCompression());
331 processor.setNoCompressionUserAgents(proto.getNoCompressionUserAgents());
332 processor.setCompressableMimeTypes(proto.getCompressableMimeTypes());
333 processor.setRestrictedUserAgents(proto.getRestrictedUserAgents());
334 processor.setSocketBuffer(proto.getSocketBuffer());
335 processor.setMaxSavePostSize(proto.getMaxSavePostSize());
336 processor.setServer(proto.getServer());
323 proto.configureProcessor(processor);
324 // APR specific configuration
337325 processor.setClientCertProvider(proto.getClientCertProvider());
338326 register(processor);
339327 return processor;
464464 }
465465 case REQ_SSL_CERTIFICATE: {
466466 if (sslSupport != null && socketWrapper.getSocket() != null) {
467 boolean force = ((Boolean) param).booleanValue();
468 if (force) {
469 /* Forced triggers a handshake so consume and buffer the
470 * request body, so that it does not interfere with the
471 * client's handshake messages
472 */
473 InputFilter[] inputFilters = inputBuffer.getFilters();
474 ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
475 .setLimit(maxSavePostSize);
476 inputBuffer.addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]);
477 }
467 /*
468 * Consume and buffer the request body, so that it does not
469 * interfere with the client's handshake messages
470 */
471 InputFilter[] inputFilters = inputBuffer.getFilters();
472 ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
473 .setLimit(maxSavePostSize);
474 inputBuffer.addActiveFilter
475 (inputFilters[Constants.BUFFERED_FILTER]);
478476 SecureNio2Channel sslChannel = (SecureNio2Channel) socketWrapper.getSocket();
479477 SSLEngine engine = sslChannel.getSslEngine();
480 if (!engine.getNeedClientAuth() && force) {
478 if (!engine.getNeedClientAuth()) {
481479 // Need to re-negotiate SSL connection
482480 engine.setNeedClientAuth(true);
483481 try {
494492 // use force=false since re-negotiation is handled above
495493 // (and it is a NO-OP for NIO anyway)
496494 Object sslO = sslSupport.getPeerCertificateChain(false);
497 if (sslO != null) {
498 request.setAttribute(SSLSupport.CERTIFICATE_KEY, sslO);
495 if( sslO != null) {
496 request.setAttribute
497 (SSLSupport.CERTIFICATE_KEY, sslO);
499498 }
500499 } catch (Exception e) {
501500 log.warn(sm.getString("http11processor.socket.ssl"), e);
249249 proto.getMaxHttpHeaderSize(), (Nio2Endpoint) proto.endpoint,
250250 proto.getMaxTrailerSize(), proto.getMaxExtensionSize(),
251251 proto.getMaxSwallowSize());
252 processor.setAdapter(proto.getAdapter());
253 processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
254 processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
255 processor.setConnectionUploadTimeout(
256 proto.getConnectionUploadTimeout());
257 processor.setDisableUploadTimeout(proto.getDisableUploadTimeout());
258 processor.setCompressionMinSize(proto.getCompressionMinSize());
259 processor.setCompression(proto.getCompression());
260 processor.setNoCompressionUserAgents(proto.getNoCompressionUserAgents());
261 processor.setCompressableMimeTypes(proto.getCompressableMimeTypes());
262 processor.setRestrictedUserAgents(proto.getRestrictedUserAgents());
263 processor.setSocketBuffer(proto.getSocketBuffer());
264 processor.setMaxSavePostSize(proto.getMaxSavePostSize());
265 processor.setServer(proto.getServer());
252 proto.configureProcessor(processor);
266253 register(processor);
267254 return processor;
268255 }
433433 }
434434 case REQ_SSL_CERTIFICATE: {
435435 if (sslSupport != null) {
436 boolean force = ((Boolean) param).booleanValue();
437 if (force) {
438 /* Forced triggers a handshake so consume and buffer the
439 * request body, so that it does not interfere with the
440 * client's handshake messages
441 */
442 InputFilter[] inputFilters = inputBuffer.getFilters();
443 ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
444 .setLimit(maxSavePostSize);
445 inputBuffer.addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]);
446 }
436 /*
437 * Consume and buffer the request body, so that it does not
438 * interfere with the client's handshake messages
439 */
440 InputFilter[] inputFilters = inputBuffer.getFilters();
441 ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
442 .setLimit(maxSavePostSize);
443 inputBuffer.addActiveFilter
444 (inputFilters[Constants.BUFFERED_FILTER]);
447445 SecureNioChannel sslChannel = (SecureNioChannel) socketWrapper.getSocket();
448446 SSLEngine engine = sslChannel.getSslEngine();
449 if (!engine.getNeedClientAuth() && force) {
447 if (!engine.getNeedClientAuth()) {
450448 // Need to re-negotiate SSL connection
451449 engine.setNeedClientAuth(true);
452450 try {
463461 // use force=false since re-negotiation is handled above
464462 // (and it is a NO-OP for NIO anyway)
465463 Object sslO = sslSupport.getPeerCertificateChain(false);
466 if (sslO != null) {
467 request.setAttribute(SSLSupport.CERTIFICATE_KEY, sslO);
464 if( sslO != null) {
465 request.setAttribute
466 (SSLSupport.CERTIFICATE_KEY, sslO);
468467 }
469468 } catch (Exception e) {
470469 log.warn(sm.getString("http11processor.socket.ssl"), e);
281281 proto.getMaxHttpHeaderSize(), (NioEndpoint)proto.endpoint,
282282 proto.getMaxTrailerSize(), proto.getMaxExtensionSize(),
283283 proto.getMaxSwallowSize());
284 processor.setAdapter(proto.getAdapter());
285 processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
286 processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
287 processor.setConnectionUploadTimeout(
288 proto.getConnectionUploadTimeout());
289 processor.setDisableUploadTimeout(proto.getDisableUploadTimeout());
290 processor.setCompressionMinSize(proto.getCompressionMinSize());
291 processor.setCompression(proto.getCompression());
292 processor.setNoCompressionUserAgents(proto.getNoCompressionUserAgents());
293 processor.setCompressableMimeTypes(proto.getCompressableMimeTypes());
294 processor.setRestrictedUserAgents(proto.getRestrictedUserAgents());
295 processor.setSocketBuffer(proto.getSocketBuffer());
296 processor.setMaxSavePostSize(proto.getMaxSavePostSize());
297 processor.setServer(proto.getServer());
284 proto.configureProcessor(processor);
298285 register(processor);
299286 return processor;
300287 }
349349 }
350350 case REQ_SSL_CERTIFICATE: {
351351 if (sslSupport != null) {
352 boolean force = ((Boolean) param).booleanValue();
353 if (force) {
354 /* Forced triggers a handshake so consume and buffer the
355 * request body, so that it does not interfere with the
356 * client's handshake messages
357 */
358 InputFilter[] inputFilters = inputBuffer.getFilters();
359 ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
360 .setLimit(maxSavePostSize);
361 inputBuffer.addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]);
362 }
352 /*
353 * Consume and buffer the request body, so that it does not
354 * interfere with the client's handshake messages
355 */
356 InputFilter[] inputFilters = inputBuffer.getFilters();
357 ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
358 .setLimit(maxSavePostSize);
359 inputBuffer.addActiveFilter
360 (inputFilters[Constants.BUFFERED_FILTER]);
363361 try {
364 Object sslO = sslSupport.getPeerCertificateChain(force);
362 Object sslO = sslSupport.getPeerCertificateChain(true);
365363 if( sslO != null) {
366364 request.setAttribute
367365 (SSLSupport.CERTIFICATE_KEY, sslO);
187187 proto.getMaxHttpHeaderSize(), (JIoEndpoint)proto.endpoint,
188188 proto.getMaxTrailerSize(),proto.getMaxExtensionSize(),
189189 proto.getMaxSwallowSize());
190 processor.setAdapter(proto.getAdapter());
191 processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
192 processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
193 processor.setConnectionUploadTimeout(
194 proto.getConnectionUploadTimeout());
195 processor.setDisableUploadTimeout(proto.getDisableUploadTimeout());
196 processor.setCompressionMinSize(proto.getCompressionMinSize());
197 processor.setCompression(proto.getCompression());
198 processor.setNoCompressionUserAgents(proto.getNoCompressionUserAgents());
199 processor.setCompressableMimeTypes(proto.getCompressableMimeTypes());
200 processor.setRestrictedUserAgents(proto.getRestrictedUserAgents());
201 processor.setSocketBuffer(proto.getSocketBuffer());
202 processor.setMaxSavePostSize(proto.getMaxSavePostSize());
203 processor.setServer(proto.getServer());
204 processor.setDisableKeepAlivePercentage(
205 proto.getDisableKeepAlivePercentage());
190 proto.configureProcessor(processor);
191 // BIO specific configuration
192 processor.setDisableKeepAlivePercentage(proto.getDisableKeepAlivePercentage());
206193 register(processor);
207194 return processor;
208195 }
248248 private static final Long ZERO = Long.valueOf(0);
249249
250250 public static final Number add(final Object obj0, final Object obj1) {
251 if (obj0 == null && obj1 == null) {
251 final ELArithmetic delegate = findDelegate(obj0, obj1);
252 if (delegate == null) {
252253 return Long.valueOf(0);
253254 }
254
255 final ELArithmetic delegate;
256 if (BIGDECIMAL.matches(obj0, obj1))
257 delegate = BIGDECIMAL;
258 else if (DOUBLE.matches(obj0, obj1)) {
259 if (BIGINTEGER.matches(obj0, obj1))
260 delegate = BIGDECIMAL;
261 else
262 delegate = DOUBLE;
263 } else if (BIGINTEGER.matches(obj0, obj1))
264 delegate = BIGINTEGER;
265 else
266 delegate = LONG;
267255
268256 Number num0 = delegate.coerce(obj0);
269257 Number num1 = delegate.coerce(obj1);
293281 }
294282
295283 public static final Number subtract(final Object obj0, final Object obj1) {
296 if (obj0 == null && obj1 == null) {
284 final ELArithmetic delegate = findDelegate(obj0, obj1);
285 if (delegate == null) {
297286 return Long.valueOf(0);
298287 }
299
300 final ELArithmetic delegate;
301 if (BIGDECIMAL.matches(obj0, obj1))
302 delegate = BIGDECIMAL;
303 else if (DOUBLE.matches(obj0, obj1)) {
304 if (BIGINTEGER.matches(obj0, obj1))
305 delegate = BIGDECIMAL;
306 else
307 delegate = DOUBLE;
308 } else if (BIGINTEGER.matches(obj0, obj1))
309 delegate = BIGINTEGER;
310 else
311 delegate = LONG;
312288
313289 Number num0 = delegate.coerce(obj0);
314290 Number num1 = delegate.coerce(obj1);
336312 }
337313
338314 public static final Number multiply(final Object obj0, final Object obj1) {
339 if (obj0 == null && obj1 == null) {
315 final ELArithmetic delegate = findDelegate(obj0, obj1);
316 if (delegate == null) {
340317 return Long.valueOf(0);
341318 }
342
343 final ELArithmetic delegate;
344 if (BIGDECIMAL.matches(obj0, obj1))
345 delegate = BIGDECIMAL;
346 else if (DOUBLE.matches(obj0, obj1)) {
347 if (BIGINTEGER.matches(obj0, obj1))
348 delegate = BIGDECIMAL;
349 else
350 delegate = DOUBLE;
351 } else if (BIGINTEGER.matches(obj0, obj1))
352 delegate = BIGINTEGER;
353 else
354 delegate = LONG;
355319
356320 Number num0 = delegate.coerce(obj0);
357321 Number num1 = delegate.coerce(obj1);
358322
359323 return delegate.multiply(num0, num1);
324 }
325
326 private static ELArithmetic findDelegate(final Object obj0, final Object obj1) {
327 if (obj0 == null && obj1 == null) {
328 return null;
329 }
330
331 if (BIGDECIMAL.matches(obj0, obj1)) {
332 return BIGDECIMAL;
333 } else if (DOUBLE.matches(obj0, obj1)) {
334 if (BIGINTEGER.matches(obj0, obj1)) {
335 return BIGDECIMAL;
336 } else {
337 return DOUBLE;
338 }
339 } else if (BIGINTEGER.matches(obj0, obj1)) {
340 return BIGINTEGER;
341 } else {
342 return LONG;
343 }
360344 }
361345
362346 public static final boolean isNumber(final Object obj) {
3636 private final Iterator<Object> iterator;
3737
3838
39 public Stream(Iterator<Object > iterator) {
39 public Stream(Iterator<Object> iterator) {
4040 this.iterator = iterator;
4141 }
4242
467467
468468
469469 private static class LambdaExpressionComparator
470 implements Comparator<Object>{
470 implements Comparator<Object> {
471471
472472 private final LambdaExpression le;
473473
6868 * servlet definition. If present on a request, this overrides the
6969 * value returned by <code>request.getServletPath()</code> to select
7070 * the JSP page to be executed.
71 * @deprecated This will be removed in Tomcat 9.0.x onwards. It is replaced
72 * by the use of the jspFile servlet initialisation parameter
7173 */
74 @Deprecated
7275 public static final String JSP_FILE =
7376 System.getProperty("org.apache.jasper.Constants.JSP_FILE", "org.apache.catalina.jsp_file");
7477
502502 @Override
503503 public boolean getMappedFile() {
504504 return mappedFile;
505 }
506
507 public void setMappedFile(boolean b) {
508 mappedFile = b;
505509 }
506510
507511 /**
483483 // Assume we constructed this correctly
484484 int entryStart = key.lastIndexOf("!/");
485485 String entry = key.substring(entryStart + 2);
486 Jar jar = JarFactory.newInstance(new URL(key.substring(4, entryStart)));
487 includeLastModified = jar.getLastModified(entry);
486 try (Jar jar = JarFactory.newInstance(new URL(key.substring(4, entryStart)))) {
487 includeLastModified = jar.getLastModified(entry);
488 }
488489 } else {
489490 if (key.startsWith("jar:") || key.startsWith("file:")) {
490491 includeUrl = new URL(key);
225225 return false;
226226 }
227227 String resourceName = result.replace('.', '/') + ".class";
228 InputStream is =
229 classLoader.getResourceAsStream(resourceName);
230 return is == null;
228 try (InputStream is =
229 classLoader.getResourceAsStream(resourceName)) {
230 return is == null;
231 } catch (IOException e) {
232 // we are here, since close on is failed. That means it was not null
233 return false;
234 }
231235 }
232236
233237 @Override
275275 }
276276
277277
278 @SuppressWarnings("deprecation") // Use of JSP_FILE to be removed in 9.0.x
278279 @Override
279280 public void service (HttpServletRequest request,
280281 HttpServletResponse response)
284285 String jspUri = jspFile;
285286
286287 if (jspUri == null) {
287 // JSP specified via <jsp-file> in <servlet> declaration and supplied through
288 //custom servlet container code
289 jspUri = (String) request.getAttribute(Constants.JSP_FILE);
288 // JSP specified via <jsp-file> in <servlet> declaration and
289 // supplied through custom servlet container code
290 String jspFile = (String) request.getAttribute(Constants.JSP_FILE);
291 if (jspFile != null) {
292 jspUri = jspFile;
293 request.removeAttribute(Constants.JSP_FILE);
294 }
290295 }
291296 if (jspUri == null) {
292297 /*
455455 }
456456 throw ex;
457457 } catch (IOException ex) {
458 if(options.getDevelopment()) {
459 throw handleJspException(ex);
458 if (options.getDevelopment()) {
459 throw new IOException(handleJspException(ex).getMessage(), ex);
460460 }
461461 throw ex;
462462 } catch (IllegalStateException ex) {
2222 * {@link ClassFileTransformer}s. These transformers can instrument
2323 * (or weave) the byte code of classes loaded through this class loader
2424 * to alter their behavior. Currently only
25 * {@link org.apache.catalina.loader.WebappClassLoader} implements this
25 * {@link org.apache.catalina.loader.WebappClassLoaderBase} implements this
2626 * interface. This allows web application frameworks or JPA providers
2727 * bundled with a web application to instrument web application classes
2828 * as necessary.
2929 * <p>
3030 * You should always program against the methods of this interface
3131 * (whether using reflection or otherwise). The methods in
32 * {@code WebappClassLoader} are protected by the default security
32 * {@code WebappClassLoaderBase} are protected by the default security
3333 * manager if one is in use.
3434 *
3535 * @since 8.0, 7.0.44
2121 import java.io.FileInputStream;
2222 import java.io.FileOutputStream;
2323 import java.io.IOException;
24 import java.net.MalformedURLException;
2425 import java.net.URL;
2526 import java.util.ArrayList;
2627 import java.util.List;
5253 */
5354 public class SignCode extends Task {
5455
56 private static final URL SIGNING_SERVICE_URL;
57
5558 private static final String NS = "cod";
5659
5760 private static final MessageFactory SOAP_MSG_FACTORY;
5861
5962 static {
63 try {
64 SIGNING_SERVICE_URL = new URL("https://api.ws.symantec.com/webtrust/SigningService");
65 } catch (MalformedURLException e) {
66 throw new IllegalArgumentException(e);
67 }
6068 try {
6169 SOAP_MSG_FACTORY = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
6270 } catch (SOAPException e) {
159167 requestSigningRequest.addChildElement("signingServiceName", NS);
160168 signingServiceName.addTextNode(this.signingService);
161169
170 List<String> fileNames = getFileNames(filesToSign);
171
162172 SOAPElement commaDelimitedFileNames =
163173 requestSigningRequest.addChildElement("commaDelimitedFileNames", NS);
164 commaDelimitedFileNames.addTextNode(getFileNames(filesToSign.size()));
174 commaDelimitedFileNames.addTextNode(listToString(fileNames));
165175
166176 SOAPElement application =
167177 requestSigningRequest.addChildElement("application", NS);
168 application.addTextNode(getApplicationString(filesToSign));
178 application.addTextNode(getApplicationString(fileNames, filesToSign));
169179
170180 // Send the message
171181 SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
172182 SOAPConnection connection = soapConnectionFactory.createConnection();
173 URL endpoint = new URL("https://test-api.ws.symantec.com:443/webtrust/SigningService");
174183
175184 log("Sending siging request to server and waiting for response");
176 SOAPMessage response = connection.call(message, endpoint);
185 SOAPMessage response = connection.call(message, SIGNING_SERVICE_URL);
177186
178187 log("Processing response");
179188 SOAPElement responseBody = response.getSOAPBody();
203212 }
204213
205214
215 private String listToString(List<String> list) {
216 StringBuilder sb = new StringBuilder(list.size() * 6);
217 boolean doneFirst = false;
218 for (String s : list) {
219 if (doneFirst) {
220 sb.append(',');
221 } else {
222 doneFirst = true;
223 }
224 sb.append(s);
225 }
226 return sb.toString();
227 }
228
229
206230 private void downloadSignedFiles(List<File> filesToSign, String id)
207231 throws SOAPException, IOException {
208232
228252 // Send the message
229253 SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
230254 SOAPConnection connection = soapConnectionFactory.createConnection();
231 URL endpoint = new URL("https://test-api.ws.symantec.com:443/webtrust/SigningService");
232255
233256 log("Requesting signed files from server and waiting for response");
234 SOAPMessage response = connection.call(message, endpoint);
257 SOAPMessage response = connection.call(message, SIGNING_SERVICE_URL);
235258
236259 log("Processing response");
237260 SOAPElement responseBody = response.getSOAPBody();
289312
290313 /**
291314 * Signing service requires unique files names. Since files will be returned
292 * in order, use dummy names that we know are unique.
315 * in order, use dummy names that we know are unique but retain the file
316 * extension since the signing service appears to use it to figure out what
317 * to sign and how to sign it.
293318 */
294 private static String getFileNames(int fileCount) {
295 StringBuilder sb = new StringBuilder();
296
297 boolean first = true;
298
299 for (int i = 0; i < fileCount; i++) {
300 if (first) {
301 first = false;
319 private static List<String> getFileNames(List<File> filesToSign) {
320 List<String> result = new ArrayList<>(filesToSign.size());
321
322 for (int i = 0; i < filesToSign.size(); i++) {
323 File f = filesToSign.get(i);
324 String fileName = f.getName();
325 int extIndex = fileName.lastIndexOf('.');
326 String newName;
327 if (extIndex < 0) {
328 newName = Integer.toString(i);
302329 } else {
303 sb.append(',');
304 }
305 sb.append(Integer.toString(i));
306 }
307 return sb.toString();
308 }
330 newName = Integer.toString(i) + fileName.substring(extIndex);
331 }
332 result.add(newName);
333 }
334 return result;
335 }
336
309337
310338 /**
311339 * Zips the files, base 64 encodes the resulting zip and then returns the
313341 * signing server but the files that need to be signed are relatively small
314342 * and this simpler to write.
315343 *
316 * @param files Files to be signed
344 * @param fileNames Modified names of files
345 * @param files Files to be signed
317346 */
318 private static String getApplicationString(List<File> files) throws IOException {
319 // 10 MB should be more than enough for Tomcat
320 ByteArrayOutputStream baos = new ByteArrayOutputStream(10 * 1024 * 1024);
347 private static String getApplicationString(List<String> fileNames, List<File> files)
348 throws IOException {
349 // 16 MB should be more than enough for Tomcat
350 ByteArrayOutputStream baos = new ByteArrayOutputStream(16 * 1024 * 1024);
321351 try (ZipOutputStream zos = new ZipOutputStream(baos)) {
322352 byte[] buf = new byte[32 * 1024];
323353 for (int i = 0; i < files.size(); i++) {
324354 try (FileInputStream fis = new FileInputStream(files.get(i))) {
325 ZipEntry zipEntry = new ZipEntry(Integer.toString(i));
355 ZipEntry zipEntry = new ZipEntry(fileNames.get(i));
326356 zos.putNextEntry(zipEntry);
327357 int numRead;
328358 while ( (numRead = fis.read(buf)) >= 0) {
13071307 * Returns the value of the flag that controls whether or not connections
13081308 * being returned to the pool will checked and configured with
13091309 * {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)}
1310 * if the auto commit setting is <code>false</false> when the connection
1310 * if the auto commit setting is {@code false} when the connection
13111311 * is returned. It is <code>true</code> by default.
13121312 */
13131313 public boolean getEnableAutoCommitOnReturn() {
13181318 * Sets the value of the flag that controls whether or not connections
13191319 * being returned to the pool will checked and configured with
13201320 * {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)}
1321 * if the auto commit setting is <code>false</false> when the connection
1321 * if the auto commit setting is {@code false} when the connection
13221322 * is returned. It is <code>true</code> by default.
13231323 */
13241324 public void setEnableAutoCommitOnReturn(boolean enableAutoCommitOnReturn) {
20772077 gop.setTestWhileIdle(testWhileIdle);
20782078 gop.setLifo(lifo);
20792079 gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log));
2080 gop.setEvictionPolicyClassName(evictionPolicyClassName);
20802081 factory.setPool(gop);
20812082 connectionPool = gop;
20822083 }
161161
162162 /**
163163 * If my underlying {@link Connection} is not a
164 * <tt>DelegatingConnection</tt>, returns it,
164 * {@code DelegatingConnection}, returns it,
165165 * otherwise recursively invokes this method on
166166 * my delegate.
167167 * <p>
168168 * Hence this method will return the first
169 * delegate that is not a <tt>DelegatingConnection</tt>,
170 * or <tt>null</tt> when no non-<tt>DelegatingConnection</tt>
169 * delegate that is not a {@code DelegatingConnection},
170 * or {@code null} when no non-{@code DelegatingConnection}
171171 * delegate can be found by traversing this chain.
172172 * <p>
173173 * This method is useful when you may have nested
174 * <tt>DelegatingConnection</tt>s, and you want to make
174 * {@code DelegatingConnection}s, and you want to make
175175 * sure to obtain a "genuine" {@link Connection}.
176176 */
177177 public Connection getInnermostDelegate() {
5151
5252 /**
5353 * If my underlying {@link ResultSet} is not a
54 * <tt>DelegatingResultSet</tt>, returns it,
54 * {@code DelegatingResultSet}, returns it,
5555 * otherwise recursively invokes this method on
5656 * my delegate.
5757 * <p>
5858 * Hence this method will return the first
59 * delegate that is not a <tt>DelegatingResultSet</tt>,
60 * or <tt>null</tt> when no non-<tt>DelegatingResultSet</tt>
59 * delegate that is not a {@code DelegatingResultSet},
60 * or {@code null} when no non-{@code DelegatingResultSet}
6161 * delegate can be found by transversing this chain.
6262 * <p>
6363 * This method is useful when you may have nested
64 * <tt>DelegatingResultSet</tt>s, and you want to make
64 * {@code DelegatingResultSet}s, and you want to make
6565 * sure to obtain a "genuine" {@link ResultSet}.
6666 */
6767 public DatabaseMetaData getInnermostDelegate() {
8686
8787 @Override
8888 public boolean allProceduresAreCallable() throws SQLException {
89 { try { return _meta.allProceduresAreCallable(); }
90 catch (SQLException e) { handleException(e); return false; } }
89 try { return _meta.allProceduresAreCallable(); }
90 catch (SQLException e) { handleException(e); return false; }
9191 }
9292
9393 @Override
9494 public boolean allTablesAreSelectable() throws SQLException {
95 { try { return _meta.allTablesAreSelectable(); }
96 catch (SQLException e) { handleException(e); return false; } }
95 try { return _meta.allTablesAreSelectable(); }
96 catch (SQLException e) { handleException(e); return false; }
9797 }
9898
9999 @Override
100100 public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
101 { try { return _meta.dataDefinitionCausesTransactionCommit(); }
102 catch (SQLException e) { handleException(e); return false; } }
101 try { return _meta.dataDefinitionCausesTransactionCommit(); }
102 catch (SQLException e) { handleException(e); return false; }
103103 }
104104
105105 @Override
106106 public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
107 { try { return _meta.dataDefinitionIgnoredInTransactions(); }
108 catch (SQLException e) { handleException(e); return false; } }
107 try { return _meta.dataDefinitionIgnoredInTransactions(); }
108 catch (SQLException e) { handleException(e); return false; }
109109 }
110110
111111 @Override
112112 public boolean deletesAreDetected(int type) throws SQLException {
113 { try { return _meta.deletesAreDetected(type); }
114 catch (SQLException e) { handleException(e); return false; } }
113 try { return _meta.deletesAreDetected(type); }
114 catch (SQLException e) { handleException(e); return false; }
115115 }
116116
117117 @Override
118118 public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
119 { try { return _meta.doesMaxRowSizeIncludeBlobs(); }
120 catch (SQLException e) { handleException(e); return false; } }
119 try { return _meta.doesMaxRowSizeIncludeBlobs(); }
120 catch (SQLException e) { handleException(e); return false; }
121121 }
122122
123123 @Override
153153
154154 @Override
155155 public String getCatalogSeparator() throws SQLException {
156 { try { return _meta.getCatalogSeparator(); }
157 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
156 try { return _meta.getCatalogSeparator(); }
157 catch (SQLException e) { handleException(e); throw new AssertionError(); }
158158 }
159159
160160 @Override
161161 public String getCatalogTerm() throws SQLException {
162 { try { return _meta.getCatalogTerm(); }
163 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
162 try { return _meta.getCatalogTerm(); }
163 catch (SQLException e) { handleException(e); throw new AssertionError(); }
164164 }
165165
166166 @Override
231231
232232 @Override
233233 public int getDatabaseMajorVersion() throws SQLException {
234 { try { return _meta.getDatabaseMajorVersion(); }
235 catch (SQLException e) { handleException(e); return 0; } }
234 try { return _meta.getDatabaseMajorVersion(); }
235 catch (SQLException e) { handleException(e); return 0; }
236236 }
237237
238238 @Override
239239 public int getDatabaseMinorVersion() throws SQLException {
240 { try { return _meta.getDatabaseMinorVersion(); }
241 catch (SQLException e) { handleException(e); return 0; } }
240 try { return _meta.getDatabaseMinorVersion(); }
241 catch (SQLException e) { handleException(e); return 0; }
242242 }
243243
244244 @Override
245245 public String getDatabaseProductName() throws SQLException {
246 { try { return _meta.getDatabaseProductName(); }
247 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
246 try { return _meta.getDatabaseProductName(); }
247 catch (SQLException e) { handleException(e); throw new AssertionError(); }
248248 }
249249
250250 @Override
251251 public String getDatabaseProductVersion() throws SQLException {
252 { try { return _meta.getDatabaseProductVersion(); }
253 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
252 try { return _meta.getDatabaseProductVersion(); }
253 catch (SQLException e) { handleException(e); throw new AssertionError(); }
254254 }
255255
256256 @Override
257257 public int getDefaultTransactionIsolation() throws SQLException {
258 { try { return _meta.getDefaultTransactionIsolation(); }
259 catch (SQLException e) { handleException(e); return 0; } }
258 try { return _meta.getDefaultTransactionIsolation(); }
259 catch (SQLException e) { handleException(e); return 0; }
260260 }
261261
262262 @Override
267267
268268 @Override
269269 public String getDriverName() throws SQLException {
270 { try { return _meta.getDriverName(); }
271 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
270 try { return _meta.getDriverName(); }
271 catch (SQLException e) { handleException(e); throw new AssertionError(); }
272272 }
273273
274274 @Override
275275 public String getDriverVersion() throws SQLException {
276 { try { return _meta.getDriverVersion(); }
277 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
276 try { return _meta.getDriverVersion(); }
277 catch (SQLException e) { handleException(e); throw new AssertionError(); }
278278 }
279279
280280 @Override
293293
294294 @Override
295295 public String getExtraNameCharacters() throws SQLException {
296 { try { return _meta.getExtraNameCharacters(); }
297 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
296 try { return _meta.getExtraNameCharacters(); }
297 catch (SQLException e) { handleException(e); throw new AssertionError(); }
298298 }
299299
300300 @Override
301301 public String getIdentifierQuoteString() throws SQLException {
302 { try { return _meta.getIdentifierQuoteString(); }
303 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
302 try { return _meta.getIdentifierQuoteString(); }
303 catch (SQLException e) { handleException(e); throw new AssertionError(); }
304304 }
305305
306306 @Override
334334
335335 @Override
336336 public int getJDBCMajorVersion() throws SQLException {
337 { try { return _meta.getJDBCMajorVersion(); }
338 catch (SQLException e) { handleException(e); return 0; } }
337 try { return _meta.getJDBCMajorVersion(); }
338 catch (SQLException e) { handleException(e); return 0; }
339339 }
340340
341341 @Override
342342 public int getJDBCMinorVersion() throws SQLException {
343 { try { return _meta.getJDBCMinorVersion(); }
344 catch (SQLException e) { handleException(e); return 0; } }
343 try { return _meta.getJDBCMinorVersion(); }
344 catch (SQLException e) { handleException(e); return 0; }
345345 }
346346
347347 @Override
348348 public int getMaxBinaryLiteralLength() throws SQLException {
349 { try { return _meta.getMaxBinaryLiteralLength(); }
350 catch (SQLException e) { handleException(e); return 0; } }
349 try { return _meta.getMaxBinaryLiteralLength(); }
350 catch (SQLException e) { handleException(e); return 0; }
351351 }
352352
353353 @Override
354354 public int getMaxCatalogNameLength() throws SQLException {
355 { try { return _meta.getMaxCatalogNameLength(); }
356 catch (SQLException e) { handleException(e); return 0; } }
355 try { return _meta.getMaxCatalogNameLength(); }
356 catch (SQLException e) { handleException(e); return 0; }
357357 }
358358
359359 @Override
360360 public int getMaxCharLiteralLength() throws SQLException {
361 { try { return _meta.getMaxCharLiteralLength(); }
362 catch (SQLException e) { handleException(e); return 0; } }
361 try { return _meta.getMaxCharLiteralLength(); }
362 catch (SQLException e) { handleException(e); return 0; }
363363 }
364364
365365 @Override
366366 public int getMaxColumnNameLength() throws SQLException {
367 { try { return _meta.getMaxColumnNameLength(); }
368 catch (SQLException e) { handleException(e); return 0; } }
367 try { return _meta.getMaxColumnNameLength(); }
368 catch (SQLException e) { handleException(e); return 0; }
369369 }
370370
371371 @Override
372372 public int getMaxColumnsInGroupBy() throws SQLException {
373 { try { return _meta.getMaxColumnsInGroupBy(); }
374 catch (SQLException e) { handleException(e); return 0; } }
373 try { return _meta.getMaxColumnsInGroupBy(); }
374 catch (SQLException e) { handleException(e); return 0; }
375375 }
376376
377377 @Override
378378 public int getMaxColumnsInIndex() throws SQLException {
379 { try { return _meta.getMaxColumnsInIndex(); }
380 catch (SQLException e) { handleException(e); return 0; } }
379 try { return _meta.getMaxColumnsInIndex(); }
380 catch (SQLException e) { handleException(e); return 0; }
381381 }
382382
383383 @Override
384384 public int getMaxColumnsInOrderBy() throws SQLException {
385 { try { return _meta.getMaxColumnsInOrderBy(); }
386 catch (SQLException e) { handleException(e); return 0; } }
385 try { return _meta.getMaxColumnsInOrderBy(); }
386 catch (SQLException e) { handleException(e); return 0; }
387387 }
388388
389389 @Override
390390 public int getMaxColumnsInSelect() throws SQLException {
391 { try { return _meta.getMaxColumnsInSelect(); }
392 catch (SQLException e) { handleException(e); return 0; } }
391 try { return _meta.getMaxColumnsInSelect(); }
392 catch (SQLException e) { handleException(e); return 0; }
393393 }
394394
395395 @Override
396396 public int getMaxColumnsInTable() throws SQLException {
397 { try { return _meta.getMaxColumnsInTable(); }
398 catch (SQLException e) { handleException(e); return 0; } }
397 try { return _meta.getMaxColumnsInTable(); }
398 catch (SQLException e) { handleException(e); return 0; }
399399 }
400400
401401 @Override
402402 public int getMaxConnections() throws SQLException {
403 { try { return _meta.getMaxConnections(); }
404 catch (SQLException e) { handleException(e); return 0; } }
403 try { return _meta.getMaxConnections(); }
404 catch (SQLException e) { handleException(e); return 0; }
405405 }
406406
407407 @Override
408408 public int getMaxCursorNameLength() throws SQLException {
409 { try { return _meta.getMaxCursorNameLength(); }
410 catch (SQLException e) { handleException(e); return 0; } }
409 try { return _meta.getMaxCursorNameLength(); }
410 catch (SQLException e) { handleException(e); return 0; }
411411 }
412412
413413 @Override
414414 public int getMaxIndexLength() throws SQLException {
415 { try { return _meta.getMaxIndexLength(); }
416 catch (SQLException e) { handleException(e); return 0; } }
415 try { return _meta.getMaxIndexLength(); }
416 catch (SQLException e) { handleException(e); return 0; }
417417 }
418418
419419 @Override
420420 public int getMaxProcedureNameLength() throws SQLException {
421 { try { return _meta.getMaxProcedureNameLength(); }
422 catch (SQLException e) { handleException(e); return 0; } }
421 try { return _meta.getMaxProcedureNameLength(); }
422 catch (SQLException e) { handleException(e); return 0; }
423423 }
424424
425425 @Override
426426 public int getMaxRowSize() throws SQLException {
427 { try { return _meta.getMaxRowSize(); }
428 catch (SQLException e) { handleException(e); return 0; } }
427 try { return _meta.getMaxRowSize(); }
428 catch (SQLException e) { handleException(e); return 0; }
429429 }
430430
431431 @Override
432432 public int getMaxSchemaNameLength() throws SQLException {
433 { try { return _meta.getMaxSchemaNameLength(); }
434 catch (SQLException e) { handleException(e); return 0; } }
433 try { return _meta.getMaxSchemaNameLength(); }
434 catch (SQLException e) { handleException(e); return 0; }
435435 }
436436
437437 @Override
438438 public int getMaxStatementLength() throws SQLException {
439 { try { return _meta.getMaxStatementLength(); }
440 catch (SQLException e) { handleException(e); return 0; } }
439 try { return _meta.getMaxStatementLength(); }
440 catch (SQLException e) { handleException(e); return 0; }
441441 }
442442
443443 @Override
444444 public int getMaxStatements() throws SQLException {
445 { try { return _meta.getMaxStatements(); }
446 catch (SQLException e) { handleException(e); return 0; } }
445 try { return _meta.getMaxStatements(); }
446 catch (SQLException e) { handleException(e); return 0; }
447447 }
448448
449449 @Override
450450 public int getMaxTableNameLength() throws SQLException {
451 { try { return _meta.getMaxTableNameLength(); }
452 catch (SQLException e) { handleException(e); return 0; } }
451 try { return _meta.getMaxTableNameLength(); }
452 catch (SQLException e) { handleException(e); return 0; }
453453 }
454454
455455 @Override
456456 public int getMaxTablesInSelect() throws SQLException {
457 { try { return _meta.getMaxTablesInSelect(); }
458 catch (SQLException e) { handleException(e); return 0; } }
457 try { return _meta.getMaxTablesInSelect(); }
458 catch (SQLException e) { handleException(e); return 0; }
459459 }
460460
461461 @Override
462462 public int getMaxUserNameLength() throws SQLException {
463 { try { return _meta.getMaxUserNameLength(); }
464 catch (SQLException e) { handleException(e); return 0; } }
463 try { return _meta.getMaxUserNameLength(); }
464 catch (SQLException e) { handleException(e); return 0; }
465465 }
466466
467467 @Override
468468 public String getNumericFunctions() throws SQLException {
469 { try { return _meta.getNumericFunctions(); }
470 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
469 try { return _meta.getNumericFunctions(); }
470 catch (SQLException e) { handleException(e); throw new AssertionError(); }
471471 }
472472
473473 @Override
502502
503503 @Override
504504 public String getProcedureTerm() throws SQLException {
505 { try { return _meta.getProcedureTerm(); }
506 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
505 try { return _meta.getProcedureTerm(); }
506 catch (SQLException e) { handleException(e); throw new AssertionError(); }
507507 }
508508
509509 @Override
523523
524524 @Override
525525 public int getResultSetHoldability() throws SQLException {
526 { try { return _meta.getResultSetHoldability(); }
527 catch (SQLException e) { handleException(e); return 0; } }
526 try { return _meta.getResultSetHoldability(); }
527 catch (SQLException e) { handleException(e); return 0; }
528528 }
529529
530530 @Override
531531 public String getSQLKeywords() throws SQLException {
532 { try { return _meta.getSQLKeywords(); }
533 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
532 try { return _meta.getSQLKeywords(); }
533 catch (SQLException e) { handleException(e); throw new AssertionError(); }
534534 }
535535
536536 @Override
537537 public int getSQLStateType() throws SQLException {
538 { try { return _meta.getSQLStateType(); }
539 catch (SQLException e) { handleException(e); return 0; } }
538 try { return _meta.getSQLStateType(); }
539 catch (SQLException e) { handleException(e); return 0; }
540540 }
541541
542542 @Override
543543 public String getSchemaTerm() throws SQLException {
544 { try { return _meta.getSchemaTerm(); }
545 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
544 try { return _meta.getSchemaTerm(); }
545 catch (SQLException e) { handleException(e); throw new AssertionError(); }
546546 }
547547
548548 @Override
560560
561561 @Override
562562 public String getSearchStringEscape() throws SQLException {
563 { try { return _meta.getSearchStringEscape(); }
564 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
563 try { return _meta.getSearchStringEscape(); }
564 catch (SQLException e) { handleException(e); throw new AssertionError(); }
565565 }
566566
567567 @Override
568568 public String getStringFunctions() throws SQLException {
569 { try { return _meta.getStringFunctions(); }
570 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
569 try { return _meta.getStringFunctions(); }
570 catch (SQLException e) { handleException(e); throw new AssertionError(); }
571571 }
572572
573573 @Override
602602
603603 @Override
604604 public String getSystemFunctions() throws SQLException {
605 { try { return _meta.getSystemFunctions(); }
606 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
605 try { return _meta.getSystemFunctions(); }
606 catch (SQLException e) { handleException(e); throw new AssertionError(); }
607607 }
608608
609609 @Override
651651
652652 @Override
653653 public String getTimeDateFunctions() throws SQLException {
654 { try { return _meta.getTimeDateFunctions(); }
655 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
654 try { return _meta.getTimeDateFunctions(); }
655 catch (SQLException e) { handleException(e); throw new AssertionError(); }
656656 }
657657
658658 @Override
685685
686686 @Override
687687 public String getURL() throws SQLException {
688 { try { return _meta.getURL(); }
689 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
688 try { return _meta.getURL(); }
689 catch (SQLException e) { handleException(e); throw new AssertionError(); }
690690 }
691691
692692 @Override
693693 public String getUserName() throws SQLException {
694 { try { return _meta.getUserName(); }
695 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
694 try { return _meta.getUserName(); }
695 catch (SQLException e) { handleException(e); throw new AssertionError(); }
696696 }
697697
698698 @Override
711711
712712 @Override
713713 public boolean insertsAreDetected(int type) throws SQLException {
714 { try { return _meta.insertsAreDetected(type); }
715 catch (SQLException e) { handleException(e); return false; } }
714 try { return _meta.insertsAreDetected(type); }
715 catch (SQLException e) { handleException(e); return false; }
716716 }
717717
718718 @Override
719719 public boolean isCatalogAtStart() throws SQLException {
720 { try { return _meta.isCatalogAtStart(); }
721 catch (SQLException e) { handleException(e); return false; } }
720 try { return _meta.isCatalogAtStart(); }
721 catch (SQLException e) { handleException(e); return false; }
722722 }
723723
724724 @Override
725725 public boolean isReadOnly() throws SQLException {
726 { try { return _meta.isReadOnly(); }
727 catch (SQLException e) { handleException(e); return false; } }
726 try { return _meta.isReadOnly(); }
727 catch (SQLException e) { handleException(e); return false; }
728728 }
729729
730730 @Override
731731 public boolean locatorsUpdateCopy() throws SQLException {
732 { try { return _meta.locatorsUpdateCopy(); }
733 catch (SQLException e) { handleException(e); return false; } }
732 try { return _meta.locatorsUpdateCopy(); }
733 catch (SQLException e) { handleException(e); return false; }
734734 }
735735
736736 @Override
737737 public boolean nullPlusNonNullIsNull() throws SQLException {
738 { try { return _meta.nullPlusNonNullIsNull(); }
739 catch (SQLException e) { handleException(e); return false; } }
738 try { return _meta.nullPlusNonNullIsNull(); }
739 catch (SQLException e) { handleException(e); return false; }
740740 }
741741
742742 @Override
743743 public boolean nullsAreSortedAtEnd() throws SQLException {
744 { try { return _meta.nullsAreSortedAtEnd(); }
745 catch (SQLException e) { handleException(e); return false; } }
744 try { return _meta.nullsAreSortedAtEnd(); }
745 catch (SQLException e) { handleException(e); return false; }
746746 }
747747
748748 @Override
749749 public boolean nullsAreSortedAtStart() throws SQLException {
750 { try { return _meta.nullsAreSortedAtStart(); }
751 catch (SQLException e) { handleException(e); return false; } }
750 try { return _meta.nullsAreSortedAtStart(); }
751 catch (SQLException e) { handleException(e); return false; }
752752 }
753753
754754 @Override
755755 public boolean nullsAreSortedHigh() throws SQLException {
756 { try { return _meta.nullsAreSortedHigh(); }
757 catch (SQLException e) { handleException(e); return false; } }
756 try { return _meta.nullsAreSortedHigh(); }
757 catch (SQLException e) { handleException(e); return false; }
758758 }
759759
760760 @Override
761761 public boolean nullsAreSortedLow() throws SQLException {
762 { try { return _meta.nullsAreSortedLow(); }
763 catch (SQLException e) { handleException(e); return false; } }
762 try { return _meta.nullsAreSortedLow(); }
763 catch (SQLException e) { handleException(e); return false; }
764764 }
765765
766766 @Override
767767 public boolean othersDeletesAreVisible(int type) throws SQLException {
768 { try { return _meta.othersDeletesAreVisible(type); }
769 catch (SQLException e) { handleException(e); return false; } }
768 try { return _meta.othersDeletesAreVisible(type); }
769 catch (SQLException e) { handleException(e); return false; }
770770 }
771771
772772 @Override
773773 public boolean othersInsertsAreVisible(int type) throws SQLException {
774 { try { return _meta.othersInsertsAreVisible(type); }
775 catch (SQLException e) { handleException(e); return false; } }
774 try { return _meta.othersInsertsAreVisible(type); }
775 catch (SQLException e) { handleException(e); return false; }
776776 }
777777
778778 @Override
779779 public boolean othersUpdatesAreVisible(int type) throws SQLException {
780 { try { return _meta.othersUpdatesAreVisible(type); }
781 catch (SQLException e) { handleException(e); return false; } }
780 try { return _meta.othersUpdatesAreVisible(type); }
781 catch (SQLException e) { handleException(e); return false; }
782782 }
783783
784784 @Override
785785 public boolean ownDeletesAreVisible(int type) throws SQLException {
786 { try { return _meta.ownDeletesAreVisible(type); }
787 catch (SQLException e) { handleException(e); return false; } }
786 try { return _meta.ownDeletesAreVisible(type); }
787 catch (SQLException e) { handleException(e); return false; }
788788 }
789789
790790 @Override
791791 public boolean ownInsertsAreVisible(int type) throws SQLException {
792 { try { return _meta.ownInsertsAreVisible(type); }
793 catch (SQLException e) { handleException(e); return false; } }
792 try { return _meta.ownInsertsAreVisible(type); }
793 catch (SQLException e) { handleException(e); return false; }
794794 }
795795
796796 @Override
797797 public boolean ownUpdatesAreVisible(int type) throws SQLException {
798 { try { return _meta.ownUpdatesAreVisible(type); }
799 catch (SQLException e) { handleException(e); return false; } }
798 try { return _meta.ownUpdatesAreVisible(type); }
799 catch (SQLException e) { handleException(e); return false; }
800800 }
801801
802802 @Override
803803 public boolean storesLowerCaseIdentifiers() throws SQLException {
804 { try { return _meta.storesLowerCaseIdentifiers(); }
805 catch (SQLException e) { handleException(e); return false; } }
804 try { return _meta.storesLowerCaseIdentifiers(); }
805 catch (SQLException e) { handleException(e); return false; }
806806 }
807807
808808 @Override
809809 public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
810 { try { return _meta.storesLowerCaseQuotedIdentifiers(); }
811 catch (SQLException e) { handleException(e); return false; } }
810 try { return _meta.storesLowerCaseQuotedIdentifiers(); }
811 catch (SQLException e) { handleException(e); return false; }
812812 }
813813
814814 @Override
815815 public boolean storesMixedCaseIdentifiers() throws SQLException {
816 { try { return _meta.storesMixedCaseIdentifiers(); }
817 catch (SQLException e) { handleException(e); return false; } }
816 try { return _meta.storesMixedCaseIdentifiers(); }
817 catch (SQLException e) { handleException(e); return false; }
818818 }
819819
820820 @Override
821821 public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
822 { try { return _meta.storesMixedCaseQuotedIdentifiers(); }
823 catch (SQLException e) { handleException(e); return false; } }
822 try { return _meta.storesMixedCaseQuotedIdentifiers(); }
823 catch (SQLException e) { handleException(e); return false; }
824824 }
825825
826826 @Override
827827 public boolean storesUpperCaseIdentifiers() throws SQLException {
828 { try { return _meta.storesUpperCaseIdentifiers(); }
829 catch (SQLException e) { handleException(e); return false; } }
828 try { return _meta.storesUpperCaseIdentifiers(); }
829 catch (SQLException e) { handleException(e); return false; }
830830 }
831831
832832 @Override
833833 public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
834 { try { return _meta.storesUpperCaseQuotedIdentifiers(); }
835 catch (SQLException e) { handleException(e); return false; } }
834 try { return _meta.storesUpperCaseQuotedIdentifiers(); }
835 catch (SQLException e) { handleException(e); return false; }
836836 }
837837
838838 @Override
839839 public boolean supportsANSI92EntryLevelSQL() throws SQLException {
840 { try { return _meta.supportsANSI92EntryLevelSQL(); }
841 catch (SQLException e) { handleException(e); return false; } }
840 try { return _meta.supportsANSI92EntryLevelSQL(); }
841 catch (SQLException e) { handleException(e); return false; }
842842 }
843843
844844 @Override
845845 public boolean supportsANSI92FullSQL() throws SQLException {
846 { try { return _meta.supportsANSI92FullSQL(); }
847 catch (SQLException e) { handleException(e); return false; } }
846 try { return _meta.supportsANSI92FullSQL(); }
847 catch (SQLException e) { handleException(e); return false; }
848848 }
849849
850850 @Override
851851 public boolean supportsANSI92IntermediateSQL() throws SQLException {
852 { try { return _meta.supportsANSI92IntermediateSQL(); }
853 catch (SQLException e) { handleException(e); return false; } }
852 try { return _meta.supportsANSI92IntermediateSQL(); }
853 catch (SQLException e) { handleException(e); return false; }
854854 }
855855
856856 @Override
857857 public boolean supportsAlterTableWithAddColumn() throws SQLException {
858 { try { return _meta.supportsAlterTableWithAddColumn(); }
859 catch (SQLException e) { handleException(e); return false; } }
858 try { return _meta.supportsAlterTableWithAddColumn(); }
859 catch (SQLException e) { handleException(e); return false; }
860860 }
861861
862862 @Override
863863 public boolean supportsAlterTableWithDropColumn() throws SQLException {
864 { try { return _meta.supportsAlterTableWithDropColumn(); }
865 catch (SQLException e) { handleException(e); return false; } }
864 try { return _meta.supportsAlterTableWithDropColumn(); }
865 catch (SQLException e) { handleException(e); return false; }
866866 }
867867
868868 @Override
869869 public boolean supportsBatchUpdates() throws SQLException {
870 { try { return _meta.supportsBatchUpdates(); }
871 catch (SQLException e) { handleException(e); return false; } }
870 try { return _meta.supportsBatchUpdates(); }
871 catch (SQLException e) { handleException(e); return false; }
872872 }
873873
874874 @Override
875875 public boolean supportsCatalogsInDataManipulation() throws SQLException {
876 { try { return _meta.supportsCatalogsInDataManipulation(); }
877 catch (SQLException e) { handleException(e); return false; } }
876 try { return _meta.supportsCatalogsInDataManipulation(); }
877 catch (SQLException e) { handleException(e); return false; }
878878 }
879879
880880 @Override
881881 public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
882 { try { return _meta.supportsCatalogsInIndexDefinitions(); }
883 catch (SQLException e) { handleException(e); return false; } }
882 try { return _meta.supportsCatalogsInIndexDefinitions(); }
883 catch (SQLException e) { handleException(e); return false; }
884884 }
885885
886886 @Override
887887 public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
888 { try { return _meta.supportsCatalogsInPrivilegeDefinitions(); }
889 catch (SQLException e) { handleException(e); return false; } }
888 try { return _meta.supportsCatalogsInPrivilegeDefinitions(); }
889 catch (SQLException e) { handleException(e); return false; }
890890 }
891891
892892 @Override
893893 public boolean supportsCatalogsInProcedureCalls() throws SQLException {
894 { try { return _meta.supportsCatalogsInProcedureCalls(); }
895 catch (SQLException e) { handleException(e); return false; } }
894 try { return _meta.supportsCatalogsInProcedureCalls(); }
895 catch (SQLException e) { handleException(e); return false; }
896896 }
897897
898898 @Override
899899 public boolean supportsCatalogsInTableDefinitions() throws SQLException {
900 { try { return _meta.supportsCatalogsInTableDefinitions(); }
901 catch (SQLException e) { handleException(e); return false; } }
900 try { return _meta.supportsCatalogsInTableDefinitions(); }
901 catch (SQLException e) { handleException(e); return false; }
902902 }
903903
904904 @Override
905905 public boolean supportsColumnAliasing() throws SQLException {
906 { try { return _meta.supportsColumnAliasing(); }
907 catch (SQLException e) { handleException(e); return false; } }
906 try { return _meta.supportsColumnAliasing(); }
907 catch (SQLException e) { handleException(e); return false; }
908908 }
909909
910910 @Override
911911 public boolean supportsConvert() throws SQLException {
912 { try { return _meta.supportsConvert(); }
913 catch (SQLException e) { handleException(e); return false; } }
912 try { return _meta.supportsConvert(); }
913 catch (SQLException e) { handleException(e); return false; }
914914 }
915915
916916 @Override
917917 public boolean supportsConvert(int fromType, int toType)
918918 throws SQLException {
919 { try { return _meta.supportsConvert(fromType, toType); }
920 catch (SQLException e) { handleException(e); return false; } }
919 try { return _meta.supportsConvert(fromType, toType); }
920 catch (SQLException e) { handleException(e); return false; }
921921 }
922922
923923 @Override
924924 public boolean supportsCoreSQLGrammar() throws SQLException {
925 { try { return _meta.supportsCoreSQLGrammar(); }
926 catch (SQLException e) { handleException(e); return false; } }
925 try { return _meta.supportsCoreSQLGrammar(); }
926 catch (SQLException e) { handleException(e); return false; }
927927 }
928928
929929 @Override
930930 public boolean supportsCorrelatedSubqueries() throws SQLException {
931 { try { return _meta.supportsCorrelatedSubqueries(); }
932 catch (SQLException e) { handleException(e); return false; } }
931 try { return _meta.supportsCorrelatedSubqueries(); }
932 catch (SQLException e) { handleException(e); return false; }
933933 }
934934
935935 @Override
936936 public boolean supportsDataDefinitionAndDataManipulationTransactions()
937937 throws SQLException {
938 { try { return _meta.supportsDataDefinitionAndDataManipulationTransactions(); }
939 catch (SQLException e) { handleException(e); return false; } }
938 try { return _meta.supportsDataDefinitionAndDataManipulationTransactions(); }
939 catch (SQLException e) { handleException(e); return false; }
940940 }
941941
942942 @Override
943943 public boolean supportsDataManipulationTransactionsOnly()
944944 throws SQLException {
945 { try { return _meta.supportsDataManipulationTransactionsOnly(); }
946 catch (SQLException e) { handleException(e); return false; } }
945 try { return _meta.supportsDataManipulationTransactionsOnly(); }
946 catch (SQLException e) { handleException(e); return false; }
947947 }
948948
949949 @Override
950950 public boolean supportsDifferentTableCorrelationNames() throws SQLException {
951 { try { return _meta.supportsDifferentTableCorrelationNames(); }
952 catch (SQLException e) { handleException(e); return false; } }
951 try { return _meta.supportsDifferentTableCorrelationNames(); }
952 catch (SQLException e) { handleException(e); return false; }
953953 }
954954
955955 @Override
956956 public boolean supportsExpressionsInOrderBy() throws SQLException {
957 { try { return _meta.supportsExpressionsInOrderBy(); }
958 catch (SQLException e) { handleException(e); return false; } }
957 try { return _meta.supportsExpressionsInOrderBy(); }
958 catch (SQLException e) { handleException(e); return false; }
959959 }
960960
961961 @Override
962962 public boolean supportsExtendedSQLGrammar() throws SQLException {
963 { try { return _meta.supportsExtendedSQLGrammar(); }
964 catch (SQLException e) { handleException(e); return false; } }
963 try { return _meta.supportsExtendedSQLGrammar(); }
964 catch (SQLException e) { handleException(e); return false; }
965965 }
966966
967967 @Override
968968 public boolean supportsFullOuterJoins() throws SQLException {
969 { try { return _meta.supportsFullOuterJoins(); }
970 catch (SQLException e) { handleException(e); return false; } }
969 try { return _meta.supportsFullOuterJoins(); }
970 catch (SQLException e) { handleException(e); return false; }
971971 }
972972
973973 @Override
974974 public boolean supportsGetGeneratedKeys() throws SQLException {
975 { try { return _meta.supportsGetGeneratedKeys(); }
976 catch (SQLException e) { handleException(e); return false; } }
975 try { return _meta.supportsGetGeneratedKeys(); }
976 catch (SQLException e) { handleException(e); return false; }
977977 }
978978
979979 @Override
980980 public boolean supportsGroupBy() throws SQLException {
981 { try { return _meta.supportsGroupBy(); }
982 catch (SQLException e) { handleException(e); return false; } }
981 try { return _meta.supportsGroupBy(); }
982 catch (SQLException e) { handleException(e); return false; }
983983 }
984984
985985 @Override
986986 public boolean supportsGroupByBeyondSelect() throws SQLException {
987 { try { return _meta.supportsGroupByBeyondSelect(); }
988 catch (SQLException e) { handleException(e); return false; } }
987 try { return _meta.supportsGroupByBeyondSelect(); }
988 catch (SQLException e) { handleException(e); return false; }
989989 }
990990
991991 @Override
992992 public boolean supportsGroupByUnrelated() throws SQLException {
993 { try { return _meta.supportsGroupByUnrelated(); }
994 catch (SQLException e) { handleException(e); return false; } }
993 try { return _meta.supportsGroupByUnrelated(); }
994 catch (SQLException e) { handleException(e); return false; }
995995 }
996996
997997 @Override
998998 public boolean supportsIntegrityEnhancementFacility() throws SQLException {
999 { try { return _meta.supportsIntegrityEnhancementFacility(); }
1000 catch (SQLException e) { handleException(e); return false; } }
999 try { return _meta.supportsIntegrityEnhancementFacility(); }
1000 catch (SQLException e) { handleException(e); return false; }
10011001 }
10021002
10031003 @Override
10041004 public boolean supportsLikeEscapeClause() throws SQLException {
1005 { try { return _meta.supportsLikeEscapeClause(); }
1006 catch (SQLException e) { handleException(e); return false; } }
1005 try { return _meta.supportsLikeEscapeClause(); }
1006 catch (SQLException e) { handleException(e); return false; }
10071007 }
10081008
10091009 @Override
10101010 public boolean supportsLimitedOuterJoins() throws SQLException {
1011 { try { return _meta.supportsLimitedOuterJoins(); }
1012 catch (SQLException e) { handleException(e); return false; } }
1011 try { return _meta.supportsLimitedOuterJoins(); }
1012 catch (SQLException e) { handleException(e); return false; }
10131013 }
10141014
10151015 @Override
10161016 public boolean supportsMinimumSQLGrammar() throws SQLException {
1017 { try { return _meta.supportsMinimumSQLGrammar(); }
1018 catch (SQLException e) { handleException(e); return false; } }
1017 try { return _meta.supportsMinimumSQLGrammar(); }
1018 catch (SQLException e) { handleException(e); return false; }
10191019 }
10201020
10211021 @Override
10221022 public boolean supportsMixedCaseIdentifiers() throws SQLException {
1023 { try { return _meta.supportsMixedCaseIdentifiers(); }
1024 catch (SQLException e) { handleException(e); return false; } }
1023 try { return _meta.supportsMixedCaseIdentifiers(); }
1024 catch (SQLException e) { handleException(e); return false; }
10251025 }
10261026
10271027 @Override
10281028 public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
1029 { try { return _meta.supportsMixedCaseQuotedIdentifiers(); }
1030 catch (SQLException e) { handleException(e); return false; } }
1029 try { return _meta.supportsMixedCaseQuotedIdentifiers(); }
1030 catch (SQLException e) { handleException(e); return false; }
10311031 }
10321032
10331033 @Override
10341034 public boolean supportsMultipleOpenResults() throws SQLException {
1035 { try { return _meta.supportsMultipleOpenResults(); }
1036 catch (SQLException e) { handleException(e); return false; } }
1035 try { return _meta.supportsMultipleOpenResults(); }
1036 catch (SQLException e) { handleException(e); return false; }
10371037 }
10381038
10391039 @Override
10401040 public boolean supportsMultipleResultSets() throws SQLException {
1041 { try { return _meta.supportsMultipleResultSets(); }
1042 catch (SQLException e) { handleException(e); return false; } }
1041 try { return _meta.supportsMultipleResultSets(); }
1042 catch (SQLException e) { handleException(e); return false; }
10431043 }
10441044
10451045 @Override
10461046 public boolean supportsMultipleTransactions() throws SQLException {
1047 { try { return _meta.supportsMultipleTransactions(); }
1048 catch (SQLException e) { handleException(e); return false; } }
1047 try { return _meta.supportsMultipleTransactions(); }
1048 catch (SQLException e) { handleException(e); return false; }
10491049 }
10501050
10511051 @Override
10521052 public boolean supportsNamedParameters() throws SQLException {
1053 { try { return _meta.supportsNamedParameters(); }
1054 catch (SQLException e) { handleException(e); return false; } }
1053 try { return _meta.supportsNamedParameters(); }
1054 catch (SQLException e) { handleException(e); return false; }
10551055 }
10561056
10571057 @Override
10581058 public boolean supportsNonNullableColumns() throws SQLException {
1059 { try { return _meta.supportsNonNullableColumns(); }
1060 catch (SQLException e) { handleException(e); return false; } }
1059 try { return _meta.supportsNonNullableColumns(); }
1060 catch (SQLException e) { handleException(e); return false; }
10611061 }
10621062
10631063 @Override
10641064 public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
1065 { try { return _meta.supportsOpenCursorsAcrossCommit(); }
1066 catch (SQLException e) { handleException(e); return false; } }
1065 try { return _meta.supportsOpenCursorsAcrossCommit(); }
1066 catch (SQLException e) { handleException(e); return false; }
10671067 }
10681068
10691069 @Override
10701070 public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
1071 { try { return _meta.supportsOpenCursorsAcrossRollback(); }
1072 catch (SQLException e) { handleException(e); return false; } }
1071 try { return _meta.supportsOpenCursorsAcrossRollback(); }
1072 catch (SQLException e) { handleException(e); return false; }
10731073 }
10741074
10751075 @Override
10761076 public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
1077 { try { return _meta.supportsOpenStatementsAcrossCommit(); }
1078 catch (SQLException e) { handleException(e); return false; } }
1077 try { return _meta.supportsOpenStatementsAcrossCommit(); }
1078 catch (SQLException e) { handleException(e); return false; }
10791079 }
10801080
10811081 @Override
10821082 public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
1083 { try { return _meta.supportsOpenStatementsAcrossRollback(); }
1084 catch (SQLException e) { handleException(e); return false; } }
1083 try { return _meta.supportsOpenStatementsAcrossRollback(); }
1084 catch (SQLException e) { handleException(e); return false; }
10851085 }
10861086
10871087 @Override
10881088 public boolean supportsOrderByUnrelated() throws SQLException {
1089 { try { return _meta.supportsOrderByUnrelated(); }
1090 catch (SQLException e) { handleException(e); return false; } }
1089 try { return _meta.supportsOrderByUnrelated(); }
1090 catch (SQLException e) { handleException(e); return false; }
10911091 }
10921092
10931093 @Override
10941094 public boolean supportsOuterJoins() throws SQLException {
1095 { try { return _meta.supportsOuterJoins(); }
1096 catch (SQLException e) { handleException(e); return false; } }
1095 try { return _meta.supportsOuterJoins(); }
1096 catch (SQLException e) { handleException(e); return false; }
10971097 }
10981098
10991099 @Override
11001100 public boolean supportsPositionedDelete() throws SQLException {
1101 { try { return _meta.supportsPositionedDelete(); }
1102 catch (SQLException e) { handleException(e); return false; } }
1101 try { return _meta.supportsPositionedDelete(); }
1102 catch (SQLException e) { handleException(e); return false; }
11031103 }
11041104
11051105 @Override
11061106 public boolean supportsPositionedUpdate() throws SQLException {
1107 { try { return _meta.supportsPositionedUpdate(); }
1108 catch (SQLException e) { handleException(e); return false; } }
1107 try { return _meta.supportsPositionedUpdate(); }
1108 catch (SQLException e) { handleException(e); return false; }
11091109 }
11101110
11111111 @Override
11121112 public boolean supportsResultSetConcurrency(int type, int concurrency)
11131113 throws SQLException {
1114 { try { return _meta.supportsResultSetConcurrency(type, concurrency); }
1115 catch (SQLException e) { handleException(e); return false; } }
1114 try { return _meta.supportsResultSetConcurrency(type, concurrency); }
1115 catch (SQLException e) { handleException(e); return false; }
11161116 }
11171117
11181118 @Override
11191119 public boolean supportsResultSetHoldability(int holdability)
11201120 throws SQLException {
1121 { try { return _meta.supportsResultSetHoldability(holdability); }
1122 catch (SQLException e) { handleException(e); return false; } }
1121 try { return _meta.supportsResultSetHoldability(holdability); }
1122 catch (SQLException e) { handleException(e); return false; }
11231123 }
11241124
11251125 @Override
11261126 public boolean supportsResultSetType(int type) throws SQLException {
1127 { try { return _meta.supportsResultSetType(type); }
1128 catch (SQLException e) { handleException(e); return false; } }
1127 try { return _meta.supportsResultSetType(type); }
1128 catch (SQLException e) { handleException(e); return false; }
11291129 }
11301130
11311131 @Override
11321132 public boolean supportsSavepoints() throws SQLException {
1133 { try { return _meta.supportsSavepoints(); }
1134 catch (SQLException e) { handleException(e); return false; } }
1133 try { return _meta.supportsSavepoints(); }
1134 catch (SQLException e) { handleException(e); return false; }
11351135 }
11361136
11371137 @Override
11381138 public boolean supportsSchemasInDataManipulation() throws SQLException {
1139 { try { return _meta.supportsSchemasInDataManipulation(); }
1140 catch (SQLException e) { handleException(e); return false; } }
1139 try { return _meta.supportsSchemasInDataManipulation(); }
1140 catch (SQLException e) { handleException(e); return false; }
11411141 }
11421142
11431143 @Override
11441144 public boolean supportsSchemasInIndexDefinitions() throws SQLException {
1145 { try { return _meta.supportsSchemasInIndexDefinitions(); }
1146 catch (SQLException e) { handleException(e); return false; } }
1145 try { return _meta.supportsSchemasInIndexDefinitions(); }
1146 catch (SQLException e) { handleException(e); return false; }
11471147 }
11481148
11491149 @Override
11501150 public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
1151 { try { return _meta.supportsSchemasInPrivilegeDefinitions(); }
1152 catch (SQLException e) { handleException(e); return false; } }
1151 try { return _meta.supportsSchemasInPrivilegeDefinitions(); }
1152 catch (SQLException e) { handleException(e); return false; }
11531153 }
11541154
11551155 @Override
11561156 public boolean supportsSchemasInProcedureCalls() throws SQLException {
1157 { try { return _meta.supportsSchemasInProcedureCalls(); }
1158 catch (SQLException e) { handleException(e); return false; } }
1157 try { return _meta.supportsSchemasInProcedureCalls(); }
1158 catch (SQLException e) { handleException(e); return false; }
11591159 }
11601160
11611161 @Override
11621162 public boolean supportsSchemasInTableDefinitions() throws SQLException {
1163 { try { return _meta.supportsSchemasInTableDefinitions(); }
1164 catch (SQLException e) { handleException(e); return false; } }
1163 try { return _meta.supportsSchemasInTableDefinitions(); }
1164 catch (SQLException e) { handleException(e); return false; }
11651165 }
11661166
11671167 @Override
11681168 public boolean supportsSelectForUpdate() throws SQLException {
1169 { try { return _meta.supportsSelectForUpdate(); }
1170 catch (SQLException e) { handleException(e); return false; } }
1169 try { return _meta.supportsSelectForUpdate(); }
1170 catch (SQLException e) { handleException(e); return false; }
11711171 }
11721172
11731173 @Override
11741174 public boolean supportsStatementPooling() throws SQLException {
1175 { try { return _meta.supportsStatementPooling(); }
1176 catch (SQLException e) { handleException(e); return false; } }
1175 try { return _meta.supportsStatementPooling(); }
1176 catch (SQLException e) { handleException(e); return false; }
11771177 }
11781178
11791179 @Override
11801180 public boolean supportsStoredProcedures() throws SQLException {
1181 { try { return _meta.supportsStoredProcedures(); }
1182 catch (SQLException e) { handleException(e); return false; } }
1181 try { return _meta.supportsStoredProcedures(); }
1182 catch (SQLException e) { handleException(e); return false; }
11831183 }
11841184
11851185 @Override
11861186 public boolean supportsSubqueriesInComparisons() throws SQLException {
1187 { try { return _meta.supportsSubqueriesInComparisons(); }
1188 catch (SQLException e) { handleException(e); return false; } }
1187 try { return _meta.supportsSubqueriesInComparisons(); }
1188 catch (SQLException e) { handleException(e); return false; }
11891189 }
11901190
11911191 @Override
11921192 public boolean supportsSubqueriesInExists() throws SQLException {
1193 { try { return _meta.supportsSubqueriesInExists(); }
1194 catch (SQLException e) { handleException(e); return false; } }
1193 try { return _meta.supportsSubqueriesInExists(); }
1194 catch (SQLException e) { handleException(e); return false; }
11951195 }
11961196
11971197 @Override
11981198 public boolean supportsSubqueriesInIns() throws SQLException {
1199 { try { return _meta.supportsSubqueriesInIns(); }
1200 catch (SQLException e) { handleException(e); return false; } }
1199 try { return _meta.supportsSubqueriesInIns(); }
1200 catch (SQLException e) { handleException(e); return false; }
12011201 }
12021202
12031203 @Override
12041204 public boolean supportsSubqueriesInQuantifieds() throws SQLException {
1205 { try { return _meta.supportsSubqueriesInQuantifieds(); }
1206 catch (SQLException e) { handleException(e); return false; } }
1205 try { return _meta.supportsSubqueriesInQuantifieds(); }
1206 catch (SQLException e) { handleException(e); return false; }
12071207 }
12081208
12091209 @Override
12101210 public boolean supportsTableCorrelationNames() throws SQLException {
1211 { try { return _meta.supportsTableCorrelationNames(); }
1212 catch (SQLException e) { handleException(e); return false; } }
1211 try { return _meta.supportsTableCorrelationNames(); }
1212 catch (SQLException e) { handleException(e); return false; }
12131213 }
12141214
12151215 @Override
12161216 public boolean supportsTransactionIsolationLevel(int level)
12171217 throws SQLException {
1218 { try { return _meta.supportsTransactionIsolationLevel(level); }
1219 catch (SQLException e) { handleException(e); return false; } }
1218 try { return _meta.supportsTransactionIsolationLevel(level); }
1219 catch (SQLException e) { handleException(e); return false; }
12201220 }
12211221
12221222 @Override
12231223 public boolean supportsTransactions() throws SQLException {
1224 { try { return _meta.supportsTransactions(); }
1225 catch (SQLException e) { handleException(e); return false; } }
1224 try { return _meta.supportsTransactions(); }
1225 catch (SQLException e) { handleException(e); return false; }
12261226 }
12271227
12281228 @Override
12291229 public boolean supportsUnion() throws SQLException {
1230 { try { return _meta.supportsUnion(); }
1231 catch (SQLException e) { handleException(e); return false; } }
1230 try { return _meta.supportsUnion(); }
1231 catch (SQLException e) { handleException(e); return false; }
12321232 }
12331233
12341234 @Override
12351235 public boolean supportsUnionAll() throws SQLException {
1236 { try { return _meta.supportsUnionAll(); }
1237 catch (SQLException e) { handleException(e); return false; } }
1236 try { return _meta.supportsUnionAll(); }
1237 catch (SQLException e) { handleException(e); return false; }
12381238 }
12391239
12401240 @Override
12411241 public boolean updatesAreDetected(int type) throws SQLException {
1242 { try { return _meta.updatesAreDetected(type); }
1243 catch (SQLException e) { handleException(e); return false; } }
1242 try { return _meta.updatesAreDetected(type); }
1243 catch (SQLException e) { handleException(e); return false; }
12441244 }
12451245
12461246 @Override
12471247 public boolean usesLocalFilePerTable() throws SQLException {
1248 { try { return _meta.usesLocalFilePerTable(); }
1249 catch (SQLException e) { handleException(e); return false; } }
1248 try { return _meta.usesLocalFilePerTable(); }
1249 catch (SQLException e) { handleException(e); return false; }
12501250 }
12511251
12521252 @Override
12531253 public boolean usesLocalFiles() throws SQLException {
1254 { try { return _meta.usesLocalFiles(); }
1255 catch (SQLException e) { handleException(e); return false; } }
1254 try { return _meta.usesLocalFiles(); }
1255 catch (SQLException e) { handleException(e); return false; }
12561256 }
12571257
12581258 /* JDBC_4_ANT_KEY_BEGIN */
12811281
12821282 @Override
12831283 public RowIdLifetime getRowIdLifetime() throws SQLException {
1284 { try { return _meta.getRowIdLifetime(); }
1285 catch (SQLException e) { handleException(e); throw new AssertionError(); } }
1284 try { return _meta.getRowIdLifetime(); }
1285 catch (SQLException e) { handleException(e); throw new AssertionError(); }
12861286 }
12871287
12881288 @Override
13011301
13021302 @Override
13031303 public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
1304 { try { return _meta.autoCommitFailureClosesAllResultSets(); }
1305 catch (SQLException e) { handleException(e); return false; } }
1304 try { return _meta.autoCommitFailureClosesAllResultSets(); }
1305 catch (SQLException e) { handleException(e); return false; }
13061306 }
13071307
13081308 @Override
13091309 public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
1310 { try { return _meta.supportsStoredFunctionsUsingCallSyntax(); }
1311 catch (SQLException e) { handleException(e); return false; } }
1310 try { return _meta.supportsStoredFunctionsUsingCallSyntax(); }
1311 catch (SQLException e) { handleException(e); return false; }
13121312 }
13131313
13141314 @Override
120120
121121 /**
122122 * If my underlying {@link ResultSet} is not a
123 * <tt>DelegatingResultSet</tt>, returns it,
123 * {@code DelegatingResultSet}, returns it,
124124 * otherwise recursively invokes this method on
125125 * my delegate.
126126 * <p>
127127 * Hence this method will return the first
128 * delegate that is not a <tt>DelegatingResultSet</tt>,
129 * or <tt>null</tt> when no non-<tt>DelegatingResultSet</tt>
128 * delegate that is not a {@code DelegatingResultSet},
129 * or {@code null} when no non-{@code DelegatingResultSet}
130130 * delegate can be found by transversing this chain.
131131 * <p>
132132 * This method is useful when you may have nested
133 * <tt>DelegatingResultSet</tt>s, and you want to make
133 * {@code DelegatingResultSet}s, and you want to make
134134 * sure to obtain a "genuine" {@link ResultSet}.
135135 */
136136 public ResultSet getInnermostDelegate() {
7373
7474 /**
7575 * If my underlying {@link Statement} is not a
76 * <tt>DelegatingStatement</tt>, returns it,
76 * {@code DelegatingStatement}, returns it,
7777 * otherwise recursively invokes this method on
7878 * my delegate.
7979 * <p>
8080 * Hence this method will return the first
81 * delegate that is not a <tt>DelegatingStatement</tt>
82 * or <tt>null</tt> when no non-<tt>DelegatingStatement</tt>
81 * delegate that is not a {@code DelegatingStatement}
82 * or {@code null} when no non-{@code DelegatingStatement}
8383 * delegate can be found by transversing this chain.
8484 * <p>
8585 * This method is useful when you may have nested
86 * <tt>DelegatingStatement</tt>s, and you want to make
86 * {@code DelegatingStatement}s, and you want to make
8787 * sure to obtain a "genuine" {@link Statement}.
8888 * @see #getDelegate
8989 */
5151 LogFactory.getLog(PoolableConnectionFactory.class);
5252
5353 /**
54 * Create a new <tt>PoolableConnectionFactory</tt>.
54 * Create a new {@code PoolableConnectionFactory}.
5555 * @param connFactory the {@link ConnectionFactory} from which to obtain
5656 * base {@link Connection}s
5757 */
8686
8787 /**
8888 * Sets the SQL statements I use to initialize newly created {@link Connection}s.
89 * Using <tt>null</tt> turns off connection initialization.
89 * Using {@code null} turns off connection initialization.
9090 * @param connectionInitSqls SQL statement to initialize {@link Connection}s.
9191 */
9292 public void setConnectionInitSql(Collection<String> connectionInitSqls) {
363363 *
364364 * @param key ignored
365365 * @param p ignored
366 * @return <tt>true</tt>
366 * @return {@code true}
367367 */
368368 @Override
369369 public boolean validateObject(PStmtKey key,
7777 */
7878 private boolean isClosed;
7979
80 /** My pool of {*link PreparedStatement}s. */
80 /** My pool of {@link PreparedStatement}s. */
8181 private KeyedObjectPool<PStmtKeyCPDS, PoolablePreparedStatement<PStmtKeyCPDS>> pstmtPool = null;
8282
8383 /**
359359 }
360360
361361 /**
362 * Create a {*link PooledConnectionImpl.PStmtKey} for the given arguments.
362 * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
363363 */
364364 protected PStmtKeyCPDS createKey(String sql, int autoGeneratedKeys) {
365365 return new PStmtKeyCPDS(normalizeSQL(sql), autoGeneratedKeys);
366366 }
367367
368368 /**
369 * Create a {*link PooledConnectionImpl.PStmtKey} for the given arguments.
369 * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
370370 */
371371 protected PStmtKeyCPDS createKey(String sql, int resultSetType,
372372 int resultSetConcurrency, int resultSetHoldability) {
375375 }
376376
377377 /**
378 * Create a {*link PooledConnectionImpl.PStmtKey} for the given arguments.
378 * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
379379 */
380380 protected PStmtKeyCPDS createKey(String sql, int columnIndexes[]) {
381381 return new PStmtKeyCPDS(normalizeSQL(sql), columnIndexes);
382382 }
383383
384384 /**
385 * Create a {*link PooledConnectionImpl.PStmtKey} for the given arguments.
385 * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
386386 */
387387 protected PStmtKeyCPDS createKey(String sql, String columnNames[]) {
388388 return new PStmtKeyCPDS(normalizeSQL(sql), columnNames);
389389 }
390390
391391 /**
392 * Create a {*link PooledConnectionImpl.PStmtKey} for the given arguments.
392 * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
393393 */
394394 protected PStmtKeyCPDS createKey(String sql, int resultSetType,
395395 int resultSetConcurrency) {
398398 }
399399
400400 /**
401 * Create a {*link PooledConnectionImpl.PStmtKey} for the given arguments.
401 * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
402402 */
403403 protected PStmtKeyCPDS createKey(String sql) {
404404 return new PStmtKeyCPDS(normalizeSQL(sql));
413413 }
414414
415415 /**
416 * My {*link KeyedPoolableObjectFactory} method for creating
417 * {*link PreparedStatement}s.
418 * @param key the key for the {*link PreparedStatement} to be created
416 * My {@link KeyedPooledObjectFactory} method for creating
417 * {@link PreparedStatement}s.
418 * @param key the key for the {@link PreparedStatement} to be created
419419 */
420420 @Override
421421 public PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> makeObject(PStmtKeyCPDS key) throws Exception {
443443 }
444444
445445 /**
446 * My {*link KeyedPoolableObjectFactory} method for destroying
447 * {*link PreparedStatement}s.
446 * My {@link KeyedPooledObjectFactory} method for destroying
447 * {@link PreparedStatement}s.
448448 * @param key ignored
449 * @param p the wrapped {*link PreparedStatement} to be destroyed.
449 * @param p the wrapped {@link PreparedStatement} to be destroyed.
450450 */
451451 @Override
452452 public void destroyObject(PStmtKeyCPDS key,
456456 }
457457
458458 /**
459 * My {*link KeyedPoolableObjectFactory} method for validating
460 * {*link PreparedStatement}s.
459 * My {@link KeyedPooledObjectFactory} method for validating
460 * {@link PreparedStatement}s.
461461 * @param key ignored
462462 * @param p ignored
463 * @return <tt>true</tt>
463 * @return {@code true}
464464 */
465465 @Override
466466 public boolean validateObject(PStmtKeyCPDS key,
469469 }
470470
471471 /**
472 * My {*link KeyedPoolableObjectFactory} method for activating
473 * {*link PreparedStatement}s.
472 * My {@link KeyedPooledObjectFactory} method for activating
473 * {@link PreparedStatement}s.
474474 * @param key ignored
475475 * @param p ignored
476476 */
482482 }
483483
484484 /**
485 * My {*link KeyedPoolableObjectFactory} method for passivating
486 * {*link PreparedStatement}s. Currently invokes {*link PreparedStatement#clearParameters}.
485 * My {@link KeyedPooledObjectFactory} method for passivating
486 * {@link PreparedStatement}s. Currently invokes {@link PreparedStatement#clearParameters}.
487487 * @param key ignored
488 * @param p a wrapped {*link PreparedStatement}
488 * @param p a wrapped {@link PreparedStatement}
489489 */
490490 @Override
491491 public void passivateObject(PStmtKeyCPDS key,
7474 new ConcurrentHashMap<>();
7575
7676 /**
77 * Create a new <tt>PoolableConnectionFactory</tt>.
77 * Create a new {@code PoolableConnectionFactory}.
7878 *
7979 * @param cpds the ConnectionPoolDataSource from which to obtain
8080 * PooledConnection's
8181 * @param validationQuery a query to use to {@link #validateObject
8282 * validate} {@link Connection}s. Should return at least one row.
83 * May be <tt>null</tt> in which case {@link Connection#isValid(int)} will
83 * May be {@code null} in which case {@link Connection#isValid(int)} will
8484 * be used to validate connections.
8585 * @param validationQueryTimeout Timeout in seconds before validation fails
8686 * @param rollbackAfterValidation whether a rollback should be issued
3737 import org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject;
3838
3939 /**
40 * A {*link PoolableObjectFactory} that creates
41 * {*link PoolableConnection}s.
40 * A {@link KeyedPooledObjectFactory} that creates
41 * {@link PoolableConnection}s.
4242 *
4343 * @author John D. McNally
4444 * @since 2.0
7373
7474
7575 /**
76 * Create a new <tt>KeyedPoolableConnectionFactory</tt>.
76 * Create a new {@code KeyedPoolableConnectionFactory}.
7777 * @param cpds the ConnectionPoolDataSource from which to obtain
7878 * PooledConnections
7979 * @param validationQuery a query to use to {@link #validateObject validate}
8080 * {@link Connection}s. Should return at least one row. May be
81 * <tt>null</tt> in which case3 {@link Connection#isValid(int)} will be used
81 * {@code null} in which case3 {@link Connection#isValid(int)} will be used
8282 * to validate connections.
8383 * @param rollbackAfterValidation whether a rollback should be issued after
8484 * {@link #validateObject validating} {@link Connection}s.
112112 * To create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver}, we do the same thing,
113113 * except that instead of creating a {@link javax.sql.DataSource} on the last line,
114114 * we create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver}, and register the
115 * <tt>connectionPool</tt> with it. E.g.,:
115 * {@code connectionPool} with it. E.g.,:
116116 * <pre>GenericObjectPool connectionPool = new GenericObjectPool(null);
117117 * ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string", "username", "password");
118118 * PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,connectionPool,null,null,false,true);
7575 /**
7676 * Ensures that the instance is safe to be returned by the pool.
7777 * <p>
78 * The default implementation always returns <tt>true</tt>.
78 * The default implementation always returns {@code true}.
7979 *
8080 * @param key the key used when selecting the object
8181 * @param p a {@code PooledObject} wrapping the the instance to be validated
4343 * @return true if abandoned objects are to be removed by borrowObject
4444 */
4545 public boolean getRemoveAbandonedOnBorrow() {
46 return (this.removeAbandonedOnBorrow);
46 return this.removeAbandonedOnBorrow;
4747 }
4848
4949 /**
8080 * @return true if abandoned objects are to be removed by the evictor
8181 */
8282 public boolean getRemoveAbandonedOnMaintenance() {
83 return (this.removeAbandonedOnMaintenance);
83 return this.removeAbandonedOnMaintenance;
8484 }
8585
8686 /**
113113 * @return the abandoned object timeout in seconds
114114 */
115115 public int getRemoveAbandonedTimeout() {
116 return (this.removeAbandonedTimeout);
116 return this.removeAbandonedTimeout;
117117 }
118118
119119 /**
151151 *
152152 */
153153 public boolean getLogAbandoned() {
154 return (this.logAbandoned);
154 return this.logAbandoned;
155155 }
156156
157157 /**
1919 import java.io.StringWriter;
2020 import java.io.Writer;
2121 import java.lang.management.ManagementFactory;
22 import java.lang.ref.WeakReference;
2223 import java.util.Iterator;
2324 import java.util.TimerTask;
2425 import java.util.concurrent.atomic.AtomicLong;
8990 private Evictor evictor = null; // @GuardedBy("evictionLock")
9091 Iterator<PooledObject<T>> evictionIterator = null; // @GuardedBy("evictionLock")
9192 /*
92 * Class loader for evictor thread to use since in a J2EE or similar
93 * environment the context class loader for the evictor thread may have
94 * visibility of the correct factory. See POOL-161.
95 */
96 private final ClassLoader factoryClassLoader;
93 * Class loader for evictor thread to use since, in a JavaEE or similar
94 * environment, the context class loader for the evictor thread may not have
95 * visibility of the correct factory. See POOL-161. Uses a weak reference to
96 * avoid potential memory leaks if the Pool is discarded rather than closed.
97 */
98 private final WeakReference<ClassLoader> factoryClassLoader;
9799
98100
99101 // Monitoring (primarily JMX) attributes
110112 private final StatsStore waitTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
111113 private final Object maxBorrowWaitTimeMillisLock = new Object();
112114 private volatile long maxBorrowWaitTimeMillis = 0; // @GuardedBy("maxBorrowWaitTimeMillisLock")
113 private SwallowedExceptionListener swallowedExceptionListener = null;
115 private volatile SwallowedExceptionListener swallowedExceptionListener = null;
114116
115117
116118 /**
133135 // Populate the creation stack trace
134136 this.creationStackTrace = getStackTrace(new Exception());
135137
136 // save the current CCL to be used later by the evictor Thread
137 factoryClassLoader = Thread.currentThread().getContextClassLoader();
138 // save the current TCCL (if any) to be used later by the evictor Thread
139 ClassLoader cl = Thread.currentThread().getContextClassLoader();
140 if (cl == null) {
141 factoryClassLoader = null;
142 } else {
143 factoryClassLoader = new WeakReference<>(cl);
144 }
145
138146 fairness = config.getFairness();
139147 }
140148
585593 public final void setEvictionPolicyClassName(
586594 String evictionPolicyClassName) {
587595 try {
588 Class<?> clazz = Class.forName(evictionPolicyClassName);
596 Class<?> clazz = Class.forName(evictionPolicyClassName, true,
597 Thread.currentThread().getContextClassLoader());
589598 Object policy = clazz.newInstance();
590599 if (policy instanceof EvictionPolicy<?>) {
591600 @SuppressWarnings("unchecked") // safe, because we just checked the class
9931002 ClassLoader savedClassLoader =
9941003 Thread.currentThread().getContextClassLoader();
9951004 try {
996 // Set the class loader for the factory
997 Thread.currentThread().setContextClassLoader(
998 factoryClassLoader);
1005 if (factoryClassLoader != null) {
1006 // Set the class loader for the factory
1007 ClassLoader cl = factoryClassLoader.get();
1008 if (cl == null) {
1009 // The pool has been dereferenced and the class loader
1010 // GC'd. Cancel this timer so the pool can be GC'd as
1011 // well.
1012 cancel();
1013 return;
1014 }
1015 Thread.currentThread().setContextClassLoader(cl);
1016 }
9991017
10001018 // Evict from the pool
10011019 try {
3838 class EvictionTimer {
3939
4040 /** Timer instance */
41 private static Timer _timer; //@GuardedBy("this")
41 private static Timer _timer; //@GuardedBy("EvictionTimer.class")
4242
4343 /** Static usage count tracker */
44 private static int _usageCount; //@GuardedBy("this")
44 private static int _usageCount; //@GuardedBy("EvictionTimer.class")
4545
4646 /** Prevent instantiation */
4747 private EvictionTimer() {
6666 try {
6767 AccessController.doPrivileged(new PrivilegedSetTccl(
6868 EvictionTimer.class.getClassLoader()));
69 _timer = new Timer("commons-pool-EvictionTimer", true);
69 _timer = AccessController.doPrivileged(new PrivilegedNewEvictionTimer());
7070 } finally {
7171 AccessController.doPrivileged(new PrivilegedSetTccl(ccl));
7272 }
128128 }
129129 }
130130
131 /**
132 * {@link PrivilegedAction} used to create a new Timer. Creating the timer
133 * with a privileged action means the associated Thread does not inherit the
134 * current access control context. In a container environment, inheriting
135 * the current access control context is likely to result in retaining a
136 * reference to the thread context class loader which would be a memory
137 * leak.
138 */
139 private static class PrivilegedNewEvictionTimer implements PrivilegedAction<Timer> {
140
141 /**
142 * {@inheritDoc}
143 */
144 @Override
145 public Timer run() {
146 return new Timer("commons-pool-EvictionTimer", true);
147 }
148 }
131149 }
106106
107107 setConfig(config);
108108
109 startEvictor(getMinEvictableIdleTimeMillis());
109 startEvictor(getTimeBetweenEvictionRunsMillis());
110110 }
111111
112112 /**
349349 if (blockWhenExhausted) {
350350 p = objectDeque.getIdleObjects().pollFirst();
351351 if (p == null) {
352 create = true;
353352 p = create(key);
353 if (p != null) {
354 create = true;
355 }
354356 }
355357 if (p == null) {
356358 if (borrowMaxWaitMillis < 0) {
370372 } else {
371373 p = objectDeque.getIdleObjects().pollFirst();
372374 if (p == null) {
373 create = true;
374375 p = create(key);
376 if (p != null) {
377 create = true;
378 }
375379 }
376380 if (p == null) {
377381 throw new NoSuchElementException("Pool exhausted");
929933 continue;
930934 }
931935
932 if (evictionPolicy.evict(evictionConfig, underTest,
933 poolMap.get(evictionKey).getIdleObjects().size())) {
936 // User provided eviction policy could throw all sorts of crazy
937 // exceptions. Protect against such an exception killing the
938 // eviction thread.
939 boolean evict;
940 try {
941 evict = evictionPolicy.evict(evictionConfig, underTest,
942 poolMap.get(evictionKey).getIdleObjects().size());
943 } catch (Throwable t) {
944 // Slightly convoluted as SwallowedExceptionListener uses
945 // Exception rather than Throwable
946 PoolUtils.checkRethrow(t);
947 swallowException(new Exception(t));
948 // Don't evict on error conditions
949 evict = false;
950 }
951
952 if (evict) {
934953 destroy(evictionKey, underTest, true);
935954 destroyedByEvictorCount.incrementAndGet();
936955 } else {
428428 if (blockWhenExhausted) {
429429 p = idleObjects.pollFirst();
430430 if (p == null) {
431 create = true;
432431 p = create();
432 if (p != null) {
433 create = true;
434 }
433435 }
434436 if (p == null) {
435437 if (borrowMaxWaitMillis < 0) {
449451 } else {
450452 p = idleObjects.pollFirst();
451453 if (p == null) {
452 create = true;
453454 p = create();
455 if (p != null) {
456 create = true;
457 }
454458 }
455459 if (p == null) {
456460 throw new NoSuchElementException("Pool exhausted");
774778 continue;
775779 }
776780
777 if (evictionPolicy.evict(evictionConfig, underTest,
778 idleObjects.size())) {
781 // User provided eviction policy could throw all sorts of crazy
782 // exceptions. Protect against such an exception killing the
783 // eviction thread.
784 boolean evict;
785 try {
786 evict = evictionPolicy.evict(evictionConfig, underTest,
787 idleObjects.size());
788 } catch (Throwable t) {
789 // Slightly convoluted as SwallowedExceptionListener uses
790 // Exception rather than Throwable
791 PoolUtils.checkRethrow(t);
792 swallowException(new Exception(t));
793 // Don't evict on error conditions
794 evict = false;
795 }
796
797 if (evict) {
779798 destroy(underTest);
780799 destroyedByEvictorCount.incrementAndGet();
781800 } else {
129129 * Invariant: (first == null && last == null) ||
130130 * (first.prev == null && first.item != null)
131131 */
132 private transient Node<E> first;
132 private transient Node<E> first; // @GuardedBy("lock")
133133
134134 /**
135135 * Pointer to last node.
136136 * Invariant: (first == null && last == null) ||
137137 * (last.next == null && last.item != null)
138138 */
139 private transient Node<E> last;
139 private transient Node<E> last; // @GuardedBy("lock")
140140
141141 /** Number of items in the deque */
142 private transient int count;
142 private transient int count; // @GuardedBy("lock")
143143
144144 /** Maximum number of items in the deque */
145145 private final int capacity;
191191 * @throws IllegalArgumentException if {@code capacity} is less than 1
192192 */
193193 public LinkedBlockingDeque(int capacity, boolean fairness) {
194 if (capacity <= 0) throw new IllegalArgumentException();
194 if (capacity <= 0) {
195 throw new IllegalArgumentException();
196 }
195197 this.capacity = capacity;
196198 lock = new InterruptibleReentrantLock(fairness);
197199 notEmpty = lock.newCondition();
213215 lock.lock(); // Never contended, but necessary for visibility
214216 try {
215217 for (E e : c) {
216 if (e == null)
218 if (e == null) {
217219 throw new NullPointerException();
218 if (!linkLast(e))
220 }
221 if (!linkLast(e)) {
219222 throw new IllegalStateException("Deque full");
223 }
220224 }
221225 } finally {
222226 lock.unlock();
235239 */
236240 private boolean linkFirst(E e) {
237241 // assert lock.isHeldByCurrentThread();
238 if (count >= capacity)
242 if (count >= capacity) {
239243 return false;
244 }
240245 Node<E> f = first;
241246 Node<E> x = new Node<>(e, null, f);
242247 first = x;
243 if (last == null)
248 if (last == null) {
244249 last = x;
245 else
250 } else {
246251 f.prev = x;
252 }
247253 ++count;
248254 notEmpty.signal();
249255 return true;
258264 */
259265 private boolean linkLast(E e) {
260266 // assert lock.isHeldByCurrentThread();
261 if (count >= capacity)
267 if (count >= capacity) {
262268 return false;
269 }
263270 Node<E> l = last;
264271 Node<E> x = new Node<>(e, l, null);
265272 last = x;
266 if (first == null)
273 if (first == null) {
267274 first = x;
268 else
275 } else {
269276 l.next = x;
277 }
270278 ++count;
271279 notEmpty.signal();
272280 return true;
280288 private E unlinkFirst() {
281289 // assert lock.isHeldByCurrentThread();
282290 Node<E> f = first;
283 if (f == null)
291 if (f == null) {
284292 return null;
293 }
285294 Node<E> n = f.next;
286295 E item = f.item;
287296 f.item = null;
288297 f.next = f; // help GC
289298 first = n;
290 if (n == null)
299 if (n == null) {
291300 last = null;
292 else
301 } else {
293302 n.prev = null;
303 }
294304 --count;
295305 notFull.signal();
296306 return item;
304314 private E unlinkLast() {
305315 // assert lock.isHeldByCurrentThread();
306316 Node<E> l = last;
307 if (l == null)
317 if (l == null) {
308318 return null;
319 }
309320 Node<E> p = l.prev;
310321 E item = l.item;
311322 l.item = null;
312323 l.prev = l; // help GC
313324 last = p;
314 if (p == null)
325 if (p == null) {
315326 first = null;
316 else
327 } else {
317328 p.next = null;
329 }
318330 --count;
319331 notFull.signal();
320332 return item;
351363 */
352364 @Override
353365 public void addFirst(E e) {
354 if (!offerFirst(e))
366 if (!offerFirst(e)) {
355367 throw new IllegalStateException("Deque full");
368 }
356369 }
357370
358371 /**
360373 */
361374 @Override
362375 public void addLast(E e) {
363 if (!offerLast(e))
376 if (!offerLast(e)) {
364377 throw new IllegalStateException("Deque full");
378 }
365379 }
366380
367381 /**
369383 */
370384 @Override
371385 public boolean offerFirst(E e) {
372 if (e == null) throw new NullPointerException();
386 if (e == null) {
387 throw new NullPointerException();
388 }
373389 lock.lock();
374390 try {
375391 return linkFirst(e);
383399 */
384400 @Override
385401 public boolean offerLast(E e) {
386 if (e == null) throw new NullPointerException();
402 if (e == null) {
403 throw new NullPointerException();
404 }
387405 lock.lock();
388406 try {
389407 return linkLast(e);
402420 * @throws InterruptedException
403421 */
404422 public void putFirst(E e) throws InterruptedException {
405 if (e == null) throw new NullPointerException();
406 lock.lock();
407 try {
408 while (!linkFirst(e))
423 if (e == null) {
424 throw new NullPointerException();
425 }
426 lock.lock();
427 try {
428 while (!linkFirst(e)) {
409429 notFull.await();
430 }
410431 } finally {
411432 lock.unlock();
412433 }
422443 * @throws InterruptedException
423444 */
424445 public void putLast(E e) throws InterruptedException {
425 if (e == null) throw new NullPointerException();
426 lock.lock();
427 try {
428 while (!linkLast(e))
446 if (e == null) {
447 throw new NullPointerException();
448 }
449 lock.lock();
450 try {
451 while (!linkLast(e)) {
429452 notFull.await();
453 }
430454 } finally {
431455 lock.unlock();
432456 }
447471 */
448472 public boolean offerFirst(E e, long timeout, TimeUnit unit)
449473 throws InterruptedException {
450 if (e == null) throw new NullPointerException();
474 if (e == null) {
475 throw new NullPointerException();
476 }
451477 long nanos = unit.toNanos(timeout);
452478 lock.lockInterruptibly();
453479 try {
454480 while (!linkFirst(e)) {
455 if (nanos <= 0)
481 if (nanos <= 0) {
456482 return false;
483 }
457484 nanos = notFull.awaitNanos(nanos);
458485 }
459486 return true;
477504 */
478505 public boolean offerLast(E e, long timeout, TimeUnit unit)
479506 throws InterruptedException {
480 if (e == null) throw new NullPointerException();
507 if (e == null) {
508 throw new NullPointerException();
509 }
481510 long nanos = unit.toNanos(timeout);
482511 lock.lockInterruptibly();
483512 try {
484513 while (!linkLast(e)) {
485 if (nanos <= 0)
514 if (nanos <= 0) {
486515 return false;
516 }
487517 nanos = notFull.awaitNanos(nanos);
488518 }
489519 return true;
498528 @Override
499529 public E removeFirst() {
500530 E x = pollFirst();
501 if (x == null) throw new NoSuchElementException();
531 if (x == null) {
532 throw new NoSuchElementException();
533 }
502534 return x;
503535 }
504536
508540 @Override
509541 public E removeLast() {
510542 E x = pollLast();
511 if (x == null) throw new NoSuchElementException();
543 if (x == null) {
544 throw new NoSuchElementException();
545 }
512546 return x;
513547 }
514548
543577 lock.lock();
544578 try {
545579 E x;
546 while ( (x = unlinkFirst()) == null)
580 while ( (x = unlinkFirst()) == null) {
547581 notEmpty.await();
582 }
548583 return x;
549584 } finally {
550585 lock.unlock();
562597 lock.lock();
563598 try {
564599 E x;
565 while ( (x = unlinkLast()) == null)
600 while ( (x = unlinkLast()) == null) {
566601 notEmpty.await();
602 }
567603 return x;
568604 } finally {
569605 lock.unlock();
587623 try {
588624 E x;
589625 while ( (x = unlinkFirst()) == null) {
590 if (nanos <= 0)
626 if (nanos <= 0) {
591627 return null;
628 }
592629 nanos = notEmpty.awaitNanos(nanos);
593630 }
594631 return x;
614651 try {
615652 E x;
616653 while ( (x = unlinkLast()) == null) {
617 if (nanos <= 0)
654 if (nanos <= 0) {
618655 return null;
656 }
619657 nanos = notEmpty.awaitNanos(nanos);
620658 }
621659 return x;
630668 @Override
631669 public E getFirst() {
632670 E x = peekFirst();
633 if (x == null) throw new NoSuchElementException();
671 if (x == null) {
672 throw new NoSuchElementException();
673 }
634674 return x;
635675 }
636676
640680 @Override
641681 public E getLast() {
642682 E x = peekLast();
643 if (x == null) throw new NoSuchElementException();
683 if (x == null) {
684 throw new NoSuchElementException();
685 }
644686 return x;
645687 }
646688
648690 public E peekFirst() {
649691 lock.lock();
650692 try {
651 return (first == null) ? null : first.item;
693 return first == null ? null : first.item;
652694 } finally {
653695 lock.unlock();
654696 }
658700 public E peekLast() {
659701 lock.lock();
660702 try {
661 return (last == null) ? null : last.item;
703 return last == null ? null : last.item;
662704 } finally {
663705 lock.unlock();
664706 }
666708
667709 @Override
668710 public boolean removeFirstOccurrence(Object o) {
669 if (o == null) return false;
711 if (o == null) {
712 return false;
713 }
670714 lock.lock();
671715 try {
672716 for (Node<E> p = first; p != null; p = p.next) {
683727
684728 @Override
685729 public boolean removeLastOccurrence(Object o) {
686 if (o == null) return false;
730 if (o == null) {
731 return false;
732 }
687733 lock.lock();
688734 try {
689735 for (Node<E> p = last; p != null; p = p.prev) {
873919 * @throws IllegalArgumentException
874920 */
875921 public int drainTo(Collection<? super E> c, int maxElements) {
876 if (c == null)
922 if (c == null) {
877923 throw new NullPointerException();
878 if (c == this)
924 }
925 if (c == this) {
879926 throw new IllegalArgumentException();
927 }
880928 lock.lock();
881929 try {
882930 int n = Math.min(maxElements, count);
9541002 */
9551003 @Override
9561004 public boolean contains(Object o) {
957 if (o == null) return false;
958 lock.lock();
959 try {
960 for (Node<E> p = first; p != null; p = p.next)
961 if (o.equals(p.item))
1005 if (o == null) {
1006 return false;
1007 }
1008 lock.lock();
1009 try {
1010 for (Node<E> p = first; p != null; p = p.next) {
1011 if (o.equals(p.item)) {
9621012 return true;
1013 }
1014 }
9631015 return false;
9641016 } finally {
9651017 lock.unlock();
10261078 try {
10271079 Object[] a = new Object[count];
10281080 int k = 0;
1029 for (Node<E> p = first; p != null; p = p.next)
1081 for (Node<E> p = first; p != null; p = p.next) {
10301082 a[k++] = p.item;
1083 }
10311084 return a;
10321085 } finally {
10331086 lock.unlock();
10471100 (a.getClass().getComponentType(), count);
10481101 }
10491102 int k = 0;
1050 for (Node<E> p = first; p != null; p = p.next)
1103 for (Node<E> p = first; p != null; p = p.next) {
10511104 a[k++] = (T)p.item;
1105 }
10521106 if (a.length > k) {
10531107 a[k] = null;
10541108 }
11641218 lock.lock();
11651219 try {
11661220 next = firstNode();
1167 nextItem = (next == null) ? null : next.item;
1221 nextItem = next == null ? null : next.item;
11681222 } finally {
11691223 lock.unlock();
11701224 }
11831237 } else {
11841238 // Skip over removed nodes.
11851239 // May be necessary if multiple interior Nodes are removed.
1186 while (s != null && s.item == null)
1240 while (s != null && s.item == null) {
11871241 s = nextNode(s);
1242 }
11881243 next = s;
11891244 }
1190 nextItem = (next == null) ? null : next.item;
1245 nextItem = next == null ? null : next.item;
11911246 } finally {
11921247 lock.unlock();
11931248 }
12001255
12011256 @Override
12021257 public E next() {
1203 if (next == null)
1258 if (next == null) {
12041259 throw new NoSuchElementException();
1260 }
12051261 lastRet = next;
12061262 E x = nextItem;
12071263 advance();
12111267 @Override
12121268 public void remove() {
12131269 Node<E> n = lastRet;
1214 if (n == null)
1270 if (n == null) {
12151271 throw new IllegalStateException();
1272 }
12161273 lastRet = null;
12171274 lock.lock();
12181275 try {
1219 if (n.item != null)
1276 if (n.item != null) {
12201277 unlink(n);
1278 }
12211279 } finally {
12221280 lock.unlock();
12231281 }
12541312 // Write out capacity and any hidden stuff
12551313 s.defaultWriteObject();
12561314 // Write out all elements in the proper order.
1257 for (Node<E> p = first; p != null; p = p.next)
1315 for (Node<E> p = first; p != null; p = p.next) {
12581316 s.writeObject(p.item);
1317 }
12591318 // Use trailing null as sentinel
12601319 s.writeObject(null);
12611320 } finally {
12781337 for (;;) {
12791338 @SuppressWarnings("unchecked")
12801339 E item = (E)s.readObject();
1281 if (item == null)
1340 if (item == null) {
12821341 break;
1342 }
12831343 add(item);
12841344 }
12851345 }
5252 private int numActive = 0; // @GuardedBy("this")
5353
5454 /** Total number of instances that have been destroyed */
55 private long destroyCount = 0;
55 private long destroyCount = 0; // @GuardedBy("this")
56
5657
5758 /** Total number of instances that have been created */
58 private long createCount = 0;
59 private long createCount = 0; // @GuardedBy("this")
5960
6061 /** Idle references - waiting to be borrowed */
6162 private final LinkedBlockingDeque<PooledSoftReference<T>> idleReferences =
9090 "CONSTANT_NameAndType", "", "", "CONSTANT_MethodHandle",
9191 "CONSTANT_MethodType", "", "CONSTANT_InvokeDynamic" };
9292
93
94 /** Attributes and their corresponding names.
95 */
96 public static final byte ATTR_UNKNOWN = -1;
97 public static final byte ATTR_SOURCE_FILE = 0;
98 public static final byte ATTR_CONSTANT_VALUE = 1;
99 public static final byte ATTR_CODE = 2;
100 public static final byte ATTR_EXCEPTIONS = 3;
101 public static final byte ATTR_LINE_NUMBER_TABLE = 4;
102 public static final byte ATTR_LOCAL_VARIABLE_TABLE = 5;
103 public static final byte ATTR_INNER_CLASSES = 6;
104 public static final byte ATTR_SYNTHETIC = 7;
105 public static final byte ATTR_DEPRECATED = 8;
106 public static final byte ATTR_PMG = 9;
107 public static final byte ATTR_SIGNATURE = 10;
108 public static final byte ATTR_STACK_MAP = 11;
109 public static final byte ATTR_RUNTIME_VISIBLE_ANNOTATIONS = 12;
110 public static final byte ATTR_RUNTIME_INVISIBLE_ANNOTATIONS = 13;
111 public static final byte ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = 14;
112 public static final byte ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = 15;
113 public static final byte ATTR_ANNOTATION_DEFAULT = 16;
114 public static final byte ATTR_LOCAL_VARIABLE_TYPE_TABLE = 17;
115 public static final byte ATTR_ENCLOSING_METHOD = 18;
116 public static final byte ATTR_STACK_MAP_TABLE = 19;
117 public static final byte ATTR_BOOTSTRAP_METHODS = 20;
118 public static final byte ATTR_METHOD_PARAMETERS = 21;
119
120 public static final short KNOWN_ATTRIBUTES = 22;
121
122 // TOFO: FIXXXXX
123 public static final String[] ATTRIBUTE_NAMES = {
124 "SourceFile", "ConstantValue", "Code", "Exceptions",
125 "LineNumberTable", "LocalVariableTable",
126 "InnerClasses", "Synthetic", "Deprecated",
127 "PMGClass", "Signature", "StackMap",
128 "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations",
129 "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations",
130 "AnnotationDefault", "LocalVariableTypeTable", "EnclosingMethod", "StackMapTable",
131 "BootstrapMethods", "MethodParameters"
132 };
133
134 /** Constants used in the StackMap attribute.
135 */
136 public static final byte ITEM_Bogus = 0;
137 public static final byte ITEM_Object = 7;
138 public static final byte ITEM_NewObject = 8;
139
140 /** Constants used to identify StackMapEntry types.
141 *
142 * For those types which can specify a range, the
143 * constant names the lowest value.
144 */
145 public static final int SAME_FRAME = 0;
146 public static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64;
147 public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247;
148 public static final int CHOP_FRAME = 248;
149 public static final int SAME_FRAME_EXTENDED = 251;
150 public static final int APPEND_FRAME = 252;
151 public static final int FULL_FRAME = 255;
152
153 /** Constants that define the maximum value of
154 * those constants which store ranges. */
155
156 public static final int SAME_FRAME_MAX = 63;
157 public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_MAX = 127;
158 public static final int CHOP_FRAME_MAX = 250;
159 public static final int APPEND_FRAME_MAX = 254;
16093 }
+0
-41
java/org/apache/tomcat/util/bcel/classfile/AccessFlags.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 /**
20 * Super class for all objects that have modifiers like private, final, ...
21 * I.e. classes, fields, and methods.
22 *
23 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
24 */
25 public abstract class AccessFlags implements java.io.Serializable {
26
27 private static final long serialVersionUID = 2548932939969293935L;
28 protected int access_flags;
29
30
31 public AccessFlags() {
32 }
33
34 /**
35 * @return Access flags of the object aka. "modifiers".
36 */
37 public final int getAccessFlags() {
38 return access_flags;
39 }
40 }
+0
-68
java/org/apache/tomcat/util/bcel/classfile/AnnotationDefault.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * represents the default value of a annotation for a method info
24 *
25 * @author <A HREF="mailto:dbrosius@qis.net">D. Brosius</A>
26 * @since 6.0
27 */
28 public class AnnotationDefault extends Attribute
29 {
30 private static final long serialVersionUID = 6715933396664171543L;
31
32 /**
33 * @param name_index
34 * Index pointing to the name <em>Code</em>
35 * @param length
36 * Content length in bytes
37 * @param file
38 * Input stream
39 * @param constant_pool
40 * Array of constants
41 */
42 public AnnotationDefault(int name_index, int length,
43 DataInputStream file, ConstantPool constant_pool)
44 throws IOException
45 {
46 this(name_index, length, (ElementValue) null,
47 constant_pool);
48 // Default value
49 ElementValue.readElementValue(file, constant_pool);
50 }
51
52 /**
53 * @param name_index
54 * Index pointing to the name <em>Code</em>
55 * @param length
56 * Content length in bytes
57 * @param defaultValue
58 * the annotation's default value
59 * @param constant_pool
60 * Array of constants
61 */
62 public AnnotationDefault(int name_index, int length,
63 ElementValue defaultValue, ConstantPool constant_pool)
64 {
65 super(name_index, length, constant_pool);
66 }
67 }
1919 public class AnnotationElementValue extends ElementValue
2020 {
2121 // For annotation element values, this is the annotation
22 private AnnotationEntry annotationEntry;
22 private final AnnotationEntry annotationEntry;
2323
24 public AnnotationElementValue(int type, AnnotationEntry annotationEntry,
24 AnnotationElementValue(int type, AnnotationEntry annotationEntry,
2525 ConstantPool cpool)
2626 {
2727 super(type, cpool);
1616 */
1717 package org.apache.tomcat.util.bcel.classfile;
1818
19 import java.io.DataInputStream;
19 import java.io.DataInput;
2020 import java.io.IOException;
2121 import java.util.ArrayList;
2222 import java.util.List;
3434 private final int type_index;
3535 private final ConstantPool constant_pool;
3636
37 private List<ElementValuePair> element_value_pairs;
37 private final List<ElementValuePair> element_value_pairs;
3838
3939 /**
40 * Factory method to create an AnnotionEntry from a DataInputStream
40 * Creates an AnnotationEntry from a DataInputStream
4141 *
4242 * @param file
4343 * @param constant_pool
44 * @return the entry
4544 * @throws IOException
4645 */
47 public static AnnotationEntry read(DataInputStream file, ConstantPool constant_pool) throws IOException {
46 AnnotationEntry(DataInput file, ConstantPool constant_pool) throws IOException {
4847
49 final AnnotationEntry annotationEntry = new AnnotationEntry(file.readUnsignedShort(), constant_pool);
50 final int num_element_value_pairs = (file.readUnsignedShort());
51 annotationEntry.element_value_pairs = new ArrayList<>();
48 this.constant_pool = constant_pool;
49
50 type_index = file.readUnsignedShort();
51 int num_element_value_pairs = file.readUnsignedShort();
52
53 element_value_pairs = new ArrayList<>(num_element_value_pairs);
5254 for (int i = 0; i < num_element_value_pairs; i++) {
53 annotationEntry.element_value_pairs.add(new ElementValuePair(file.readUnsignedShort(), ElementValue.readElementValue(file, constant_pool),
54 constant_pool));
55 element_value_pairs.add(new ElementValuePair(file, constant_pool));
5556 }
56 return annotationEntry;
57 }
58
59 public AnnotationEntry(int type_index, ConstantPool constant_pool) {
60 this.type_index = type_index;
61 this.constant_pool = constant_pool;
6257 }
6358
6459 /**
7267 /**
7368 * @return the element value pairs in this annotation entry
7469 */
75 public ElementValuePair[] getElementValuePairs() {
76 // TODO return List
77 return element_value_pairs.toArray(new ElementValuePair[element_value_pairs.size()]);
70 public List<ElementValuePair> getElementValuePairs() {
71 return element_value_pairs;
7872 }
7973 }
1616 */
1717 package org.apache.tomcat.util.bcel.classfile;
1818
19 import java.io.DataInputStream;
19 import java.io.DataInput;
2020 import java.io.IOException;
2121
2222 /**
2525 * @author <A HREF="mailto:dbrosius@qis.net">D. Brosius</A>
2626 * @since 6.0
2727 */
28 public abstract class Annotations extends Attribute {
28 public class Annotations {
2929
30 private static final long serialVersionUID = 1L;
31
32 private AnnotationEntry[] annotation_table;
30 private final AnnotationEntry[] annotation_table;
3331
3432 /**
35 * @param name_index Index pointing to the name <em>Code</em>
36 * @param length Content length in bytes
3733 * @param file Input stream
3834 * @param constant_pool Array of constants
3935 */
40 public Annotations(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException {
41 this(name_index, length, (AnnotationEntry[]) null, constant_pool);
36 Annotations(DataInput file, ConstantPool constant_pool)
37 throws IOException {
4238 final int annotation_table_length = (file.readUnsignedShort());
4339 annotation_table = new AnnotationEntry[annotation_table_length];
4440 for (int i = 0; i < annotation_table_length; i++) {
45 annotation_table[i] = AnnotationEntry.read(file, constant_pool);
41 annotation_table[i] = new AnnotationEntry(file, constant_pool);
4642 }
4743 }
4844
49
50 /**
51 * @param name_index Index pointing to the name <em>Code</em>
52 * @param length Content length in bytes
53 * @param annotation_table the actual annotations
54 * @param constant_pool Array of constants
55 */
56 public Annotations(int name_index, int length, AnnotationEntry[] annotation_table, ConstantPool constant_pool) {
57 super(name_index, length, constant_pool);
58 setAnnotationTable(annotation_table);
59 }
60
61 /**
62 * @param annotation_table the entries to set in this annotation
63 */
64 public final void setAnnotationTable( AnnotationEntry[] annotation_table ) {
65 this.annotation_table = annotation_table;
66 }
6745
6846 /**
6947 * returns the array of annotation entries in this annotation
1919 public class ArrayElementValue extends ElementValue
2020 {
2121 // For array types, this is the array
22 private ElementValue[] evalues;
22 private final ElementValue[] evalues;
2323
24 public ArrayElementValue(int type, ElementValue[] datums, ConstantPool cpool)
24 ArrayElementValue(int type, ElementValue[] datums, ConstantPool cpool)
2525 {
2626 super(type, cpool);
2727 if (type != ARRAY) {
+0
-198
java/org/apache/tomcat/util/bcel/classfile/Attribute.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21 import java.io.Serializable;
22
23 import org.apache.tomcat.util.bcel.Constants;
24
25 /**
26 * Abstract super class for <em>Attribute</em> objects. Currently the
27 * <em>ConstantValue</em>, <em>SourceFile</em>, <em>Code</em>,
28 * <em>ExceptionTable</em>, <em>LineNumberTable</em>,
29 * <em>LocalVariableTable</em>, <em>InnerClasses</em> and
30 * <em>Synthetic</em> attributes are supported. The <em>Unknown</em>
31 * attribute stands for non-standard-attributes.
32 *
33 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
34 * @see ConstantValue
35 * @see SourceFile
36 * @see Code
37 * @see ExceptionTable
38 * @see LineNumberTable
39 * @see LocalVariableTable
40 * @see InnerClasses
41 * @see Deprecated
42 */
43 public abstract class Attribute implements Cloneable, Serializable
44 {
45 private static final long serialVersionUID = 1514136303496688899L;
46
47 protected int name_index; // Points to attribute name in constant pool
48
49 protected int length; // Content length of attribute field
50
51 protected ConstantPool constant_pool;
52
53 protected Attribute(int name_index, int length,
54 ConstantPool constant_pool)
55 {
56 this.name_index = name_index;
57 this.length = length;
58 this.constant_pool = constant_pool;
59 }
60
61 /*
62 * Class method reads one attribute from the input data stream. This method
63 * must not be accessible from the outside. It is called by the Field and
64 * Method constructor methods.
65 *
66 * @see Field
67 * @see Method @param file Input stream @param constant_pool Array of
68 * constants @return Attribute @throws IOException @throws
69 * ClassFormatException
70 */
71 public static final Attribute readAttribute(DataInputStream file,
72 ConstantPool constant_pool) throws IOException,
73 ClassFormatException
74 {
75 ConstantUtf8 c;
76 String name;
77 int name_index;
78 int length;
79 byte tag = Constants.ATTR_UNKNOWN; // Unknown attribute
80 // Get class name from constant pool via `name_index' indirection
81 name_index = file.readUnsignedShort();
82 c = (ConstantUtf8) constant_pool.getConstant(name_index,
83 Constants.CONSTANT_Utf8);
84 name = c.getBytes();
85 // Length of data in bytes
86 length = file.readInt();
87 // Compare strings to find known attribute
88 // System.out.println(name);
89 for (byte i = 0; i < Constants.KNOWN_ATTRIBUTES; i++)
90 {
91 if (name.equals(Constants.ATTRIBUTE_NAMES[i]))
92 {
93 tag = i; // found!
94 break;
95 }
96 }
97 // Call proper constructor, depending on `tag'
98 switch (tag)
99 {
100 case Constants.ATTR_UNKNOWN:
101 Utility.swallowUnknownAttribute(file, length);
102 return null;
103 case Constants.ATTR_CONSTANT_VALUE:
104 return new ConstantValue(name_index, length, file, constant_pool);
105 case Constants.ATTR_SOURCE_FILE:
106 return new SourceFile(name_index, length, file, constant_pool);
107 case Constants.ATTR_CODE:
108 return new Code(name_index, length, file, constant_pool);
109 case Constants.ATTR_EXCEPTIONS:
110 return new ExceptionTable(name_index, length, file, constant_pool);
111 case Constants.ATTR_LINE_NUMBER_TABLE:
112 return new LineNumberTable(name_index, length, file, constant_pool);
113 case Constants.ATTR_LOCAL_VARIABLE_TABLE:
114 return new LocalVariableTable(name_index, length, file,
115 constant_pool);
116 case Constants.ATTR_INNER_CLASSES:
117 return new InnerClasses(name_index, length, file, constant_pool);
118 case Constants.ATTR_SYNTHETIC:
119 Utility.swallowSynthetic(file, length);
120 return null;
121 case Constants.ATTR_DEPRECATED:
122 return new Deprecated(name_index, length, file, constant_pool);
123 case Constants.ATTR_PMG:
124 return new PMGClass(name_index, length, file, constant_pool);
125 case Constants.ATTR_SIGNATURE:
126 Utility.swallowSignature(file);
127 return null;
128 case Constants.ATTR_STACK_MAP:
129 Utility.swallowStackMap(file);
130 return null;
131 case Constants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
132 return new RuntimeVisibleAnnotations(name_index, length, file,
133 constant_pool);
134 case Constants.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
135 return new RuntimeInvisibleAnnotations(name_index, length, file,
136 constant_pool);
137 case Constants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
138 return new RuntimeVisibleParameterAnnotations(name_index, length,
139 file, constant_pool);
140 case Constants.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
141 return new RuntimeInvisibleParameterAnnotations(name_index, length,
142 file, constant_pool);
143 case Constants.ATTR_ANNOTATION_DEFAULT:
144 return new AnnotationDefault(name_index, length, file,
145 constant_pool);
146 case Constants.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
147 return new LocalVariableTypeTable(name_index, length, file,
148 constant_pool);
149 case Constants.ATTR_ENCLOSING_METHOD:
150 return new EnclosingMethod(name_index, length, file, constant_pool);
151 case Constants.ATTR_STACK_MAP_TABLE:
152 Utility.swallowStackMapTable(file);
153 return null;
154 case Constants.ATTR_BOOTSTRAP_METHODS:
155 Utility.swallowBootstrapMethods(file);
156 return null;
157 case Constants.ATTR_METHOD_PARAMETERS:
158 Utility.swallowMethodParameters(file);
159 return null;
160 default: // Never reached
161 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
162 }
163 }
164
165 /**
166 * @return Name of attribute
167 */
168 public String getName()
169 {
170 ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index,
171 Constants.CONSTANT_Utf8);
172 return c.getBytes();
173 }
174
175
176 /**
177 * Use copy() if you want to have a deep copy(), i.e., with all references
178 * copied correctly.
179 *
180 * @return shallow copy of this attribute
181 */
182 @Override
183 public Attribute clone()
184 {
185 Attribute attr = null;
186 try
187 {
188 attr = (Attribute) super.clone();
189 }
190 catch (CloneNotSupportedException e)
191 {
192 throw new Error("Clone Not Supported"); // never happens
193 }
194 return attr;
195 }
196
197 }
2323 // For primitive types and string type, this points to the value entry in
2424 // the cpool
2525 // For 'class' this points to the class entry in the cpool
26 private int idx;
26 private final int idx;
2727
28 public ClassElementValue(int type, int idx, ConstantPool cpool)
29 {
28 ClassElementValue(int type, int idx, ConstantPool cpool) {
3029 super(type, cpool);
3130 this.idx = idx;
3231 }
1616 */
1717 package org.apache.tomcat.util.bcel.classfile;
1818
19 import java.io.BufferedInputStream;
20 import java.io.DataInputStream;
19 import java.io.DataInput;
2120 import java.io.IOException;
2221 import java.io.InputStream;
2322
4140
4241 private static final int MAGIC = 0xCAFEBABE;
4342
44 private DataInputStream file;
45 private String file_name;
46 private int class_name_index, superclass_name_index;
43 private final DataInput file;
44 private String class_name, superclass_name;
4745 private int access_flags; // Access rights of parsed class
48 private int[] interfaces; // Names of implemented interfaces
46 private String[] interface_names; // Names of implemented interfaces
4947 private ConstantPool constant_pool; // collection of constants
50 private FieldOrMethod[] fields; // class fields, i.e., its variables
51 private FieldOrMethod[] methods; // methods defined in the class
52 private Attribute[] attributes; // attributes defined in the class
48 private Annotations runtimeVisibleAnnotations; // "RuntimeVisibleAnnotations" attribute defined in the class
5349 private static final int BUFSIZE = 8192;
5450
51 private static final String[] INTERFACES_EMPTY_ARRAY = new String[0];
5552
5653 /**
5754 * Parse class from the given stream.
5855 *
5956 * @param file Input stream
60 * @param file_name File name
61 */
62 public ClassParser(InputStream file, String file_name) {
63 this.file_name = file_name;
64 if (file instanceof DataInputStream) {
65 this.file = (DataInputStream) file;
66 } else {
67 this.file = new DataInputStream(new BufferedInputStream(file, BUFSIZE));
68 }
57 */
58 public ClassParser(InputStream file) {
59 this.file = new FastDataInputStream(file, BUFSIZE);
6960 }
7061
7162
10091 readMethods();
10192 // Read class attributes
10293 readAttributes();
103 // Check for unknown variables
104 //Unknown[] u = Unknown.getUnknownAttributes();
105 //for(int i=0; i < u.length; i++)
106 // System.err.println("WARNING: " + u[i]);
107 // Everything should have been read now
108 // if(file.available() > 0) {
109 // int bytes = file.available();
110 // byte[] buf = new byte[bytes];
111 // file.read(buf);
112 // if(!(is_zip && (buf.length == 1))) {
113 // System.err.println("WARNING: Trailing garbage at end of " + file_name);
114 // System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf));
115 // }
116 // }
11794
11895 // Return the information we have gathered in a new object
119 return new JavaClass(class_name_index, superclass_name_index,
120 access_flags, constant_pool, interfaces, attributes);
96 return new JavaClass(class_name, superclass_name,
97 access_flags, constant_pool, interface_names,
98 runtimeVisibleAnnotations);
12199 }
122100
123101
129107 private void readAttributes() throws IOException, ClassFormatException {
130108 int attributes_count;
131109 attributes_count = file.readUnsignedShort();
132 attributes = new Attribute[attributes_count];
133110 for (int i = 0; i < attributes_count; i++) {
134 attributes[i] = Attribute.readAttribute(file, constant_pool);
111 ConstantUtf8 c;
112 String name;
113 int name_index;
114 int length;
115 // Get class name from constant pool via `name_index' indirection
116 name_index = file.readUnsignedShort();
117 c = (ConstantUtf8) constant_pool.getConstant(name_index,
118 Constants.CONSTANT_Utf8);
119 name = c.getBytes();
120 // Length of data in bytes
121 length = file.readInt();
122
123 if (name.equals("RuntimeVisibleAnnotations")) {
124 if (runtimeVisibleAnnotations != null) {
125 throw new ClassFormatException(
126 "RuntimeVisibleAnnotations attribute is not allowed more than once in a class file");
127 }
128 runtimeVisibleAnnotations = new Annotations(file, constant_pool);
129 } else {
130 // All other attributes are skipped
131 Utility.skipFully(file, length);
132 }
135133 }
136134 }
137135
151149 }
152150 if (((access_flags & Constants.ACC_ABSTRACT) != 0)
153151 && ((access_flags & Constants.ACC_FINAL) != 0)) {
154 throw new ClassFormatException("Class " + file_name + " can't be both final and abstract");
155 }
156 class_name_index = file.readUnsignedShort();
157 superclass_name_index = file.readUnsignedShort();
152 throw new ClassFormatException("Class can't be both final and abstract");
153 }
154
155 int class_name_index = file.readUnsignedShort();
156 class_name = Utility.getClassName(constant_pool, class_name_index);
157
158 int superclass_name_index = file.readUnsignedShort();
159 if (superclass_name_index > 0) {
160 // May be zero -> class is java.lang.Object
161 superclass_name = Utility.getClassName(constant_pool, superclass_name_index);
162 } else {
163 superclass_name = "java.lang.Object";
164 }
158165 }
159166
160167
174181 * @throws ClassFormatException
175182 */
176183 private void readFields() throws IOException, ClassFormatException {
177 int fields_count;
178 fields_count = file.readUnsignedShort();
179 fields = new FieldOrMethod[fields_count];
184 int fields_count = file.readUnsignedShort();
180185 for (int i = 0; i < fields_count; i++) {
181 fields[i] = new FieldOrMethod(file, constant_pool);
186 Utility.swallowFieldOrMethod(file);
182187 }
183188 }
184189
192197 */
193198 private void readID() throws IOException, ClassFormatException {
194199 if (file.readInt() != MAGIC) {
195 throw new ClassFormatException(file_name + " is not a Java .class file");
200 throw new ClassFormatException("It is not a Java .class file");
196201 }
197202 }
198203
205210 private void readInterfaces() throws IOException, ClassFormatException {
206211 int interfaces_count;
207212 interfaces_count = file.readUnsignedShort();
208 interfaces = new int[interfaces_count];
209 for (int i = 0; i < interfaces_count; i++) {
210 interfaces[i] = file.readUnsignedShort();
213 if (interfaces_count > 0) {
214 interface_names = new String[interfaces_count];
215 for (int i = 0; i < interfaces_count; i++) {
216 int index = file.readUnsignedShort();
217 interface_names[i] = Utility.getClassName(constant_pool, index);
218 }
219 } else {
220 interface_names = INTERFACES_EMPTY_ARRAY;
211221 }
212222 }
213223
220230 private void readMethods() throws IOException, ClassFormatException {
221231 int methods_count;
222232 methods_count = file.readUnsignedShort();
223 methods = new FieldOrMethod[methods_count];
224233 for (int i = 0; i < methods_count; i++) {
225 methods[i] = new FieldOrMethod(file, constant_pool);
234 Utility.swallowFieldOrMethod(file);
226235 }
227236 }
228237
233242 * @throws ClassFormatException
234243 */
235244 private void readVersion() throws IOException, ClassFormatException {
236 file.readUnsignedShort(); // Unused minor
237 file.readUnsignedShort(); // Unused major
245 // file.readUnsignedShort(); // Unused minor
246 // file.readUnsignedShort(); // Unused major
247 Utility.skipFully(file, 4);
238248 }
239249 }
+0
-148
java/org/apache/tomcat/util/bcel/classfile/Code.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * This class represents a chunk of Java byte code contained in a
24 * method. It is instantiated by the
25 * <em>Attribute.readAttribute()</em> method. A <em>Code</em>
26 * attribute contains informations about operand stack, local
27 * variables, byte code and the exceptions handled within this
28 * method.
29 *
30 * This attribute has attributes itself, namely <em>LineNumberTable</em> which
31 * is used for debugging purposes and <em>LocalVariableTable</em> which
32 * contains information about the local variables.
33 *
34 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
35 * @see Attribute
36 * @see LineNumberTable
37 * @see LocalVariableTable
38 */
39 public final class Code extends Attribute {
40
41 private static final long serialVersionUID = 8936843273318969602L;
42 private int code_length; // Length of code in bytes
43 private byte[] code; // Actual byte code
44 private int exception_table_length;
45 private int attributes_count; // Attributes of code: LineNumber
46 private Attribute[] attributes; // or LocalVariable
47
48
49 /**
50 * @param name_index Index pointing to the name <em>Code</em>
51 * @param length Content length in bytes
52 * @param file Input stream
53 * @param constant_pool Array of constants
54 */
55 Code(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
56 throws IOException {
57 // Initialize with some default values which will be overwritten later
58 this(name_index, length, (byte[]) null, (Attribute[]) null,
59 constant_pool);
60 file.readUnsignedShort(); // Unused max_stack
61 file.readUnsignedShort(); // Unused max_locals
62 code_length = file.readInt();
63 code = new byte[code_length]; // Read byte code
64 file.readFully(code);
65 /* Read exception table that contains all regions where an exception
66 * handler is active, i.e., a try { ... } catch() block.
67 */
68 exception_table_length = file.readUnsignedShort();
69 for (int i = 0; i < exception_table_length; i++) {
70 Utility.swallowCodeException(file);
71 }
72 /* Read all attributes, currently `LineNumberTable' and
73 * `LocalVariableTable'
74 */
75 attributes_count = file.readUnsignedShort();
76 attributes = new Attribute[attributes_count];
77 for (int i = 0; i < attributes_count; i++) {
78 attributes[i] = Attribute.readAttribute(file, constant_pool);
79 }
80 /* Adjust length, because of setAttributes in this(), s.b. length
81 * is incorrect, because it didn't take the internal attributes
82 * into account yet! Very subtle bug, fixed in 3.1.1.
83 */
84 this.length = length;
85 }
86
87
88 /**
89 * @param name_index Index pointing to the name <em>Code</em>
90 * @param length Content length in bytes
91 * @param code Actual byte code
92 * @param attributes Attributes of code: LineNumber or LocalVariable
93 * @param constant_pool Array of constants
94 */
95 public Code(int name_index, int length, byte[] code,
96 Attribute[] attributes, ConstantPool constant_pool) {
97 super(name_index, length, constant_pool);
98 setCode(code);
99 setAttributes(attributes); // Overwrites length!
100 }
101
102
103 /**
104 * @return the internal length of this code attribute (minus the first 6 bytes)
105 * and excluding all its attributes
106 */
107 private int getInternalLength() {
108 return 2 /*max_stack*/+ 2 /*max_locals*/+ 4 /*code length*/
109 + code_length /*byte-code*/
110 + 2 /*exception-table length*/
111 + 8 * exception_table_length /* exception table */
112 + 2 /* attributes count */;
113 }
114
115
116 /**
117 * @return the full size of this code attribute, minus its first 6 bytes,
118 * including the size of all its contained attributes
119 */
120 private int calculateLength() {
121 int len = 0;
122 for (int i = 0; i < attributes_count; i++) {
123 len += attributes[i].length + 6 /*attribute header size*/;
124 }
125 return len + getInternalLength();
126 }
127
128
129 /**
130 * @param attributes the attributes to set for this Code
131 */
132 public final void setAttributes( Attribute[] attributes ) {
133 this.attributes = attributes;
134 attributes_count = (attributes == null) ? 0 : attributes.length;
135 length = calculateLength(); // Adjust length
136 }
137
138
139 /**
140 * @param code byte code
141 */
142 public final void setCode( byte[] code ) {
143 this.code = code;
144 code_length = (code == null) ? 0 : code.length;
145 length = calculateLength(); // Adjust length
146 }
147 }
1616 */
1717 package org.apache.tomcat.util.bcel.classfile;
1818
19 import java.io.DataInputStream;
19 import java.io.DataInput;
2020 import java.io.IOException;
21 import java.io.Serializable;
2221
2322 import org.apache.tomcat.util.bcel.Constants;
24 import org.apache.tomcat.util.bcel.util.BCELComparator;
2523
2624 /**
2725 * Abstract superclass for classes to represent the different constant types
3028 *
3129 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
3230 */
33 public abstract class Constant implements Cloneable, Serializable {
31 public abstract class Constant {
3432
35 private static final long serialVersionUID = 2827409182154809454L;
36 private static BCELComparator _cmp = new BCELComparator() {
37
38 @Override
39 public boolean equals( Object o1, Object o2 ) {
40 Constant THIS = (Constant) o1;
41 Constant THAT = (Constant) o2;
42 return THIS.toString().equals(THAT.toString());
43 }
44
45
46 @Override
47 public int hashCode( Object o ) {
48 Constant THIS = (Constant) o;
49 return THIS.toString().hashCode();
50 }
51 };
5233 /* In fact this tag is redundant since we can distinguish different
5334 * `Constant' objects by their type, i.e., via `instanceof'. In some
5435 * places we will use the tag for switch()es anyway.
5738 * need the tag as an index to select the corresponding class name from the
5839 * `CONSTANT_NAMES' array.
5940 */
60 protected byte tag;
41 protected final byte tag;
6142
6243
6344 Constant(byte tag) {
7455 }
7556
7657
77 @Override
78 public Object clone() {
79 try {
80 return super.clone();
81 } catch (CloneNotSupportedException e) {
82 throw new Error("Clone Not Supported"); // never happens
83 }
84 }
85
86
8758 /**
8859 * Read one constant from the given file, the type depends on a tag byte.
8960 *
9061 * @param file Input stream
9162 * @return Constant object
9263 */
93 static Constant readConstant( DataInputStream file ) throws IOException,
64 static Constant readConstant(DataInput file ) throws IOException,
9465 ClassFormatException {
9566 byte b = file.readByte(); // Read tag byte
67 int skipSize;
9668 switch (b) {
9769 case Constants.CONSTANT_Class:
9870 return new ConstantClass(file);
99 case Constants.CONSTANT_Fieldref:
100 return new ConstantFieldref(file);
101 case Constants.CONSTANT_Methodref:
102 return new ConstantMethodref(file);
103 case Constants.CONSTANT_InterfaceMethodref:
104 return new ConstantInterfaceMethodref(file);
105 case Constants.CONSTANT_String:
106 return new ConstantString(file);
10771 case Constants.CONSTANT_Integer:
10872 return new ConstantInteger(file);
10973 case Constants.CONSTANT_Float:
11276 return new ConstantLong(file);
11377 case Constants.CONSTANT_Double:
11478 return new ConstantDouble(file);
115 case Constants.CONSTANT_NameAndType:
116 return new ConstantNameAndType(file);
11779 case Constants.CONSTANT_Utf8:
11880 return ConstantUtf8.getInstance(file);
81 case Constants.CONSTANT_String:
82 case Constants.CONSTANT_MethodType:
83 skipSize = 2; // unsigned short
84 break;
11985 case Constants.CONSTANT_MethodHandle:
120 return new ConstantMethodHandle(file);
121 case Constants.CONSTANT_MethodType:
122 return new ConstantMethodType(file);
86 skipSize = 3; // unsigned byte, unsigned short
87 break;
88 case Constants.CONSTANT_Fieldref:
89 case Constants.CONSTANT_Methodref:
90 case Constants.CONSTANT_InterfaceMethodref:
91 case Constants.CONSTANT_NameAndType:
12392 case Constants.CONSTANT_InvokeDynamic:
124 return new ConstantInvokeDynamic(file);
93 skipSize = 4; // unsigned short, unsigned short
94 break;
12595 default:
12696 throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
12797 }
98 Utility.skipFully(file, skipSize);
99 return null;
128100 }
129101
130102
133105 public String toString() {
134106 return "[" + tag + "]";
135107 }
136
137
138 /**
139 * Return value as defined by given BCELComparator strategy.
140 * By default two Constant objects are said to be equal when
141 * the result of toString() is equal.
142 *
143 * @see java.lang.Object#equals(java.lang.Object)
144 */
145 @Override
146 public boolean equals( Object obj ) {
147 return _cmp.equals(this, obj);
148 }
149
150
151 /**
152 * Return value as defined by given BCELComparator strategy.
153 * By default return the hashcode of the result of toString().
154 *
155 * @see java.lang.Object#hashCode()
156 */
157 @Override
158 public int hashCode() {
159 return _cmp.hashCode(this);
160 }
161108 }
+0
-76
java/org/apache/tomcat/util/bcel/classfile/ConstantCP.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInput;
20 import java.io.IOException;
21
22 /**
23 * Abstract super class for Fieldref and Methodref constants.
24 *
25 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
26 * @see ConstantFieldref
27 * @see ConstantMethodref
28 * @see ConstantInterfaceMethodref
29 */
30 public abstract class ConstantCP extends Constant {
31
32 private static final long serialVersionUID = 7282382456501145526L;
33 /** References to the constants containing the class and the field signature
34 */
35 protected int class_index, name_and_type_index;
36
37
38 /**
39 * Initialize instance from file data.
40 *
41 * @param tag Constant type tag
42 * @param file Input stream
43 * @throws IOException
44 */
45 ConstantCP(byte tag, DataInput file) throws IOException {
46 this(tag, file.readUnsignedShort(), file.readUnsignedShort());
47 }
48
49
50 /**
51 * @param class_index Reference to the class containing the field
52 * @param name_and_type_index and the field signature
53 */
54 protected ConstantCP(byte tag, int class_index, int name_and_type_index) {
55 super(tag);
56 this.class_index = class_index;
57 this.name_and_type_index = name_and_type_index;
58 }
59
60
61 /**
62 * @return Reference (index) to class this field or method belongs to.
63 */
64 public final int getClassIndex() {
65 return class_index;
66 }
67
68
69 /**
70 * @return Reference (index) to signature of the field.
71 */
72 public final int getNameAndTypeIndex() {
73 return name_and_type_index;
74 }
75 }
3131 */
3232 public final class ConstantClass extends Constant {
3333
34 private static final long serialVersionUID = -6603658849582876642L;
35 private int name_index; // Identical to ConstantString except for the name
34 private final int name_index; // Identical to ConstantString except for the name
3635
3736
3837 /**
4241 * @throws IOException
4342 */
4443 ConstantClass(DataInput file) throws IOException {
45 this(file.readUnsignedShort());
46 }
47
48
49 /**
50 * @param name_index Name index in constant pool. Should refer to a
51 * ConstantUtf8.
52 */
53 public ConstantClass(int name_index) {
5444 super(Constants.CONSTANT_Class);
55 this.name_index = name_index;
45 this.name_index = file.readUnsignedShort();
5646 }
5747
5848
3131 */
3232 public final class ConstantDouble extends Constant {
3333
34 private static final long serialVersionUID = 3450743772468544760L;
35 private double bytes;
36
37
38 /**
39 * @param bytes Data
40 */
41 public ConstantDouble(double bytes) {
42 super(Constants.CONSTANT_Double);
43 this.bytes = bytes;
44 }
34 private final double bytes;
4535
4636
4737 /**
5141 * @throws IOException
5242 */
5343 ConstantDouble(DataInput file) throws IOException {
54 this(file.readDouble());
44 super(Constants.CONSTANT_Double);
45 this.bytes = file.readDouble();
5546 }
5647
5748
+0
-44
java/org/apache/tomcat/util/bcel/classfile/ConstantFieldref.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23
24 /**
25 * This class represents a constant pool reference to a field.
26 *
27 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
28 */
29 public final class ConstantFieldref extends ConstantCP {
30
31
32 private static final long serialVersionUID = -8062332095934294437L;
33
34 /**
35 * Initialize instance from file data.
36 *
37 * @param file input stream
38 * @throws IOException
39 */
40 ConstantFieldref(DataInputStream file) throws IOException {
41 super(Constants.CONSTANT_Fieldref, file);
42 }
43 }
3131 */
3232 public final class ConstantFloat extends Constant {
3333
34 private static final long serialVersionUID = 8301269629885378651L;
35 private float bytes;
36
37
38 /**
39 * @param bytes Data
40 */
41 public ConstantFloat(float bytes) {
42 super(Constants.CONSTANT_Float);
43 this.bytes = bytes;
44 }
34 private final float bytes;
4535
4636
4737 /**
5141 * @throws IOException
5242 */
5343 ConstantFloat(DataInput file) throws IOException {
54 this(file.readFloat());
44 super(Constants.CONSTANT_Float);
45 this.bytes = file.readFloat();
5546 }
5647
5748
3131 */
3232 public final class ConstantInteger extends Constant {
3333
34 private static final long serialVersionUID = -6415476571232528966L;
35 private int bytes;
36
37
38 /**
39 * @param bytes Data
40 */
41 public ConstantInteger(int bytes) {
42 super(Constants.CONSTANT_Integer);
43 this.bytes = bytes;
44 }
34 private final int bytes;
4535
4636
4737 /**
5141 * @throws IOException
5242 */
5343 ConstantInteger(DataInput file) throws IOException {
54 this(file.readInt());
44 super(Constants.CONSTANT_Integer);
45 this.bytes = file.readInt();
5546 }
5647
5748
+0
-44
java/org/apache/tomcat/util/bcel/classfile/ConstantInterfaceMethodref.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23
24 /**
25 * This class represents a constant pool reference to an interface method.
26 *
27 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
28 */
29 public final class ConstantInterfaceMethodref extends ConstantCP {
30
31
32 private static final long serialVersionUID = -8587605570227841891L;
33
34 /**
35 * Initialize instance from file data.
36 *
37 * @param file input stream
38 * @throws IOException
39 */
40 ConstantInterfaceMethodref(DataInputStream file) throws IOException {
41 super(Constants.CONSTANT_InterfaceMethodref, file);
42 }
43 }
+0
-48
java/org/apache/tomcat/util/bcel/classfile/ConstantInvokeDynamic.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInput;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23
24 /**
25 * This class is derived from the abstract
26 * <A HREF="org.apache.bcel.classfile.Constant.html">Constant</A> class
27 * and represents a reference to a invoke dynamic.
28 *
29 * @see Constant
30 */
31 public final class ConstantInvokeDynamic extends Constant {
32
33 private static final long serialVersionUID = 4310367359017396174L;
34
35
36 /**
37 * Initialize instance from file data.
38 *
39 * @param file Input stream
40 * @throws IOException
41 */
42 ConstantInvokeDynamic(DataInput file) throws IOException {
43 super(Constants.CONSTANT_InvokeDynamic);
44 file.readUnsignedShort(); // Unused bootstrap_method_attr_index
45 file.readUnsignedShort(); // Unused name_and_type_index
46 }
47 }
3131 */
3232 public final class ConstantLong extends Constant {
3333
34 private static final long serialVersionUID = -1893131676489003562L;
35 private long bytes;
36
37
38 /**
39 * @param bytes Data
40 */
41 public ConstantLong(long bytes) {
42 super(Constants.CONSTANT_Long);
43 this.bytes = bytes;
44 }
34 private final long bytes;
4535
4636
4737 /**
5141 * @throws IOException
5242 */
5343 ConstantLong(DataInput file) throws IOException {
54 this(file.readLong());
44 super(Constants.CONSTANT_Long);
45 this.bytes = file.readLong();
5546 }
5647
5748
+0
-48
java/org/apache/tomcat/util/bcel/classfile/ConstantMethodHandle.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInput;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23
24 /**
25 * This class is derived from the abstract
26 * <A HREF="org.apache.bcel.classfile.Constant.html">Constant</A> class
27 * and represents a reference to a method handle.
28 *
29 * @see Constant
30 */
31 public final class ConstantMethodHandle extends Constant {
32
33 private static final long serialVersionUID = -7875124116920198044L;
34
35
36 /**
37 * Initialize instance from file data.
38 *
39 * @param file Input stream
40 * @throws IOException
41 */
42 ConstantMethodHandle(DataInput file) throws IOException {
43 super(Constants.CONSTANT_MethodHandle);
44 file.readUnsignedByte(); // Unused reference_kind
45 file.readUnsignedShort(); // Unused reference_index
46 }
47 }
+0
-47
java/org/apache/tomcat/util/bcel/classfile/ConstantMethodType.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInput;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23
24 /**
25 * This class is derived from the abstract
26 * <A HREF="org.apache.bcel.classfile.Constant.html">Constant</A> class
27 * and represents a reference to a method type.
28 *
29 * @see Constant
30 */
31 public final class ConstantMethodType extends Constant {
32
33 private static final long serialVersionUID = 6750768220616618881L;
34
35
36 /**
37 * Initialize instance from file data.
38 *
39 * @param file Input stream
40 * @throws IOException
41 */
42 ConstantMethodType(DataInput file) throws IOException {
43 super(Constants.CONSTANT_MethodType);
44 file.readUnsignedShort(); // Unused descriptor_index
45 }
46 }
+0
-44
java/org/apache/tomcat/util/bcel/classfile/ConstantMethodref.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23
24 /**
25 * This class represents a constant pool reference to a method.
26 *
27 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
28 */
29 public final class ConstantMethodref extends ConstantCP {
30
31
32 private static final long serialVersionUID = -7857009620954576086L;
33
34 /**
35 * Initialize instance from file data.
36 *
37 * @param file input stream
38 * @throws IOException
39 */
40 ConstantMethodref(DataInputStream file) throws IOException {
41 super(Constants.CONSTANT_Methodref, file);
42 }
43 }
+0
-77
java/org/apache/tomcat/util/bcel/classfile/ConstantNameAndType.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInput;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23
24 /**
25 * This class is derived from the abstract
26 * <A HREF="org.apache.tomcat.util.bcel.classfile.Constant.html">Constant</A> class
27 * and represents a reference to the name and signature
28 * of a field or method.
29 *
30 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
31 * @see Constant
32 */
33 public final class ConstantNameAndType extends Constant {
34
35 private static final long serialVersionUID = 1010506730811368756L;
36 private int name_index; // Name of field/method
37 private int signature_index; // and its signature.
38
39
40 /**
41 * Initialize instance from file data.
42 *
43 * @param file Input stream
44 * @throws IOException
45 */
46 ConstantNameAndType(DataInput file) throws IOException {
47 this(file.readUnsignedShort(), file.readUnsignedShort());
48 }
49
50
51 /**
52 * @param name_index Name of field/method
53 * @param signature_index and its signature
54 */
55 public ConstantNameAndType(int name_index, int signature_index) {
56 super(Constants.CONSTANT_NameAndType);
57 this.name_index = name_index;
58 this.signature_index = signature_index;
59 }
60
61
62 /**
63 * @return Name index in constant pool of field/method name.
64 */
65 public final int getNameIndex() {
66 return name_index;
67 }
68
69
70 /**
71 * @return Index in constant pool of field/method signature.
72 */
73 public final int getSignatureIndex() {
74 return signature_index;
75 }
76 }
1616 */
1717 package org.apache.tomcat.util.bcel.classfile;
1818
19 import java.io.DataInputStream;
19 import java.io.DataInput;
2020 import java.io.IOException;
21 import java.io.Serializable;
2221
2322 import org.apache.tomcat.util.bcel.Constants;
2423
3332 * @see Constant
3433 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
3534 */
36 public class ConstantPool implements Cloneable, Serializable {
35 public class ConstantPool {
3736
38 private static final long serialVersionUID = -6765503791185687014L;
39 private int constant_pool_count;
40 private Constant[] constant_pool;
37 private final Constant[] constant_pool;
4138
4239
4340 /**
4744 * @throws IOException
4845 * @throws ClassFormatException
4946 */
50 ConstantPool(DataInputStream file) throws IOException, ClassFormatException {
51 byte tag;
52 constant_pool_count = file.readUnsignedShort();
47 ConstantPool(DataInput file) throws IOException, ClassFormatException {
48 int constant_pool_count = file.readUnsignedShort();
5349 constant_pool = new Constant[constant_pool_count];
5450 /* constant_pool[0] is unused by the compiler and may be used freely
5551 * by the implementation.
6359 *
6460 * Thus we have to increment the index counter.
6561 */
66 tag = constant_pool[i].getTag();
67 if ((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long)) {
68 i++;
62 if (constant_pool[i] != null) {
63 byte tag = constant_pool[i].getTag();
64 if ((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long)) {
65 i++;
66 }
6967 }
7068 }
71 }
72
73
74 /**
75 * Resolve constant to a string representation.
76 *
77 * @param c Constant to be printed
78 * @return String representation
79 */
80 public String constantToString( Constant c ) throws ClassFormatException {
81 String str;
82 int i;
83 byte tag = c.getTag();
84 switch (tag) {
85 case Constants.CONSTANT_Class:
86 i = ((ConstantClass) c).getNameIndex();
87 c = getConstant(i, Constants.CONSTANT_Utf8);
88 str = Utility.compactClassName(((ConstantUtf8) c).getBytes());
89 break;
90 case Constants.CONSTANT_String:
91 i = ((ConstantString) c).getStringIndex();
92 c = getConstant(i, Constants.CONSTANT_Utf8);
93 str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
94 break;
95 case Constants.CONSTANT_Utf8:
96 str = ((ConstantUtf8) c).getBytes();
97 break;
98 case Constants.CONSTANT_Double:
99 str = String.valueOf(((ConstantDouble) c).getBytes());
100 break;
101 case Constants.CONSTANT_Float:
102 str = String.valueOf(((ConstantFloat) c).getBytes());
103 break;
104 case Constants.CONSTANT_Long:
105 str = String.valueOf(((ConstantLong) c).getBytes());
106 break;
107 case Constants.CONSTANT_Integer:
108 str = String.valueOf(((ConstantInteger) c).getBytes());
109 break;
110 case Constants.CONSTANT_NameAndType:
111 str = (constantToString(((ConstantNameAndType) c).getNameIndex(),
112 Constants.CONSTANT_Utf8)
113 + " " + constantToString(((ConstantNameAndType) c).getSignatureIndex(),
114 Constants.CONSTANT_Utf8));
115 break;
116 case Constants.CONSTANT_InterfaceMethodref:
117 case Constants.CONSTANT_Methodref:
118 case Constants.CONSTANT_Fieldref:
119 str = (constantToString(((ConstantCP) c).getClassIndex(), Constants.CONSTANT_Class)
120 + "." + constantToString(((ConstantCP) c).getNameAndTypeIndex(),
121 Constants.CONSTANT_NameAndType));
122 break;
123 default: // Never reached
124 throw new RuntimeException("Unknown constant type " + tag);
125 }
126 return str;
127 }
128
129
130 private static String escape( String str ) {
131 int len = str.length();
132 StringBuilder buf = new StringBuilder(len + 5);
133 char[] ch = str.toCharArray();
134 for (int i = 0; i < len; i++) {
135 switch (ch[i]) {
136 case '\n':
137 buf.append("\\n");
138 break;
139 case '\r':
140 buf.append("\\r");
141 break;
142 case '\t':
143 buf.append("\\t");
144 break;
145 case '\b':
146 buf.append("\\b");
147 break;
148 case '"':
149 buf.append("\\\"");
150 break;
151 default:
152 buf.append(ch[i]);
153 }
154 }
155 return buf.toString();
156 }
157
158
159 /**
160 * Retrieve constant at `index' from constant pool and resolve it to
161 * a string representation.
162 *
163 * @param index of constant in constant pool
164 * @param tag expected type
165 * @return String representation
166 */
167 public String constantToString( int index, byte tag ) throws ClassFormatException {
168 Constant c = getConstant(index, tag);
169 return constantToString(c);
17069 }
17170
17271
208107 }
209108 return c;
210109 }
211
212
213 /**
214 * Get string from constant pool and bypass the indirection of
215 * `ConstantClass' and `ConstantString' objects. I.e. these classes have
216 * an index field that points to another entry of the constant pool of
217 * type `ConstantUtf8' which contains the real data.
218 *
219 * @param index Index in constant pool
220 * @param tag Tag of expected constant, either ConstantClass or ConstantString
221 * @return Contents of string reference
222 * @see ConstantClass
223 * @see ConstantString
224 * @throws ClassFormatException
225 */
226 public String getConstantString( int index, byte tag ) throws ClassFormatException {
227 Constant c;
228 int i;
229 c = getConstant(index, tag);
230 /* This switch() is not that elegant, since the two classes have the
231 * same contents, they just differ in the name of the index
232 * field variable.
233 * But we want to stick to the JVM naming conventions closely though
234 * we could have solved these more elegantly by using the same
235 * variable name or by subclassing.
236 */
237 switch (tag) {
238 case Constants.CONSTANT_Class:
239 i = ((ConstantClass) c).getNameIndex();
240 break;
241 case Constants.CONSTANT_String:
242 i = ((ConstantString) c).getStringIndex();
243 break;
244 default:
245 throw new RuntimeException("getConstantString called with illegal tag " + tag);
246 }
247 // Finally get the string from the constant pool
248 c = getConstant(i, Constants.CONSTANT_Utf8);
249 return ((ConstantUtf8) c).getBytes();
250 }
251110 }
+0
-65
java/org/apache/tomcat/util/bcel/classfile/ConstantString.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInput;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23
24 /**
25 * This class is derived from the abstract
26 * <A HREF="org.apache.tomcat.util.bcel.classfile.Constant.html">Constant</A> class
27 * and represents a reference to a String object.
28 *
29 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
30 * @see Constant
31 */
32 public final class ConstantString extends Constant {
33
34 private static final long serialVersionUID = 2809338612858801341L;
35 private int string_index; // Identical to ConstantClass except for this name
36
37
38 /**
39 * Initialize instance from file data.
40 *
41 * @param file Input stream
42 * @throws IOException
43 */
44 ConstantString(DataInput file) throws IOException {
45 this(file.readUnsignedShort());
46 }
47
48
49 /**
50 * @param string_index Index of Constant_Utf8 in constant pool
51 */
52 public ConstantString(int string_index) {
53 super(Constants.CONSTANT_String);
54 this.string_index = string_index;
55 }
56
57
58 /**
59 * @return Index in constant pool of the string (ConstantUtf8).
60 */
61 public final int getStringIndex() {
62 return string_index;
63 }
64 }
1616 package org.apache.tomcat.util.bcel.classfile;
1717
1818 import java.io.DataInput;
19 import java.io.DataInputStream;
2019 import java.io.IOException;
21 import java.util.HashMap;
22 import java.util.LinkedHashMap;
23 import java.util.Map;
2420
2521 import org.apache.tomcat.util.bcel.Constants;
2622
3430 */
3531 public final class ConstantUtf8 extends Constant {
3632
37 private static final long serialVersionUID = 8119001312020421976L;
3833 private final String bytes;
3934
40 private static final int MAX_CACHE_ENTRIES = 20000;
41 private static final int INITIAL_CACHE_CAPACITY = (int)(MAX_CACHE_ENTRIES/0.75);
42 private static HashMap<String, ConstantUtf8> cache;
4335
44 private static synchronized ConstantUtf8 getCachedInstance(String s) {
45 if (s.length() > 200) {
46 return new ConstantUtf8(s);
47 }
48 if (cache == null) {
49 cache = new LinkedHashMap<String, ConstantUtf8>(INITIAL_CACHE_CAPACITY, 0.75f, true) {
50 private static final long serialVersionUID = 1L;
51
52 @Override
53 protected boolean removeEldestEntry(Map.Entry<String, ConstantUtf8> eldest) {
54 return size() > MAX_CACHE_ENTRIES;
55 }
56 };
57 }
58 ConstantUtf8 result = cache.get(s);
59 if (result != null) {
60 return result;
61 }
62 result = new ConstantUtf8(s);
63 cache.put(s, result);
64 return result;
65 }
66
67 private static ConstantUtf8 getInstance(String s) {
68 return getCachedInstance(s);
69 }
70
71 static ConstantUtf8 getInstance(DataInputStream file) throws IOException {
72 return getInstance(file.readUTF());
73 }
74
75 /**
76 * Initialize instance from file data.
77 *
78 * @param file Input stream
79 * @throws IOException
80 */
81 ConstantUtf8(DataInput file) throws IOException {
82 super(Constants.CONSTANT_Utf8);
83 bytes = file.readUTF();
36 static ConstantUtf8 getInstance(DataInput file) throws IOException {
37 return new ConstantUtf8(file.readUTF());
8438 }
8539
8640
+0
-48
java/org/apache/tomcat/util/bcel/classfile/ConstantValue.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.bcel.classfile;
17
18 import java.io.DataInput;
19 import java.io.IOException;
20
21 /**
22 * This class is derived from <em>Attribute</em> and represents a constant
23 * value, i.e., a default value for initializing a class field.
24 * This class is instantiated by the <em>Attribute.readAttribute()</em> method.
25 *
26 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
27 * @see Attribute
28 */
29 public final class ConstantValue extends Attribute {
30
31 private static final long serialVersionUID = -388222612752527969L;
32
33
34 /**
35 * Construct object from file stream.
36 * @param name_index Name index in constant pool
37 * @param length Content length in bytes
38 * @param file Input stream
39 * @param constant_pool Array of constants
40 * @throws IOException
41 */
42 ConstantValue(int name_index, int length, DataInput file, ConstantPool constant_pool)
43 throws IOException {
44 super(name_index, length, constant_pool);
45 file.readUnsignedShort(); // Unused constantvalue_index
46 }
47 }
+0
-66
java/org/apache/tomcat/util/bcel/classfile/Deprecated.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * This class is derived from <em>Attribute</em> and denotes that this is a
24 * deprecated method.
25 * It is instantiated from the <em>Attribute.readAttribute()</em> method.
26 *
27 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
28 * @see Attribute
29 */
30 public final class Deprecated extends Attribute {
31
32 private static final long serialVersionUID = 8499975360019639912L;
33 private byte[] bytes;
34
35
36 /**
37 * @param name_index Index in constant pool to CONSTANT_Utf8
38 * @param length Content length in bytes
39 * @param bytes Attribute contents
40 * @param constant_pool Array of constants
41 */
42 public Deprecated(int name_index, int length, byte[] bytes, ConstantPool constant_pool) {
43 super(name_index, length, constant_pool);
44 this.bytes = bytes;
45 }
46
47
48 /**
49 * Construct object from file stream.
50 * @param name_index Index in constant pool to CONSTANT_Utf8
51 * @param length Content length in bytes
52 * @param file Input stream
53 * @param constant_pool Array of constants
54 * @throws IOException
55 */
56 Deprecated(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
57 throws IOException {
58 this(name_index, length, (byte[]) null, constant_pool);
59 if (length > 0) {
60 bytes = new byte[length];
61 file.readFully(bytes);
62 System.err.println("Deprecated attribute with length > 0");
63 }
64 }
65 }
1616 */
1717 package org.apache.tomcat.util.bcel.classfile;
1818
19 import java.io.DataInputStream;
19 import java.io.DataInput;
2020 import java.io.IOException;
2121
2222 /**
2525 */
2626 public abstract class ElementValue
2727 {
28 protected int type;
28 protected final int type;
2929
30 protected ConstantPool cpool;
30 protected final ConstantPool cpool;
3131
3232
33 protected ElementValue(int type, ConstantPool cpool)
34 {
33 ElementValue(int type, ConstantPool cpool) {
3534 this.type = type;
3635 this.cpool = cpool;
3736 }
6463
6564 public static final int PRIMITIVE_BOOLEAN = 'Z';
6665
67 public static ElementValue readElementValue(DataInputStream dis,
66 public static ElementValue readElementValue(DataInput dis,
6867 ConstantPool cpool) throws IOException
6968 {
7069 byte type = dis.readByte();
105104 return new ClassElementValue(CLASS, dis.readUnsignedShort(), cpool);
106105 case '@': // Annotation
107106 // TODO isRuntimeVisible
108 return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(
107 return new AnnotationElementValue(ANNOTATION, new AnnotationEntry(
109108 dis, cpool), cpool);
110109 case '[': // Array
111110 int numArrayVals = dis.readUnsignedShort();
116115 }
117116 return new ArrayElementValue(ARRAY, evalues, cpool);
118117 default:
119 throw new RuntimeException(
118 throw new ClassFormatException(
120119 "Unexpected element value kind in annotation: " + type);
121120 }
122121 }
1616 */
1717 package org.apache.tomcat.util.bcel.classfile;
1818
19 import java.io.DataInput;
20 import java.io.IOException;
21
1922 import org.apache.tomcat.util.bcel.Constants;
2023
2124 /**
2629 */
2730 public class ElementValuePair
2831 {
29 private ElementValue elementValue;
32 private final ElementValue elementValue;
3033
31 private ConstantPool constantPool;
34 private final ConstantPool constantPool;
3235
33 private int elementNameIndex;
36 private final int elementNameIndex;
3437
35 public ElementValuePair(int elementNameIndex, ElementValue elementValue,
36 ConstantPool constantPool)
37 {
38 this.elementValue = elementValue;
39 this.elementNameIndex = elementNameIndex;
38 ElementValuePair(DataInput file, ConstantPool constantPool) throws IOException {
4039 this.constantPool = constantPool;
40 this.elementNameIndex = file.readUnsignedShort();
41 this.elementValue = ElementValue.readElementValue(file, constantPool);
4142 }
4243
4344 public String getNameString()
+0
-39
java/org/apache/tomcat/util/bcel/classfile/EnclosingMethod.java less more
0 /**
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.bcel.classfile;
17
18 import java.io.DataInputStream;
19 import java.io.IOException;
20
21 /**
22 * This attribute exists for local or
23 * anonymous classes and ... there can be only one.
24 */
25 public class EnclosingMethod extends Attribute {
26
27 private static final long serialVersionUID = 6755214228300933233L;
28
29 // Ctors - and code to read an attribute in.
30 public EnclosingMethod(int nameIndex, int len, DataInputStream dis,
31 ConstantPool cpool) throws IOException {
32 super(nameIndex, len, cpool);
33 // Unused class index
34 dis.readUnsignedShort();
35 // Unused method index
36 dis.readUnsignedShort();
37 }
38 }
2020
2121 public class EnumElementValue extends ElementValue
2222 {
23 private int valueIdx;
23 private final int valueIdx;
2424
25 public EnumElementValue(int type, int valueIdx, ConstantPool cpool)
26 {
25 EnumElementValue(int type, int valueIdx, ConstantPool cpool) {
2726 super(type, cpool);
2827 if (type != ENUM_CONSTANT)
2928 throw new RuntimeException(
+0
-81
java/org/apache/tomcat/util/bcel/classfile/ExceptionTable.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * This class represents the table of exceptions that are thrown by a
24 * method. This attribute may be used once per method. The name of
25 * this class is <em>ExceptionTable</em> for historical reasons; The
26 * Java Virtual Machine Specification, Second Edition defines this
27 * attribute using the name <em>Exceptions</em> (which is inconsistent
28 * with the other classes).
29 *
30 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
31 * @see Code
32 */
33 public final class ExceptionTable extends Attribute {
34
35 private static final long serialVersionUID = -5109672682663772900L;
36 private int number_of_exceptions; // Table of indices into
37 private int[] exception_index_table; // constant pool
38
39
40 /**
41 * @param name_index Index in constant pool
42 * @param length Content length in bytes
43 * @param exception_index_table Table of indices in constant pool
44 * @param constant_pool Array of constants
45 */
46 public ExceptionTable(int name_index, int length, int[] exception_index_table,
47 ConstantPool constant_pool) {
48 super(name_index, length, constant_pool);
49 setExceptionIndexTable(exception_index_table);
50 }
51
52
53 /**
54 * Construct object from file stream.
55 * @param name_index Index in constant pool
56 * @param length Content length in bytes
57 * @param file Input stream
58 * @param constant_pool Array of constants
59 * @throws IOException
60 */
61 ExceptionTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
62 throws IOException {
63 this(name_index, length, (int[]) null, constant_pool);
64 number_of_exceptions = file.readUnsignedShort();
65 exception_index_table = new int[number_of_exceptions];
66 for (int i = 0; i < number_of_exceptions; i++) {
67 exception_index_table[i] = file.readUnsignedShort();
68 }
69 }
70
71
72 /**
73 * @param exception_index_table the list of exception indexes
74 * Also redefines number_of_exceptions according to table length.
75 */
76 public final void setExceptionIndexTable( int[] exception_index_table ) {
77 this.exception_index_table = exception_index_table;
78 number_of_exceptions = (exception_index_table == null) ? 0 : exception_index_table.length;
79 }
80 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.bcel.classfile;
17
18 import java.io.BufferedInputStream;
19 import java.io.DataInput;
20 import java.io.DataInputStream;
21 import java.io.EOFException;
22 import java.io.IOException;
23 import java.io.InputStream;
24
25 /**
26 * A "FastDataInputStream" that get the numbers from buffer and from the target
27 * directly instead of "DataInputStream".
28 */
29 class FastDataInputStream extends BufferedInputStream implements DataInput {
30
31 private final byte readBuffer[] = new byte[8];
32
33
34 public FastDataInputStream(InputStream in, int size) {
35 super(in, size);
36 }
37
38
39 @Override
40 public final int read(byte b[]) throws IOException {
41 return this.read(b, 0, b.length);
42 }
43
44
45 @Override
46 public final void readFully(byte b[]) throws IOException {
47 readFully(b, 0, b.length);
48 }
49
50
51 @Override
52 public final void readFully(byte b[], int off, int len) throws IOException {
53 if (len < 0)
54 throw new IndexOutOfBoundsException();
55 // Total read
56 int sum = 0;
57 // Current read
58 int cur = 0;
59 for(; sum < len; sum += cur){
60 cur = read(b, off + sum, len - sum);
61 if(cur < 0)
62 throw new EOFException();
63 sum += cur;
64 }
65 }
66
67
68 @Override
69 public boolean readBoolean() throws IOException {
70 if (pos >= count) {
71 fillNew();
72 if (pos >= count)
73 throw new EOFException();
74 }
75 int ch = this.buf[pos++] & 0xff;
76 return (ch != 0);
77 }
78
79
80 @Override
81 public final byte readByte() throws IOException {
82 if (pos >= count) {
83 fillNew();
84 if (pos >= count)
85 throw new EOFException();
86 }
87 return this.buf[pos++];
88 }
89
90
91 @Override
92 public int readUnsignedByte() throws IOException {
93 if (pos >= count) {
94 fillNew();
95 if (pos >= count)
96 throw new EOFException();
97 }
98 int ch = this.buf[pos++] & 0xff;
99 return ch;
100 }
101
102
103 @Override
104 public final short readShort() throws IOException {
105 if(pos + 1 >= count){
106 fillNew();
107 if(pos + 1 >= count) throw new EOFException();
108 }
109 int ch1 = this.buf[pos++] & 0xff;
110 int ch2 = this.buf[pos++] & 0xff;
111 return (short)((ch1 << 8) + ch2);
112 }
113
114
115 @Override
116 public int readUnsignedShort() throws IOException{
117 if(pos + 1 >= count) {
118 fillNew();
119 if(pos + 1 >= count) throw new EOFException();
120 }
121
122 int ch1 = this.buf[pos++] & 0xff;
123 int ch2 = this.buf[pos++] & 0xff;
124 return (ch1 << 8) + ch2;
125 }
126
127
128 @Override
129 public final char readChar() throws IOException {
130 if(pos + 1 >= count) {
131 fillNew();
132 if(pos + 1 >= count) throw new EOFException();
133 }
134 int ch1 = this.buf[pos++] & 0xff;
135 int ch2 = this.buf[pos++] & 0xff;
136 return (char)((ch1 << 8) + ch2);
137 }
138
139
140 @Override
141 public final int readInt() throws IOException {
142 if(pos + 3 >= count){
143 fillNew();
144 if(pos + 3 >= count) throw new EOFException();
145 }
146 int ch1 = this.buf[pos++] & 0xff;
147 int ch2 = this.buf[pos++] & 0xff;
148 int ch3 = this.buf[pos++] & 0xff;
149 int ch4 = this.buf[pos++] & 0xff;
150 return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
151 }
152
153
154 @Override
155 public final long readLong() throws IOException {
156 readFully(readBuffer, 0, 8);
157 return (((long)readBuffer[0] << 56) +
158 ((long)(readBuffer[1] & 255) << 48) +
159 ((long)(readBuffer[2] & 255) << 40) +
160 ((long)(readBuffer[3] & 255) << 32) +
161 ((long)(readBuffer[4] & 255) << 24) +
162 ((readBuffer[5] & 255) << 16) +
163 ((readBuffer[6] & 255) << 8) +
164 (readBuffer[7] & 255));
165 }
166
167
168 @Override
169 public final float readFloat() throws IOException {
170 return Float.intBitsToFloat(readInt());
171 }
172
173
174 @Override
175 public double readDouble() throws IOException {
176 return Double.longBitsToDouble(readLong());
177 }
178
179
180 @Override
181 public final String readUTF() throws IOException {
182 return DataInputStream.readUTF(this);
183 }
184
185
186 private void fillNew() throws IOException {
187 int remain = 0;
188 if(pos < count){
189 remain = count - pos;
190 System.arraycopy(buf, pos, buf, 0, remain);
191 }
192 pos = 0;
193 int n = this.in.read(buf, remain, buf.length - remain);
194 count = pos + n + remain;
195 }
196
197
198 @Override
199 public int skipBytes(int n) throws IOException {
200 int avail = count - pos;
201 // Total Skipped
202 int sum = 0;
203 // Current skipped
204 int cur = 0;
205 if (avail <= 0) {
206 // buffer is exhausted, read via stream directly
207 while (sum < n && (cur = (int) in.skip(n - sum)) > 0) {
208 sum += cur;
209 }
210 return sum;
211 }
212 // Data in the buffer is not enough
213 if(n > avail){
214 // Skip the data in buffer
215 pos += avail;
216 sum += avail;
217 // Read via stream
218 while (sum < n && (cur = (int) in.skip(n - sum)) > 0) {
219 sum += cur;
220 }
221 return sum;
222 }
223 pos += n;
224 return n;
225 }
226
227
228 @Override
229 public String readLine() throws IOException {
230 // Unimplemented
231 throw new UnsupportedOperationException();
232 }
233 }
+0
-149
java/org/apache/tomcat/util/bcel/classfile/FieldOrMethod.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23 import org.apache.tomcat.util.bcel.util.BCELComparator;
24
25 /**
26 * Class for fields and methods.
27 *
28 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
29 */
30 public class FieldOrMethod extends AccessFlags implements Cloneable {
31
32 private static final long serialVersionUID = -3383525930205542157L;
33 private static BCELComparator _cmp = new BCELComparator() {
34
35 @Override
36 public boolean equals( Object o1, Object o2 ) {
37 FieldOrMethod THIS = (FieldOrMethod) o1;
38 FieldOrMethod THAT = (FieldOrMethod) o2;
39 return THIS.getName().equals(THAT.getName())
40 && THIS.getSignature().equals(THAT.getSignature());
41 }
42
43
44 @Override
45 public int hashCode( Object o ) {
46 FieldOrMethod THIS = (FieldOrMethod) o;
47 return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
48 }
49 };
50
51 protected int name_index; // Points to field name in constant pool
52 protected int signature_index; // Points to encoded signature
53 protected int attributes_count; // No. of attributes
54 protected Attribute[] attributes; // Collection of attributes
55
56 protected ConstantPool constant_pool;
57
58 FieldOrMethod() {
59 }
60
61
62 /**
63 * Construct object from file stream.
64 * @param file Input stream
65 * @throws IOException
66 * @throws ClassFormatException
67 */
68 protected FieldOrMethod(DataInputStream file, ConstantPool constant_pool) throws IOException,
69 ClassFormatException {
70 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null,
71 constant_pool);
72 attributes_count = file.readUnsignedShort();
73 attributes = new Attribute[attributes_count];
74 for (int i = 0; i < attributes_count; i++) {
75 attributes[i] = Attribute.readAttribute(file, constant_pool);
76 }
77 }
78
79
80 /**
81 * @param access_flags Access rights of method
82 * @param name_index Points to field name in constant pool
83 * @param signature_index Points to encoded signature
84 * @param attributes Collection of attributes
85 * @param constant_pool Array of constants
86 */
87 protected FieldOrMethod(int access_flags, int name_index, int signature_index,
88 Attribute[] attributes, ConstantPool constant_pool) {
89 this.access_flags = access_flags;
90 this.name_index = name_index;
91 this.signature_index = signature_index;
92 this.constant_pool = constant_pool;
93 setAttributes(attributes);
94 }
95
96
97 /**
98 * @param attributes Collection of object attributes.
99 */
100 public final void setAttributes( Attribute[] attributes ) {
101 this.attributes = attributes;
102 attributes_count = (attributes == null) ? 0 : attributes.length;
103 }
104
105
106 /**
107 * @return Name of object, i.e., method name or field name
108 */
109 public final String getName() {
110 ConstantUtf8 c;
111 c = (ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8);
112 return c.getBytes();
113 }
114
115
116 /**
117 * @return String representation of object's type signature (java style)
118 */
119 public final String getSignature() {
120 ConstantUtf8 c;
121 c = (ConstantUtf8) constant_pool.getConstant(signature_index, Constants.CONSTANT_Utf8);
122 return c.getBytes();
123 }
124
125 /**
126 * Return value as defined by given BCELComparator strategy.
127 * By default two FieldOrMethod objects are said to be equal when
128 * their names and signatures are equal.
129 *
130 * @see java.lang.Object#equals(java.lang.Object)
131 */
132 @Override
133 public boolean equals( Object obj ) {
134 return _cmp.equals(this, obj);
135 }
136
137
138 /**
139 * Return value as defined by given BCELComparator strategy.
140 * By default return the hashcode of the FieldOrMethod's name XOR signature.
141 *
142 * @see java.lang.Object#hashCode()
143 */
144 @Override
145 public int hashCode() {
146 return _cmp.hashCode(this);
147 }
148 }
+0
-55
java/org/apache/tomcat/util/bcel/classfile/InnerClasses.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * This class is derived from <em>Attribute</em> and denotes that this class
24 * is an Inner class of another.
25 * to the source file of this class.
26 * It is instantiated from the <em>Attribute.readAttribute()</em> method.
27 *
28 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
29 * @see Attribute
30 */
31 public final class InnerClasses extends Attribute {
32
33 private static final long serialVersionUID = 54179484605570305L;
34 private int number_of_classes;
35
36
37 /**
38 * Construct object from file stream.
39 *
40 * @param name_index Index in constant pool to CONSTANT_Utf8
41 * @param length Content length in bytes
42 * @param file Input stream
43 * @param constant_pool Array of constants
44 * @throws IOException
45 */
46 InnerClasses(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
47 throws IOException {
48 super(name_index, length, constant_pool);
49 number_of_classes = file.readUnsignedShort();
50 for (int i = 0; i < number_of_classes; i++) {
51 Utility.swallowInnerClass(file);
52 }
53 }
54 }
1616 */
1717 package org.apache.tomcat.util.bcel.classfile;
1818
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.apache.tomcat.util.bcel.Constants;
23 import org.apache.tomcat.util.bcel.util.BCELComparator;
24
2519 /**
2620 * Represents a Java class, i.e., the data structures, constant pool,
2721 * fields, methods and commands contained in a Java .class file.
3226
3327 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
3428 */
35 public class JavaClass extends AccessFlags
36 implements Cloneable, Comparable<JavaClass> {
29 public class JavaClass {
3730
38 private static final long serialVersionUID = 7029227708237523236L;
39 private String class_name;
40 private String superclass_name;
41 private String[] interface_names;
42 private Attribute[] attributes; // attributes defined in the class
43 private AnnotationEntry[] annotations; // annotations defined on the class
44
45
46 // Annotations are collected from certain attributes, don't do it more than necessary!
47 private boolean annotationsOutOfDate = true;
48
49 private static BCELComparator _cmp = new BCELComparator() {
50
51 @Override
52 public boolean equals( Object o1, Object o2 ) {
53 JavaClass THIS = (JavaClass) o1;
54 JavaClass THAT = (JavaClass) o2;
55 return THIS.getClassName().equals(THAT.getClassName());
56 }
57
58
59 @Override
60 public int hashCode( Object o ) {
61 JavaClass THIS = (JavaClass) o;
62 return THIS.getClassName().hashCode();
63 }
64 };
65
31 private final int access_flags;
32 private final String class_name;
33 private final String superclass_name;
34 private final String[] interface_names;
35 private final Annotations runtimeVisibleAnnotations; // "RuntimeVisibleAnnotations" attribute defined in the class
6636
6737 /**
6838 * Constructor gets all contents as arguments.
6939 *
70 * @param class_name_index Index into constant pool referencing a
71 * ConstantClass that represents this class.
72 * @param superclass_name_index Index into constant pool referencing a
73 * ConstantClass that represents this class's superclass.
40 * @param class_name Name of this class.
41 * @param superclass_name Name of this class's superclass.
7442 * @param access_flags Access rights defined by bit flags
7543 * @param constant_pool Array of constants
7644 * @param interfaces Implemented interfaces
77 * @param attributes Class attributes
45 * @param runtimeVisibleAnnotations "RuntimeVisibleAnnotations" attribute defined on the Class, or null
7846 */
79 public JavaClass(int class_name_index, int superclass_name_index,
80 int access_flags, ConstantPool constant_pool, int[] interfaces,
81 Attribute[] attributes) {
82 if (interfaces == null) {
83 interfaces = new int[0];
84 }
85 if (attributes == null) {
86 attributes = new Attribute[0];
87 }
47 JavaClass(String class_name, String superclass_name,
48 int access_flags, ConstantPool constant_pool, String[] interface_names,
49 Annotations runtimeVisibleAnnotations) {
8850 this.access_flags = access_flags;
89 this.attributes = attributes;
90 annotationsOutOfDate = true;
91
92 /* According to the specification the following entries must be of type
93 * `ConstantClass' but we check that anyway via the
94 * `ConstPool.getConstant' method.
95 */
96 class_name = constant_pool.getConstantString(class_name_index, Constants.CONSTANT_Class);
97 class_name = Utility.compactClassName(class_name);
98 if (superclass_name_index > 0) {
99 // May be zero -> class is java.lang.Object
100 superclass_name = constant_pool.getConstantString(superclass_name_index,
101 Constants.CONSTANT_Class);
102 superclass_name = Utility.compactClassName(superclass_name);
103 } else {
104 superclass_name = "java.lang.Object";
105 }
106 interface_names = new String[interfaces.length];
107 for (int i = 0; i < interfaces.length; i++) {
108 String str = constant_pool.getConstantString(interfaces[i], Constants.CONSTANT_Class);
109 interface_names[i] = Utility.compactClassName(str);
110 }
51 this.runtimeVisibleAnnotations = runtimeVisibleAnnotations;
52 this.class_name = class_name;
53 this.superclass_name = superclass_name;
54 this.interface_names = interface_names;
11155 }
11256
57 /**
58 * @return Access flags of the object aka. "modifiers".
59 */
60 public final int getAccessFlags() {
61 return access_flags;
62 }
11363
64 /**
65 * Return annotations entries from "RuntimeVisibleAnnotations" attribute on
66 * the class, if there is any.
67 *
68 * @return An array of entries or {@code null}
69 */
11470 public AnnotationEntry[] getAnnotationEntries() {
115 if (annotationsOutOfDate) {
116 // Find attributes that contain annotation data
117 List<AnnotationEntry> accumulatedAnnotations = new ArrayList<>();
118 for (Attribute attribute : attributes) {
119 if (attribute instanceof Annotations) {
120 Annotations runtimeAnnotations = (Annotations)attribute;
121 for(int j = 0; j < runtimeAnnotations.getAnnotationEntries().length; j++)
122 accumulatedAnnotations.add(runtimeAnnotations.getAnnotationEntries()[j]);
123 }
124 }
125 annotations = accumulatedAnnotations.toArray(new AnnotationEntry[accumulatedAnnotations.size()]);
126 annotationsOutOfDate = false;
71 if (runtimeVisibleAnnotations != null) {
72 return runtimeVisibleAnnotations.getAnnotationEntries();
12773 }
128 return annotations;
74 return null;
12975 }
13076
13177 /**
154100 public String getSuperclassName() {
155101 return superclass_name;
156102 }
157
158
159 /**
160 * Return value as defined by given BCELComparator strategy.
161 * By default two JavaClass objects are said to be equal when
162 * their class names are equal.
163 *
164 * @see java.lang.Object#equals(java.lang.Object)
165 */
166 @Override
167 public boolean equals( Object obj ) {
168 return _cmp.equals(this, obj);
169 }
170
171
172 /**
173 * Return the natural ordering of two JavaClasses.
174 * This ordering is based on the class name
175 */
176 @Override
177 public int compareTo(JavaClass obj) {
178 return getClassName().compareTo(obj.getClassName());
179 }
180
181
182 /**
183 * Return value as defined by given BCELComparator strategy.
184 * By default return the hashcode of the class name.
185 *
186 * @see java.lang.Object#hashCode()
187 */
188 @Override
189 public int hashCode() {
190 return _cmp.hashCode(this);
191 }
192103 }
+0
-52
java/org/apache/tomcat/util/bcel/classfile/LineNumberTable.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * This class represents a table of line numbers for debugging
24 * purposes. This attribute is used by the <em>Code</em> attribute. It
25 * contains pairs of PCs and line numbers.
26 *
27 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
28 * @see Code
29 */
30 public final class LineNumberTable extends Attribute {
31
32 private static final long serialVersionUID = 6585122636118666124L;
33
34
35 /**
36 * Construct object from file stream.
37 * @param name_index Index of name
38 * @param length Content length in bytes
39 * @param file Input stream
40 * @param constant_pool Array of constants
41 * @throws IOException
42 */
43 LineNumberTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
44 throws IOException {
45 super(name_index, length, constant_pool);
46 int line_number_table_length = (file.readUnsignedShort());
47 for (int i = 0; i < line_number_table_length; i++) {
48 Utility.swallowLineNumber(file);
49 }
50 }
51 }
+0
-51
java/org/apache/tomcat/util/bcel/classfile/LocalVariableTable.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * This class represents colection of local variables in a
24 * method. This attribute is contained in the <em>Code</em> attribute.
25 *
26 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
27 * @see Code
28 */
29 public class LocalVariableTable extends Attribute {
30
31 private static final long serialVersionUID = -3904314258294133920L;
32
33
34 /**
35 * Construct object from file stream.
36 * @param name_index Index in constant pool
37 * @param length Content length in bytes
38 * @param file Input stream
39 * @param constant_pool Array of constants
40 * @throws IOException
41 */
42 LocalVariableTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
43 throws IOException {
44 super(name_index, length, constant_pool);
45 int local_variable_table_length = (file.readUnsignedShort());
46 for (int i = 0; i < local_variable_table_length; i++) {
47 Utility.swallowLocalVariable(file);
48 }
49 }
50 }
+0
-63
java/org/apache/tomcat/util/bcel/classfile/LocalVariableTypeTable.java less more
0 /**
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.bcel.classfile;
17
18 import java.io.DataInputStream;
19 import java.io.IOException;
20
21 // The new table is used when generic types are about...
22
23 //LocalVariableTable_attribute {
24 // u2 attribute_name_index;
25 // u4 attribute_length;
26 // u2 local_variable_table_length;
27 // { u2 start_pc;
28 // u2 length;
29 // u2 name_index;
30 // u2 descriptor_index;
31 // u2 index;
32 // } local_variable_table[local_variable_table_length];
33 // }
34
35 //LocalVariableTypeTable_attribute {
36 // u2 attribute_name_index;
37 // u4 attribute_length;
38 // u2 local_variable_type_table_length;
39 // {
40 // u2 start_pc;
41 // u2 length;
42 // u2 name_index;
43 // u2 signature_index;
44 // u2 index;
45 // } local_variable_type_table[local_variable_type_table_length];
46 // }
47 // J5TODO: Needs some testing !
48 public class LocalVariableTypeTable extends Attribute {
49 private static final long serialVersionUID = -5466082154076451597L;
50
51 LocalVariableTypeTable(int name_index, int length,
52 DataInputStream dis, ConstantPool constant_pool)
53 throws IOException {
54 super(name_index, length, constant_pool);
55
56 int local_variable_type_table_length = (dis.readUnsignedShort());
57
58 for(int i=0; i < local_variable_type_table_length; i++) {
59 Utility.swallowLocalVariable(dis);
60 }
61 }
62 }
+0
-49
java/org/apache/tomcat/util/bcel/classfile/PMGClass.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInput;
20 import java.io.IOException;
21
22 /**
23 * This class is derived from <em>Attribute</em> and represents a reference
24 * to a PMG attribute.
25 *
26 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
27 * @see Attribute
28 */
29 public final class PMGClass extends Attribute {
30
31 private static final long serialVersionUID = -1876065562391587509L;
32
33
34 /**
35 * Construct object from file stream.
36 * @param name_index Index in constant pool to CONSTANT_Utf8
37 * @param length Content length in bytes
38 * @param file Input stream
39 * @param constant_pool Array of constants
40 * @throws IOException
41 */
42 PMGClass(int name_index, int length, DataInput file, ConstantPool constant_pool)
43 throws IOException {
44 super(name_index, length, constant_pool);
45 file.readUnsignedShort(); // Unused pmg_index
46 file.readUnsignedShort(); // Unused pmg_class_index
47 }
48 }
+0
-50
java/org/apache/tomcat/util/bcel/classfile/ParameterAnnotationEntry.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 import org.apache.tomcat.util.bcel.Constants;
23
24 /**
25 * represents one parameter annotation in the parameter annotation table
26 *
27 * @author <A HREF="mailto:dbrosius@qis.net">D. Brosius</A>
28 * @since 6.0
29 */
30 public class ParameterAnnotationEntry implements Constants {
31
32 private int annotation_table_length;
33 private AnnotationEntry[] annotation_table;
34
35
36 /**
37 * Construct object from file stream.
38 * @param file Input stream
39 * @throws IOException
40 */
41 ParameterAnnotationEntry(DataInputStream file, ConstantPool constant_pool) throws IOException {
42 annotation_table_length = (file.readUnsignedShort());
43 annotation_table = new AnnotationEntry[annotation_table_length];
44 for (int i = 0; i < annotation_table_length; i++) {
45 annotation_table[i] = AnnotationEntry.read(file, constant_pool);
46 }
47 }
48
49 }
+0
-77
java/org/apache/tomcat/util/bcel/classfile/ParameterAnnotations.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * base class for parameter annotations
24 *
25 * @author <A HREF="mailto:dbrosius@qis.net">D. Brosius</A>
26 * @since 6.0
27 */
28 public abstract class ParameterAnnotations extends Attribute {
29
30 private static final long serialVersionUID = -8831779739803248091L;
31 private int num_parameters;
32 private ParameterAnnotationEntry[] parameter_annotation_table; // Table of parameter annotations
33
34
35 /**
36 * @param name_index Index pointing to the name <em>Code</em>
37 * @param length Content length in bytes
38 * @param file Input stream
39 * @param constant_pool Array of constants
40 */
41 ParameterAnnotations(int name_index, int length,
42 DataInputStream file, ConstantPool constant_pool) throws IOException {
43 this(name_index, length, (ParameterAnnotationEntry[]) null,
44 constant_pool);
45 num_parameters = (file.readUnsignedByte());
46 parameter_annotation_table = new ParameterAnnotationEntry[num_parameters];
47 for (int i = 0; i < num_parameters; i++) {
48 parameter_annotation_table[i] = new ParameterAnnotationEntry(file, constant_pool);
49 }
50 }
51
52
53 /**
54 * @param name_index Index pointing to the name <em>Code</em>
55 * @param length Content length in bytes
56 * @param parameter_annotation_table the actual parameter annotations
57 * @param constant_pool Array of constants
58 */
59 public ParameterAnnotations(int name_index, int length,
60 ParameterAnnotationEntry[] parameter_annotation_table, ConstantPool constant_pool) {
61 super(name_index, length, constant_pool);
62 setParameterAnnotationTable(parameter_annotation_table);
63 }
64
65
66 /**
67 * @param parameter_annotation_table the entries to set in this parameter annotation
68 */
69 public final void setParameterAnnotationTable(
70 ParameterAnnotationEntry[] parameter_annotation_table ) {
71 this.parameter_annotation_table = parameter_annotation_table;
72 num_parameters = (parameter_annotation_table == null)
73 ? 0
74 : parameter_annotation_table.length;
75 }
76 }
+0
-50
java/org/apache/tomcat/util/bcel/classfile/RuntimeInvisibleAnnotations.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * represents an annotation that is represented in the class file but is not
24 * provided to the JVM.
25 *
26 * @author <A HREF="mailto:dbrosius@qis.net">D. Brosius</A>
27 * @since 6.0
28 */
29 public class RuntimeInvisibleAnnotations extends Annotations
30 {
31 private static final long serialVersionUID = -7962627688723310248L;
32
33 /**
34 * @param name_index
35 * Index pointing to the name <em>Code</em>
36 * @param length
37 * Content length in bytes
38 * @param file
39 * Input stream
40 * @param constant_pool
41 * Array of constants
42 */
43 RuntimeInvisibleAnnotations(int name_index, int length,
44 DataInputStream file, ConstantPool constant_pool)
45 throws IOException
46 {
47 super(name_index, length, file, constant_pool);
48 }
49 }
+0
-45
java/org/apache/tomcat/util/bcel/classfile/RuntimeInvisibleParameterAnnotations.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * represents a parameter annotation that is represented in the class file
24 * but is not provided to the JVM.
25 *
26 * @author <A HREF="mailto:dbrosius@qis.net">D. Brosius</A>
27 * @since 6.0
28 */
29 public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations {
30
31 private static final long serialVersionUID = -6819370369102352536L;
32
33
34 /**
35 * @param name_index Index pointing to the name <em>Code</em>
36 * @param length Content length in bytes
37 * @param file Input stream
38 * @param constant_pool Array of constants
39 */
40 RuntimeInvisibleParameterAnnotations(int name_index, int length, DataInputStream file,
41 ConstantPool constant_pool) throws IOException {
42 super(name_index, length, file, constant_pool);
43 }
44 }
+0
-50
java/org/apache/tomcat/util/bcel/classfile/RuntimeVisibleAnnotations.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * represents an annotation that is represented in the class file and is
24 * provided to the JVM.
25 *
26 * @author <A HREF="mailto:dbrosius@qis.net">D. Brosius</A>
27 * @since 6.0
28 */
29 public class RuntimeVisibleAnnotations extends Annotations
30 {
31 private static final long serialVersionUID = 2912284875689024413L;
32
33 /**
34 * @param name_index
35 * Index pointing to the name <em>Code</em>
36 * @param length
37 * Content length in bytes
38 * @param file
39 * Input stream
40 * @param constant_pool
41 * Array of constants
42 */
43 public RuntimeVisibleAnnotations(int name_index, int length,
44 DataInputStream file, ConstantPool constant_pool)
45 throws IOException
46 {
47 super(name_index, length, file, constant_pool);
48 }
49 }
+0
-45
java/org/apache/tomcat/util/bcel/classfile/RuntimeVisibleParameterAnnotations.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.IOException;
21
22 /**
23 * represents a parameter annotation that is represented in the class file
24 * and is provided to the JVM.
25 *
26 * @author <A HREF="mailto:dbrosius@qis.net">D. Brosius</A>
27 * @since 6.0
28 */
29 public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations {
30
31 private static final long serialVersionUID = 7633756460868573992L;
32
33
34 /**
35 * @param name_index Index pointing to the name <em>Code</em>
36 * @param length Content length in bytes
37 * @param file Input stream
38 * @param constant_pool Array of constants
39 */
40 RuntimeVisibleParameterAnnotations(int name_index, int length, DataInputStream file,
41 ConstantPool constant_pool) throws IOException {
42 super(name_index, length, file, constant_pool);
43 }
44 }
2020
2121 public class SimpleElementValue extends ElementValue
2222 {
23 private int index;
23 private final int index;
2424
25 public SimpleElementValue(int type, int index, ConstantPool cpool)
26 {
25 SimpleElementValue(int type, int index, ConstantPool cpool) {
2726 super(type, cpool);
2827 this.index = index;
2928 }
+0
-50
java/org/apache/tomcat/util/bcel/classfile/SourceFile.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.classfile;
18
19 import java.io.DataInput;
20 import java.io.IOException;
21
22 /**
23 * This class is derived from <em>Attribute</em> and represents a reference
24 * to the source file of this class. At most one SourceFile attribute
25 * should appear per classfile. The intention of this class is that it is
26 * instantiated from the <em>Attribute.readAttribute()</em> method.
27 *
28 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
29 * @see Attribute
30 */
31 public final class SourceFile extends Attribute {
32
33 private static final long serialVersionUID = 332346699609443704L;
34
35
36 /**
37 * Construct object from file stream.
38 * @param name_index Index in constant pool to CONSTANT_Utf8
39 * @param length Content length in bytes
40 * @param file Input stream
41 * @param constant_pool Array of constants
42 * @throws IOException
43 */
44 SourceFile(int name_index, int length, DataInput file, ConstantPool constant_pool)
45 throws IOException {
46 super(name_index, length, constant_pool);
47 file.readUnsignedShort(); // Unused sourcefile_index
48 }
49 }
1717 package org.apache.tomcat.util.bcel.classfile;
1818
1919 import java.io.DataInput;
20 import java.io.DataInputStream;
20 import java.io.EOFException;
2121 import java.io.IOException;
2222
2323 import org.apache.tomcat.util.bcel.Constants;
4646 return str.replace('/', '.'); // Is `/' on all systems, even DOS
4747 }
4848
49 static void swallowCodeException(DataInput file) throws IOException {
50 file.readUnsignedShort(); // Unused start_pc
51 file.readUnsignedShort(); // Unused end_pc
52 file.readUnsignedShort(); // Unused handler_pc
53 file.readUnsignedShort(); // Unused catch_type
49 static String getClassName(ConstantPool constant_pool, int index) {
50 Constant c = constant_pool.getConstant(index, Constants.CONSTANT_Class);
51 int i = ((ConstantClass) c).getNameIndex();
52
53 // Finally get the string from the constant pool
54 c = constant_pool.getConstant(i, Constants.CONSTANT_Utf8);
55 String name = ((ConstantUtf8) c).getBytes();
56
57 return compactClassName(name);
5458 }
5559
56 static void swallowInnerClass(DataInput file) throws IOException {
57 file.readUnsignedShort(); // Unused inner_class_index
58 file.readUnsignedShort(); // Unused outer_class_index
59 file.readUnsignedShort(); // Unused inner_name_index
60 file.readUnsignedShort(); // Unused inner_access_flags
61 }
62
63 static void swallowLineNumber(DataInput file) throws IOException {
64 file.readUnsignedShort(); // Unused start_pc
65 file.readUnsignedShort(); // Unused line_number
66 }
67
68 static void swallowLocalVariable(DataInput file) throws IOException {
69 file.readUnsignedShort(); // Unused start_pc
70 file.readUnsignedShort(); // Unused length
71 file.readUnsignedShort(); // Unused name_index
72 file.readUnsignedShort(); // Unused signature_index
73 file.readUnsignedShort(); // Unused index
74 }
75
76 static void swallowStackMap(DataInput file) throws IOException {
77 int map_length = file.readUnsignedShort();
78 for (int i = 0; i < map_length; i++) {
79 Utility.swallowStackMapEntry(file);
60 static void skipFully(DataInput file, int length) throws IOException {
61 int total = file.skipBytes(length);
62 if (total != length) {
63 throw new EOFException();
8064 }
8165 }
8266
83 static void swallowStackMapTable(DataInputStream file) throws IOException {
84 int map_length = file.readUnsignedShort();
85 for (int i = 0; i < map_length; i++) {
86 Utility.swallowStackMapTableEntry(file);
67 static void swallowFieldOrMethod(DataInput file)
68 throws IOException {
69 // file.readUnsignedShort(); // Unused access flags
70 // file.readUnsignedShort(); // name index
71 // file.readUnsignedShort(); // signature index
72 skipFully(file, 6);
73
74 int attributes_count = file.readUnsignedShort();
75 for (int i = 0; i < attributes_count; i++) {
76 swallowAttribute(file);
8777 }
8878 }
8979
90 static void swallowStackMapType(DataInput file) throws IOException {
91 byte type = file.readByte();
92 if ((type < Constants.ITEM_Bogus) || (type > Constants.ITEM_NewObject)) {
93 throw new ClassFormatException("Illegal type for StackMapType: " + type);
94 }
95 // Check to see if type has an index
96 if ((type == Constants.ITEM_Object) || (type == Constants.ITEM_NewObject)) {
97 file.readShort(); // Unused index
98 }
80 static void swallowAttribute(DataInput file)
81 throws IOException {
82 //file.readUnsignedShort(); // Unused name index
83 skipFully(file, 2);
84 // Length of data in bytes
85 int length = file.readInt();
86 skipFully(file, length);
9987 }
10088
101 static void swallowStackMapEntry(DataInput file) throws IOException {
102 file.readShort(); // Unused byte_code_offset
103 int number_of_locals = file.readShort();
104 for (int i = 0; i < number_of_locals; i++) {
105 Utility.swallowStackMapType(file);
106 }
107 int number_of_stack_items = file.readShort();
108 for (int i = 0; i < number_of_stack_items; i++) {
109 Utility.swallowStackMapType(file);
110 }
111 }
112
113 static void swallowStackMapTableEntry(DataInputStream file) throws IOException {
114 int frame_type = file.read();
115
116 if (frame_type >= Constants.SAME_FRAME && frame_type <= Constants.SAME_FRAME_MAX) {
117 // NO-OP
118 } else if (frame_type >= Constants.SAME_LOCALS_1_STACK_ITEM_FRAME &&
119 frame_type <= Constants.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
120 Utility.swallowStackMapType(file); // Unused single stack item
121 } else if (frame_type == Constants.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
122 file.readShort(); // Unused byte_code_offset_delta
123 Utility.swallowStackMapType(file); // Unused single stack item
124 } else if (frame_type >= Constants.CHOP_FRAME &&
125 frame_type <= Constants.CHOP_FRAME_MAX) {
126 file.readShort(); // Unused byte_code_offset_delta
127 } else if (frame_type == Constants.SAME_FRAME_EXTENDED) {
128 file.readShort(); // Unused byte_code_offset_delta
129 } else if (frame_type >= Constants.APPEND_FRAME &&
130 frame_type <= Constants.APPEND_FRAME_MAX) {
131 file.readShort(); // Unused byte_code_offset_delta
132 int number_of_locals = frame_type - 251;
133 for (int i = 0; i < number_of_locals; i++) {
134 Utility.swallowStackMapType(file);
135 }
136 } else if (frame_type == Constants.FULL_FRAME) {
137 file.readShort(); // Unused byte_code_offset_delta
138 int number_of_locals = file.readShort();
139 for (int i = 0; i < number_of_locals; i++) {
140 Utility.swallowStackMapType(file);
141 }
142 int number_of_stack_items = file.readShort();
143 for (int i = 0; i < number_of_stack_items; i++) {
144 Utility.swallowStackMapType(file);
145 }
146 } else {
147 /* Can't happen */
148 throw new ClassFormatException (
149 "Invalid frame type found while parsing stack map table: " + frame_type);
150 }
151 }
152
153 static void swallowUnknownAttribute(DataInput file, int length) throws IOException {
154 if (length > 0) {
155 byte[] bytes = new byte[length];
156 file.readFully(bytes);
157 }
158 }
159
160 static void swallowSignature(DataInput file) throws IOException {
161 file.readUnsignedShort(); // Unused signature_index
162 }
163
164 static void swallowSynthetic(DataInput file, int length) throws IOException {
165 if (length > 0) {
166 byte[] bytes = new byte[length];
167 file.readFully(bytes);
168 throw new ClassFormatException("Synthetic attribute with length > 0");
169 }
170 }
171
172 static void swallowBootstrapMethods(DataInput file) throws IOException {
173 int num_bootstrap_methods = file.readUnsignedShort();
174 for (int i = 0; i < num_bootstrap_methods; i++) {
175 file.readUnsignedShort(); // Unused bootstrap_method_ref
176 int num_bootstrap_args = file.readUnsignedShort();
177 for (int j = 0; j < num_bootstrap_args; j++) {
178 file.readUnsignedShort(); // Unused bootstrap method argument
179 }
180 }
181 }
182
183 static void swallowMethodParameters(DataInput file) throws IOException {
184 int parameters_count = file.readUnsignedByte();
185 for (int i = 0; i < parameters_count; i++) {
186 file.readUnsignedShort(); // Unused name_index
187 file.readUnsignedShort(); // Unused access_flags
188 }
189 }
19089 }
+0
-45
java/org/apache/tomcat/util/bcel/util/BCELComparator.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 package org.apache.tomcat.util.bcel.util;
18
19 /**
20 * Used for BCEL comparison strategy
21 *
22 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
23 * @since 5.2
24 */
25 public interface BCELComparator {
26
27 /**
28 * Compare two objects and return what THIS.equals(THAT) should return
29 *
30 * @param THIS
31 * @param THAT
32 * @return true if and only if THIS equals THAT
33 */
34 boolean equals( Object THIS, Object THAT );
35
36
37 /**
38 * Return hashcode for THIS.hashCode()
39 *
40 * @param THIS
41 * @return hashcode for THIS.hashCode()
42 */
43 int hashCode( Object THIS );
44 }
+0
-38
java/org/apache/tomcat/util/bcel/util/package.html less more
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
17 <html>
18 <head>
19 </head>
20 <body bgcolor="white">
21 <p>
22 This package contains utility classes for the
23 <a href="http://commons.apache.org/bcel/">Byte Code Engineering
24 Library</a>, namely:
25 </p>
26 <p>
27 <ul>
28 <li>Collection classes for JavaClass objects</li>
29 <li>A converter for class files to HTML</li>
30 <li>A tool to find instructions patterns via regular expressions</li>
31 <li>A class to find classes as defined in the CLASSPATH</li>
32 <li>A class loader that allows to create classes at run time</li>
33 </ul>
34
35 </p>
36 </body>
37 </html>
2222 *
2323 * @author Craig R. McClanahan
2424 */
25
2625 public final class HexUtils {
2726
2827
2928 // -------------------------------------------------------------- Constants
30
3129
3230 /**
3331 * Table for HEX to DEC byte translation.
5452 */
5553 private static final char[] hex = "0123456789abcdef".toCharArray();
5654
55
5756 // --------------------------------------------------------- Static Methods
5857
59
60 public static int getDec(int index){
58 public static int getDec(int index) {
6159 // Fast for correct values, slower for incorrect ones
6260 try {
6361 return DEC[index - '0'];
6664 }
6765 }
6866
69 public static byte getHex(int index){
67
68 public static byte getHex(int index) {
7069 return HEX[index];
7170 }
7271
73 public static String toHexString(byte[] bytes)
74 {
75 if(null == bytes) {
72
73 public static String toHexString(byte[] bytes) {
74 if (null == bytes) {
7675 return null;
7776 }
7877
7978 StringBuilder sb = new StringBuilder(bytes.length << 1);
8079
81 for(int i=0; i<bytes.length; ++i) {
80 for(int i = 0; i < bytes.length; ++i) {
8281 sb.append(hex[(bytes[i] & 0xf0) >> 4])
8382 .append(hex[(bytes[i] & 0x0f)])
8483 ;
8685
8786 return sb.toString();
8887 }
88
89
90 public static byte[] fromHexString(String input) {
91 if (input == null) {
92 return null;
93 }
94
95 char[] inputChars = input.toCharArray();
96 byte[] result = new byte[input.length() >> 1];
97 for (int i = 0; i < result.length; i++) {
98 result[i] = (byte) ((getDec(inputChars[2*i]) << 4) + getDec(inputChars[2*i + 1]));
99 }
100 return result;
101 }
89102 }
110110 @Override
111111 public void scan(File file, String webappPath, boolean isWebapp) throws IOException {
112112
113 InputStream stream = null;
114113 WebXml fragment = new WebXml();
115114 fragment.setWebappJar(isWebapp);
116115 fragment.setDelegate(delegate);
117116
117 File fragmentFile = new File(file, FRAGMENT_LOCATION);
118118 try {
119 File fragmentFile = new File(file, FRAGMENT_LOCATION);
120119 if (fragmentFile.isFile()) {
121 stream = new FileInputStream(fragmentFile);
122 InputSource source =
123 new InputSource(fragmentFile.toURI().toURL().toString());
124 source.setByteStream(stream);
125 if (!webXmlParser.parseWebXml(source, fragment, true)) {
126 ok = false;
120 try (InputStream stream = new FileInputStream(fragmentFile)) {
121 InputSource source =
122 new InputSource(fragmentFile.toURI().toURL().toString());
123 source.setByteStream(stream);
124 if (!webXmlParser.parseWebXml(source, fragment, true)) {
125 ok = false;
126 }
127127 }
128128 } else {
129129 // If there is no web.xml, normal folder no impact on
20812081
20822082 if (dest.getMaxFileSize() == null) {
20832083 dest.setMaxFileSize(src.getMaxFileSize());
2084 } else if (src.getLocation() != null) {
2084 } else if (src.getMaxFileSize() != null) {
20852085 if (failOnConflict &&
20862086 !src.getMaxFileSize().equals(dest.getMaxFileSize())) {
20872087 return false;
2222 import org.apache.juli.logging.LogFactory;
2323 import org.apache.tomcat.util.buf.ByteChunk;
2424 import org.apache.tomcat.util.buf.MessageBytes;
25 import org.apache.tomcat.util.http.parser.Cookie;
2526 import org.apache.tomcat.util.log.UserDataHelper;
2627 import org.apache.tomcat.util.res.StringManager;
2728
2829 /**
2930 * A collection of cookies - reusable and tuned for server side performance.
30 * Based on RFC2965 (and 2109).
31 * Based on RFC6265 and RFC2109.
3132 *
3233 * This class is not thread-safe.
3334 *
4546
4647 // expected average number of cookies per request
4748 public static final int INITIAL_SIZE = 4;
48 private ServerCookie scookies[] = new ServerCookie[INITIAL_SIZE];
49 private int cookieCount = 0;
49 private ServerCookies scookies = new ServerCookies(INITIAL_SIZE);
5050 private boolean unprocessed = true;
51 private boolean useRfc6265 = false;
5152
5253 private final MimeHeaders headers;
5354
6566
6667
6768 public void recycle() {
68 for (int i = 0; i < cookieCount; i++) {
69 if (scookies[i] != null) {
70 scookies[i].recycle();
71 }
72 }
73 cookieCount = 0;
69 scookies.recycle();
7470 unprocessed = true;
71 useRfc6265 = false;
7572 }
7673
7774
9996 // This will trigger cookie processing
10097 getCookieCount();
10198 }
102 return scookies[idx];
99 return scookies.getCookie(idx);
103100 }
104101
105102
108105 unprocessed = false;
109106 processCookies(headers);
110107 }
111 return cookieCount;
112 }
113
114
115 /**
116 * Register a new, initialized cookie. Cookies are recycled, and most of the
117 * time an existing ServerCookie object is returned. The caller can set the
118 * name/value and attributes for the cookie.
119 */
120 private ServerCookie addCookie() {
121 if (cookieCount >= scookies.length) {
122 ServerCookie scookiesTmp[] = new ServerCookie[2*cookieCount];
123 System.arraycopy(scookies, 0, scookiesTmp, 0, cookieCount);
124 scookies = scookiesTmp;
125 }
126
127 ServerCookie c = scookies[cookieCount];
128 if (c == null) {
129 c = new ServerCookie();
130 scookies[cookieCount] = c;
131 }
132 cookieCount++;
133 return c;
108 return scookies.getCookieCount();
134109 }
135110
136111
169144 // search from the next position
170145 pos = headers.findHeader("Cookie", ++pos);
171146 }
147 }
148
149
150 public void setUseRfc6265(boolean useRfc6265) {
151 this.useRfc6265 = useRfc6265;
172152 }
173153
174154
245225 }
246226
247227
228 final void processCookieHeader(byte bytes[], int off, int len) {
229 if (useRfc6265) {
230 Cookie.parseCookie(bytes, off, len, scookies);
231 } else {
232 doProcessCookieHeaderOriginal(bytes, off, len);
233 }
234 }
235
236
248237 /**
249238 * Parses a cookie header after the initial "Cookie:"
250239 * [WS][$]token[WS]=[WS](token|QV)[;|,]
251 * RFC 2965
240 * RFC 2965 / RFC 2109
252241 * JVK
253242 */
254 final void processCookieHeader(byte bytes[], int off, int len){
243 private void doProcessCookieHeaderOriginal(byte bytes[], int off, int len){
255244 if (len <= 0 || bytes == null) {
256245 return;
257246 }
470459 continue;
471460 }
472461
473 sc = addCookie();
462 sc = scookies.addCookie();
474463 sc.setVersion( version );
475464 sc.getName().setBytes( bytes, nameStart,
476465 nameEnd-nameStart);
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.http;
17
18 /**
19 * This class is not thread-safe.
20 */
21 public class ServerCookies {
22
23 private ServerCookie[] serverCookies;
24
25 private int cookieCount = 0;
26
27
28 public ServerCookies(int initialSize) {
29 serverCookies = new ServerCookie[initialSize];
30 }
31
32
33 /**
34 * Register a new, initialized cookie. Cookies are recycled, and most of the
35 * time an existing ServerCookie object is returned. The caller can set the
36 * name/value and attributes for the cookie.
37 */
38 public ServerCookie addCookie() {
39 if (cookieCount >= serverCookies.length) {
40 ServerCookie scookiesTmp[] = new ServerCookie[2*cookieCount];
41 System.arraycopy(serverCookies, 0, scookiesTmp, 0, cookieCount);
42 serverCookies = scookiesTmp;
43 }
44
45 ServerCookie c = serverCookies[cookieCount];
46 if (c == null) {
47 c = new ServerCookie();
48 serverCookies[cookieCount] = c;
49 }
50 cookieCount++;
51 return c;
52 }
53
54
55 public ServerCookie getCookie(int idx) {
56 return serverCookies[idx];
57 }
58
59
60 public int getCookieCount() {
61 return cookieCount;
62 }
63
64
65 public void recycle() {
66 for (int i = 0; i < cookieCount; i++) {
67 serverCookies[i].recycle();
68 }
69 cookieCount = 0;
70 }
71 }
6262
6363 // See if a quality has been provided
6464 double quality = 1;
65 HttpParser.SkipResult lookForSemiColon = HttpParser.skipConstant(input, ";");
66 if (lookForSemiColon == HttpParser.SkipResult.FOUND) {
65 SkipResult lookForSemiColon = HttpParser.skipConstant(input, ";");
66 if (lookForSemiColon == SkipResult.FOUND) {
6767 quality = HttpParser.readWeight(input, ',');
6868 }
6969
7777
7878 Map<String,String> result = new HashMap<>();
7979
80 if (HttpParser.skipConstant(input, "Digest") != HttpParser.SkipResult.FOUND) {
80 if (HttpParser.skipConstant(input, "Digest") != SkipResult.FOUND) {
8181 return null;
8282 }
8383 // All field names are valid tokens
8686 return null;
8787 }
8888 while (!field.equals("")) {
89 if (HttpParser.skipConstant(input, "=") != HttpParser.SkipResult.FOUND) {
89 if (HttpParser.skipConstant(input, "=") != SkipResult.FOUND) {
9090 return null;
9191 }
9292 String value;
126126 }
127127 result.put(field, value);
128128
129 if (HttpParser.skipConstant(input, ",") == HttpParser.SkipResult.NOT_FOUND) {
129 if (HttpParser.skipConstant(input, ",") == SkipResult.NOT_FOUND) {
130130 return null;
131131 }
132132 field = HttpParser.readToken(input);
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.http.parser;
17
18 import java.nio.charset.StandardCharsets;
19
20 import org.apache.juli.logging.Log;
21 import org.apache.juli.logging.LogFactory;
22 import org.apache.tomcat.util.http.ServerCookie;
23 import org.apache.tomcat.util.http.ServerCookies;
24 import org.apache.tomcat.util.log.UserDataHelper;
25 import org.apache.tomcat.util.res.StringManager;
26
27
28 /**
29 * <p>Cookie header parser based on RFC6265 and RFC2109.</p>
30 * <p>The parsing of cookies using RFC6265 is more relaxed that the
31 * specification in the following ways:</p>
32 * <ul>
33 * <li>Values 0x80 to 0xFF are permitted in cookie-octet to support the use of
34 * UTF-8 in cookie values as used by HTML 5.</li>
35 * <li>For cookies without a value, the '=' is not required after the name as
36 * some browsers do not sent it.</li>
37 * </ul>
38 * <p>The parsing of cookies using RFC2109 is more relaxed that the
39 * specification in the following ways:</p>
40 * <ul>
41 * <li>Values for the path attribute that contain a / character do not have to
42 * be quoted even though / is not permitted in a token.</li>
43 * </ul>
44 *
45 * <p>Implementation note:<br/>
46 * This class has been carefully tuned to ensure that it has equal or better
47 * performance than the original Netscape/RFC2109 cookie parser. Before
48 * committing and changes, ensure that the TesterCookiePerformance unit test
49 * continues to give results within 1% for the old and new parsers.</p>
50 */
51 public class Cookie {
52
53 private static final Log log = LogFactory.getLog(Cookie.class);
54 private static final UserDataHelper invalidCookieVersionLog = new UserDataHelper(log);
55 private static final UserDataHelper invalidCookieLog = new UserDataHelper(log);
56 private static final StringManager sm =
57 StringManager.getManager("org.apache.tomcat.util.http.parser");
58
59 private static final boolean isCookieOctet[] = new boolean[256];
60 private static final boolean isText[] = new boolean[256];
61 private static final byte[] VERSION_BYTES = "$Version".getBytes(StandardCharsets.ISO_8859_1);
62 private static final byte[] PATH_BYTES = "$Path".getBytes(StandardCharsets.ISO_8859_1);
63 private static final byte[] DOMAIN_BYTES = "$Domain".getBytes(StandardCharsets.ISO_8859_1);
64 private static final byte[] EMPTY_BYTES = new byte[0];
65 private static final byte TAB_BYTE = (byte) 0x09;
66 private static final byte SPACE_BYTE = (byte) 0x20;
67 private static final byte QUOTE_BYTE = (byte) 0x22;
68 private static final byte COMMA_BYTE = (byte) 0x2C;
69 private static final byte FORWARDSLASH_BYTE = (byte) 0x2F;
70 private static final byte SEMICOLON_BYTE = (byte) 0x3B;
71 private static final byte EQUALS_BYTE = (byte) 0x3D;
72 private static final byte SLASH_BYTE = (byte) 0x5C;
73 private static final byte DEL_BYTE = (byte) 0x7F;
74
75
76 static {
77 // %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E (RFC6265)
78 // %x80 to %xFF (UTF-8)
79 for (int i = 0; i < 256; i++) {
80 if (i < 0x21 || i == QUOTE_BYTE || i == COMMA_BYTE ||
81 i == SEMICOLON_BYTE || i == SLASH_BYTE || i == DEL_BYTE) {
82 isCookieOctet[i] = false;
83 } else {
84 isCookieOctet[i] = true;
85 }
86 }
87 for (int i = 0; i < 256; i++) {
88 if (i < 0x21 || i == DEL_BYTE) {
89 isText[i] = false;
90 } else {
91 isText[i] = true;
92 }
93 }
94 }
95
96
97 private Cookie() {
98 // Hide default constructor
99 }
100
101
102 public static void parseCookie(byte[] bytes, int offset, int len,
103 ServerCookies serverCookies) {
104
105 // ByteBuffer is used throughout this parser as it allows the byte[]
106 // and position information to be easily passed between parsing methods
107 ByteBuffer bb = new ByteBuffer(bytes, offset, len);
108
109 // Using RFC6265 parsing rules, check to see if the header starts with a
110 // version marker. An RFC2109 version marker may be read using RFC6265
111 // parsing rules. If version 1, use RFC2109. Else use RFC6265.
112
113 skipLWS(bb);
114
115 // Record position in case we need to return.
116 int mark = bb.position();
117
118 SkipResult skipResult = skipBytes(bb, VERSION_BYTES);
119 if (skipResult != SkipResult.FOUND) {
120 // No need to reset position since skipConstant() will have done it
121 parseCookieRfc6265(bb, serverCookies);
122 return;
123 }
124
125 skipLWS(bb);
126
127 skipResult = skipByte(bb, EQUALS_BYTE);
128 if (skipResult != SkipResult.FOUND) {
129 // Need to reset position as skipConstant() will only have reset to
130 // position before it was called
131 bb.position(mark);
132 parseCookieRfc6265(bb, serverCookies);
133 return;
134 }
135
136 skipLWS(bb);
137
138 ByteBuffer value = readCookieValue(bb);
139 if (value != null && value.remaining() == 1) {
140 if (value.get() == (byte) 49) {
141 // $Version=1 -> RFC2109
142 skipLWS(bb);
143 byte b = bb.get();
144 if (b == SEMICOLON_BYTE || b == COMMA_BYTE) {
145 parseCookieRfc2109(bb, serverCookies);
146 }
147 return;
148 } else {
149 // Unrecognised version.
150 // Ignore this header.
151 value.rewind();
152 logInvalidVersion(value);
153 }
154 } else {
155 // Unrecognised version.
156 // Ignore this header.
157 logInvalidVersion(value);
158 }
159 }
160
161
162 public static String unescapeCookieValueRfc2109(String input) {
163 if (input == null || input.length() < 2) {
164 return input;
165 }
166 if (input.charAt(0) != '"' && input.charAt(input.length() - 1) != '"') {
167 return input;
168 }
169
170 StringBuilder sb = new StringBuilder(input.length());
171 char[] chars = input.toCharArray();
172 boolean escaped = false;
173
174 for (int i = 1; i < input.length() - 1; i++) {
175 if (chars[i] == '\\') {
176 escaped = true;
177 } else if (escaped) {
178 escaped = false;
179 if (chars[i] < 128) {
180 sb.append(chars[i]);
181 } else {
182 sb.append('\\');
183 sb.append(chars[i]);
184 }
185 } else {
186 sb.append(chars[i]);
187 }
188 }
189 return sb.toString();
190 }
191
192
193 private static void parseCookieRfc6265(ByteBuffer bb, ServerCookies serverCookies) {
194
195 boolean moreToProcess = true;
196
197 while (moreToProcess) {
198 skipLWS(bb);
199
200 ByteBuffer name = readToken(bb);
201 ByteBuffer value = null;
202
203 skipLWS(bb);
204
205 SkipResult skipResult = skipByte(bb, EQUALS_BYTE);
206 if (skipResult == SkipResult.FOUND) {
207 skipLWS(bb);
208 value = readCookieValueRfc6265(bb);
209 if (value == null) {
210 logInvalidHeader(bb);
211 // Invalid cookie value. Skip to the next semi-colon
212 skipUntilSemiColon(bb);
213 continue;
214 }
215 skipLWS(bb);
216 }
217
218 skipResult = skipByte(bb, SEMICOLON_BYTE);
219 if (skipResult == SkipResult.FOUND) {
220 // NO-OP
221 } else if (skipResult == SkipResult.NOT_FOUND) {
222 logInvalidHeader(bb);
223 // Invalid cookie. Ignore it and skip to the next semi-colon
224 skipUntilSemiColon(bb);
225 continue;
226 } else {
227 // SkipResult.EOF
228 moreToProcess = false;
229 }
230
231 if (name.hasRemaining()) {
232 ServerCookie sc = serverCookies.addCookie();
233 sc.getName().setBytes(name.array(), name.position(), name.remaining());
234 if (value == null) {
235 sc.getValue().setBytes(EMPTY_BYTES, 0, EMPTY_BYTES.length);
236 } else {
237 sc.getValue().setBytes(value.array(), value.position(), value.remaining());
238 }
239 }
240 }
241 }
242
243
244 private static void parseCookieRfc2109(ByteBuffer bb, ServerCookies serverCookies) {
245
246 boolean moreToProcess = true;
247
248 while (moreToProcess) {
249 skipLWS(bb);
250
251 boolean parseAttributes = true;
252
253 ByteBuffer name = readToken(bb);
254 ByteBuffer value = null;
255 ByteBuffer path = null;
256 ByteBuffer domain = null;
257
258 skipLWS(bb);
259
260 SkipResult skipResult = skipByte(bb, EQUALS_BYTE);
261 if (skipResult == SkipResult.FOUND) {
262 skipLWS(bb);
263 value = readCookieValueRfc2109(bb, false);
264 if (value == null) {
265 skipInvalidCookie(bb);
266 continue;
267 }
268 skipLWS(bb);
269 }
270
271 skipResult = skipByte(bb, COMMA_BYTE);
272 if (skipResult == SkipResult.FOUND) {
273 parseAttributes = false;
274 }
275 skipResult = skipByte(bb, SEMICOLON_BYTE);
276 if (skipResult == SkipResult.EOF) {
277 parseAttributes = false;
278 moreToProcess = false;
279 } else if (skipResult == SkipResult.NOT_FOUND) {
280 skipInvalidCookie(bb);
281 continue;
282 }
283
284 if (parseAttributes) {
285 skipResult = skipBytes(bb, PATH_BYTES);
286 if (skipResult == SkipResult.FOUND) {
287 skipLWS(bb);
288 skipResult = skipByte(bb, EQUALS_BYTE);
289 if (skipResult != SkipResult.FOUND) {
290 skipInvalidCookie(bb);
291 continue;
292 }
293 path = readCookieValueRfc2109(bb, true);
294 if (path == null) {
295 skipInvalidCookie(bb);
296 continue;
297 }
298 skipLWS(bb);
299
300 skipResult = skipByte(bb, COMMA_BYTE);
301 if (skipResult == SkipResult.FOUND) {
302 parseAttributes = false;
303 }
304 skipResult = skipByte(bb, SEMICOLON_BYTE);
305 if (skipResult == SkipResult.EOF) {
306 parseAttributes = false;
307 moreToProcess = false;
308 } else if (skipResult == SkipResult.NOT_FOUND) {
309 skipInvalidCookie(bb);
310 continue;
311 }
312 }
313 }
314
315 if (parseAttributes) {
316 skipResult = skipBytes(bb, DOMAIN_BYTES);
317 if (skipResult == SkipResult.FOUND) {
318 skipLWS(bb);
319 skipResult = skipByte(bb, EQUALS_BYTE);
320 if (skipResult != SkipResult.FOUND) {
321 skipInvalidCookie(bb);
322 continue;
323 }
324 domain = readCookieValueRfc2109(bb, false);
325 if (domain == null) {
326 skipInvalidCookie(bb);
327 continue;
328 }
329
330 skipResult = skipByte(bb, COMMA_BYTE);
331 if (skipResult == SkipResult.FOUND) {
332 parseAttributes = false;
333 }
334 skipResult = skipByte(bb, SEMICOLON_BYTE);
335 if (skipResult == SkipResult.EOF) {
336 parseAttributes = false;
337 moreToProcess = false;
338 } else if (skipResult == SkipResult.NOT_FOUND) {
339 skipInvalidCookie(bb);
340 continue;
341 }
342 }
343 }
344
345 if (name.hasRemaining() && value != null && value.hasRemaining()) {
346 ServerCookie sc = serverCookies.addCookie();
347 sc.setVersion(1);
348 sc.getName().setBytes(name.array(), name.position(), name.remaining());
349 sc.getValue().setBytes(value.array(), value.position(), value.remaining());
350 if (domain != null) {
351 sc.getDomain().setBytes(domain.array(), domain.position(), domain.remaining());
352 }
353 if (path != null) {
354 sc.getPath().setBytes(path.array(), path.position(), path.remaining());
355 }
356 }
357 }
358 }
359
360
361 private static void skipInvalidCookie(ByteBuffer bb) {
362 logInvalidHeader(bb);
363 // Invalid cookie value. Skip to the next semi-colon
364 skipUntilSemiColonOrComma(bb);
365 }
366
367
368 private static void skipLWS(ByteBuffer bb) {
369 while(bb.hasRemaining()) {
370 byte b = bb.get();
371 if (b != TAB_BYTE && b != SPACE_BYTE) {
372 bb.rewind();
373 break;
374 }
375 }
376 }
377
378
379 private static void skipUntilSemiColon(ByteBuffer bb) {
380 while(bb.hasRemaining()) {
381 if (bb.get() == SEMICOLON_BYTE) {
382 break;
383 }
384 }
385 }
386
387
388 private static void skipUntilSemiColonOrComma(ByteBuffer bb) {
389 while(bb.hasRemaining()) {
390 byte b = bb.get();
391 if (b == SEMICOLON_BYTE || b == COMMA_BYTE) {
392 break;
393 }
394 }
395 }
396
397
398 private static SkipResult skipByte(ByteBuffer bb, byte target) {
399
400 if (!bb.hasRemaining()) {
401 return SkipResult.EOF;
402 }
403 if (bb.get() == target) {
404 return SkipResult.FOUND;
405 }
406
407 bb.rewind();
408 return SkipResult.NOT_FOUND;
409 }
410
411
412 private static SkipResult skipBytes(ByteBuffer bb, byte[] target) {
413 int mark = bb.position();
414
415 for (int i = 0; i < target.length; i++) {
416 if (!bb.hasRemaining()) {
417 bb.position(mark);
418 return SkipResult.EOF;
419 }
420 if (bb.get() != target[i]) {
421 bb.position(mark);
422 return SkipResult.NOT_FOUND;
423 }
424 }
425 return SkipResult.FOUND;
426 }
427
428
429 /**
430 * Similar to readCookieValueRfc6265() but also allows a comma to terminate
431 * the value (as permitted by RFC2109).
432 */
433 private static ByteBuffer readCookieValue(ByteBuffer bb) {
434 boolean quoted = false;
435 if (bb.hasRemaining()) {
436 if (bb.get() == QUOTE_BYTE) {
437 quoted = true;
438 } else {
439 bb.rewind();
440 }
441 }
442 int start = bb.position();
443 int end = bb.limit();
444 while (bb.hasRemaining()) {
445 byte b = bb.get();
446 if (isCookieOctet[(b & 0xFF)]) {
447 // NO-OP
448 } else if (b == SEMICOLON_BYTE || b == COMMA_BYTE || b == SPACE_BYTE || b == TAB_BYTE) {
449 end = bb.position() - 1;
450 bb.position(end);
451 break;
452 } else if (quoted && b == QUOTE_BYTE) {
453 end = bb.position() - 1;
454 break;
455 } else {
456 // Invalid cookie
457 return null;
458 }
459 }
460
461 return new ByteBuffer(bb.bytes, start, end - start);
462 }
463
464
465 /**
466 * Similar to readCookieValue() but treats a comma as part of an invalid
467 * value.
468 */
469 private static ByteBuffer readCookieValueRfc6265(ByteBuffer bb) {
470 boolean quoted = false;
471 if (bb.hasRemaining()) {
472 if (bb.get() == QUOTE_BYTE) {
473 quoted = true;
474 } else {
475 bb.rewind();
476 }
477 }
478 int start = bb.position();
479 int end = bb.limit();
480 while (bb.hasRemaining()) {
481 byte b = bb.get();
482 if (isCookieOctet[(b & 0xFF)]) {
483 // NO-OP
484 } else if (b == SEMICOLON_BYTE || b == SPACE_BYTE || b == TAB_BYTE) {
485 end = bb.position() - 1;
486 bb.position(end);
487 break;
488 } else if (quoted && b == QUOTE_BYTE) {
489 end = bb.position() - 1;
490 break;
491 } else {
492 // Invalid cookie
493 return null;
494 }
495 }
496
497 return new ByteBuffer(bb.bytes, start, end - start);
498 }
499
500
501 private static ByteBuffer readCookieValueRfc2109(ByteBuffer bb, boolean allowForwardSlash) {
502 if (!bb.hasRemaining()) {
503 return null;
504 }
505
506 if (bb.peek() == QUOTE_BYTE) {
507 return readQuotedString(bb);
508 } else {
509 if (allowForwardSlash) {
510 return readTokenAllowForwardSlash(bb);
511 } else {
512 return readToken(bb);
513 }
514 }
515 }
516
517
518 private static ByteBuffer readToken(ByteBuffer bb) {
519 final int start = bb.position();
520 int end = bb.limit();
521 while (bb.hasRemaining()) {
522 if (!HttpParser.isToken(bb.get())) {
523 end = bb.position() - 1;
524 bb.position(end);
525 break;
526 }
527 }
528
529 return new ByteBuffer(bb.bytes, start, end - start);
530 }
531
532
533 private static ByteBuffer readTokenAllowForwardSlash(ByteBuffer bb) {
534 final int start = bb.position();
535 int end = bb.limit();
536 while (bb.hasRemaining()) {
537 byte b = bb.get();
538 if (b != FORWARDSLASH_BYTE && !HttpParser.isToken(b)) {
539 end = bb.position() - 1;
540 bb.position(end);
541 break;
542 }
543 }
544
545 return new ByteBuffer(bb.bytes, start, end - start);
546 }
547
548
549 private static ByteBuffer readQuotedString(ByteBuffer bb) {
550 int start = bb.position();
551
552 // Read the opening quote
553 bb.get();
554 boolean escaped = false;
555 while (bb.hasRemaining()) {
556 byte b = bb.get();
557 if (b == SLASH_BYTE) {
558 // Escaping another character
559 escaped = true;
560 } else if (escaped && b > (byte) -1) {
561 escaped = false;
562 } else if (b == QUOTE_BYTE) {
563 return new ByteBuffer(bb.bytes, start, bb.position() - start);
564 } else if (isText[b & 0xFF]) {
565 escaped = false;
566 } else {
567 return null;
568 }
569 }
570
571 return null;
572 }
573
574
575 private static void logInvalidHeader(ByteBuffer bb) {
576 UserDataHelper.Mode logMode = invalidCookieLog.getNextMode();
577 if (logMode != null) {
578 String headerValue = new String(bb.array(), bb.position(), bb.limit() - bb.position(),
579 StandardCharsets.UTF_8);
580 String message = sm.getString("cookie.invalidCookieValue", headerValue);
581 switch (logMode) {
582 case INFO_THEN_DEBUG:
583 message += sm.getString("cookie.fallToDebug");
584 //$FALL-THROUGH$
585 case INFO:
586 log.info(message);
587 break;
588 case DEBUG:
589 log.debug(message);
590 }
591 }
592 }
593
594
595 private static void logInvalidVersion(ByteBuffer value) {
596 UserDataHelper.Mode logMode = invalidCookieVersionLog.getNextMode();
597 if (logMode != null) {
598 String version;
599 if (value == null) {
600 version = sm.getString("cookie.valueNotPresent");
601 } else {
602 version = new String(value.bytes, value.position(),
603 value.limit() - value.position(), StandardCharsets.UTF_8);
604 }
605 String message = sm.getString("cookie.invalidCookieVersion", version);
606 switch (logMode) {
607 case INFO_THEN_DEBUG:
608 message += sm.getString("cookie.fallToDebug");
609 //$FALL-THROUGH$
610 case INFO:
611 log.info(message);
612 break;
613 case DEBUG:
614 log.debug(message);
615 }
616 }
617 }
618
619
620 /**
621 * Custom implementation that skips many of the safety checks in
622 * {@link javax.nio.ByteBuffer}.
623 */
624 private static class ByteBuffer {
625
626 private final byte[] bytes;
627 private int limit;
628 private int position = 0;
629
630 public ByteBuffer(byte[] bytes, int offset, int len) {
631 this.bytes = bytes;
632 this.position = offset;
633 this.limit = offset + len;
634 }
635
636 public int position() {
637 return position;
638 }
639
640 public void position(int position) {
641 this.position = position;
642 }
643
644 public int limit() {
645 return limit;
646 }
647
648 public int remaining() {
649 return limit - position;
650 }
651
652 public boolean hasRemaining() {
653 return position < limit;
654 }
655
656 public byte get() {
657 return bytes[position++];
658 }
659
660 public byte peek() {
661 return bytes[position];
662 }
663
664 public void rewind() {
665 position--;
666 }
667
668 public byte[] array() {
669 return bytes;
670 }
671
672 // For debug purposes
673 @Override
674 public String toString() {
675 return "position [" + position + "], limit [" + limit + "]";
676 }
677 }
678 }
397397 return SkipResult.FOUND;
398398 }
399399 }
400
401
402 static enum SkipResult {
403 FOUND,
404 NOT_FOUND,
405 EOF
406 }
407400 }
0 # Licensed to the Apache Software Foundation (ASF) under one or more
1 # contributor license agreements. See the NOTICE file distributed with
2 # this work for additional information regarding copyright ownership.
3 # The ASF licenses this file to You under the Apache License, Version 2.0
4 # (the "License"); you may not use this file except in compliance with
5 # the License. You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 cookie.fallToDebug=Note: further occurrences of this error will be logged at DEBUG level.
16 cookie.invalidCookieValue=A cookie header was received [{0}] that contained an invalid cookie. That cookie will be ignored.
17 cookie.invalidCookieVersion=A cookie header was received using an unrecognised cookie version of [{0}]. The header and the cookies it contains will be ignored.
18 cookie.valueNotPresent=<not present>
137137 return null;
138138 }
139139
140 if (HttpParser.skipConstant(input, "/") == HttpParser.SkipResult.NOT_FOUND) {
140 if (HttpParser.skipConstant(input, "/") == SkipResult.NOT_FOUND) {
141141 return null;
142142 }
143143
149149
150150 LinkedHashMap<String,String> parameters = new LinkedHashMap<>();
151151
152 HttpParser.SkipResult lookForSemiColon = HttpParser.skipConstant(input, ";");
153 if (lookForSemiColon == HttpParser.SkipResult.NOT_FOUND) {
152 SkipResult lookForSemiColon = HttpParser.skipConstant(input, ";");
153 if (lookForSemiColon == SkipResult.NOT_FOUND) {
154154 return null;
155155 }
156 while (lookForSemiColon == HttpParser.SkipResult.FOUND) {
156 while (lookForSemiColon == SkipResult.FOUND) {
157157 String attribute = HttpParser.readToken(input);
158158
159159 String value = "";
160 if (HttpParser.skipConstant(input, "=") == HttpParser.SkipResult.FOUND) {
160 if (HttpParser.skipConstant(input, "=") == SkipResult.FOUND) {
161161 value = HttpParser.readTokenOrQuotedString(input, true);
162162 }
163163
166166 }
167167
168168 lookForSemiColon = HttpParser.skipConstant(input, ";");
169 if (lookForSemiColon == HttpParser.SkipResult.NOT_FOUND) {
169 if (lookForSemiColon == SkipResult.NOT_FOUND) {
170170 return null;
171171 }
172172 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.http.parser;
17
18 enum SkipResult {
19 FOUND,
20 NOT_FOUND,
21 EOF
22 }
351351 // TODO : Investigate if it is possible to extract the current list of
352352 // available ciphers. Native code changes will be required.
353353 return new String[] { getSSLCipherSuite() };
354 }
355
356
357 /**
358 * This endpoint does not support <code>-1</code> for unlimited connections,
359 * nor does it support setting this attribute while the endpoint is running.
360 *
361 * {@inheritDoc}
362 */
363 @Override
364 public void setMaxConnections(int maxConnections) {
365 if (maxConnections == -1) {
366 log.warn(sm.getString("endpoint.apr.maxConnections.unlimited",
367 Integer.valueOf(getMaxConnections())));
368 return;
369 }
370 if (running) {
371 log.warn(sm.getString("endpoint.apr.maxConnections.running",
372 Integer.valueOf(getMaxConnections())));
373 return;
374 }
375 super.setMaxConnections(maxConnections);
354376 }
355377
356378
5151 endpoint.timeout.err=Error processing socket timeout
5252 endpoint.apr.failSslContextMake=Unable to create SSLContext. Check that SSLEngine is enabled in the AprLifecycleListener, the AprLifecycleListener has initialised correctly and that a valid SSLProtocol has been specified
5353 endpoint.apr.invalidSslProtocol=An invalid value [{0}] was provided for the SSLProtocol attribute
54 endpoint.apr.maxConnections.running=The APR endpoint does not support the setting of maxConnections while it is running. The existing value of [{0}] will continue to be used.
55 endpoint.apr.maxConnections.unlimited=The APR endpoint does not support unlimited connections. The existing value of [{0}] will continue to be used.
5456 endpoint.apr.noSendfileWithSSL=Sendfile is not supported for the APR/native connector when SSL is enabled
5557 endpoint.apr.noSslCertFile=Connector attribute SSLCertificateFile must be defined when using SSL with APR
5658 endpoint.apr.pollAddInvalid=Invalid attempted to add a socket [{0}] to the poller
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.security;
17
18 import java.security.MessageDigest;
19 import java.security.NoSuchAlgorithmException;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Queue;
23 import java.util.concurrent.ConcurrentLinkedQueue;
24
25 /**
26 * A thread safe wrapper around {@link MessageDigest} that does not make use
27 * of ThreadLocal and - broadly - only creates enough MessageDigest objects
28 * to satisfy the concurrency requirements.
29 */
30 public class ConcurrentMessageDigest {
31
32 private static final String MD5 = "MD5";
33 private static final String SHA1 = "SHA-1";
34
35 private static final Map<String,Queue<MessageDigest>> queues =
36 new HashMap<>();
37
38
39 private ConcurrentMessageDigest() {
40 // Hide default constructor for this utility class
41 }
42
43 static {
44 try {
45 // Init commonly used algorithms
46 init(MD5);
47 init(SHA1);
48 } catch (NoSuchAlgorithmException e) {
49 throw new IllegalArgumentException(e);
50 }
51 }
52
53 public static byte[] digestMD5(byte[]... input) {
54 return digest(MD5, input);
55 }
56
57 public static byte[] digestSHA1(byte[]... input) {
58 return digest(SHA1, input);
59 }
60
61 public static byte[] digest(String algorithm, byte[]... input) {
62
63 Queue<MessageDigest> queue = queues.get(algorithm);
64 if (queue == null) {
65 throw new IllegalStateException("Must call init() first");
66 }
67
68 MessageDigest md = queue.poll();
69 if (md == null) {
70 try {
71 md = MessageDigest.getInstance(algorithm);
72 } catch (NoSuchAlgorithmException e) {
73 // Ignore. Impossible if init() has been successfully called
74 // first.
75 throw new IllegalStateException("Must call init() first");
76 }
77 }
78
79 for (byte[] bytes : input) {
80 md.update(bytes);
81 }
82 byte[] result = md.digest();
83
84 queue.add(md);
85
86 return result;
87 }
88
89
90 /**
91 * Ensures that {@link #digest(String, byte[])} will support the specified
92 * algorithm. This method <b>must</b> be called and return successfully
93 * before using {@link #digest(String, byte[])}.
94 *
95 * @param algorithm The message digest algorithm to be supported
96 *
97 * @throws NoSuchAlgorithmException If the algorithm is not supported by the
98 * JVM
99 */
100 public static void init(String algorithm) throws NoSuchAlgorithmException {
101 synchronized (queues) {
102 if (!queues.containsKey(algorithm)) {
103 MessageDigest md = MessageDigest.getInstance(algorithm);
104 Queue<MessageDigest> queue = new ConcurrentLinkedQueue<>();
105 queue.add(md);
106 queues.put(algorithm, queue);
107 }
108 }
109 }
110 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.security;
17
18 /**
19 * Encode an MD5 digest into a String.
20 * <p>
21 * The 128 bit MD5 hash is converted into a 32 character long String.
22 * Each character of the String is the hexadecimal representation of 4 bits
23 * of the digest.
24 *
25 * @author Remy Maucherat
26 */
27 public final class MD5Encoder {
28
29
30 private MD5Encoder() {
31 // Hide default constructor for utility class
32 }
33
34
35 private static final char[] hexadecimal = {'0', '1', '2', '3', '4', '5',
36 '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
37
38
39 /**
40 * Encodes the 128 bit (16 bytes) MD5 into a 32 character String.
41 *
42 * @param binaryData Array containing the digest
43 *
44 * @return Encoded MD5, or null if encoding failed
45 */
46 public static String encode(byte[] binaryData) {
47
48 if (binaryData.length != 16)
49 return null;
50
51 char[] buffer = new char[32];
52
53 for (int i=0; i<16; i++) {
54 int low = binaryData[i] & 0x0f;
55 int high = (binaryData[i] & 0xf0) >> 4;
56 buffer[i*2] = hexadecimal[high];
57 buffer[i*2 + 1] = hexadecimal[low];
58 }
59
60 return new String(buffer);
61 }
62 }
63
2323 public static final String Package = "org.apache.tomcat.util.threads";
2424
2525 public static final long DEFAULT_THREAD_RENEWAL_DELAY = 1000L;
26
27 /**
28 * Has security been turned on?
29 */
30 public static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null);
2631 }
2020 import java.util.concurrent.ThreadFactory;
2121 import java.util.concurrent.atomic.AtomicInteger;
2222
23 import org.apache.tomcat.util.net.Constants;
2423 import org.apache.tomcat.util.security.PrivilegedSetTccl;
24
2525 /**
2626 * Simple task thread factory to use to create threads for an executor
2727 * implementation.
5050 private final Inflater inflater = new Inflater(true);
5151 private final ByteBuffer readBuffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE);
5252 private final Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
53 private final byte[] EOM_BUFFER = new byte[EOM_BYTES.length + 1];
5354
5455 private volatile Transformation next;
5556 private volatile boolean skipDecompression = false;
5657 private volatile ByteBuffer writeBuffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE);
5758 private volatile boolean firstCompressedFrameWritten = false;
58 private volatile byte[] EOM_BUFFER = new byte[EOM_BYTES.length + 1];
5959
6060 static PerMessageDeflate negotiate(List<List<Parameter>> preferences) {
6161 // Accept the first preference that the server is able to support
171171 }
172172
173173
174 public static Class<?> getDecoderType(Class<? extends Decoder> decoder) {
174 private static Class<?> getDecoderType(Class<? extends Decoder> decoder) {
175175 return Util.getGenericType(Decoder.class, decoder).getClazz();
176176 }
177177
352352 }
353353
354354
355 public static Set<MessageHandlerResult> getMessageHandlers(
355 static Set<MessageHandlerResult> getMessageHandlers(Class<?> target,
356356 MessageHandler listener, EndpointConfig endpointConfig,
357357 Session session) {
358
359 Class<?> target = Util.getMessageType(listener);
360358
361359 // Will never be more than 2 types
362360 Set<MessageHandlerResult> results = new HashSet<>(2);
3636 import javax.websocket.EndpointConfig;
3737 import javax.websocket.Extension;
3838 import javax.websocket.MessageHandler;
39 import javax.websocket.MessageHandler.Partial;
40 import javax.websocket.MessageHandler.Whole;
3941 import javax.websocket.PongMessage;
4042 import javax.websocket.RemoteEndpoint;
4143 import javax.websocket.SendResult;
7476 private final Principal userPrincipal;
7577 private final EndpointConfig endpointConfig;
7678
79 private final List<Extension> negotiatedExtensions;
7780 private final String subProtocol;
7881 private final Map<String,String> pathParameters;
7982 private final boolean secure;
104107 *
105108 * @param localEndpoint
106109 * @param wsRemoteEndpoint
110 * @param negotiatedExtensions
107111 * @throws DeploymentException
108112 */
109113 public WsSession(Endpoint localEndpoint,
111115 WsWebSocketContainer wsWebSocketContainer,
112116 URI requestUri, Map<String,List<String>> requestParameterMap,
113117 String queryString, Principal userPrincipal, String httpSessionId,
114 String subProtocol, Map<String,String> pathParameters,
118 List<Extension> negotiatedExtensions, String subProtocol, Map<String,String> pathParameters,
115119 boolean secure, EndpointConfig endpointConfig) throws DeploymentException {
116120 this.localEndpoint = localEndpoint;
117121 this.wsRemoteEndpoint = wsRemoteEndpoint;
137141 this.queryString = queryString;
138142 this.userPrincipal = userPrincipal;
139143 this.httpSessionId = httpSessionId;
144 this.negotiatedExtensions = negotiatedExtensions;
140145 if (subProtocol == null) {
141146 this.subProtocol = "";
142147 } else {
159164 }
160165
161166
167 @Override
168 public void addMessageHandler(MessageHandler listener) {
169 Class<?> target = Util.getMessageType(listener);
170 doAddMessageHandler(target, listener);
171 }
172
173
174 @Override
175 public <T> void addMessageHandler(Class<T> clazz, Partial<T> handler)
176 throws IllegalStateException {
177 doAddMessageHandler(clazz, handler);
178 }
179
180
181 @Override
182 public <T> void addMessageHandler(Class<T> clazz, Whole<T> handler)
183 throws IllegalStateException {
184 doAddMessageHandler(clazz, handler);
185 }
186
187
162188 @SuppressWarnings("unchecked")
163 @Override
164 public void addMessageHandler(MessageHandler listener) {
165
189 private void doAddMessageHandler(Class<?> target, MessageHandler listener) {
166190 checkState();
167191
168192 // Message handlers that require decoders may map to text messages,
176200 // just as easily.
177201
178202 Set<MessageHandlerResult> mhResults =
179 Util.getMessageHandlers(listener, endpointConfig, this);
203 Util.getMessageHandlers(target, listener, endpointConfig, this);
180204
181205 for (MessageHandlerResult mhResult : mhResults) {
182206 switch (mhResult.getType()) {
301325 @Override
302326 public List<Extension> getNegotiatedExtensions() {
303327 checkState();
304 return Collections.emptyList();
328 return negotiatedExtensions;
305329 }
306330
307331
272272
273273 ByteBuffer response;
274274 String subProtocol;
275 boolean success = false;
275276 try {
276277 fConnect.get(timeout, TimeUnit.MILLISECONDS);
277278
309310 throw new DeploymentException(
310311 sm.getString("Sec-WebSocket-Protocol"));
311312 }
313 success = true;
312314 } catch (ExecutionException | InterruptedException | SSLException |
313315 EOFException | TimeoutException e) {
314316 throw new DeploymentException(
315317 sm.getString("wsWebSocketContainer.httpRequestFailed"), e);
318 } finally {
319 if (!success) {
320 channel.close();
321 }
316322 }
317323
318324 // Switch to WebSocket
319325 WsRemoteEndpointImplClient wsRemoteEndpointClient = new WsRemoteEndpointImplClient(channel);
320326
321327 WsSession wsSession = new WsSession(endpoint, wsRemoteEndpointClient,
322 this, null, null, null, null, null, subProtocol,
323 Collections.<String, String> emptyMap(), secure,
328 this, null, null, null, null, null, Collections.<Extension>emptyList(),
329 subProtocol, Collections.<String,String>emptyMap(), secure,
324330 clientEndpointConfiguration);
325331
326332 WsFrameClient wsFrameClient = new WsFrameClient(response, channel,
3535 setPojo(pojo);
3636 setMethodMapping(
3737 new PojoMethodMapping(pojo.getClass(), decoders, null));
38 setPathParameters(Collections.<String, String> emptyMap());
38 setPathParameters(Collections.<String,String>emptyMap());
3939 }
4040
4141 @Override
2424 * ByteBuffer specific concrete implementation for handling partial messages.
2525 */
2626 public class PojoMessageHandlerPartialBinary
27 extends PojoMessageHandlerPartialBase<ByteBuffer>{
27 extends PojoMessageHandlerPartialBase<ByteBuffer> {
2828
2929 public PojoMessageHandlerPartialBinary(Object pojo, Method method,
3030 Session session, Object[] params, int indexPayload, boolean convert,
2323 * Text specific concrete implementation for handling partial messages.
2424 */
2525 public class PojoMessageHandlerPartialText
26 extends PojoMessageHandlerPartialBase<String>{
26 extends PojoMessageHandlerPartialBase<String> {
2727
2828 public PojoMessageHandlerPartialText(Object pojo, Method method,
2929 Session session, Object[] params, int indexPayload, boolean convert,
2121 serverContainer.pojoDeploy=POJO class [{0}] deploying to path [{1}] in ServletContext [{2}]
2222 serverContainer.servletContextMismatch=Attempted to register a POJO annotated for WebSocket at path [{0}] in the ServletContext with context path [{1}] when the WebSocket ServerContainer is allocated to the ServletContext with context path [{2}]
2323 serverContainer.servletContextMissing=No ServletContext was specified
24 serverContainer.threadGroupNotDestroyed=Unable to destroy WebSocket thread group [{0}] as some threads were still running when the web application was stopped
24 serverContainer.threadGroupNotDestroyed=Unable to destroy WebSocket thread group [{0}] as [{1}] threads were still running when the web application was stopped. The thread group will be destroyed once the threads terminate.
2525
2626 uriTemplate.duplicateParameter=The parameter [{0}] appears more than once in the path which is not permitted
2727 uriTemplate.emptySegment=The path [{0}] contains one or more empty segments which are is not permitted
1717
1818 import java.io.IOException;
1919 import java.nio.charset.StandardCharsets;
20 import java.security.MessageDigest;
21 import java.security.NoSuchAlgorithmException;
2220 import java.util.ArrayList;
21 import java.util.Collections;
2322 import java.util.Enumeration;
2423 import java.util.LinkedHashMap;
2524 import java.util.List;
2625 import java.util.Map;
2726 import java.util.Map.Entry;
28 import java.util.Queue;
29 import java.util.concurrent.ConcurrentLinkedQueue;
3027
3128 import javax.servlet.ServletException;
3229 import javax.servlet.ServletRequest;
3936 import javax.websocket.server.ServerEndpointConfig;
4037
4138 import org.apache.tomcat.util.codec.binary.Base64;
39 import org.apache.tomcat.util.security.ConcurrentMessageDigest;
4240 import org.apache.tomcat.websocket.Constants;
4341 import org.apache.tomcat.websocket.Transformation;
4442 import org.apache.tomcat.websocket.TransformationFactory;
5149 private static final byte[] WS_ACCEPT =
5250 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(
5351 StandardCharsets.ISO_8859_1);
54 private static final Queue<MessageDigest> sha1Helpers =
55 new ConcurrentLinkedQueue<>();
5652
5753 private UpgradeUtil() {
5854 // Utility class. Hide default constructor.
126122 while (extHeaders.hasMoreElements()) {
127123 Util.parseExtensionHeader(extensionsRequested, extHeaders.nextElement());
128124 }
129 List<Extension> negotiatedExtensions = sec.getConfigurator().getNegotiatedExtensions(
125 // Negotiation phase 1. By default this simply filters out the
126 // extensions that the server does not support but applications could
127 // use a custom configurator to do more than this.
128 List<Extension> negotiatedExtensionsPhase1 = sec.getConfigurator().getNegotiatedExtensions(
130129 Constants.INSTALLED_EXTENSIONS, extensionsRequested);
131130
132 // Create the Transformations that will be applied to this connection
133 List<Transformation> transformations = createTransformations(negotiatedExtensions);
131 // Negotiation phase 2. Create the Transformations that will be applied
132 // to this connection. Note than an extension may be dropped at this
133 // point if the client has requested a configuration that the server is
134 // unable to support.
135 List<Transformation> transformations = createTransformations(negotiatedExtensionsPhase1);
136
137 List<Extension> negotiatedExtensionsPhase2;
138 if (transformations.isEmpty()) {
139 negotiatedExtensionsPhase2 = Collections.emptyList();
140 } else {
141 negotiatedExtensionsPhase2 = new ArrayList<>(transformations.size());
142 for (Transformation t : transformations) {
143 negotiatedExtensionsPhase2.add(t.getExtensionResponse());
144 }
145 }
134146
135147 // Build the transformation pipeline
136148 Transformation transformation = null;
203215 WsHttpUpgradeHandler wsHandler =
204216 req.upgrade(WsHttpUpgradeHandler.class);
205217 wsHandler.preInit(ep, perSessionServerEndpointConfig, sc, wsRequest,
206 subProtocol, transformation, pathParams, req.isSecure());
218 negotiatedExtensionsPhase2, subProtocol, transformation, pathParams,
219 req.isSecure());
207220
208221 }
209222
299312 }
300313
301314
302 private static String getWebSocketAccept(String key) throws ServletException {
303 MessageDigest sha1Helper = sha1Helpers.poll();
304 if (sha1Helper == null) {
305 try {
306 sha1Helper = MessageDigest.getInstance("SHA1");
307 } catch (NoSuchAlgorithmException e) {
308 throw new ServletException(e);
309 }
310 }
311 sha1Helper.reset();
312 sha1Helper.update(key.getBytes(StandardCharsets.ISO_8859_1));
313 String result = Base64.encodeBase64String(sha1Helper.digest(WS_ACCEPT));
314 sha1Helpers.add(sha1Helper);
315 return result;
315 private static String getWebSocketAccept(String key) {
316 byte[] digest = ConcurrentMessageDigest.digestSHA1(
317 key.getBytes(StandardCharsets.ISO_8859_1), WS_ACCEPT);
318 return Base64.encodeBase64String(digest);
316319 }
317320 }
1717
1818 import java.io.EOFException;
1919 import java.io.IOException;
20 import java.util.List;
2021 import java.util.Map;
2122
2223 import javax.servlet.ReadListener;
3132 import javax.websocket.DeploymentException;
3233 import javax.websocket.Endpoint;
3334 import javax.websocket.EndpointConfig;
35 import javax.websocket.Extension;
3436
3537 import org.apache.juli.logging.Log;
3638 import org.apache.juli.logging.LogFactory;
5557 private EndpointConfig endpointConfig;
5658 private WsServerContainer webSocketContainer;
5759 private WsHandshakeRequest handshakeRequest;
60 private List<Extension> negotiatedExtensions;
5861 private String subProtocol;
5962 private Transformation transformation;
6063 private Map<String,String> pathParameters;
7174
7275 public void preInit(Endpoint ep, EndpointConfig endpointConfig,
7376 WsServerContainer wsc, WsHandshakeRequest handshakeRequest,
74 String subProtocol, Transformation transformation,
75 Map<String,String> pathParameters, boolean secure) {
77 List<Extension> negotiatedExtensionsPhase2, String subProtocol,
78 Transformation transformation, Map<String,String> pathParameters,
79 boolean secure) {
7680 this.ep = ep;
7781 this.endpointConfig = endpointConfig;
7882 this.webSocketContainer = wsc;
7983 this.handshakeRequest = handshakeRequest;
84 this.negotiatedExtensions = negotiatedExtensionsPhase2;
8085 this.subProtocol = subProtocol;
8186 this.transformation = transformation;
8287 this.pathParameters = pathParameters;
122127 handshakeRequest.getParameterMap(),
123128 handshakeRequest.getQueryString(),
124129 handshakeRequest.getUserPrincipal(), httpSessionId,
125 subProtocol, pathParameters, secure, endpointConfig);
130 negotiatedExtensions, subProtocol, pathParameters, secure,
131 endpointConfig);
126132 WsFrameServer wsFrame = new WsFrameServer(sis, wsSession, transformation);
127133 sos.setWriteListener(new WsWriteListener(this, wsRemoteEndpointServer));
128134 // WsFrame adds the necessary final transformations. Copy the
139139
140140 fr.addMappingForUrlPatterns(types, true, "/*");
141141
142 // Use a per web application executor for any threads the the WebSocket
142 // Use a per web application executor for any threads that the WebSocket
143143 // server code needs to create. Group all of the threads under a single
144144 // ThreadGroup.
145145 StringBuffer threadGroupName = new StringBuffer("WebSocketServer-");
272272 public void destroy() {
273273 shutdownExecutor();
274274 super.destroy();
275 // If the executor hasn't fully shutdown it won't be possible to
276 // destroy this thread group as there will still be threads running.
277 // Mark the thread group as daemon one, so that it destroys itself
278 // when thread count reaches zero.
279 // Synchronization on threadGroup is needed, as there is a race between
280 // destroy() call from termination of the last thread in thread group
281 // marked as daemon versus the explicit destroy() call.
282 int threadCount = threadGroup.activeCount();
283 boolean success = false;
275284 try {
276 threadGroup.destroy();
277 } catch (IllegalThreadStateException itse) {
278 // If the executor hasn't fully shutdown it won't be possible to
279 // destroy this thread group as there will still be threads running
285 while (true) {
286 int oldThreadCount = threadCount;
287 synchronized (threadGroup) {
288 if (threadCount > 0) {
289 Thread.yield();
290 threadCount = threadGroup.activeCount();
291 }
292 if (threadCount > 0 && threadCount != oldThreadCount) {
293 // Value not stabilized. Retry.
294 continue;
295 }
296 if (threadCount > 0) {
297 threadGroup.setDaemon(true);
298 } else {
299 threadGroup.destroy();
300 success = true;
301 }
302 break;
303 }
304 }
305 } catch (IllegalThreadStateException exception) {
306 // Fall-through
307 }
308 if (!success) {
280309 log.warn(sm.getString("serverContainer.threadGroupNotDestroyed",
281 threadGroup.getName()));
282 }
310 threadGroup.getName(), Integer.valueOf(threadCount))); }
283311 }
284312
285313
307335 // Check an exact match. Simple case as there are no templates.
308336 ServerEndpointConfig sec = configExactMatchMap.get(path);
309337 if (sec != null) {
310 return new WsMappingResult(sec,
311 Collections.<String, String> emptyMap());
338 return new WsMappingResult(sec, Collections.<String, String>emptyMap());
312339 }
313340
314341 // No exact match. Need to look for template matches.
11 X-Compile-Source-JDK: @source.jdk@
22 X-Compile-Target-JDK: @target.jdk@
33
4 Name: javax/el/
4 Name: javax/websocket/
55 Specification-Title: WebSocket
6 Specification-Version: 1.0
6 Specification-Version: 1.1
77 Specification-Vendor: Oracle, Inc.
8 Implementation-Title: javax.net.websocket
9 Implementation-Version: 1.0.@websocket.revision@
8 Implementation-Title: javax.websocket
9 Implementation-Version: 1.1.@websocket.revision@
1010 Implementation-Vendor: Apache Software Foundation
4242 value="${tomcat.output}/res/checkstyle/cachefile-checkstyle.xml"/>
4343
4444 <!-- Block Checks -->
45 <!-- ~60 errors
46 <module name="AvoidNestedBlocks"/>
47 -->
45 <module name="AvoidNestedBlocks">
46 <property name="allowInSwitchCase" value="true"/>
47 </module>
4848
4949 <!-- Coding -->
5050 <module name="IllegalInstantiation"/>
6060 <property name="illegalPkgs" value="sun,junit.framework"/>
6161 </module>
6262 <module name="ImportOrder">
63 <property name="groups" value="java,javax,async,jsp2,junit,org.junit,org,util"/>
63 <property name="groups" value="java,javax,org.hamcrest,org.junit,org,async,jsp2,util"/>
6464 <property name="ordered" value="true"/>
6565 <property name="separated" value="true"/>
6666 <property name="option" value="above"/>
8181 -->
8282 <module name="EmptyForInitializerPad"/>
8383 <module name="EmptyForIteratorPad"/>
84 <!-- ~ 1000 errors
84 <!-- ~ 1200 errors
8585 <module name="OperatorWrap">
86 <property name="option" value="oel"/>
86 <property name="option" value="eol"/>
8787 </module>
8888 -->
8989 </module>
3434 maven.asf.release.repo.repositoryId=apache.releases
3535
3636 # Release version info
37 maven.asf.release.deploy.version=8.0.12
37 maven.asf.release.deploy.version=8.0.14
3838
3939 #Where do we load the libraries from
4040 tomcat.lib.path=../../output/build/lib
3636 import org.apache.catalina.startup.TesterServlet;
3737 import org.apache.catalina.startup.Tomcat;
3838 import org.apache.catalina.startup.TomcatBaseTest;
39 import org.apache.catalina.util.ConcurrentMessageDigest;
40 import org.apache.catalina.util.MD5Encoder;
4139 import org.apache.tomcat.util.buf.ByteChunk;
4240 import org.apache.tomcat.util.descriptor.web.LoginConfig;
4341 import org.apache.tomcat.util.descriptor.web.SecurityCollection;
4442 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
43 import org.apache.tomcat.util.security.ConcurrentMessageDigest;
44 import org.apache.tomcat.util.security.MD5Encoder;
4545
4646 public class TestDigestAuthenticator extends TomcatBaseTest {
4747
2929 import org.apache.catalina.startup.TesterServlet;
3030 import org.apache.catalina.startup.Tomcat;
3131 import org.apache.catalina.startup.TomcatBaseTest;
32 import org.apache.catalina.util.ConcurrentMessageDigest;
33 import org.apache.catalina.util.MD5Encoder;
3432 import org.apache.tomcat.util.buf.ByteChunk;
3533 import org.apache.tomcat.util.descriptor.web.LoginConfig;
3634 import org.apache.tomcat.util.descriptor.web.SecurityCollection;
3735 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
36 import org.apache.tomcat.util.security.ConcurrentMessageDigest;
37 import org.apache.tomcat.util.security.MD5Encoder;
3838
3939 /**
4040 * Test DigestAuthenticator and NonLoginAuthenticator when a
3030 import org.apache.catalina.core.StandardContext;
3131 import org.apache.catalina.filters.TesterHttpServletResponse;
3232 import org.apache.catalina.startup.TesterMapRealm;
33 import org.apache.catalina.util.ConcurrentMessageDigest;
34 import org.apache.catalina.util.MD5Encoder;
3533 import org.apache.tomcat.util.descriptor.web.LoginConfig;
34 import org.apache.tomcat.util.security.ConcurrentMessageDigest;
35 import org.apache.tomcat.util.security.MD5Encoder;
3636
3737 public class TesterDigestAuthenticatorPerformance {
3838
660660 writer.append("Content-Disposition: form-data; name=\"part\"\r\n");
661661 writer.append("Content-Type: text/plain; charset=UTF-8\r\n");
662662 writer.append("\r\n");
663 writer.append("��").append("\r\n");
663 writer.append("äö").append("\r\n");
664664 writer.flush();
665665
666666 writer.append("\r\n");
681681 while ((line = reader.readLine()) != null) {
682682 response.add(line);
683683 }
684 assertTrue(response.contains("Part ��"));
684 assertTrue(response.contains("Part äö"));
685685 }
686686 } else {
687687 fail("OK status was expected: " + status);
1818 import java.io.File;
1919 import java.io.IOException;
2020 import java.io.PrintWriter;
21 import java.util.Arrays;
2122 import java.util.HashSet;
2223 import java.util.Set;
2324
4142 import javax.servlet.http.HttpServletRequest;
4243 import javax.servlet.http.HttpServletResponse;
4344
45 import org.hamcrest.CoreMatchers;
46
4447 import static org.junit.Assert.assertEquals;
4548 import static org.junit.Assert.assertFalse;
4649 import static org.junit.Assert.assertNotSame;
6972 import org.apache.tomcat.util.descriptor.web.FilterDef;
7073 import org.apache.tomcat.util.descriptor.web.FilterMap;
7174 import org.apache.tomcat.util.descriptor.web.LoginConfig;
75
7276
7377 public class TestStandardContext extends TomcatBaseTest {
7478
944948
945949 Assert.assertNull(realPath);
946950 }
951
952 @Test
953 public void testBug56903() {
954 Context context = new StandardContext();
955
956 context.setResourceOnlyServlets("a,b,c");
957 Assert.assertThat(Arrays.asList(context.getResourceOnlyServlets().split(",")),
958 CoreMatchers.hasItems("a", "b", "c"));
959 }
947960 }
1818 import java.beans.PropertyChangeListener;
1919 import java.io.File;
2020 import java.net.URL;
21 import java.nio.charset.Charset;
22 import java.nio.charset.StandardCharsets;
2123 import java.util.ArrayList;
2224 import java.util.List;
2325 import java.util.Locale;
12201222 public Object getNamingToken() {
12211223 return null;
12221224 }
1225
1226 @Override
1227 public void setUseRfc6265(boolean useRfc6265) { /* NO-OP */ }
1228
1229 @Override
1230 public boolean getUseRfc6265() {return false; }
1231
1232 @Override
1233 public void setCookieEncoding(String encoding) { /* NO-OP */ }
1234
1235 @Override
1236 public String getCookieEncoding() { return "UTF-8"; }
1237
1238 @Override
1239 public Charset getCookieEncodingCharset() { return StandardCharsets.UTF_8; }
12231240 }
7979 tomcat.start();
8080 try {
8181 // VERIFY EXCLUDED RESPONSE STATUS CODES
82 {
83 int[] excludedResponseStatusCodes = expiresFilter.getExcludedResponseStatusCodesAsInts();
84 Assert.assertEquals(2, excludedResponseStatusCodes.length);
85 Assert.assertEquals(304, excludedResponseStatusCodes[0]);
86 Assert.assertEquals(503, excludedResponseStatusCodes[1]);
87 }
82 int[] excludedResponseStatusCodes = expiresFilter.getExcludedResponseStatusCodesAsInts();
83 Assert.assertEquals(2, excludedResponseStatusCodes.length);
84 Assert.assertEquals(304, excludedResponseStatusCodes[0]);
85 Assert.assertEquals(503, excludedResponseStatusCodes[1]);
8886
8987 // VERIFY DEFAULT CONFIGURATION
90 {
91 ExpiresConfiguration expiresConfiguration = expiresFilter.getDefaultExpiresConfiguration();
92 Assert.assertEquals(StartingPoint.ACCESS_TIME,
93 expiresConfiguration.getStartingPoint());
94 Assert.assertEquals(1,
95 expiresConfiguration.getDurations().size());
96 Assert.assertEquals(DurationUnit.MONTH,
97 expiresConfiguration.getDurations().get(0).getUnit());
98 Assert.assertEquals(1, expiresConfiguration.getDurations().get(
99 0).getAmount());
100 }
88 ExpiresConfiguration expiresConfigurationDefault =
89 expiresFilter.getDefaultExpiresConfiguration();
90 Assert.assertEquals(StartingPoint.ACCESS_TIME,
91 expiresConfigurationDefault.getStartingPoint());
92 Assert.assertEquals(1, expiresConfigurationDefault.getDurations().size());
93 Assert.assertEquals(DurationUnit.MONTH,
94 expiresConfigurationDefault.getDurations().get(0).getUnit());
95 Assert.assertEquals(1, expiresConfigurationDefault.getDurations().get(0).getAmount());
10196
10297 // VERIFY TEXT/HTML
103 {
104 ExpiresConfiguration expiresConfiguration = expiresFilter.getExpiresConfigurationByContentType().get(
105 "text/html");
106 Assert.assertEquals(StartingPoint.ACCESS_TIME,
107 expiresConfiguration.getStartingPoint());
108
109 Assert.assertEquals(3,
110 expiresConfiguration.getDurations().size());
111
112 Duration oneMonth = expiresConfiguration.getDurations().get(0);
113 Assert.assertEquals(DurationUnit.MONTH, oneMonth.getUnit());
114 Assert.assertEquals(1, oneMonth.getAmount());
115
116 Duration fifteenDays = expiresConfiguration.getDurations().get(
117 1);
118 Assert.assertEquals(DurationUnit.DAY, fifteenDays.getUnit());
119 Assert.assertEquals(15, fifteenDays.getAmount());
120
121 Duration twoHours = expiresConfiguration.getDurations().get(2);
122 Assert.assertEquals(DurationUnit.HOUR, twoHours.getUnit());
123 Assert.assertEquals(2, twoHours.getAmount());
124 }
98 ExpiresConfiguration expiresConfigurationTextHtml =
99 expiresFilter.getExpiresConfigurationByContentType().get("text/html");
100 Assert.assertEquals(StartingPoint.ACCESS_TIME,
101 expiresConfigurationTextHtml.getStartingPoint());
102
103 Assert.assertEquals(3, expiresConfigurationTextHtml.getDurations().size());
104
105 Duration oneMonth = expiresConfigurationTextHtml.getDurations().get(0);
106 Assert.assertEquals(DurationUnit.MONTH, oneMonth.getUnit());
107 Assert.assertEquals(1, oneMonth.getAmount());
108
109 Duration fifteenDays = expiresConfigurationTextHtml.getDurations().get(1);
110 Assert.assertEquals(DurationUnit.DAY, fifteenDays.getUnit());
111 Assert.assertEquals(15, fifteenDays.getAmount());
112
113 Duration twoHours = expiresConfigurationTextHtml.getDurations().get(2);
114 Assert.assertEquals(DurationUnit.HOUR, twoHours.getUnit());
115 Assert.assertEquals(2, twoHours.getAmount());
116
125117 // VERIFY IMAGE/GIF
126 {
127 ExpiresConfiguration expiresConfiguration = expiresFilter.getExpiresConfigurationByContentType().get(
128 "image/gif");
129 Assert.assertEquals(StartingPoint.LAST_MODIFICATION_TIME,
130 expiresConfiguration.getStartingPoint());
131
132 Assert.assertEquals(2,
133 expiresConfiguration.getDurations().size());
134
135 Duration fiveHours = expiresConfiguration.getDurations().get(0);
136 Assert.assertEquals(DurationUnit.HOUR, fiveHours.getUnit());
137 Assert.assertEquals(5, fiveHours.getAmount());
138
139 Duration threeMinutes = expiresConfiguration.getDurations().get(
140 1);
141 Assert.assertEquals(DurationUnit.MINUTE, threeMinutes.getUnit());
142 Assert.assertEquals(3, threeMinutes.getAmount());
143
144 }
118 ExpiresConfiguration expiresConfigurationImageGif =
119 expiresFilter.getExpiresConfigurationByContentType().get("image/gif");
120 Assert.assertEquals(StartingPoint.LAST_MODIFICATION_TIME,
121 expiresConfigurationImageGif.getStartingPoint());
122
123 Assert.assertEquals(2, expiresConfigurationImageGif.getDurations().size());
124
125 Duration fiveHours = expiresConfigurationImageGif.getDurations().get(0);
126 Assert.assertEquals(DurationUnit.HOUR, fiveHours.getUnit());
127 Assert.assertEquals(5, fiveHours.getAmount());
128
129 Duration threeMinutes = expiresConfigurationImageGif.getDurations().get(1);
130 Assert.assertEquals(DurationUnit.MINUTE, threeMinutes.getUnit());
131 Assert.assertEquals(3, threeMinutes.getAmount());
132
145133 // VERIFY IMAGE/JPG
146 {
147 ExpiresConfiguration expiresConfiguration = expiresFilter.getExpiresConfigurationByContentType().get(
148 "image/jpg");
149 Assert.assertEquals(StartingPoint.ACCESS_TIME,
150 expiresConfiguration.getStartingPoint());
151
152 Assert.assertEquals(1,
153 expiresConfiguration.getDurations().size());
154
155 Duration tenThousandSeconds = expiresConfiguration.getDurations().get(
156 0);
157 Assert.assertEquals(DurationUnit.SECOND,
158 tenThousandSeconds.getUnit());
159 Assert.assertEquals(10000, tenThousandSeconds.getAmount());
160
161 }
134 ExpiresConfiguration expiresConfigurationImageJpg =
135 expiresFilter.getExpiresConfigurationByContentType().get("image/jpg");
136 Assert.assertEquals(StartingPoint.ACCESS_TIME,
137 expiresConfigurationImageJpg.getStartingPoint());
138
139 Assert.assertEquals(1, expiresConfigurationImageJpg.getDurations().size());
140
141 Duration tenThousandSeconds = expiresConfigurationImageJpg.getDurations().get(0);
142 Assert.assertEquals(DurationUnit.SECOND, tenThousandSeconds.getUnit());
143 Assert.assertEquals(10000, tenThousandSeconds.getAmount());
144
162145 // VERIFY VIDEO/MPEG
163 {
164 ExpiresConfiguration expiresConfiguration = expiresFilter.getExpiresConfigurationByContentType().get(
165 "video/mpeg");
166 Assert.assertEquals(StartingPoint.LAST_MODIFICATION_TIME,
167 expiresConfiguration.getStartingPoint());
168
169 Assert.assertEquals(1,
170 expiresConfiguration.getDurations().size());
171
172 Duration twentyThousandSeconds = expiresConfiguration.getDurations().get(
173 0);
174 Assert.assertEquals(DurationUnit.SECOND,
175 twentyThousandSeconds.getUnit());
176 Assert.assertEquals(20000, twentyThousandSeconds.getAmount());
177 }
146 ExpiresConfiguration expiresConfiguration =
147 expiresFilter.getExpiresConfigurationByContentType().get("video/mpeg");
148 Assert.assertEquals(StartingPoint.LAST_MODIFICATION_TIME,
149 expiresConfiguration.getStartingPoint());
150
151 Assert.assertEquals(1, expiresConfiguration.getDurations().size());
152
153 Duration twentyThousandSeconds = expiresConfiguration.getDurations().get(0);
154 Assert.assertEquals(DurationUnit.SECOND, twentyThousandSeconds.getUnit());
155 Assert.assertEquals(20000, twentyThousandSeconds.getAmount());
178156 } finally {
179157 tomcat.stop();
180158 }
7676
7777 /*
7878 * Get the set of current threads as an array.
79 * Copied from WebappClassLoader
79 * Copied from WebappClassLoaderBase
8080 */
8181 private Thread[] getThreads() {
8282 // Get the current thread group
5959 LogValidationFilter f = new LogValidationFilter(
6060 "The web application [] created a ThreadLocal with key of");
6161 LogManager.getLogManager().getLogger(
62 "org.apache.catalina.loader.WebappClassLoader").setFilter(f);
62 "org.apache.catalina.loader.WebappClassLoaderBase").setFilter(f);
6363
6464 // Need to force loading of all web application classes via the web
6565 // application class loader
113113 LogValidationFilter f = new LogValidationFilter(
114114 "The web application [] created a ThreadLocal with key of");
115115 LogManager.getLogManager().getLogger(
116 "org.apache.catalina.loader.WebappClassLoader").setFilter(f);
116 "org.apache.catalina.loader.WebappClassLoaderBase").setFilter(f);
117117
118118 // Need to force loading of all web application classes via the web
119119 // application class loader
7979 Assert.assertTrue(result.contains("OK"));
8080 }
8181
82 @Test
83 public void testIncludeThrowsIOException() throws Exception {
84 Tomcat tomcat = getTomcatInstance();
85
86 File appDir = new File("test/webapp");
87 tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
88
89 tomcat.start();
90
91 ByteChunk res = new ByteChunk();
92
93 int rc = getUrl("http://localhost:" + getPort() + "/test/jsp/pageContext1.jsp", res, null);
94
95 Assert.assertEquals(HttpServletResponse.SC_OK, rc);
96
97 String body = res.toString();
98 Assert.assertTrue(body.contains("OK"));
99 Assert.assertFalse(body.contains("FAILED"));
100
101 res = new ByteChunk();
102
103 rc = getUrl("http://localhost:" + getPort() + "/test/jsp/pageContext1.jsp?flush=true", res,
104 null);
105
106 Assert.assertEquals(HttpServletResponse.SC_OK, rc);
107
108 body = res.toString();
109 Assert.assertTrue(body.contains("Flush"));
110 Assert.assertTrue(body.contains("OK"));
111 Assert.assertFalse(body.contains("FAILED"));
112 }
113
82114 public static class Bug56010 extends HttpServlet {
83115
84116 private static final long serialVersionUID = 1L;
4242 // Get dfc.cache.cache field
4343 Object dfcCache;
4444 Field dfcCacheArray;
45 {
46 Field dfcCacheField = dfc.getClass().getDeclaredField("cache");
47 dfcCacheField.setAccessible(true);
48 dfcCache = dfcCacheField.get(dfc);
49 dfcCacheArray = dfcCache.getClass().getDeclaredField("cache");
50 dfcCacheArray.setAccessible(true);
51 }
45 Field dfcCacheField = dfc.getClass().getDeclaredField("cache");
46 dfcCacheField.setAccessible(true);
47 dfcCache = dfcCacheField.get(dfc);
48 dfcCacheArray = dfcCache.getClass().getDeclaredField("cache");
49 dfcCacheArray.setAccessible(true);
5250
5351 // Create an array to hold the expected values
5452 String[] expected = new String[cacheSize];
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.bcel;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.URL;
22 import java.util.HashSet;
23 import java.util.Locale;
24 import java.util.Set;
25
26 import org.junit.Test;
27
28 import org.apache.tomcat.util.bcel.classfile.ClassParser;
29 import org.apache.tomcat.util.scan.Jar;
30 import org.apache.tomcat.util.scan.JarFactory;
31
32 public class TesterPerformance {
33
34 private static final String JAR_LOCATION = "/tmp/jira-libs";
35
36 @Test
37 public void testClassParserPerformance() throws IOException {
38 File libDir = new File(JAR_LOCATION);
39 String[] libs = libDir.list();
40
41 Set<URL> jarURLs = new HashSet<>();
42
43 for (String lib : libs) {
44 if (!lib.toLowerCase(Locale.ENGLISH).endsWith(".jar")) {
45 continue;
46 }
47 jarURLs.add(new URL("jar:" + new File (libDir, lib).toURI().toURL().toExternalForm() + "!/"));
48 }
49
50 long duration = 0;
51
52 for (URL jarURL : jarURLs) {
53 Jar jar = JarFactory.newInstance(jarURL);
54 jar.nextEntry();
55 String jarEntryName = jar.getEntryName();
56 while (jarEntryName != null) {
57 if (jarEntryName.endsWith(".class")) {
58 InputStream is = jar.getEntryInputStream();
59 long start = System.nanoTime();
60 ClassParser cp = new ClassParser(is);
61 cp.parse();
62 duration += System.nanoTime() - start;
63 }
64 jar.nextEntry();
65 jarEntryName = jar.getEntryName();
66 }
67 }
68
69 System.out.println("ClassParser performance test took: " + duration + "ns");
70 }
71 }
1616
1717 package org.apache.tomcat.util.buf;
1818
19 import static org.junit.Assert.assertEquals;
19 import java.nio.charset.StandardCharsets;
2020
21 import org.junit.Assert;
2122 import org.junit.Test;
2223
2324 /**
2526 */
2627 public class TestHexUtils {
2728
29 private static final String TEST01_STRING = "Hello World";
30 private static final byte[] TEST01_BYTES = TEST01_STRING.getBytes(StandardCharsets.UTF_8);
31 private static final String TEST02_STRING = "foo";
32 private static final byte[] TEST02_BYTES = TEST02_STRING.getBytes(StandardCharsets.UTF_8);
33
2834 @Test
2935 public void testGetDec() {
30 assertEquals(0, HexUtils.getDec('0'));
31 assertEquals(9, HexUtils.getDec('9'));
32 assertEquals(10, HexUtils.getDec('a'));
33 assertEquals(15, HexUtils.getDec('f'));
34 assertEquals(10, HexUtils.getDec('A'));
35 assertEquals(15, HexUtils.getDec('F'));
36 assertEquals(-1, HexUtils.getDec(0));
37 assertEquals(-1, HexUtils.getDec('Z'));
38 assertEquals(-1, HexUtils.getDec(255));
39 assertEquals(-1, HexUtils.getDec(-60));
36 Assert.assertEquals(0, HexUtils.getDec('0'));
37 Assert.assertEquals(9, HexUtils.getDec('9'));
38 Assert.assertEquals(10, HexUtils.getDec('a'));
39 Assert.assertEquals(15, HexUtils.getDec('f'));
40 Assert.assertEquals(10, HexUtils.getDec('A'));
41 Assert.assertEquals(15, HexUtils.getDec('F'));
42 Assert.assertEquals(-1, HexUtils.getDec(0));
43 Assert.assertEquals(-1, HexUtils.getDec('Z'));
44 Assert.assertEquals(-1, HexUtils.getDec(255));
45 Assert.assertEquals(-1, HexUtils.getDec(-60));
4046 }
41 }
47
48 @Test
49 public void testRoundTrip01() {
50 Assert.assertArrayEquals(TEST01_STRING, TEST01_BYTES,
51 HexUtils.fromHexString(HexUtils.toHexString(TEST01_BYTES)));
52 }
53
54 @Test
55 public void testRoundTrip02() {
56 Assert.assertArrayEquals(TEST02_STRING, TEST02_BYTES,
57 HexUtils.fromHexString(HexUtils.toHexString(TEST02_BYTES)));
58 }
59 }
2323 import org.junit.Assert;
2424 import org.junit.Test;
2525
26 import org.apache.tomcat.util.buf.MessageBytes;
27
2628 public class TestCookies {
27 private Cookie FOO = new Cookie("foo", "bar");
28 private Cookie BAR = new Cookie("bar", "rab");
29 private Cookie A = new Cookie("a", "b");
30
31 @Test
32 public void testBasicCookie() {
33 test("foo=bar; a=b", FOO, A);
34 test("foo=bar;a=b", FOO, A);
35 test("foo=bar;a=b;", FOO, A);
36 test("foo=bar;a=b; ", FOO, A);
37 test("foo=bar;a=b; ;", FOO, A);
38 }
39
40 @Test
41 public void testNameOnlyAreDropped() {
42 test("foo=;a=b; ;", A);
43 test("foo;a=b; ;", A);
44 test("foo;a=b;bar", A);
45 test("foo;a=b;bar;", A);
46 test("foo;a=b;bar ", A);
47 test("foo;a=b;bar ;", A);
29 private final Cookie FOO = new Cookie("foo", "bar");
30 private final Cookie FOO_EMPTY = new Cookie("foo", "");
31 private final Cookie FOO_CONTROL = new Cookie("foo", "b\u00e1r");
32 private final Cookie BAR = new Cookie("bar", "rab");
33 private final Cookie BAR_EMPTY = new Cookie("bar", "");
34 private final Cookie A = new Cookie("a", "b");
35 private final Cookie HASH_EMPTY = new Cookie("#", "");
36 private final Cookie $PORT = new Cookie("$Port", "8080");
37
38 @Test
39 public void testBasicCookieOld() {
40 doTestBasicCookie(false);
41 }
42
43 @Test
44 public void testBasicCookieRfc6265() {
45 doTestBasicCookie(true);
46 }
47
48 private void doTestBasicCookie(boolean useRfc6265) {
49 test(useRfc6265, "foo=bar; a=b", FOO, A);
50 test(useRfc6265, "foo=bar;a=b", FOO, A);
51 test(useRfc6265, "foo=bar;a=b;", FOO, A);
52 test(useRfc6265, "foo=bar;a=b; ", FOO, A);
53 test(useRfc6265, "foo=bar;a=b; ;", FOO, A);
54 }
55
56 @Test
57 public void testNameOnlyAreDroppedOld() {
58 test(false, "foo=;a=b; ;", A);
59 test(false, "foo;a=b; ;", A);
60 test(false, "foo;a=b;bar", A);
61 test(false, "foo;a=b;bar;", A);
62 test(false, "foo;a=b;bar ", A);
63 test(false, "foo;a=b;bar ;", A);
4864
4965 // Bug 49000
5066 Cookie fred = new Cookie("fred", "1");
5167 Cookie jim = new Cookie("jim", "2");
5268 Cookie george = new Cookie("george", "3");
53 test("fred=1; jim=2; bob", fred, jim);
54 test("fred=1; jim=2; bob; george=3", fred, jim, george);
55 test("fred=1; jim=2; bob=; george=3", fred, jim, george);
56 test("fred=1; jim=2; bob=", fred, jim);
57 }
58
59 @Test
60 public void testQuotedValue() {
61 test("foo=bar;a=\"b\"", FOO, A);
62 test("foo=bar;a=\"b\";", FOO, A);
63 }
64
65 @Test
66 public void testEmptyPairs() {
67 test("foo;a=b; ;bar", A);
68 test("foo;a=b;;bar", A);
69 test("foo;a=b; ;;bar=rab", A, BAR);
70 test("foo;a=b;; ;bar=rab", A, BAR);
71 test("foo;a=b;;#;bar=rab", A, BAR);
72 test("foo;a=b;;\\;bar=rab", A, BAR);
73 }
74
75 @Test
76 public void testSeparatorsInValue() {
77 test("a=()<>@:\\\"/[]?={}\t; foo=bar", FOO);
78 }
79
80
81 @Test
82 public void v1TokenValue() {
83 FOO.setVersion(1);
84 A.setVersion(1);
85 test("$Version=1; foo=bar;a=b", FOO, A);
86 test("$Version=1;foo=bar;a=b; ; ", FOO, A);
87 }
88
89 @Test
90 public void v1NameOnlyIsDropped() {
91 A.setVersion(1);
92 test("$Version=1;foo=;a=b; ; ", A);
93 test("$Version=1;foo= ;a=b; ; ", A);
94 test("$Version=1;foo;a=b; ; ", A);
95 }
96
97 @Test
98 public void v1QuotedValue() {
69 test(false, "fred=1; jim=2; bob", fred, jim);
70 test(false, "fred=1; jim=2; bob; george=3", fred, jim, george);
71 test(false, "fred=1; jim=2; bob=; george=3", fred, jim, george);
72 test(false, "fred=1; jim=2; bob=", fred, jim);
73 }
74
75 @Test
76 public void testNameOnlyAreDroppedRfc6265() {
77 // Name only cookies are not dropped in RFC6265
78 test(true, "foo=;a=b; ;", FOO_EMPTY, A);
79 test(true, "foo;a=b; ;", FOO_EMPTY, A);
80 test(true, "foo;a=b;bar", FOO_EMPTY, A, BAR_EMPTY);
81 test(true, "foo;a=b;bar;", FOO_EMPTY, A, BAR_EMPTY);
82 test(true, "foo;a=b;bar ", FOO_EMPTY, A, BAR_EMPTY);
83 test(true, "foo;a=b;bar ;", FOO_EMPTY, A, BAR_EMPTY);
84
85 // Bug 49000
86 Cookie fred = new Cookie("fred", "1");
87 Cookie jim = new Cookie("jim", "2");
88 Cookie bobEmpty = new Cookie("bob", "");
89 Cookie george = new Cookie("george", "3");
90 test(true, "fred=1; jim=2; bob", fred, jim, bobEmpty);
91 test(true, "fred=1; jim=2; bob; george=3", fred, jim, bobEmpty, george);
92 test(true, "fred=1; jim=2; bob=; george=3", fred, jim, bobEmpty, george);
93 test(true, "fred=1; jim=2; bob=", fred, jim, bobEmpty);
94 }
95
96 @Test
97 public void testQuotedValueOld() {
98 doTestQuotedValue(false);
99 }
100
101 @Test
102 public void testQuotedValueRfc6265() {
103 doTestQuotedValue(true);
104 }
105
106 private void doTestQuotedValue(boolean useRfc6265) {
107 test(useRfc6265, "foo=bar;a=\"b\"", FOO, A);
108 test(useRfc6265, "foo=bar;a=\"b\";", FOO, A);
109 }
110
111 @Test
112 public void testEmptyPairsOld() {
113 test(false, "foo;a=b; ;bar", A);
114 test(false, "foo;a=b;;bar", A);
115 test(false, "foo;a=b; ;;bar=rab", A, BAR);
116 test(false, "foo;a=b;; ;bar=rab", A, BAR);
117 test(false, "foo;a=b;;#;bar=rab", A, BAR);
118 test(false, "foo;a=b;;\\;bar=rab", A, BAR);
119 }
120
121 @Test
122 public void testEmptyPairsRfc6265() {
123 test(true, "foo;a=b; ;bar", FOO_EMPTY, A, BAR_EMPTY);
124 test(true, "foo;a=b;;bar", FOO_EMPTY, A, BAR_EMPTY);
125 test(true, "foo;a=b; ;;bar=rab", FOO_EMPTY, A, BAR);
126 test(true, "foo;a=b;; ;bar=rab", FOO_EMPTY, A, BAR);
127 test(true, "foo;a=b;;#;bar=rab", FOO_EMPTY, A, HASH_EMPTY, BAR);
128 test(true, "foo;a=b;;\\;bar=rab", FOO_EMPTY, A, BAR);
129 }
130
131 @Test
132 public void testSeparatorsInValueOld() {
133 doTestSeparatorsInValue(false);
134 }
135
136 @Test
137 public void testSeparatorsInValueRfc6265() {
138 doTestSeparatorsInValue(true);
139 }
140
141 private void doTestSeparatorsInValue(boolean useRfc6265) {
142 test(useRfc6265, "a=()<>@:\\\"/[]?={}\t; foo=bar", FOO);
143 }
144
145
146 @Test
147 public void v1TokenValueOld() {
148 doV1TokenValue(false);
149 }
150
151 @Test
152 public void v1TokenValueRfc6265() {
153 doV1TokenValue(true);
154 }
155
156 private void doV1TokenValue(boolean useRfc6265) {
157 FOO.setVersion(1);
158 A.setVersion(1);
159 test(useRfc6265, "$Version=1; foo=bar;a=b", FOO, A);
160 test(useRfc6265, "$Version=1;foo=bar;a=b; ; ", FOO, A);
161 }
162
163 @Test
164 public void v1NameOnlyIsDroppedOld() {
165 doV1NameOnlyIsDropped(false);
166 }
167
168 @Test
169 public void v1NameOnlyIsDroppedRfc6265() {
170 doV1NameOnlyIsDropped(true);
171 }
172
173 private void doV1NameOnlyIsDropped(boolean useRfc6265) {
174 A.setVersion(1);
175 test(useRfc6265, "$Version=1;foo=;a=b; ; ", A);
176 test(useRfc6265, "$Version=1;foo= ;a=b; ; ", A);
177 test(useRfc6265, "$Version=1;foo;a=b; ; ", A);
178 }
179
180 @Test
181 public void v1QuotedValueOld() {
182 doV1QuotedValue(false);
183 }
184
185 @Test
186 public void v1QuotedValueRfc6265() {
187 doV1QuotedValue(true);
188 }
189
190 private void doV1QuotedValue(boolean useRfc6265) {
99191 FOO.setVersion(1);
100192 A.setVersion(1);
101193 // presumes quotes are removed
102 test("$Version=1;foo=\"bar\";a=b; ; ", FOO, A);
103 }
104
105 @Test
106 public void v1DQuoteInValue() {
194 test(useRfc6265, "$Version=1;foo=\"bar\";a=b; ; ", FOO, A);
195 }
196
197 @Test
198 public void v1DQuoteInValueOld() {
107199 FOO.setValue("b");
108200 FOO.setVersion(1);
109201 A.setVersion(1);
110 test("$Version=1;foo=\"b\"ar\";a=b", FOO, A); // Incorrectly escaped.
111 }
112
113 @Test
114 public void v1QuoteInValue() {
202 test(false, "$Version=1;foo=\"b\"ar\";a=b", FOO, A); // Incorrectly escaped.
203 }
204
205 @Test
206 public void v1DQuoteInValueRfc6265() {
207 A.setVersion(1);
208 test(true, "$Version=1;foo=\"b\"ar\";a=b", A); // Incorrectly escaped.
209 }
210
211 @Test
212 public void v1QuoteInValueOld() {
213 doV1QuoteInValue(false);
214 }
215
216 @Test
217 public void v1QuoteInValueRfc6265() {
218 doV1QuoteInValue(true);
219 }
220
221 private void doV1QuoteInValue(boolean useRfc6265) {
115222 FOO.setValue("b'ar");
116223 FOO.setVersion(1);
117224 A.setVersion(1);
118 test("$Version=1;foo=b'ar;a=b", FOO, A);
119 }
120
121
122 @Test
123 public void v1QuoteInQuotedValue() {
225 test(useRfc6265, "$Version=1;foo=b'ar;a=b", FOO, A);
226 }
227
228
229 @Test
230 public void v1QuoteInQuotedValueOld() {
231 doV1QuoteInQuotedValue(false);
232 }
233
234 @Test
235 public void v1QuoteInQuotedValueRfc6265() {
236 doV1QuoteInQuotedValue(true);
237 }
238
239 private void doV1QuoteInQuotedValue(boolean useRfc6265) {
124240 FOO.setValue("b'ar");
125241 FOO.setVersion(1);
126242 A.setVersion(1);
127 test("$Version=1;foo=\"b'ar\";a=b", FOO, A);
128 }
129
130 @Test
131 public void v1EscapedDQuoteInValue() {
243 test(useRfc6265, "$Version=1;foo=\"b'ar\";a=b", FOO, A);
244 }
245
246 @Test
247 public void v1EscapedDQuoteInValueOld() {
248 doV1EscapedDQuoteInValue(false);
249 }
250
251 @Test
252 public void v1EscapedDQuoteInValueRfc6265() {
253 doV1EscapedDQuoteInValue(true);
254 }
255
256 private void doV1EscapedDQuoteInValue(boolean useRfc6265) {
132257 FOO.setValue("b\"ar");
133258 FOO.setVersion(1);
134259 A.setVersion(1);
135 test("$Version=1;foo=\"b\\\"ar\";a=b", FOO, A); // correctly escaped.
136 }
137
138 @Test
139 public void v1QuotedValueEndsInBackslash() {
140 FOO.setVersion(1);
141 test("$Version=1;foo=bar;a=\"b\\\"", FOO);
142 }
143
144 @Test
145 public void v1MismatchedQuotes() {
146 FOO.setVersion(1);
147 test("$Version=1;foo=bar;a=\"b\\", FOO);
148 }
149
150 @Test
151 public void v1SingleQuotesAreValidTokenCharacters() {
260 test(useRfc6265, "$Version=1;foo=\"b\\\"ar\";a=b", FOO, A); // correctly escaped.
261 }
262
263 @Test
264 public void v1QuotedValueEndsInBackslashOld() {
265 doV1QuotedValueEndsInBackslash(false);
266 }
267
268 @Test
269 public void v1QuotedValueEndsInBackslashRfc6265() {
270 doV1QuotedValueEndsInBackslash(true);
271 }
272
273 private void doV1QuotedValueEndsInBackslash(boolean useRfc6265) {
274 FOO.setVersion(1);
275 test(useRfc6265, "$Version=1;foo=bar;a=\"b\\\"", FOO);
276 }
277
278 @Test
279 public void v1MismatchedQuotesOld() {
280 doV1MismatchedQuotes(false);
281 }
282
283 @Test
284 public void v1MismatchedQuotesRfc6265() {
285 doV1MismatchedQuotes(true);
286 }
287
288 private void doV1MismatchedQuotes(boolean useRfc6265) {
289 FOO.setVersion(1);
290 test(useRfc6265, "$Version=1;foo=bar;a=\"b\\", FOO);
291 }
292
293 @Test
294 public void v1SingleQuotesAreValidTokenCharactersOld() {
295 doV1SingleQuotesAreValidTokenCharacters(false);
296 }
297
298 @Test
299 public void v1SingleQuotesAreValidTokenCharactersRfc6265() {
300 doV1SingleQuotesAreValidTokenCharacters(true);
301 }
302
303 private void doV1SingleQuotesAreValidTokenCharacters(boolean useRfc6265) {
152304 FOO.setVersion(1);
153305 FOO.setValue("'bar'");
154 test("$Version=1; foo='bar'", FOO);
155 }
156
157 @Test
158 public void v1DomainIsParsed() {
306 test(useRfc6265, "$Version=1; foo='bar'", FOO);
307 }
308
309 @Test
310 public void v1DomainIsParsedOld() {
311 doV1DomainIsParsed(false);
312 }
313
314 @Test
315 public void v1DomainIsParsedRfc6265() {
316 doV1DomainIsParsed(true);
317 }
318
319 private void doV1DomainIsParsed(boolean useRfc6265) {
159320 FOO.setVersion(1);
160321 FOO.setDomain("apache.org");
161322 A.setVersion(1);
162323 A.setDomain("yahoo.com");
163 test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b;$Domain=yahoo.com", FOO, A);
164 }
165
166 @Test
167 public void v1DomainOnlyAffectsPrecedingCookie() {
324 test(useRfc6265, "$Version=1;foo=\"bar\";$Domain=apache.org;a=b;$Domain=yahoo.com", FOO, A);
325 }
326
327 @Test
328 public void v1DomainOnlyAffectsPrecedingCookieOld() {
329 doV1DomainOnlyAffectsPrecedingCookie(false);
330 }
331
332 @Test
333 public void v1DomainOnlyAffectsPrecedingCookieRfc6265() {
334 doV1DomainOnlyAffectsPrecedingCookie(true);
335 }
336
337 private void doV1DomainOnlyAffectsPrecedingCookie(boolean useRfc6265) {
168338 FOO.setVersion(1);
169339 FOO.setDomain("apache.org");
170340 A.setVersion(1);
171 test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b", FOO, A);
172 }
173
174 @Test
175 public void v1PortIsIgnored() {
341 test(useRfc6265, "$Version=1;foo=\"bar\";$Domain=apache.org;a=b", FOO, A);
342 }
343
344 @Test
345 public void v1PortIsIgnoredOld() {
176346 FOO.setVersion(1);
177347 FOO.setDomain("apache.org");
178348 A.setVersion(1);
179 test("$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b", FOO, A);
180 }
181
182 @Test
183 public void v1PathAffectsPrecedingCookie() {
349 test(false, "$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b", FOO, A);
350 }
351
352 @Test
353 public void v1PortIsIgnoredRfc6265() {
354 FOO.setVersion(1);
355 FOO.setDomain("apache.org");
356 $PORT.setVersion(1);
357 A.setVersion(1);
358 test(true, "$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b", FOO, $PORT, A);
359 }
360
361 @Test
362 public void v1PathAffectsPrecedingCookieOld() {
363 doV1PathAffectsPrecedingCookie(false);
364 }
365
366 @Test
367 public void v1PathAffectsPrecedingCookieRfc6265() {
368 doV1PathAffectsPrecedingCookie(true);
369 }
370
371 private void doV1PathAffectsPrecedingCookie(boolean useRfc6265) {
184372 FOO.setVersion(1);
185373 FOO.setPath("/examples");
186374 A.setVersion(1);
187 test("$Version=1;foo=\"bar\";$Path=/examples;a=b; ; ", FOO, A);
188 }
189
190 @Test
191 public void rfc2109Version0() {
375 test(useRfc6265, "$Version=1;foo=\"bar\";$Path=/examples;a=b; ; ", FOO, A);
376 }
377
378 @Test
379 public void rfc2109Version0Old() {
192380 // rfc2109 semantically does not allow $Version to be 0 but it is valid syntax
193 test("$Version=0;foo=bar", FOO);
194 }
195
196 private void test(String header, Cookie... expected) {
197 Cookies cookies = new Cookies(null);
381 test(false, "$Version=0;foo=bar", FOO);
382 }
383
384 @Test
385 public void rfc2109Version0Rfc6265() {
386 // Neither RFC2109 nor RFc6265 allow version 0
387 test(true, "$Version=0;foo=bar");
388 }
389
390 @Test
391 public void disallow8bitInName() {
392 // Bug 55917
393 test(true, "f\u00f6o=bar");
394 }
395
396 @Test
397 public void disallowControlInName() {
398 // Bug 55917
399 test(true, "f\010o=bar");
400 }
401
402 @Test
403 public void disallow8BitControlInName() {
404 // Bug 55917
405 test(true, "f\210o=bar");
406 }
407
408 @Test
409 public void allow8BitInV0Value() {
410 // Bug 55917
411 test(true, "foo=b\u00e1r", FOO_CONTROL);
412 }
413
414 @Test
415 public void disallow8bitInV1UnquotedValue() {
416 // Bug 55917
417 test(true, "$Version=1; foo=b\u00e1r");
418 }
419
420 @Test
421 public void allow8bitInV1QuotedValue() {
422 // Bug 55917
423 FOO_CONTROL.setVersion(1);
424 test(true, "$Version=1; foo=\"b\u00e1r\"", FOO_CONTROL);
425 }
426
427 @Test
428 public void disallowControlInV0Value() {
429 // Bug 55917
430 test(true, "foo=b\010r");
431 }
432
433 @Test
434 public void disallowControlInV1UnquotedValue() {
435 // Bug 55917
436 test(true, "$Version=1; foo=b\010r");
437 }
438
439 @Test
440 public void disallowControlInV1QuotedValue() {
441 // Bug 55917 / Bug 55918
442 test(true, "$Version=1; foo=\"b\010r\"");
443 }
444
445 @Test
446 public void disallow8BitControlInV1UnquotedValue() {
447 // Bug 55917
448 test(true, "$Version=1; foo=b\210r");
449 }
450
451 @Test
452 public void testJsonInV0() {
453 // Bug 55921
454 test(true, "{\"a\":true, \"b\":false};a=b", A);
455 }
456
457 @Test
458 public void testJsonInV1() {
459 // Bug 55921
460 A.setVersion(1);
461 test(true, "$Version=1;{\"a\":true, \"b\":false};a=b", A);
462 }
463
464 @Test
465 public void testSkipSemicolonOrComma() {
466 // V1 cookies can also use commas to separate cookies
467 FOO.setVersion(1);
468 A.setVersion(1);
469 test(true, "$Version=1;x\tx=yyy,foo=bar;a=b", FOO, A);
470 }
471
472 private void test(boolean useRfc6265, String header, Cookie... expected) {
473 MimeHeaders mimeHeaders = new MimeHeaders();
474 Cookies cookies = new Cookies(mimeHeaders);
475 cookies.setUseRfc6265(useRfc6265);
476 MessageBytes cookieHeaderValue = mimeHeaders.addValue("Cookie");
198477 byte[] bytes = header.getBytes(StandardCharsets.UTF_8);
199 cookies.processCookieHeader(bytes, 0, bytes.length);
478 cookieHeaderValue.setBytes(bytes, 0, bytes.length);
479 // Calling getCookieCount() triggers parsing
200480 Assert.assertEquals(expected.length, cookies.getCookieCount());
201481 for (int i = 0; i < expected.length; i++) {
202482 Cookie cookie = expected[i];
203483 ServerCookie actual = cookies.getCookie(i);
204484 Assert.assertEquals(cookie.getVersion(), actual.getVersion());
205485 Assert.assertEquals(cookie.getName(), actual.getName().toString());
206 Assert.assertEquals(cookie.getValue(), actual.getValue().toString());
486 actual.getValue().getByteChunk().setCharset(StandardCharsets.UTF_8);
487 Assert.assertEquals(cookie.getValue(),
488 org.apache.tomcat.util.http.parser.Cookie.unescapeCookieValueRfc2109(
489 actual.getValue().toString()));
207490 if (cookie.getVersion() == 1) {
208491 Assert.assertEquals(cookie.getDomain(), actual.getDomain().toString());
209492 Assert.assertEquals(cookie.getPath(), actual.getPath().toString());
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.tomcat.util.http;
17
18 import org.junit.Assert;
19 import org.junit.Test;
20
21 import org.apache.tomcat.util.buf.MessageBytes;
22
23 public class TesterCookiesPerformance {
24
25 @Test
26 public void testPerformance01() throws Exception {
27 final int cookieCount = 100;
28 final int parsingLoops = 200000;
29
30 MimeHeaders mimeHeaders = new MimeHeaders();
31
32 StringBuilder cookieHeader = new StringBuilder();
33 // Create cookies
34 for (int i = 0; i < cookieCount; i++) {
35 cookieHeader.append("name");
36 cookieHeader.append(i);
37 cookieHeader.append('=');
38 cookieHeader.append("value");
39 cookieHeader.append(i);
40 cookieHeader.append(';');
41 }
42
43 byte[] cookieHeaderBytes = cookieHeader.toString().getBytes("UTF-8");
44
45 MessageBytes headerValue = mimeHeaders.addValue("Cookie");
46 headerValue.setBytes(cookieHeaderBytes, 0, cookieHeaderBytes.length);
47
48 Cookies cookies = new Cookies(mimeHeaders);
49 // warm up
50 for (int i = 0; i < parsingLoops; i++) {
51 Assert.assertEquals(cookieCount, cookies.getCookieCount());
52 cookies.recycle();
53 }
54
55 long oldStart = System.nanoTime();
56 for (int i = 0; i < parsingLoops; i++) {
57 cookies.setUseRfc6265(false);
58 Assert.assertEquals(cookieCount, cookies.getCookieCount());
59 cookies.recycle();
60 }
61 long oldDuration = System.nanoTime() - oldStart;
62
63 long newStart = System.nanoTime();
64 for (int i = 0; i < parsingLoops; i++) {
65 cookies.setUseRfc6265(true);
66 Assert.assertEquals(cookieCount, cookies.getCookieCount());
67 cookies.recycle();
68 }
69 long newDuration = System.nanoTime() - newStart;
70
71 System.out.println("Old duration: " + oldDuration);
72 System.out.println("New duration: " + newDuration);
73 }
74 }
5454 Context c = (Context) tomcat.getHost().findChildren()[0];
5555 // Enable pre-emptive auth
5656 c.setPreemptiveAuthentication(true);
57
58 // Connector needs to advertise is accepts client certs for
59 // pre-emptive to work
60 tomcat.getConnector().setAttribute("clientAuth", "want");
6157 }
6258
6359 getTomcatInstance().start();
139139 }
140140
141141
142 private abstract static class GenericMessageHandler<T>
143 implements MessageHandler.Whole<T> {
144 }
145
146
147 private static class GenericSubMessageHandler
148 extends GenericMessageHandler<String>{
149
142 private abstract static class GenericMessageHandler<T> implements MessageHandler.Whole<T> {
143 }
144
145
146 private static class GenericSubMessageHandler extends GenericMessageHandler<String> {
150147 @Override
151148 public void onMessage(String message) {
152149 // NO-OP
241238 }
242239
243240
244 private static class GenericSubEncoder
245 extends GenericEncoder<String>{
241 private static class GenericSubEncoder extends GenericEncoder<String> {
246242
247243 @Override
248244 public String encode(String object) throws EncodeException {
6868 public void testProgrammaticEndPoints() throws Exception{
6969 Tomcat tomcat = getTomcatInstance();
7070 // Must have a real docBase - just use temp
71 Context ctx =
72 tomcat.addContext("", System.getProperty("java.io.tmpdir"));
71 Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
7372 ctx.addApplicationListener(ProgramaticServerEndpointConfig.class.getName());
7473 Tomcat.addServlet(ctx, "default", new DefaultServlet());
7574 ctx.addServletMapping("/", "default");
7675
77 WebSocketContainer wsContainer =
78 ContainerProvider.getWebSocketContainer();
76 WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer();
7977
8078 tomcat.start();
8179
340338 }
341339
342340
343 public static class MsgStringMessageHandler
344 implements MessageHandler.Whole<MsgString>{
341 public static class MsgStringMessageHandler implements MessageHandler.Whole<MsgString> {
345342
346343 public static Queue<Object> received = new ConcurrentLinkedQueue<>();
347344 private final Session session;
0 <%--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 --%>
16 <%@ page import="java.io.IOException" contentType="text/plain"%>
17 <%
18 boolean flush = Boolean.valueOf(request.getParameter("flush"));
19 if (pageContext != null) {
20 try {
21 if (flush) {
22 out.println("Flush");
23 pageContext.include("/jsp/pageContext2.jsp", true);
24 } else {
25 pageContext.include("/jsp/pageContext2.jsp");
26 }
27 } catch (IOException e) {
28 out.println("OK");
29 return;
30 } catch (Throwable t) {
31 out.println("FAILED. Expected IOException, received: " + t.getClass().getName());
32 return;
33 }
34 out.println("FAILED. Expected IOException.");
35 } else {
36 out.println("FAILED. Expected IOException.");
37 }
38 %>
0 <%--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 --%>
16 <%@ page import="java.io.IOException" contentType="text/plain"%>
17 <% throw new IOException("Throws IOException."); %>
4343 They eventually become mixed with the numbered issues. (I.e., numbered
4444 issues to not "pop up" wrt. others).
4545 -->
46 <section name="Tomcat 8.0.12 (markt)">
46 <section name="Tomcat 8.0.14 (markt)">
47 <subsection name="Other">
48 <changelog>
49 <fix>
50 <bug>56079</bug>: The Apache Tomcat Windows installer, the Apache Tomcat
51 Windows service and the Apache Tomcat Windows service monitor
52 application are now digitally signed. (markt)
53 </fix>
54 </changelog>
55 </subsection>
56 </section>
57 <section name="Tomcat 8.0.13 (markt)" rtext="not released">
58 <subsection name="Catalina">
59 <changelog>
60 <fix>
61 <bug>55917</bug>: Allow bytes in the range 0x80 to 0xFF to appear in
62 cookie values if the cookie is a V1 (RFC2109) cookie and the value is
63 correctly quoted. The new RFC6265 based cookie parser must be enabled to
64 correctly handle these cookies. (markt)
65 </fix>
66 <fix>
67 <bug>55918</bug>: Do not permit control characters to appear in quoted
68 V1 (RFC2109) cookie values. The new RFC6265 based cookie parser must be
69 enabled to correctly handle these cookies. (markt)
70 </fix>
71 <fix>
72 <bug>55921</bug>: Correctly handle (ignore the cookie) unescaped JSON in
73 a cookie value. The new RFC6265 based cookie parser must be enabled to
74 correctly handle these cookies. (markt)
75 </fix>
76 <add>
77 <bug>56401</bug>: Log version information when Tomcat starts.
78 (markt/kkolinko)
79 </add>
80 <add>
81 <bug>56530</bug>: Add a web application class loader implementation that
82 supports the parallel loading of web application classes. (markt)
83 </add>
84 <fix>
85 <bug>56900</bug>: Fix some potential resource leaks when reading
86 property files reported by Coverity Scan. Based on patches provided by
87 Felix Schumacher. (markt)
88 </fix>
89 <fix>
90 <bug>56902</bug>: Fix a potential resource leak in the Default Servlet
91 reported by Coverity Scan. Based on a patch provided by Felix
92 Schumacher. (markt)
93 </fix>
94 <fix>
95 <bug>56903</bug>: Correct the return value for
96 <code>StandardContext.getResourceOnlyServlets()</code> so that multiple
97 names are separated by commas. Identified by Coverity Scan and fixed
98 based on a patch by Felix Schumacher. (markt)
99 </fix>
100 <add>
101 Add an additional implementation of a RFC6265 based cookie parser along
102 with new Context options to select and configure it. This parser is
103 currently considered experiemental and is not used by default. (markt)
104 </add>
105 <fix>
106 Fixed the multipart elements merge operation performed during web
107 application deployment. Identified by Coverity Scan. (violetagg)
108 </fix>
109 <fix>
110 Correct the information written by
111 <code>ExtendedAccessLogValve</code> when a format token x-O(XXX) is
112 used so that multiple values for a header XXX are separated by commas.
113 Identified by Coverity Scan. (violetagg)
114 </fix>
115 <fix>
116 Fix a potential resource leak when reading MANIFEST.MF file for
117 extension dependencies reported by Coverity Scan. (violetagg)
118 </fix>
119 <fix>
120 Fix some potential resource leaks when reading properties, files and
121 other resources. Reported by Coverity Scan. (violetagg)
122 </fix>
123 <fix>
124 Correct the previous fix for <bug>56825</bug> that enabled pre-emptive
125 authentication to work with the SSL authenticator. (markt)
126 </fix>
127 <scode>
128 Refactor to reduce code duplication identified by Simian. (markt)
129 </scode>
130 <fix>
131 When using parallel deployment and <code>undeployOldVersions</code>
132 feature is enabled on a Host, correctly undeploy context of old
133 version. Make sure that Tomcat does not undeploy older Context if
134 current context is not running. (kfujino)
135 </fix>
136 <fix>
137 Fix a rare threading issue when locking resources via WebDAV.
138 (markt)
139 </fix>
140 <fix>
141 Fix a rare threading issue when using HTTP digest authentication.
142 (markt)
143 </fix>
144 <fix>
145 When deploying war, add XML file in the config base to the redeploy
146 resources if war does not have META-INF/context.xml or
147 <code>deployXML</code> is false. If XML file is created in the config
148 base, redeploy will occur. (kfujino)
149 </fix>
150 <scode>
151 Various changes to reduce unnecessary code in Tomcat&apos;s copy of
152 Apache Commons BCEL to reduce the time taken for annotation scanning
153 when web applications start. Includes contributions from kkolinko and
154 hzhang9. (markt)
155 </scode>
156 <fix>
157 <bug>56938</bug>: Ensure web applications that have mixed case context
158 paths and are deployed as directories are correctly removed on undeploy
159 when running on a case sensitive file system. (markt)
160 </fix>
161 <add>
162 <bug>57004</bug>: Add <code>stuckThreadCount</code> property to
163 <code>StuckThreadDetectionValve</code>'s JMX bean. Patch provided by
164 Ji&#x159;&#xED; Pejchal. (schultz)
165 </add>
166 <fix>
167 <bug>57011</bug>: Ensure that the request and response are correctly
168 recycled when processing errors during async processing. (markt)
169 </fix>
170 </changelog>
171 </subsection>
172 <subsection name="Coyote">
173 <changelog>
174 <fix>
175 <bug>56910</bug>: Prevent the invalid value of <code>-1</code> being
176 used for <code>maxConnections</code> with APR connectors. (markt)
177 </fix>
178 <fix>
179 Ensure that AJP connectors enable the <code>KeepAliveTimeout</code>.
180 (kfujino)
181 </fix>
182 <fix>
183 Reduce duplicated code. All AJP connectors use common method to
184 configuration of processor. (kfujino)
185 </fix>
186 </changelog>
187 </subsection>
188 <subsection name="Jasper">
189 <changelog>
190 <fix>
191 <bug>43001</bug>: Enable the JspC Ant task to set the JspC option
192 <code>mappedFile</code>. (markt)
193 </fix>
194 <fix>
195 Ensure that the implementation of
196 <code>javax.servlet.jsp.PageContext.include(String)</code>
197 and
198 <code>javax.servlet.jsp.PageContext.include(String, boolean)</code>
199 will throw <code>IOException</code> when an I/O error occur during
200 the operation. (violetagg)
201 </fix>
202 <fix>
203 <bug>56908</bug>: Fix some potential resource leaks when reading
204 jar files. Reported by Coverity Scan. Patch provided by Felix
205 Schumacher. (violetagg)
206 </fix>
207 <fix>
208 Fix a potential resource leak in JDTCompiler when checking wether
209 a resource is a package. Reported by Coverity Scan. (fschumacher)
210 </fix>
211 <fix>
212 <bug>56991</bug>: Deprecate the use of a request attribute to pass a
213 &lt;jsp-file&gt; declaration to Jasper and prevent an infinite loop
214 if this technique is used in conjunction with an include. (markt)
215 </fix>
216 </changelog>
217 </subsection>
218 <subsection name="WebSocket">
219 <changelog>
220 <fix>
221 <bug>56905</bug>: Make destruction on web application stop of thread
222 group used for WebSocket connections more robust. (kkolinko/markt)
223 </fix>
224 <fix>
225 <bug>56907</bug>: Ensure that client IO threads are stopped if a secure
226 WebSocket client connection fails. (markt)
227 </fix>
228 <fix>
229 <bug>56982</bug>: Return the actual negotiated extensions rather than an
230 empty list for <code>Session.getNegotiatedExtensions()</code>. (markt)
231 </fix>
232 <update>
233 Update the WebSocket implementation to support the Java WebSocket
234 specification version 1.1. (markt)
235 </update>
236 </changelog>
237 </subsection>
238 <subsection name="Web applications">
239 <changelog>
240 <add>
241 Add <code>JarScanner</code> to the nested components listed for a
242 Context. (markt)
243 </add>
244 <update>
245 Update the Windows authentication documentation after some additional
246 testing to answer the remaining questions. (markt)
247 </update>
248 </changelog>
249 </subsection>
250 <subsection name="Other">
251 <changelog>
252 <fix>
253 <bug>56895</bug>: Correctly compose <code>JAVA_OPTS</code> in
254 <code>catalina.bat</code> so that escape sequences are preserved. Patch
255 by Lucas Theisen. (markt)
256 </fix>
257 <update>
258 <bug>56988</bug>: Allow to use relative path in <code>base.path</code>
259 setting when building Tomcat. (kkolinko)
260 </update>
261 <fix>
262 <bug>56990</bug>: Ensure that the <code>ide-eclipse</code> build target
263 downloads all the libraries required by the default Eclipse
264 configuration files. (markt)
265 </fix>
266 <fix>
267 Update the package renamed copy of Apache Commons DBCP 2 to revision
268 1626988 to pick up the fixes since the 2.0.1 release including support
269 for custom eviction policies. (markt)
270 </fix>
271 <fix>
272 Update the package renamed copy of Apache Commons Pool 2 to revision
273 1627271 to pick up the fixes since the 2.2 release including some memory
274 leak fixes and support for application provided eviction policies.
275 (markt)
276 </fix>
277 </changelog>
278 </subsection>
279 </section>
280 <section name="Tomcat 8.0.12 (markt)" rtext="2014-09-03">
47281 <subsection name="Catalina">
48282 <changelog>
49283 <add>
685919 </fix>
686920 <add>
687921 Add a new limit, defaulting to 2MB, for the amount of data Tomcat will
688 swallow for an aborted upload. (markt)
922 swallow for an aborted upload. The limit is configurable by
923 <code>maxSwallowSize</code> attribute of an HTTP connector. (markt)
689924 </add>
690925 </changelog>
691926 </subsection>
188188 loading looks in the following repositories, in this order:</p>
189189 <ul>
190190 <li>Bootstrap classes of your JVM</li>
191 <li>System class loader classes (described above)</li>
192191 <li><em>/WEB-INF/classes</em> of your web application</li>
193192 <li><em>/WEB-INF/lib/*.jar</em> of your web application</li>
193 <li>System class loader classes (described above)</li>
194194 <li>Common class loader classes (described above)</li>
195 </ul>
196
197 <p>If the web application class loader is configuered with
198 <code>delegate=&quot;true&quot;</code> then the order becomes:</p>
199 <ul>
200 <li>Bootstrap classes of your JVM</li>
201 <li>System class loader classes (described above)</li>
202 <li>Common class loader classes (described above)</li>
203 <li><em>/WEB-INF/classes</em> of your web application</li>
204 <li><em>/WEB-INF/lib/*.jar</em> of your web application</li>
195205 </ul>
196206
197207 </section>
164164 removeSuspects will be automatically removed after removeSuspectsTimeout.
165165 If a negative value specified, the removeSuspects members never be
166166 removed until disappeared really. If the attribute is not provided,
167 a default of 300 milliseconds (5 minutes) is used.
167 a default of 300 seconds (5 minutes) is used.
168168 </attribute>
169169 </attributes>
170170 </subsection>
299299 no filtering will be applied.</p>
300300 </attribute>
301301
302 <attribute name="cookieEncoding" required="false">
303 <p>If the RFC6265 based cookie parser is used this attribute determines
304 the encoding to be used to convert the byte values in the HTTP header to
305 strings. If not specified, the default of <code>UTF-8</code> will be
306 used.</p>
307 </attribute>
308
302309 <attribute name="cookies" required="false">
303310 <p>Set to <code>true</code> if you want cookies to be used for
304311 session identifier communication if supported by the client (this
528535 penalty.</p>
529536 </attribute>
530537
538 <attribute name="useRfc6265" required="false">
539 <p>Determines if the RFC6265 based cookie parser is used. The default
540 value is <code>false</code> in which case the original parser based on
541 RFC2109 and the Netscape cookie specification will be used.</p>
542 </attribute>
543
531544 <attribute name="useHttpOnly" required="false">
532545 <p>Should the HttpOnly flag be set on session cookies to prevent client
533546 side script from accessing the session ID? Defaults to
627640 <p>If <code>true</code> and an <code>sun.net.www.http.HttpClient</code>
628641 keep-alive timer thread has been started by this web application and is
629642 still running, Tomcat will change the context class loader for that
630 thread from the current <code>WebappClassLoader</code> to
631 <code>WebappClassLoader#parent</code> to prevent a memory leak. Note
632 that the keep-alive timer thread will stop on its own once the
633 keep-alives all expire however, on a busy system that might not happen
634 for some time. If not specified, the default value of
635 <code>true</code> will be used.</p>
643 thread from the web application class loader to the the parent of the web
644 application class loader to prevent a memory leak. Note that the
645 keep-alive timer thread will stop on its own once the keep-alives all
646 expire however, on a busy system that might not happen for some time. If
647 not specified, the default value of <code>true</code> will be used.</p>
636648 </attribute>
637649
638650 <attribute name="clearReferencesStatic" required = "false">
694706 and methods that return values will return <code>null</code>. If not
695707 specified, the specification compliant default of <code>true</code> will
696708 be used.</p>
697 </attribute>
698
699 <attribute name="processTlds" required="false">
700 <p>Whether the context should process TLDs on startup. The default
701 is true. The false setting is intended for special cases
702 that know in advance TLDs are not part of the webapp.</p>
703709 </attribute>
704710
705711 <attribute name="renewThreadsWhenStoppingContext" required="false">
782788 specified static resource of the web application for updates, and will
783789 reload the web application if it is updated. The content of this element
784790 must be a string.</li>
791 <li><a href="jar-scanner.html"><strong>JarScanner</strong></a> -
792 Configure the Jar Scanner that will be used to scan the web application
793 for JAR files and directories of class files. It is typically used during
794 web application start to identify configuration files such as TLDs o
795 web-fragment.xml files that must be processed as part of the web
796 application initialisation.. Normally, the default Jar Scanner
797 configuration will be sufficient.</li>
785798 </ul>
786799
787800 </section>
383383 </attribute>
384384
385385 </attributes>
386
387 </subsection>
388
389 <subsection name="Version Logging Lifecycle Listener - org.apache.catalina.startup.VersionLoggerListener">
390
391 <p>The <strong>Version Logging Lifecycle Listener</strong> logs Tomcat, Java
392 and operating system information when Tomcat starts.</p>
393
394 <p>This listener must only be nested within <a href="server.html">Server</a>
395 elements and should be the first listener defined.</p>
396
397 <p>No additional attributes are supported by the <strong>Version Logging
398 Lifecycle Listener</strong>.</p>
386399
387400 </subsection>
388401
121121
122122 <attribute name="loaderClass" required="false">
123123 <p>Java class name of the <code>java.lang.ClassLoader</code>
124 implementation class to use. If not specified, the default value is
125 <code>org.apache.catalina.loader.WebappClassLoader</code>. Custom
126 <strong>loaderClass</strong> implementations must extend
127 <code>org.apache.catalina.loader.WebappClassLoader</code>.</p>
124 implementation class to use. Custom implementations must extend
125 <code>org.apache.catalina.loader.WebappClassLoaderBase</code>.
126 </p>
127
128 <p>If not specified, the default value is
129 <code>org.apache.catalina.loader.WebappClassLoader</code>. The
130 default <strong>loaderClass</strong> is not parallel capable, which
131 means that loading a class from this classloader is performed by one
132 thread at a time. A parallel capable <strong>loaderClass</strong> is
133 available and can be used by specifying
134 <code>org.apache.catalina.loader.ParallelWebappClassLoader</code>.</p>
128135 </attribute>
129136
130137 <attribute name="searchExternalFirst" required="false">
197197 JSP page to be executed.</p>
198198 <p>If not specified, the default value of
199199 <code>org.apache.catalina.jsp_file</code> will be used.</p>
200 <p><strong>Deprecated:</strong> This will be removed in Tomcat 9.0.x
201 onwards. It is replaced by the use of the jspFile servlet initialisation
202 parameter</p>
200203 </property>
201204
202205 <property name="org.apache.jasper.Constants. PRECOMPILE">
5252 <section name="Built-in Tomcat support">
5353 <p>Kerberos (the basis for integrated Windows authentication) requires careful
5454 configuration. If the steps in this guide are followed exactly, then a working
55 configuration will result. There may be some flexibility in some of the steps
56 below but further testing is required to explore this. From the testing to date
57 it is known that:</p>
55 configuration will result. It is important that the steps below are followed
56 exactly. There is very little scope for flexibility in the configuration. From
57 the testing to date it is known that:</p>
5858 <ul>
59 <li>The host name of the Tomcat server must match the host name in the SPN
60 exactly else authentication will fail. A checksum error may be reported in the
61 debug logs in this case.</li>
59 <li>The host name used to access the Tomcat server must match the host name in
60 the SPN exactly else authentication will fail. A checksum error may be reported
61 in the debug logs in this case.</li>
6262 <li>The client must be of the view that the server is part of the local trusted
6363 intranet.</li>
64 </ul>
65 <p>The areas where further testing is required include:</p>
66 <ul>
67 <li>Does the domain name have to be in upper case?</li>
68 <li>Does the SPN have to start with HTTP/...?</li>
69 <li>Can a port number be appended to the end of the host in the SPN?</li>
70 <li>Can the domain be left off the user in the ktpass command?</li>
71 <li>What are the limitations on the account that Tomcat can run as? SPN
72 associated account works, domain admin works, local admin doesn't
73 work</li>
64 <li>The SPN must be HTTP/&lt;hostname&gt; and it must be exactly the same in all
65 the places it is used.</li>
66 <li>The port number must not be included in the SPN.</li>
67 <li>No more than one SPN may be mapped to a domain user.</li>
68 <li>Tomcat must run as the domain account with which the SPN has been associated
69 or as domain admin. It is <strong>NOT</strong> recommended to run Tomcat under a
70 domain admin user.</li>
71 <li>The domain name (<code>DEV.LOCAL</code>) is not case sensitive when used in
72 the ktpass command, nor when used in jaas.conf</li>
73 <li>The domain must be specified when using the ktpass command</li>
7474 </ul>
7575 <p>There are four components to the configuration of the built-in Tomcat
7676 support for Windows authentication. The domain controller, the server hosting
145145 dev.local= DEV.LOCAL
146146 .dev.local= DEV.LOCAL</source>
147147 The location of this file can be changed by setting the
148 <code>java.security.krb5.conf</code> systm property.</li>
148 <code>java.security.krb5.conf</code> system property.</li>
149149 <li>Create the JAAS login configuration file
150150 <code>$CATALINA_BASE/conf/jaas.conf</code>. The file used in this how-to
151151 contained:<source>com.sun.security.jgss.krb5.initiate {