Import Upstream version 1.2

This commit is contained in:
zhouganqing 2022-11-17 20:37:50 +08:00
commit e8a71d016c
109 changed files with 18825 additions and 0 deletions

202
LICENSE.txt Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

6
NOTICE.txt Normal file
View File

@ -0,0 +1,6 @@
Apache Commons Logging
Copyright 2003-2014 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).

121
PROPOSAL.html Normal file
View File

@ -0,0 +1,121 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<title>Proposal for Logging Library Package</title>
</head>
<body bgcolor="white">
<div align="center">
<h1>Proposal for <em>Logging</em> Package</h1>
</div>
<h3>(0) Rationale</h3>
<p>There is a great need for debugging and logging information inside of
Commons components such as HTTPClient and dbcp. However, there are many
logging APIs out there and it is difficult to choose among them.
</p>
<p>The Logging package will be an ultra-thin bridge between different logging
libraries. Commons components may use the Logging JAR to remove
compile-time/runtime dependencies on any particular logging package,
and contributors may write Log implementations for the library of their choice.
</p>
<h3>(1) Scope of the Package</h3>
<p>The package shall create and maintain a package that provides extremely
basic logging functionality and bridges to other, more sophisticated logging
implementations.
</p>
<p>
The package should :
<ul>
<li>Have an API which should be as simple to use as possible</li>
<li>Provide support for log4j</li>
<li>Provide pluggable support for other logging APIs</li>
</ul>
</p>
<p>
Non-goals:
<ul>
<li>This package will not perform logging itself, except at the most basic
level.</li>
<li>We do not seek to become a "standard" API.</li>
</ul>
</p>
<h3>(1.5) Interaction With Other Packages</h3>
<p><em>Logging</em> relies on:
</p>
<ul>
<li>Java Development Kit (Version 1.1 or later)
</li>
<li>Avalon Framework (compile-time dependency only unless this Log
implementation is selected at runtime)
<li>Avalon LogKit (compile-time dependency only unless this Log
implementation is selected at runtime)
<li>JDK 1.4 (compile-time dependency only unless this log implementation
is selected at runtime).
<li>Log4J (compile-time dependency only unless this Log
implementation is selected at runtime)</li>
<li><a href="http://sourceforge.net/projects/lumberjack/">Lumberjack</a>
(compile-time dependency only unless this Log
implementation is selected at runtime)</li>
</ul>
<h3>(2) Required Jakarta-Commons Resources</h3>
<ul>
<li>CVS Repository - New directory <code>logging</code> in the
<code>jakarta-commons</code> CVS repository.</li>
<li>Initial Committers - The list is provided below. </li>
<li>Mailing List - Discussions will take place on the general
<em>dev@commons.apache.org</em> mailing list. To help list
subscribers identify messages of interest, it is suggested that the
message subject of messages about this component be prefixed with
[Logging].</li>
<li>Bugzilla - New component "Logging" under the "Commons" product
category, with appropriate version identifiers as needed.</li>
<li>Jyve FAQ - New category "commons-logging" (when available).</li>
</ul>
<h3>(4) Initial Committers</h3>
<p>The initial committers on the Logging component shall be:</p>
<ul>
<li>Morgan Delagrange</li>
<li>Rodney Waldhoff</li>
<li>Craig McClanahan</li>
</ul>
</body>
</html>

50
README.txt Normal file
View File

@ -0,0 +1,50 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
Logging
-------
Getting started:
1) Build the jar file
If you have the source distribution you will need to build the jar file
using Maven 2/3. For instructions on downloading and installing Maven see
http://maven.apache.org/.
To build execute the command 'mvn package verify'.
The jar file will be built in the target directory.
Note: the unit tests are executed during the verify phase and require that
the respective jar files have been created successfully.
2) Generate the documentation
Run the 'mvn verify site' command. The documentation will be written
to the target/site directory. The documentation has some examples of
how to use this package as well as a troubleshooting guide.
3) Create source and binary distributions
Run the 'mvn verify site assembly:assembly' command. The source and binary
distributions are created in the 'target' directory.
4) Use
Simply include the jar file built in step #1 in your classpath. Import the
classes that you want to use and you are ready to go!

31
RELEASE-NOTES.txt Normal file
View File

@ -0,0 +1,31 @@
Apache Commons Logging
Version 1.2
RELEASE NOTES
The Apache Commons Logging team is pleased to announce
the release of Apache Commons Logging 1.2
Apache Commons Logging is a thin adapter allowing configurable
bridging to other, well known logging systems.
This is a maintenance release containing bug fixes.
Java 1.2 or later is required.
Changes in this version include:
Fixed Bugs:
o LOGGING-37: Improve performance of LogFactory#getFactory() by calling
Thread#currentThread()#getContextClassLoader() directly instead
of using reflection. As a consequence support for JDK 1.1 has
been dropped. Thanks to Matthias Ernst, Archie Cobbs.
o LOGGING-156: Fix SecurityAllowedTestCase when executed with OpenJDK 1.7 due
to an additional required RuntimePermission. Thanks to Mikolaj Izdebski.
o LOGGING-157: Fix javadoc to comply with javadoc tool from jdk 1.8. Thanks to Ville Skyttä.
Historical list of changes: http://commons.apache.org/proper/commons-logging/changes-report.html
For complete information on Apache Commons Logging, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache Commons Logging website:
http://commons.apache.org/proper/commons-logging/

350
build-testing.xml Normal file
View File

@ -0,0 +1,350 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
- Ant file for running tests for commons-logging.
-
- Quick build instructions:
- * mvn package
- * ant getlibs
- * cp build.properties.sample build.properties
- * Depending on which platform you are on, do either
- set JAVA_COMPILER=NONE
- or
- setenv JAVA_COMPILER NONE
- * ant -lib lib/junit-3.8.1.jar -f build-testing.xml test
-
- Note that we have to run Ant without the JIT compiler to get around bugs in
- the 1.2 JVM. That's why we need to set JAVA_COMPILER to NONE.
- See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4240622
-
- Note that this build file uses the optional <junit> task. While the
- task "adapter" class comes by default with ant 1.6+, the junit libraries
- (3.8.1 or later) are also required to be made available to ant. This
- requires that you do one of the following:
- * create directory ~/.ant/lib and place the junit jar there
- * put the junit jar in $ANT_HOME/lib
- * run ant as "ant -lib path-to-junit-jar"
- * put the junit jar in $CLASSPATH
-
- Note when running these test before a JCL release it is strongly
- recommended that a 1.2 JVM is used.
-
- $Id: build-testing.xml 558565 2007-07-22 23:58:45Z dennisl $
-->
<project name="Logging" default="all" basedir=".">
<!-- ========== Initialize Properties ===================================== -->
<property file="build.properties"/> <!-- Component local -->
<property file="../build.properties"/> <!-- Commons local -->
<property file="${user.home}/build.properties"/> <!-- User local -->
<!-- ========== External Dependencies ===================================== -->
<!-- The directories corresponding to your necessary dependencies -->
<property name="junit.home" value="/usr/local/junit3.5"/>
<property name="jakarta.home" value="../.."/>
<!--
- The names of the unit tests to run. By default all tests are run, but
- this can be overridden from the command line by something like:
- ant -Dtestmatch=**/FooTestCase test
-->
<property name="testmatch" value="**/*TestCase"/>
<!-- ========== Derived Values ============================================ -->
<!-- The locations of necessary jar files -->
<property name="junit.jar" value="junit-3.8.1.jar"/>
<property name="log4j12.jar" value="log4j-1.2.12.jar"/>
<property name="log4j13.jar" value="log4j-1.3.0.jar"/>
<property name="logkit.jar" value="logkit-1.0.1.jar"/>
<property name="avalon-framework.jar" value="avalon-framework-4.1.3.jar"/>
<property name="servletapi.jar" value="servletapi-2.3.jar"/>
<!-- ========== Component Declarations ==================================== -->
<!-- The name of this component -->
<property name="component.name" value="logging"/>
<!-- The primary package name of this component -->
<property name="component.package" value="org.apache.commons.logging"/>
<!-- The title of this component -->
<property name="component.title" value="Logging Wrapper Library"/>
<!-- The current version number of this component -->
<property name="component.version" value="1.1.1-SNAPSHOT"/>
<!-- The base directory for compilation targets -->
<property name="build.home" value="${basedir}/target"/>
<!-- The base directory for component configuration files -->
<property name="conf.home" value="src/conf"/>
<!-- jar names -->
<property name="core.jar.name" value="commons-${component.name}-${component.version}.jar"/>
<property name="api.jar.name" value="commons-${component.name}-api-${component.version}.jar"/>
<property name="adapters.jar.name" value="commons-${component.name}-adapters-${component.version}.jar"/>
<property name="src.ide.name" value="commons-${component.name}-${component.version}-ide.zip"/>
<!-- Construct compile classpath -->
<path id="compile.classpath">
<pathelement location="${build.home}/classes"/>
<pathelement location="${junit.jar}"/>
<pathelement location="${logkit.jar}"/>
<pathelement location="${avalon-framework.jar}"/>
<pathelement location="${servletapi.jar}"/>
</path>
<!-- ========== Test Execution Defaults =================================== -->
<!--
- Construct unit test classpath (generic tests).
-
- Note that unit tests that use the PathableTestSuite approach don't need
- any of this (except junit). However unit tests that don't use PathableTestSuite
- to configure their classpath will need the basic classes to be provided
- via this mechanism.
-->
<path id="test.classpath">
<pathelement location="${build.home}/classes"/>
<pathelement location="${build.home}/test-classes"/>
<pathelement location="${junit.jar}"/>
<pathelement location="${logkit.jar}"/>
<pathelement location="${avalon-framework.jar}"/>
<pathelement location="${conf.home}"/>
<pathelement location="${servletapi.jar}"/>
</path>
<!-- Construct unit test classpath (Log4J tests) -->
<path id="test.classpath.log4j13">
<pathelement location="${build.home}/classes"/>
<pathelement location="${build.home}/test-classes"/>
<pathelement location="${junit.jar}"/>
<pathelement location="${log4j13.jar}"/>
</path>
<!-- Construct unit test classpath (Log4J tests) -->
<path id="test.classpath.log4j12">
<pathelement location="${build.home}/classes"/>
<pathelement location="${build.home}/test-classes"/>
<pathelement location="${junit.jar}"/>
<pathelement location="${log4j12.jar}"/>
</path>
<!-- Should all tests fail if one does? -->
<property name="test.failonerror" value="true"/>
<!-- The test runner to execute -->
<property name="test.runner" value="junit.textui.TestRunner"/>
<!-- libs to pass to the tests -->
<property name="test.sysprops.testclasses" value="${build.home}/test-classes"/>
<property name="test.sysprops.log4j12" value="${log4j12.jar}"/>
<property name="test.sysprops.log4j13" value="${log4j13.jar}"/>
<property name="test.sysprops.logkit" value="${logkit.jar}"/>
<property name="test.sysprops.servlet-api" value="${servletapi.jar}"/>
<property name="test.sysprops.commons-logging" value="${build.home}/${core.jar.name}"/>
<property name="test.sysprops.commons-logging-api" value="${build.home}/${api.jar.name}"/>
<property name="test.sysprops.commons-logging-adapters" value="${build.home}/${adapters.jar.name}"/>
<propertyset id="test-lib-props">
<propertyref prefix="test.sysprops."/>
<mapper type="glob" from="test.sysprops.*" to="*"/>
</propertyset>
<!-- ========== Executable Targets ======================================== -->
<!--
- Running this target will download all the necessary dependencies into the "lib" subdirectory.
-->
<property name="getlibs.base" value="http://repo1.maven.org/maven"/>
<target name="getlibs">
<mkdir dir="lib"/>
<get dest="lib/junit-3.8.1.jar" src="${getlibs.base}/junit/jars/junit-3.8.1.jar"/>
<get dest="lib/logkit-1.0.1.jar" src="${getlibs.base}/logkit/jars/logkit-1.0.1.jar"/>
<get dest="lib/avalon-framework-4.1.3.jar" src="${getlibs.base}/avalon-framework/jars/avalon-framework-4.1.3.jar"/>
<get dest="lib/log4j-1.2.12.jar" src="${getlibs.base}/log4j/jars/log4j-1.2.12.jar"/>
<get dest="lib/servletapi-2.3.jar" src="${getlibs.base}/servletapi/jars/servletapi-2.3.jar"/>
</target>
<target name="init"
description="Initialize and evaluate conditionals">
<echo message="-------- ${component.title} ${component.version} --------"/>
<filter token="name" value="${component.name}"/>
<filter token="package" value="${component.package}"/>
<filter token="version" value="${component.version}"/>
</target>
<target name="prepare" depends="init"
description="Prepare build directory">
<echo>
Log4j12: ${log4j12.jar}
<!-- Note: log4j13 support is not available in the 1.1 release. -->
<!--Log4j13: ${log4j13.jar}-->
LogKit: ${logkit.jar}
Avalon-Framework: ${avalon-framework.jar}
</echo>
<mkdir dir="${build.home}"/>
<mkdir dir="${build.home}/classes"/>
<mkdir dir="${build.home}/conf"/>
<mkdir dir="${build.home}/tests"/>
</target>
<target name='discovery' depends='init'>
<available property="jdk.1.4.present"
classname="java.util.logging.Logger"/>
<available property="logkit.present"
classpathref="compile.classpath"
classname="org.apache.log.Logger"/>
<available property="avalon-framework.present"
classpathref="compile.classpath"
classname="org.apache.avalon.framework.logger.Logger"/>
<available file="${log4j12.jar}" property="log4j12.present"/>
<available file="${log4j13.jar}" property="log4j13.present"/>
<available file="${build.home}/docs" property="maven.generated.docs.present"/>
</target>
<target name="log4j12-test-warning" unless='log4j12.jar' depends='init,discovery'>
<echo>
*** WARNING ***
Log4J 1.2.x Jar not found: Cannot execute 1.2.x tests
</echo>
</target>
<target name="show-lib-presence">
<echo message="jdk.1.4.present=${jdk.1.4.present}"/>
<echo message="log4j12.present=${log4j12.present}"/>
<!-- Note: log4j13 support is not available in the 1.1 release. -->
<!--<echo message="log4j13.present=${log4j13.present}"/>-->
<echo message="logkit.present=${logkit.present}"/>
<echo message="avalon-framework.present=${avalon-framework.present}"/>
</target>
<target name="all" depends="test"
description="Test all components"/>
<!-- ========== Unit Test Targets ========================================= -->
<!--
- Target to run all unit tests.
-
- The batchtest task auto-detects what tests are available without
- any need to define TestSuite objects in the code to compose
- sets of tests to be run.
-
- Details of the unit test results for each TestCase will appear in
- a file in directory ${build.home}/test-reports, together with any
- output to stdout or stderr generated by the test code.
-
- If you're having problems running this target due to the use of
- the "junit" task below, see the comments at the head of this file.
-
- Individual tests (or subsets of tests) can be run by doing
- ant -Dtestmatch=**/FooTestCase testall
-->
<target name="test" depends="log4j12-test-warning"
description="Run all unit tests">
<echo message="Test output can be found in directory ${build.home}/test-reports."/>
<delete dir="${build.home}/test-reports"/>
<mkdir dir="${build.home}/test-reports"/>
<echo message="executing tests [${testmatch}.java]"/>
<!--
- Note that the fork/forkmode settings define default behaviour for tests.
- The <test> and <batchtest> tags can override these settings if needed.
- The default settings cause a single VM to be created in which all of
- the tests are then run.
-->
<junit printsummary="off" showoutput="no" fork="yes" forkmode="once" failureproperty="test.failure">
<!-- plain output to file; brief output to console. -->
<formatter type="plain"/>
<formatter usefile="false" type="brief"/>
<!--
- Provide a set of properties pointing to the logging libs for
- the use of the PathableClassLoader class used by some unit tests.
-->
<syspropertyset refid="test-lib-props"/>
<classpath refid="test.classpath"/>
<!--
- Uncomment this to enable logging diagnostics for tests
- <jvmarg value="-Dorg.apache.commons.logging.diagnostics.dest=STDERR"/>
-->
<!--
- Auto-detect the tests to run. Checking the ${build.home}/tests
- directory for .class files rather than the src/test directory
- for .java files means that when we run the tests on platforms
- where some components (eg jdk14 logging) is not available,
- just ensuring the tests are skipped from the compile will
- also cause them to be skipped from the testing.
-
- This does introduce the danger that if tests accidentally
- fail to compile then we won't notice it here. However that
- should have been reported earlier anyway.
-->
<batchtest todir="${build.home}/test-reports">
<fileset dir="${build.home}/test-classes">
<include name="${testmatch}.class"/>
<!--
- Exclude the jdk14 tests because we are running these tests on
- a jvm < 1.4
-->
<exclude name="org/apache/commons/logging/jdk14/*"/>
<!--
- Exclude the security tests because they rely on the
- MockSecurityManager that uses code that was first introduced in
- Java 1.4
-->
<exclude name="org/apache/commons/logging/security/*"/>
</fileset>
</batchtest>
</junit>
<fail if="test.failure">
One or more unit tests failed.
</fail>
</target>
</project>

59
build.properties.sample Normal file
View File

@ -0,0 +1,59 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
######################################################################
#
# TO USE:
#
# Copy this file to build.properties and either
#
# a) Use 'ant getlibs' to populate the default directory
# with dependencies
# or b) Change the property values to appropriate values
#
########################################################################
# Apache Log4j 1.2.x series
log4j12.jar=lib/log4j-1.2.12.jar
# Apache Log4j 1.3.x series
# Note: Log4j 1.3 support not available in the 1.1 release
#log4j13.jar=lib/log4j-1.3.0.jar
# logkit.jar - Avalon LogKit classes (see http://jakarta.apache.org/avalon)
logkit.jar=lib/logkit-1.0.1.jar
# Avalon framework - used for wrapper for avalon framework logger
avalon-framework.jar=lib/avalon-framework-4.1.3.jar
# ServletApi - used to build ServletContextCleaner class
servletapi.jar=lib/servletapi-2.3.jar
#
# if you want to run the test cases, junit needs to be in the classpath.
# the build.xml uses a default value so you might not need to set this property.
# Note that version junit 3.8 is required and 3.8.1 recommended.
#
junit.jar=lib/junit-3.8.1.jar
# Maven properties (for web site build)
# Those committers using agents may like to use
#maven.username=rdonkin
#logging.cvs=lserver:rdonkin@cvs.apache.org:/home/cvs
# The path to a 1.4 JSDK javac
# Optional - used when building with a 1.2 JVM for releases
# executable.javac1.4=/opt/java/jdks/j2sdk1.4.2_10/bin/javac

776
build.xml Normal file
View File

@ -0,0 +1,776 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
- Ant build file for commons-logging.
-
- Quick build instructions:
- * ant getlibs
- * cp build.properties.sample build.properties
- * ant -lib lib/junit-3.8.1.jar dist
-
- Note that this build file uses the optional <junit> task. While the
- task "adapter" class comes by default with ant 1.6+, the junit libraries
- (3.8.1 or later) are also required to be made available to ant. This
- requires that you do one of the following:
- * create directory ~/.ant/lib and place the junit jar there
- * put the junit jar in $ANT_HOME/lib
- * run ant as "ant -lib path-to-junit-jar"
- * put the junit jar in $CLASSPATH
-
- Note when building JCL for release it is strongly recommended that a 1.2 JVM
- is used for the main compile and the home.jdk4 property used to specify
- the path to a 1.4 J2SDK. This will be used to compile those classes
- which require the 1.4 API.
-
- $Id: build.xml 1608092 2014-07-05 18:11:22Z tn $
-->
<project name="Logging" default="all" basedir=".">
<!-- ========== Initialize Properties ===================================== -->
<property file="build.properties"/> <!-- Component local -->
<property file="../build.properties"/> <!-- Commons local -->
<property file="${user.home}/build.properties"/> <!-- User local -->
<!-- ========== External Dependencies ===================================== -->
<!-- The directories corresponding to your necessary dependencies -->
<property name="junit.home" value="/usr/local/junit3.5"/>
<property name="jakarta.home" value="../.."/>
<property name="commons.home" value="../.."/>
<!--
- The names of the unit tests to run. By default all tests are run, but
- this can be overridden from the command line by something like:
- ant -Dtestmatch=**/FooTestCase test
-->
<property name="testmatch" value="**/*TestCase"/>
<!-- ========== Derived Values ============================================ -->
<!-- The locations of necessary jar files -->
<property name="junit.jar" value="junit-3.8.1.jar"/>
<property name="log4j12.jar" value="log4j-1.2.17.jar"/>
<property name="log4j13.jar" value="log4j-1.3.0.jar"/>
<property name="logkit.jar" value="logkit-1.0.1.jar"/>
<property name="avalon-framework.jar" value="avalon-framework-4.1.5.jar"/>
<property name="servletapi.jar" value="servletapi-2.3.jar"/>
<!-- ========== Component Declarations ==================================== -->
<!-- The name of this component -->
<property name="component.name" value="logging"/>
<!-- The primary package name of this component -->
<property name="component.package" value="org.apache.commons.logging"/>
<!-- The title of this component -->
<property name="component.title" value="Logging Wrapper Library"/>
<!-- The current version number of this component -->
<property name="component.version" value="1.2"/>
<!-- The base directory for compilation targets -->
<property name="build.home" value="${basedir}/target"/>
<!-- The base directory for component configuration files -->
<property name="conf.home" value="src/conf"/>
<!-- The base directory for distribution targets -->
<property name="dist.home" value="dist"/>
<!-- The base directory for releases -->
<property name="artifacts.home" value="artifacts"/>
<!-- The base directory for component sources -->
<property name="source.home" value="src/main/java"/>
<!-- The base directory for unit test sources -->
<property name="test.home" value="src/test/java"/>
<!-- The base directory for unit test resources -->
<property name="test.resources" value="src/test/resources"/>
<!-- jar names -->
<property name="core.jar.name" value="commons-${component.name}-${component.version}.jar"/>
<property name="api.jar.name" value="commons-${component.name}-api-${component.version}.jar"/>
<property name="adapters.jar.name" value="commons-${component.name}-adapters-${component.version}.jar"/>
<property name="src.ide.name" value="commons-${component.name}-${component.version}-ide.zip"/>
<!-- dist names -->
<property name="windows.dist.name" value="commons-${component.name}-${component.version}.zip"/>
<property name="nix.dist.name" value="commons-${component.name}-${component.version}.tar.gz"/>
<!-- ========== Compiler Defaults ========================================= -->
<!-- Version of java class files to generate. -->
<property name="target.version" value="1.2"/>
<!-- Version of java source to accept -->
<property name="source.version" value="1.2"/>
<!-- Should Java compilations set the 'debug' compiler option? -->
<property name="compile.debug" value="true"/>
<!-- Should Java compilations set the 'deprecation' compiler option? -->
<property name="compile.deprecation" value="false"/>
<!-- Should Java compilations set the 'optimize' compiler option? -->
<property name="compile.optimize" value="false"/>
<!-- Construct compile classpath -->
<path id="compile.classpath">
<pathelement location="${build.home}/classes"/>
<pathelement location="${junit.jar}"/>
<pathelement location="${logkit.jar}"/>
<pathelement location="${avalon-framework.jar}"/>
<pathelement location="${servletapi.jar}"/>
</path>
<!-- ========== Test Execution Defaults =================================== -->
<!--
- Construct unit test classpath (generic tests).
-
- Note that unit tests that use the PathableTestSuite approach don't need
- any of this (except junit). However unit tests that don't use PathableTestSuite
- to configure their classpath will need the basic classes to be provided
- via this mechanism.
-->
<path id="test.classpath">
<pathelement location="${build.home}/classes"/>
<pathelement location="${build.home}/tests"/>
<pathelement location="${junit.jar}"/>
<pathelement location="${logkit.jar}"/>
<pathelement location="${avalon-framework.jar}"/>
<pathelement location="${conf.home}"/>
<pathelement location="${servletapi.jar}"/>
</path>
<!-- Construct unit test classpath (Log4J tests) -->
<path id="test.classpath.log4j13">
<pathelement location="${build.home}/classes"/>
<pathelement location="${build.home}/tests"/>
<pathelement location="${junit.jar}"/>
<pathelement location="${log4j13.jar}"/>
</path>
<!-- Construct unit test classpath (Log4J tests) -->
<path id="test.classpath.log4j12">
<pathelement location="${build.home}/classes"/>
<pathelement location="${build.home}/tests"/>
<pathelement location="${junit.jar}"/>
<pathelement location="${log4j12.jar}"/>
</path>
<!-- Construct javadoc classpath -->
<path id="javadoc.classpath">
<path refid="compile.classpath"/>
<pathelement location="${log4j12.jar}"/>
</path>
<!-- Should all tests fail if one does? -->
<property name="test.failonerror" value="true"/>
<!-- The test runner to execute -->
<property name="test.runner" value="junit.textui.TestRunner"/>
<!-- libs to pass to the tests -->
<property name="test.sysprops.testclasses" value="${build.home}/tests"/>
<property name="test.sysprops.log4j12" value="${log4j12.jar}"/>
<property name="test.sysprops.log4j13" value="${log4j13.jar}"/>
<property name="test.sysprops.logkit" value="${logkit.jar}"/>
<property name="test.sysprops.servlet-api" value="${servletapi.jar}"/>
<property name="test.sysprops.commons-logging" value="${build.home}/${core.jar.name}"/>
<property name="test.sysprops.commons-logging-api" value="${build.home}/${api.jar.name}"/>
<property name="test.sysprops.commons-logging-adapters" value="${build.home}/${adapters.jar.name}"/>
<propertyset id="test-lib-props">
<propertyref prefix="test.sysprops."/>
<mapper type="glob" from="test.sysprops.*" to="*"/>
</propertyset>
<!-- ========== Executable Targets ======================================== -->
<!--
- Running this target will download all the necessary dependencies into the "lib" subdirectory.
-->
<property name="getlibs.base" value="http://repo1.maven.org/maven"/>
<target name="getlibs">
<mkdir dir="lib"/>
<get dest="lib/junit-3.8.1.jar" src="${getlibs.base}/junit/jars/junit-3.8.1.jar"/>
<get dest="lib/logkit-1.0.1.jar" src="${getlibs.base}/logkit/jars/logkit-1.0.1.jar"/>
<get dest="lib/avalon-framework-4.1.3.jar" src="${getlibs.base}/avalon-framework/jars/avalon-framework-4.1.3.jar"/>
<get dest="lib/log4j-1.2.12.jar" src="${getlibs.base}/log4j/jars/log4j-1.2.12.jar"/>
<get dest="lib/servletapi-2.3.jar" src="${getlibs.base}/servletapi/jars/servletapi-2.3.jar"/>
</target>
<target name="init"
description="Initialize and evaluate conditionals">
<echo message="-------- ${component.title} ${component.version} --------"/>
<filter token="name" value="${component.name}"/>
<filter token="package" value="${component.package}"/>
<filter token="version" value="${component.version}"/>
</target>
<target name="prepare" depends="init"
description="Prepare build directory">
<echo>
Log4j12: ${log4j12.jar}
<!-- Note: log4j13 support is not available in the 1.1 release. -->
<!--Log4j13: ${log4j13.jar}-->
LogKit: ${logkit.jar}
Avalon-Framework: ${avalon-framework.jar}
</echo>
<mkdir dir="${build.home}"/>
<mkdir dir="${build.home}/classes"/>
<mkdir dir="${build.home}/conf"/>
<mkdir dir="${build.home}/tests"/>
</target>
<target name="static" depends="prepare"
description="Copy static files to build directory">
<tstamp/>
<copy todir="${build.home}/conf" filtering="on">
<fileset dir="${conf.home}" includes="*.MF"/>
<fileset dir="${conf.home}" includes="*.properties"/>
</copy>
</target>
<target name="compile" depends="static,compile-only"
description="Compile shareable components"/>
<target name='discovery' depends='init'>
<available property="jdk.1.4.present"
classname="java.util.logging.Logger"/>
<available property="logkit.present"
classpathref="compile.classpath"
classname="org.apache.log.Logger"/>
<available property="avalon-framework.present"
classpathref="compile.classpath"
classname="org.apache.avalon.framework.logger.Logger"/>
<available file="${log4j12.jar}" property="log4j12.present"/>
<available file="${log4j13.jar}" property="log4j13.present"/>
<available file="${build.home}/docs" property="maven.generated.docs.present"/>
</target>
<target name="log4j12-warning" unless='log4j12.present' depends='init,discovery'>
<echo>
*** WARNING ***
Log4j 1.2 not found: Cannot Build Log4JLogger
</echo>
</target>
<target name="log4j13-warning" unless='log4j13.present' depends='init,discovery'>
<!--
- Note: log4j13 support is not available in the 1.1 release.
- If we add it in a future release, the code below should be uncommented.
-->
<!--
<echo>
*** WARNING ***
Log4j 1.3 not found: Cannot Build Log4J13Logger
</echo>
-->
</target>
<target name="logkit-warning" unless='logkit.present' depends='init,discovery'>
<echo>
*** WARNING ***
LogKit not found: Cannot Build LogKitLogger
</echo>
</target>
<target name="avalon-framework-warning" unless='avalon-framework.present' depends='init,discovery'>
<echo>
*** WARNING ***
Avalon-Framework not found: Cannot Build AvalonLogger
</echo>
</target>
<target name="jdk1.4-warning" unless='jdk.1.4.present' depends='init,discovery'>
<echo>
*** WARNING ***
JDK 1.4 not present: Cannot Build Jdk14Logger
</echo>
</target>
<target name="log4j12-test-warning" unless='log4j12.jar' depends='init,discovery'>
<echo>
*** WARNING ***
Log4J 1.2.x Jar not found: Cannot execute 1.2.x tests
</echo>
</target>
<target name='warning'
depends='log4j12-warning,log4j13-warning,logkit-warning,jdk1.4-warning,avalon-framework-warning,compile-1.4'/>
<target name="compile-only"
depends="prepare,discovery,warning,show-lib-presence,compile-non-log4j,compile-log4j12,compile-log4j13,build-jar"/>
<target name="show-lib-presence">
<echo message="jdk.1.4.present=${jdk.1.4.present}"/>
<echo message="log4j12.present=${log4j12.present}"/>
<!-- Note: log4j13 support is not available in the 1.1 release. -->
<!--<echo message="log4j13.present=${log4j13.present}"/>-->
<echo message="logkit.present=${logkit.present}"/>
<echo message="avalon-framework.present=${avalon-framework.present}"/>
</target>
<target name="compile-non-log4j" depends="prepare,discovery">
<!-- compile everything except Log4J classes -->
<javac srcdir="${source.home}"
destdir="${build.home}/classes"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
source="${source.version}"
target="${target.version}">
<classpath refid="compile.classpath"/>
<exclude name="org/apache/commons/logging/impl/Log4J*.java"/>
<exclude name="org/apache/commons/logging/impl/Jdk13LumberjackLogger.java"
unless="jdk.1.4.present"/>
<exclude name="org/apache/commons/logging/impl/Jdk14Logger.java"
unless="jdk.1.4.present"/>
<exclude name="org/apache/commons/logging/impl/LogKitLogger.java"
unless="logkit.present"/>
<exclude name="org/apache/commons/logging/impl/AvalonLogger.java"
unless="avalon-framework.present"/>
</javac>
</target>
<target name="compile-1.4" depends="prepare,discovery,compile-non-log4j" if='executable.javac1.4'>
<!--
- Compiles those classes which require a 1.4+ JSDK.
- This target will only be executed when ant is running a pre-1.4 JVM
- and the home.jdk4 property is set.
- This configuration is typically used to create a release only.
-->
<echo message=""/>
<echo message="************************************************************"/>
<echo message=" Compiling 1.4 only classes using compiler@${executable.javac1.4}"/>
<echo message="************************************************************"/>
<echo message=""/>
<javac srcdir="${source.home}"
destdir="${build.home}/classes"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
source="${source.version}"
target="${target.version}"
compiler='javac1.4'
fork='yes'
executable='${executable.javac1.4}'>
<classpath refid="compile.classpath"/>
<include name="org/apache/commons/logging/impl/Jdk13LumberjackLogger.java"
unless="jdk.1.4.present"/>
<include name="org/apache/commons/logging/impl/Jdk14Logger.java"
unless="jdk.1.4.present"/>
</javac>
</target>
<target name="compile-log4j12" depends="prepare,discovery">
<!-- compile the log4j1.2 support classes -->
<javac srcdir="${source.home}"
destdir="${build.home}/classes"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
source="${source.version}"
target="${target.version}">
<classpath refid="compile.classpath"/>
<classpath>
<!--
<pathelement refid="compile.classpath"/>
<classpath refid="compile.classpath"/>
-->
<pathelement location="${log4j12.jar}"/>
</classpath>
<include name="org/apache/commons/logging/impl/Log4JLogger.java"
if="log4j12.present"/>
</javac>
</target>
<target name="compile-log4j13" depends="prepare,discovery">
<!-- compile the log4j1.3 support classes -->
<javac srcdir="${source.home}"
destdir="${build.home}/classes"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
source="${source.version}"
target="${target.version}">
<classpath refid="compile.classpath"/>
<classpath>
<pathelement location="${log4j13.jar}"/>
</classpath>
<!--
- Note: log4j13 support not available in 1.1 release. However if we do add it
- in a future release, this entry will pick it up. In the meantime, this
- simply compiles no classes.
-->
<include name="org/apache/commons/logging/impl/Log4J13Logger.java"
if="log4j13.present"/>
</javac>
</target>
<target name="build-jar">
<copy todir="${build.home}/classes" filtering="on">
<fileset dir="${source.home}" excludes="**/*.java"/>
</copy>
<mkdir dir="${build.home}/classes/META-INF"/>
<copy file="LICENSE.txt"
todir="${build.home}/classes/META-INF"/>
<copy file="NOTICE.txt"
todir="${build.home}/classes/META-INF"/>
<jar jarfile="${build.home}/${core.jar.name}"
basedir="${build.home}/classes"
manifest="${build.home}/conf/MANIFEST.MF">
<include name="org/apache/commons/logging/**" />
<include name="META-INF/LICENSE.txt"/>
<include name="META-INF/NOTICE.txt"/>
<exclude name="**/package.html"/>
</jar>
<jar jarfile="${build.home}/${api.jar.name}"
basedir="${build.home}/classes"
manifest="${build.home}/conf/MANIFEST.MF">
<include name="org/apache/commons/logging/*.class" />
<include name="org/apache/commons/logging/impl/LogFactoryImpl*.class" />
<include name="org/apache/commons/logging/impl/WeakHashtable*.class" />
<include name="org/apache/commons/logging/impl/SimpleLog*.class" />
<include name="org/apache/commons/logging/impl/NoOpLog*.class" />
<include name="org/apache/commons/logging/impl/Jdk14Logger.class" />
<include name="META-INF/LICENSE.txt"/>
<include name="META-INF/NOTICE.txt"/>
<exclude name="**/package.html"/>
</jar>
<jar jarfile="${build.home}/${adapters.jar.name}"
basedir="${build.home}/classes"
manifest="${build.home}/conf/MANIFEST.MF">
<include name="org/apache/commons/logging/impl/**.class" />
<include name="META-INF/LICENSE.txt"/>
<include name="META-INF/NOTICE.txt"/>
<exclude name="org/apache/commons/logging/impl/WeakHashtable*.class" />
<exclude name="org/apache/commons/logging/impl/LogFactoryImpl*.class" />
</jar>
</target>
<target name='compile.jdk1.4.tests' if='jdk.1.4.present'>
<javac srcdir="${test.home}"
destdir="${build.home}/tests"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
source="${source.version}"
target="${target.version}">
<classpath refid="test.classpath"/>
<include name='**/jdk14/**'/>
</javac>
</target>
<target name='compile.log4j.tests' if='log4j12.present'>
<javac srcdir="${test.home}"
destdir="${build.home}/tests"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
source="${source.version}"
target="${target.version}">
<classpath refid="test.classpath.log4j12"/>
<include name='**/log4j/**'/>
<!-- NOTE -->
<!--
Pathable tests do not reference the Log4J Logger directly
but try to load them by reflection from particular loaders.
They will therefore fail unless this logger is available.
-->
<include name='**/pathable/**'/>
<!-- END NOTE -->
</javac>
</target>
<target name='compile.avalon.tests' if='avalon-framework.present'>
<javac srcdir="${test.home}"
destdir="${build.home}/tests"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
source="${source.version}"
target="${target.version}">
<classpath refid="test.classpath"/>
<include name='**/avalon/**'/>
</javac>
</target>
<target name='compile.logkit.tests' if='logkit.present'>
<javac srcdir="${test.home}"
destdir="${build.home}/tests"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
source="${source.version}"
target="${target.version}">
<classpath refid="test.classpath"/>
<include name='**/logkit/**'/>
</javac>
</target>
<target name="compile.tests" depends="compile"
description="Compile unit test cases">
<javac srcdir="${test.home}"
destdir="${build.home}/tests"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
source="${source.version}"
target="${target.version}">
<classpath refid="test.classpath"/>
<exclude name='**/jdk14/**'/>
<exclude name='**/log4j/**'/>
<!-- NOTE -->
<!--
Pathable tests do not reference the Log4J Logger directly
but try to load them by reflection from particular loaders.
They will therefore fail unless this logger is available.
-->
<exclude name='**/pathable/**'/>
<!-- END NOTE -->
<exclude name='**/avalon/**'/>
<exclude name='**/logkit/**'/>
</javac>
<antcall target='compile.log4j.tests'/>
<antcall target='compile.jdk1.4.tests'/>
<antcall target='compile.avalon.tests'/>
<antcall target='compile.logkit.tests'/>
<copy todir="${build.home}/tests" filtering="on">
<fileset dir="${test.resources}" excludes="**/*.java"/>
</copy>
<jar jarfile="${build.home}/commons-${component.name}-tests.jar"
basedir="${build.home}/tests"
manifest="${build.home}/conf/MANIFEST.MF">
<exclude name="org/apache/commons/logging/Wrapper.class"/>
<exclude name="org/apache/commons/logging/jdk14/TestHandler.class"
if="jdk.1.4.present"/>
</jar>
</target>
<target name="clean" description="Clean build and distribution directories">
<mkdir dir='${build.home}'/>
<delete includeemptydirs='yes'>
<fileset dir="${build.home}" excludes='docs/**/*'/>
</delete>
<delete dir="${dist.home}"/>
<delete dir="${artifacts.home}"/>
</target>
<target name="all" depends="clean,compile,test"
description="Clean and compile all components"/>
<target name="maven-docs-warning" unless="maven.generated.docs.present" depends="discovery">
<echo>
*** WARNING ***
Maven generated documentation not found: Documentation distribution will be empty
</echo>
</target>
<target name="dist" depends="all,maven-docs-warning"
description="Create binary distribution">
<!--
- Maven is used to generate the documentation.
- However, we cannot assume that it has been run.
- So, create the appropriate directories.
-->
<mkdir dir='${build.home}'/>
<mkdir dir='${build.home}/docs'/>
<mkdir dir='${build.home}/docs/apidocs'/>
<!--
- Create a dist directory to hold all the files that go into a distribution.
- Copy the needed files from the build directory to the dist directory.
-->
<mkdir dir="${dist.home}"/>
<copy todir="${dist.home}">
<fileset dir=".">
<include name="LICENSE.txt"/>
<include name="NOTICE.txt"/>
<include name="RELEASE-NOTES.txt"/>
</fileset>
<fileset dir="${build.home}">
<include name="${core.jar.name}"/>
<include name="${api.jar.name}"/>
<include name="${adapters.jar.name}"/>
</fileset>
</copy>
<!-- Copy documentation generated by maven -->
<mkdir dir="${dist.home}/docs"/>
<copy todir="${dist.home}/docs">
<fileset dir="${build.home}/docs"/>
</copy>
<!--
- And copy the source too; we don't have separate source and binary distributions
- for logging; the source is so small there's little point.
-->
<mkdir dir="${dist.home}/src"/>
<copy todir="${dist.home}/src" filtering="on">
<fileset dir="${source.home}"/>
</copy>
<zip destfile='${dist.home}/${src.ide.name}'>
<zipfileset dir='${dist.home}/src'/>
<zipfileset dir='${dist.home}/docs/apidocs'/>
<zipfileset dir='${dist.home}' prefix='META-INF'>
<include name="LICENSE.txt"/>
<include name="NOTICE.txt"/>
</zipfileset>
</zip>
<!-- Create release artifacts in the artifacts directory -->
<mkdir dir="${artifacts.home}"/>
<fixcrlf srcdir='${dist.home}' eol='dos' includes='**/*.txt,**/*.java,**/*.html'/>
<zip destfile='${artifacts.home}/${windows.dist.name}'>
<zipfileset dir='${dist.home}' prefix='commons-${component.name}-${component.version}'/>
</zip>
<fixcrlf srcdir='${dist.home}' eol='unix' includes='**/*.txt,**/*.java,**/*.html'/>
<tar compression="gzip" destfile='${artifacts.home}/${nix.dist.name}' longfile='gnu'>
<tarfileset dir='${dist.home}' prefix='commons-${component.name}-${component.version}'/>
</tar>
<copy todir="${artifacts.home}">
<fileset dir="${build.home}">
<include name="${core.jar.name}"/>
<include name="${api.jar.name}"/>
<include name="${adapters.jar.name}"/>
</fileset>
</copy>
</target>
<!-- ========== Unit Test Targets ========================================= -->
<!--
- Target to run all unit tests.
-
- The batchtest task auto-detects what tests are available without
- any need to define TestSuite objects in the code to compose
- sets of tests to be run.
-
- Details of the unit test results for each TestCase will appear in
- a file in directory ${build.home}/test-reports, together with any
- output to stdout or stderr generated by the test code.
-
- If you're having problems running this target due to the use of
- the "junit" task below, see the comments at the head of this file.
-
- Individual tests (or subsets of tests) can be run by doing
- ant -Dtestmatch=**/FooTestCase testall
-->
<target name="test" depends="log4j12-test-warning, compile.tests"
description="Run all unit tests">
<echo message="Test output can be found in directory ${build.home}/test-reports."/>
<delete dir="${build.home}/test-reports"/>
<mkdir dir="${build.home}/test-reports"/>
<echo message="executing tests [${testmatch}.java]"/>
<!--
- Note that the fork/forkmode settings define default behaviour for tests.
- The <test> and <batchtest> tags can override these settings if needed.
- The default settings cause a single VM to be created in which all of
- the tests are then run.
-->
<junit printsummary="off" showoutput="no" fork="yes" forkmode="once" failureproperty="test.failure">
<!-- plain output to file; brief output to console. -->
<formatter type="plain"/>
<formatter usefile="false" type="brief"/>
<!--
- Provide a set of properties pointing to the logging libs for
- the use of the PathableClassLoader class used by some unit tests.
-->
<syspropertyset refid="test-lib-props"/>
<classpath refid="test.classpath"/>
<!--
- Uncomment this to enable logging diagnostics for tests
- <jvmarg value="-Dorg.apache.commons.logging.diagnostics.dest=STDERR"/>
-->
<!--
- Auto-detect the tests to run. Checking the ${build.home}/tests
- directory for .class files rather than the src/test directory
- for .java files means that when we run the tests on platforms
- where some components (eg jdk14 logging) is not available,
- just ensuring the tests are skipped from the compile will
- also cause them to be skipped from the testing.
-
- This does introduce the danger that if tests accidentally
- fail to compile then we won't notice it here. However that
- should have been reported earlier anyway.
-->
<batchtest todir="${build.home}/test-reports">
<fileset dir="${build.home}/tests">
<include name="${testmatch}.class"/>
</fileset>
</batchtest>
</junit>
<fail if="test.failure">
One or more unit tests failed.
</fail>
</target>
</project>

69
checkstyle.xml Normal file
View File

@ -0,0 +1,69 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.1//EN"
"http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
<!-- commons logging customization of default Checkstyle behavior -->
<module name="Checker">
<property name="localeLanguage" value="en" />
<property name="severity" value="warning"/>
<!-- Checks whether files end with a new line. -->
<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
<module name="NewlineAtEndOfFile" />
<!-- Verify that EVERY source file has the appropriate license -->
<module name="Header">
<property name="headerFile" value="${checkstyle.header.file}" />
</module>
<!-- Checks for Tab characters -->
<!-- See http://checkstyle.sourceforge.net/config_whitespace.html#FileTabCharacter -->
<module name="FileTabCharacter">
<property name="fileExtensions" value="java" />
</module>
<!-- Checks for white space at the end of the line -->
<!-- See http://checkstyle.sourceforge.net/config_regexp.html -->
<module name="RegexpSingleline">
<property name="format" value="\s+$" />
<property name="message" value="Line has trailing spaces." />
<property name="fileExtensions" value="java" />
</module>
<!-- @author tags are deprecated -->
<module name="RegexpSingleline">
<property name="format" value="^\s+\*\s+@author\s" />
<property name="message" value="Deprecated @author tag" />
<property name="fileExtensions" value="java" />
<property name="severity" value="warning" />
</module>
<module name="TreeWalker">
<property name="cacheFile" value="target/cachefile" />
<module name="OperatorWrap">
<property name="option" value="eol" />
</module>
<module name="LineLength">
<property name="max" value="120"/>
</module>
</module>
</module>

16
license-header.txt Normal file
View File

@ -0,0 +1,16 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

26
pmd.xml Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ruleset name="mybraces"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>Excludes from default PMD rules.</description>
<rule ref="rulesets/java/unusedcode.xml">
<exclude name="UnnecessaryParentheses"/>
</rule>
</ruleset>

547
pom.xml Normal file
View File

@ -0,0 +1,547 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--
- Note that due to the special requirements of logging unit-tests, most
- tests are executed in the "integration-test" phase rather than the
- "test" phase. Please run "mvn integration-test" to run the full suite of
- available unit tests.
-->
<parent>
<groupId>org.apache.commons</groupId>
<artifactId>commons-parent</artifactId>
<version>34</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<name>Apache Commons Logging</name>
<version>1.2</version>
<description>Apache Commons Logging is a thin adapter allowing configurable bridging to other,
well known logging systems.</description>
<url>http://commons.apache.org/proper/commons-logging/</url>
<issueManagement>
<system>JIRA</system>
<url>http://issues.apache.org/jira/browse/LOGGING</url>
</issueManagement>
<inceptionYear>2001</inceptionYear>
<developers>
<developer>
<id>baliuka</id>
<name>Juozas Baliuka</name>
<email>baliuka@apache.org</email>
<roles>
<role>Java Developer</role>
</roles>
</developer>
<developer>
<id>morgand</id>
<name>Morgan Delagrange</name>
<email>morgand@apache.org</email>
<organization>Apache</organization>
<roles>
<role>Java Developer</role>
</roles>
</developer>
<developer>
<id>donaldp</id>
<name>Peter Donald</name>
<email>donaldp@apache.org</email>
</developer>
<developer>
<id>rdonkin</id>
<name>Robert Burrell Donkin</name>
<email>rdonkin@apache.org</email>
<organization>The Apache Software Foundation</organization>
</developer>
<developer>
<id>skitching</id>
<name>Simon Kitching</name>
<email>skitching@apache.org</email>
<organization>The Apache Software Foundation</organization>
</developer>
<developer>
<id>dennisl</id>
<name>Dennis Lundberg</name>
<email>dennisl@apache.org</email>
<organization>The Apache Software Foundation</organization>
</developer>
<developer>
<id>costin</id>
<name>Costin Manolache</name>
<email>costin@apache.org</email>
<organization>The Apache Software Foundation</organization>
</developer>
<developer>
<id>craigmcc</id>
<name>Craig McClanahan</name>
<email>craigmcc@apache.org</email>
<organization>The Apache Software Foundation</organization>
</developer>
<developer>
<id>tn</id>
<name>Thomas Neidhart</name>
<email>tn@apache.org</email>
<organization>The Apache Software Foundation</organization>
</developer>
<developer>
<id>sanders</id>
<name>Scott Sanders</name>
<email>sanders@apache.org</email>
<organization>The Apache Software Foundation</organization>
</developer>
<developer>
<id>rsitze</id>
<name>Richard Sitze</name>
<email>rsitze@apache.org</email>
<organization>The Apache Software Foundation</organization>
</developer>
<developer>
<id>bstansberry</id>
<name>Brian Stansberry</name>
</developer>
<developer>
<id>rwaldhoff</id>
<name>Rodney Waldhoff</name>
<email>rwaldhoff@apache.org</email>
<organization>The Apache Software Foundation</organization>
</developer>
</developers>
<contributors>
<contributor>
<name>Matthew P. Del Buono</name>
<roles>
<role>Provided patch</role>
</roles>
</contributor>
<contributor>
<name>Vince Eagen</name>
<email>vince256 at comcast dot net</email>
<roles>
<role>Lumberjack logging abstraction</role>
</roles>
</contributor>
<contributor>
<name>Peter Lawrey</name>
<roles>
<role>Provided patch</role>
</roles>
</contributor>
<contributor>
<name>Berin Loritsch</name>
<email>bloritsch at apache dot org</email>
<roles>
<role>Lumberjack logging abstraction</role>
<role>JDK 1.4 logging abstraction</role>
</roles>
</contributor>
<contributor>
<name>Philippe Mouawad</name>
<roles>
<role>Provided patch</role>
</roles>
</contributor>
<contributor>
<name>Neeme Praks</name>
<email>neeme at apache dot org</email>
<roles>
<role>Avalon logging abstraction</role>
</roles>
</contributor>
</contributors>
<scm>
<connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/logging/trunk</connection>
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/logging/trunk</developerConnection>
<url>http://svn.apache.org/repos/asf/commons/proper/logging/trunk</url>
</scm>
<build>
<plugins>
<!--
- We want to create four jarfiles from this project: normal, tests, api
- and adapters. The first two are handled by the normal jar:jar and
- jar:test-jar targets.
- The jar plugin with some includes/excludes is used to create the other
- ones.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<!--
- The custom test framework requires the unit test code to be
- in a jarfile so it can control its place in the classpath.
-->
<id>testjar</id>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<jarName>commons-logging</jarName>
</configuration>
</execution>
<execution>
<id>apijar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<jarName>${project.artifactId}-api-${project.version}</jarName>
<includes>
<include>org/apache/commons/logging/*.class</include>
<include>org/apache/commons/logging/impl/LogFactoryImpl*.class</include>
<include>org/apache/commons/logging/impl/WeakHashtable*.class</include>
<include>org/apache/commons/logging/impl/SimpleLog*.class</include>
<include>org/apache/commons/logging/impl/NoOpLog*.class</include>
<include>org/apache/commons/logging/impl/Jdk14Logger.class</include>
<include>META-INF/LICENSE.txt</include>
<include>META-INF/NOTICE.txt</include>
</includes>
<excludes>
<exclude>**/package.html</exclude>
</excludes>
</configuration>
</execution>
<execution>
<id>adaptersjar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<jarName>${project.artifactId}-adapters-${project.version}</jarName>
<includes>
<include>org/apache/commons/logging/impl/**.class</include>
<include>META-INF/LICENSE.txt</include>
<include>META-INF/NOTICE.txt</include>
</includes>
<excludes>
<exclude>org/apache/commons/logging/impl/WeakHashtable*.class</exclude>
<exclude>org/apache/commons/logging/impl/LogFactoryImpl*.class</exclude>
</excludes>
</configuration>
</execution>
<!--
- Define the full jar last, the deploy/install plugin seems to be broken
- and takes the last definition from here.
-->
<execution>
<id>fulljar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<jarName>${project.artifactId}-${project.version}</jarName>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>site.resources</id>
<phase>site</phase>
<configuration>
<target>
<copy todir="${project.reporting.outputDirectory}">
<fileset dir="${basedir}">
<include name="RELEASE-NOTES.txt" />
</fileset>
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!--
- Attach the adapters and api jars to the normal artifact. This way
- they will be deployed when the normal artifact is deployed.
-->
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${project.build.directory}/${project.artifactId}-adapters-${project.version}.jar</file>
<type>jar</type>
<classifier>adapters</classifier>
</artifact>
<artifact>
<file>${project.build.directory}/${project.artifactId}-api-${project.version}.jar</file>
<type>jar</type>
<classifier>api</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!--
- Many of JCL's tests use tricky techniques to place the generated
- JCL jarfiles on the classpath in various configurations. This means
- that those tests must be run *after* the "package" build phase.
-
- In order to not mess with the Ant build we "disable" the normal test
- phase. This is done by skipping the execution of the surefire plugin.
-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<!--
- Many of JCL's tests use tricky techniques to place the generated
- JCL jarfiles on the classpath in various configurations. This means
- that those tests must be run *after* the "package" build phase.
-
- Disable cobertura report generation as this does not work correctly
- with integration-tests and the normal unit tests are disabled too.
-->
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${commons.cobertura.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<!--
- Many of JCL's tests use tricky techniques to place the generated
- JCL jarfiles on the classpath in various configurations. This means
- that those tests must be run *after* the "package" build phase.
-
- For this we use the failsafe plugin which is bound to the
- "integration-test" phase by default.
-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${commons.surefire.version}</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<runOrder>${failsafe.runorder}</runOrder>
<includes>
<include>**/*TestCase.java</include>
</includes>
<systemPropertyVariables>
<!--
<org.apache.commons.logging.diagnostics.dest>STDOUT</org.apache.commons.logging.diagnostics.dest>
-->
<log4j12>${log4j:log4j:jar}</log4j12>
<logkit>${logkit:logkit:jar}</logkit>
<servlet-api>${javax.servlet:servlet-api:jar}</servlet-api>
<commons-logging>target/${project.build.finalName}.jar</commons-logging>
<commons-logging-api>target/${project.artifactId}-api-${project.version}.jar</commons-logging-api>
<commons-logging-adapters>target/${project.artifactId}-adapters-${project.version}.jar</commons-logging-adapters>
<testclasses>target/commons-logging-tests.jar</testclasses>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.3</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/bin.xml</descriptor>
<descriptor>src/main/assembly/src.xml</descriptor>
</descriptors>
<tarLongFileMode>gnu</tarLongFileMode>
</configuration>
</plugin>
<!-- Define properties for referencing dependencies -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-publish-plugin</artifactId>
<configuration>
<ignorePathsToDelete>
<ignorePathToDelete>javadocs</ignorePathToDelete>
<ignorePathToDelete>commons-logging-**</ignorePathToDelete>
</ignorePathsToDelete>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>logkit</groupId>
<artifactId>logkit</artifactId>
<version>1.0.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>avalon-framework</groupId>
<artifactId>avalon-framework</artifactId>
<version>4.1.5</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.3</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.7</version>
<configuration>
<configLocation>${basedir}/checkstyle.xml</configLocation>
<enableRulesSummary>false</enableRulesSummary>
<headerFile>${basedir}/license-header.txt</headerFile>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
<version>2.2.2</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jdepend-maven-plugin</artifactId>
<version>2.0-beta-1</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<!-- targetJdk 1.1, 1.2 is not supported -->
<targetJdk>1.3</targetJdk>
<linkXref>true</linkXref>
<rulesets>
<ruleset>${basedir}/pmd.xml</ruleset>
</rulesets>
</configuration>
</plugin>
</plugins>
</reporting>
<distributionManagement>
<site>
<id>apache.website</id>
<url>${commons.deployment.protocol}://people.apache.org/www/commons.apache.org/logging/</url>
</site>
</distributionManagement>
<properties>
<maven.compiler.source>1.2</maven.compiler.source>
<maven.compiler.target>1.2</maven.compiler.target>
<commons.componentid>logging</commons.componentid>
<commons.release.version>1.2</commons.release.version>
<commons.jira.id>LOGGING</commons.jira.id>
<commons.jira.pid>12310484</commons.jira.pid>
<!-- The RC version used in the staging repository URL. -->
<commons.rc.version>RC2</commons.rc.version>
<commons.surefire.version>2.12</commons.surefire.version>
<skipSurefireReport>true</skipSurefireReport>
<!-- Allow default test run order to be changed -->
<failsafe.runorder>filesystem</failsafe.runorder>
<commons.osgi.import>
javax.servlet;version="[2.1.0, 3.0.0)";resolution:=optional,
org.apache.avalon.framework.logger;version="[4.1.3, 4.1.5]";resolution:=optional,
org.apache.log;version="[1.0.1, 1.0.1]";resolution:=optional,
org.apache.log4j;version="[1.2.15, 2.0.0)";resolution:=optional
</commons.osgi.import>
</properties>
</project>

112
src/changes/changes.xml Normal file
View File

@ -0,0 +1,112 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
This file is also used by the maven-changes-plugin to generate the release notes.
Useful ways of finding items to add to this file are:
1. Add items when you fix a bug or add a feature (this makes the
release process easy :-).
2. Do a JIRA search for tickets closed since the previous release.
3. Use the report generated by the maven-changelog-plugin to see all
SVN commits. TBA how to use this with SVN.
To generate the release notes from this file:
mvn changes:announcement-generate -Prelease-notes [-Dchanges.version=nn]
then tweak the formatting if necessary
and commit
The <action> type attribute can be add,update,fix,remove.
-->
<document xmlns="http://maven.apache.org/changes/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 http://maven.apache.org/xsd/changes-1.0.0.xsd">
<properties>
<title>Release Notes</title>
</properties>
<body>
<release version="1.2" date="2014-07-11" description="This is a maintenance release containing bug fixes. Java 1.2 or later is required.">
<action issue="LOGGING-37" dev="tn" type="fix" due-to="Matthias Ernst,Archie Cobbs">
Improve performance of LogFactory#getFactory() by calling Thread#currentThread()#getContextClassLoader()
directly instead of using reflection. As a consequence support for JDK 1.1 has been dropped.
</action>
<action issue="LOGGING-156" dev="tn" type="fix" due-to="Mikolaj Izdebski">
Fix SecurityAllowedTestCase when executed with OpenJDK 1.7 due to an additional required RuntimePermission.
</action>
<action issue="LOGGING-157" dev="tn" type="fix" due-to="Ville Skyttä">
Fix javadoc to comply with javadoc tool from jdk 1.8.
</action>
</release>
<release version="1.1.3" date="2013-05-23" description="This is a maintenance release containing bug fixes.">
<action issue="LOGGING-151" dev="tn" type="fix" due-to="Krzysztof Daniel">
Use "org.apache.commons.logging" as bundle symbolic name.
</action>
</release>
<release version="1.1.2" date="2013-03-20" description="This is a maintenance release containing bug fixes.">
<action issue="LOGGING-124" dev="tn" type="fix" due-to="Christian Schneider">
The jar manifest now contains proper OSGi-related metadata information.
</action>
<action issue="LOGGING-144" dev="tn" type="fix" due-to="Sebastian Bazley">
LogFactory and LogFactoryImpl will not swallow certain errors anymore (ThreadDeath
and VirtualMachineError).
</action>
<action issue="LOGGING-135" dev="tn" type="update" due-to="Sebastian Bazley">
Improved thread-safety for several log adapters, including AvalonLogger, SimpleLog,
Log4JLogger, LogKitLogger.
</action>
<action issue="LOGGING-138" dev="tn" type="update" due-to="Luke Lu">
In case of a discovery failure now also the stacktrace of the cause will be
added to the diagnostic message.
</action>
<action issue="LOGGING-132" dev="tn" type="fix" due-to="Nathan Niesen">
Jdk14Logger now correctly uses the specified logger name.
</action>
<action issue="LOGGING-133" dev="tn" type="update" due-to="Shevek">
Change scope of Jdk14Logger.log(Level, String, Throwable) to protected, allowing
subclasses to modify the logging output.
</action>
<action issue="LOGGING-146" dev="tn" type="fix" due-to="Sebastian Bazley">
Properly synchronize access to protected static field LogFactory.nullClassLoaderFactory.
</action>
<action issue="LOGGING-119" dev="tn" type="fix" due-to="Nitzan Niv, Philippe Mouawad">
Prevent potential deadlock scenario in WeakHashtable.
</action>
<action issue="LOGGING-130" dev="sebb" type="fix" due-to="Matthew P. Del Buono">
Potential missing privileged block for class loader.
</action>
<action issue="LOGGING-145" dev="sebb" type="fix">
LogFactoryImpl.setAttribute - possible NPE.
</action>
<action issue="LOGGING-142" dev="sebb" type="fix" due-to="Jingguo Yao">
Log4JLogger uses deprecated static members of Priority such as INFO.
</action>
<action issue="LOGGING-128" dev="sebb" type="fix" due-to="Peter Lawrey">
Static analysis suggests a number of potential improvements.
</action>
<action issue="LOGGING-147" dev="sebb" type="fix">
SimpleLog.log - unsafe update of shortLogName.
</action>
<action issue="LOGGING-148" dev="sebb" type="fix">
LogFactory.diagnosticPrefix and diagnosticsStream could be final.
</action>
</release>
</body>
</document>

View File

@ -0,0 +1,109 @@
## Licensed to the Apache Software Foundation (ASF) under one
## or more contributor license agreements. See the NOTICE file
## distributed with this work for additional information
## regarding copyright ownership. The ASF licenses this file
## to you under the Apache License, Version 2.0 (the
## "License"); you may not use this file except in compliance
## with the License. You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing,
## software distributed under the License is distributed on an
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
## KIND, either express or implied. See the License for the
## specific language governing permissions and limitations
## under the License.
Apache ${project.name}
Version ${version}
RELEASE NOTES
The ${developmentTeam} is pleased to announce the release of Apache ${project.name} ${version}
$introduction.replaceAll("(?<!\015)\012", "
").replaceAll("(?m)^ +","")
## N.B. the available variables are described here:
## http://maven.apache.org/plugins/maven-changes-plugin/examples/using-a-custom-announcement-template.html
## Hack to improve layout: replace all pairs of spaces with a single new-line
$release.description.replaceAll(" ", "
")
## set up indent sizes. Only change indent1
#set($props=${project.properties})
#set($jiralen=$props.get("commons.jira.id").length())
## indent1 = POOL-nnnn:
#set($blanklen=$jiralen+6)## +6 for "-nnnn:"
## must be at least as long as the longest JIRA id
#set($blanks=" ")
#set($indent1=$blanks.substring(0,$blanklen))
## indent2 allows for issue wrapper
#set($indent2="$indent1 ")
##
#macro ( processaction )
## Use replaceAll to fix up LF-only line ends on Windows.
#set($action=$actionItem.getAction().replaceAll("\n","
"))
## Fix up indentation for multi-line action descriptions
#set($action=$action.replaceAll("(?m)^ +",$indent2))
#if ($actionItem.getIssue())
#set($issue="$actionItem.getIssue():")
## Pad shorter issue numbers
#if ($issue.length() < $indent1.length())#set ($issue="$issue ")#end
#if ($issue.length() < $indent1.length())#set ($issue="$issue ")#end
#if ($issue.length() < $indent1.length())#set ($issue="$issue ")#end
#else
#set($issue=$indent1)
#end
#if ($actionItem.getDueTo())
#set($dueto=" Thanks to $actionItem.getDueTo().")
#else
#set($dueto="")
#end
o $issue ${action}$dueto
#set($action="")
#set($issue="")
#set($dueto="")
#end
##
#if ($release.getActions().size() == 0)
No changes defined in this version.
#else
Changes in this version include:
#if ($release.getActions('add').size() !=0)
New features:
#foreach($actionItem in $release.getActions('add'))
#processaction()
#end
#end
#if ($release.getActions('fix').size() !=0)
Fixed Bugs:
#foreach($actionItem in $release.getActions('fix'))
#processaction()
#end
#end
#if ($release.getActions('update').size() !=0)
Changes:
#foreach($actionItem in $release.getActions('update'))
#processaction()
#end
#end
#if ($release.getActions('remove').size() !=0)
Removed:
#foreach($actionItem in $release.getActions('remove'))
#processaction()
#end
#end
## End of main loop
#end
Historical list of changes: ${project.url}changes-report.html
For complete information on ${project.name}, including instructions on how to submit bug reports,
patches, or suggestions for improvement, see the Apache ${project.name} website:
${project.url}

28
src/conf/MANIFEST.MF Normal file
View File

@ -0,0 +1,28 @@
Manifest-Version: 1.0
Export-Package: org.apache.commons.logging;version="1.2.0",org.apache.
commons.logging.impl;version="1.2.0"
Implementation-Title: Commons Logging
Implementation-Vendor: The Apache Software Foundation
Implementation-Vendor-Id: org.apache
Specification-Title: Commons Logging
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-SymbolicName: org.apache.commons.logging
X-Compile-Target-JDK: 1.2
Implementation-Version: 1.2
Specification-Vendor: The Apache Software Foundation
Bundle-Name: Commons Logging
Created-By: Apache Maven Bundle Plugin
X-Compile-Source-JDK: 1.2
Bundle-Vendor: The Apache Software Foundation
Bundle-Version: 1.2.0
Bundle-ManifestVersion: 2
Bundle-Description: Commons Logging is a thin adapter allowing configu
rable bridging to other, well known logging systems.
Bundle-DocURL: http://commons.apache.org/proper/commons-logging/
Import-Package: javax.servlet;resolution:=optional;version="[2.1.0,3.0
.0)",org.apache.avalon.framework.logger;resolution:=optional;version=
"[4.1.3,4.1.5]",org.apache.log;resolution:=optional;version="[1.0.1,1
.0.1]",org.apache.log4j;resolution:=optional;version="[1.2.15,2.0.0)"
Include-Resource: META-INF/NOTICE.txt=NOTICE.txt,META-INF/LICENSE.txt=
LICENSE.txt
Specification-Version: 1.2

47
src/main/assembly/bin.xml Normal file
View File

@ -0,0 +1,47 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<assembly>
<id>bin</id>
<formats>
<format>tar.gz</format>
<format>zip</format>
</formats>
<includeSiteDirectory>false</includeSiteDirectory>
<fileSets>
<fileSet>
<includes>
<include>LICENSE*</include>
<include>NOTICE*</include>
<include>RELEASE-NOTES*</include>
</includes>
</fileSet>
<fileSet>
<directory>target</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>target/site/apidocs</directory>
<outputDirectory>apidocs</outputDirectory>
</fileSet>
</fileSets>
</assembly>

52
src/main/assembly/src.xml Normal file
View File

@ -0,0 +1,52 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<assembly>
<id>src</id>
<formats>
<format>tar.gz</format>
<format>zip</format>
</formats>
<baseDirectory>${project.artifactId}-${project.version}-src</baseDirectory>
<fileSets>
<fileSet>
<includes>
<include>checkstyle.xml</include>
<include>README.txt</include>
<include>LICENSE.txt</include>
<include>NOTICE.txt</include>
<include>pmd.xml</include>
<include>pom.xml</include>
<include>PROPOSAL.html</include>
<include>RELEASE-NOTES.txt</include>
<include>STATUS.txt</include>
<include>build.xml</include>
<include>build-testing.xml</include>
<include>build.properties.sample</include>
<include>license-header.txt</include>
</includes>
</fileSet>
<fileSet>
<directory>src</directory>
<excludes>
<exclude>**/download*.cgi</exclude>
</excludes>
</fileSet>
</fileSets>
</assembly>

View File

@ -0,0 +1,216 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
/**
* A simple logging interface abstracting logging APIs. In order to be
* instantiated successfully by {@link LogFactory}, classes that implement
* this interface must have a constructor that takes a single String
* parameter representing the "name" of this Log.
* <p>
* The six logging levels used by <code>Log</code> are (in order):
* <ol>
* <li>trace (the least serious)</li>
* <li>debug</li>
* <li>info</li>
* <li>warn</li>
* <li>error</li>
* <li>fatal (the most serious)</li>
* </ol>
* The mapping of these log levels to the concepts used by the underlying
* logging system is implementation dependent.
* The implementation should ensure, though, that this ordering behaves
* as expected.
* <p>
* Performance is often a logging concern.
* By examining the appropriate property,
* a component can avoid expensive operations (producing information
* to be logged).
* <p>
* For example,
* <pre>
* if (log.isDebugEnabled()) {
* ... do something expensive ...
* log.debug(theResult);
* }
* </pre>
* <p>
* Configuration of the underlying logging system will generally be done
* external to the Logging APIs, through whatever mechanism is supported by
* that system.
*
* @version $Id: Log.java 1606045 2014-06-27 12:11:56Z tn $
*/
public interface Log {
/**
* Logs a message with debug log level.
*
* @param message log this message
*/
void debug(Object message);
/**
* Logs an error with debug log level.
*
* @param message log this message
* @param t log this cause
*/
void debug(Object message, Throwable t);
/**
* Logs a message with error log level.
*
* @param message log this message
*/
void error(Object message);
/**
* Logs an error with error log level.
*
* @param message log this message
* @param t log this cause
*/
void error(Object message, Throwable t);
/**
* Logs a message with fatal log level.
*
* @param message log this message
*/
void fatal(Object message);
/**
* Logs an error with fatal log level.
*
* @param message log this message
* @param t log this cause
*/
void fatal(Object message, Throwable t);
/**
* Logs a message with info log level.
*
* @param message log this message
*/
void info(Object message);
/**
* Logs an error with info log level.
*
* @param message log this message
* @param t log this cause
*/
void info(Object message, Throwable t);
/**
* Is debug logging currently enabled?
* <p>
* Call this method to prevent having to perform expensive operations
* (for example, <code>String</code> concatenation)
* when the log level is more than debug.
*
* @return true if debug is enabled in the underlying logger.
*/
boolean isDebugEnabled();
/**
* Is error logging currently enabled?
* <p>
* Call this method to prevent having to perform expensive operations
* (for example, <code>String</code> concatenation)
* when the log level is more than error.
*
* @return true if error is enabled in the underlying logger.
*/
boolean isErrorEnabled();
/**
* Is fatal logging currently enabled?
* <p>
* Call this method to prevent having to perform expensive operations
* (for example, <code>String</code> concatenation)
* when the log level is more than fatal.
*
* @return true if fatal is enabled in the underlying logger.
*/
boolean isFatalEnabled();
/**
* Is info logging currently enabled?
* <p>
* Call this method to prevent having to perform expensive operations
* (for example, <code>String</code> concatenation)
* when the log level is more than info.
*
* @return true if info is enabled in the underlying logger.
*/
boolean isInfoEnabled();
/**
* Is trace logging currently enabled?
* <p>
* Call this method to prevent having to perform expensive operations
* (for example, <code>String</code> concatenation)
* when the log level is more than trace.
*
* @return true if trace is enabled in the underlying logger.
*/
boolean isTraceEnabled();
/**
* Is warn logging currently enabled?
* <p>
* Call this method to prevent having to perform expensive operations
* (for example, <code>String</code> concatenation)
* when the log level is more than warn.
*
* @return true if warn is enabled in the underlying logger.
*/
boolean isWarnEnabled();
/**
* Logs a message with trace log level.
*
* @param message log this message
*/
void trace(Object message);
/**
* Logs an error with trace log level.
*
* @param message log this message
* @param t log this cause
*/
void trace(Object message, Throwable t);
/**
* Logs a message with warn log level.
*
* @param message log this message
*/
void warn(Object message);
/**
* Logs an error with warn log level.
*
* @param message log this message
* @param t log this cause
*/
void warn(Object message, Throwable t);
}

View File

@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
/**
* An exception that is thrown only if a suitable <code>LogFactory</code>
* or <code>Log</code> instance cannot be created by the corresponding
* factory methods.
*
* @version $Id: LogConfigurationException.java 1432663 2013-01-13 17:24:18Z tn $
*/
public class LogConfigurationException extends RuntimeException {
/** Serializable version identifier. */
private static final long serialVersionUID = 8486587136871052495L;
/**
* Construct a new exception with <code>null</code> as its detail message.
*/
public LogConfigurationException() {
super();
}
/**
* Construct a new exception with the specified detail message.
*
* @param message The detail message
*/
public LogConfigurationException(String message) {
super(message);
}
/**
* Construct a new exception with the specified cause and a derived
* detail message.
*
* @param cause The underlying cause
*/
public LogConfigurationException(Throwable cause) {
this(cause == null ? null : cause.toString(), cause);
}
/**
* Construct a new exception with the specified detail message and cause.
*
* @param message The detail message
* @param cause The underlying cause
*/
public LogConfigurationException(String message, Throwable cause) {
super(message + " (Caused by " + cause + ")");
this.cause = cause; // Two-argument version requires JDK 1.4 or later
}
/**
* The underlying cause of this exception.
*/
protected Throwable cause = null;
/**
* Return the underlying cause of this exception (if any).
*/
public Throwable getCause() {
return this.cause;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,219 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import java.lang.reflect.Constructor;
import java.util.Hashtable;
import org.apache.commons.logging.impl.NoOpLog;
/**
* Factory for creating {@link Log} instances. Applications should call
* the <code>makeNewLogInstance()</code> method to instantiate new instances
* of the configured {@link Log} implementation class.
* <p>
* By default, calling <code>getInstance()</code> will use the following
* algorithm:
* <ul>
* <li>If Log4J is available, return an instance of
* <code>org.apache.commons.logging.impl.Log4JLogger</code>.</li>
* <li>If JDK 1.4 or later is available, return an instance of
* <code>org.apache.commons.logging.impl.Jdk14Logger</code>.</li>
* <li>Otherwise, return an instance of
* <code>org.apache.commons.logging.impl.NoOpLog</code>.</li>
* </ul>
* <p>
* You can change the default behavior in one of two ways:
* <ul>
* <li>On the startup command line, set the system property
* <code>org.apache.commons.logging.log</code> to the name of the
* <code>org.apache.commons.logging.Log</code> implementation class
* you want to use.</li>
* <li>At runtime, call <code>LogSource.setLogImplementation()</code>.</li>
* </ul>
*
* @deprecated Use {@link LogFactory} instead - The default factory
* implementation performs exactly the same algorithm as this class did
*
* @version $Id: LogSource.java 1432675 2013-01-13 17:53:30Z tn $
*/
public class LogSource {
// ------------------------------------------------------- Class Attributes
static protected Hashtable logs = new Hashtable();
/** Is log4j available (in the current classpath) */
static protected boolean log4jIsAvailable = false;
/** Is JDK 1.4 logging available */
static protected boolean jdk14IsAvailable = false;
/** Constructor for current log class */
static protected Constructor logImplctor = null;
// ----------------------------------------------------- Class Initializers
static {
// Is Log4J Available?
try {
log4jIsAvailable = null != Class.forName("org.apache.log4j.Logger");
} catch (Throwable t) {
log4jIsAvailable = false;
}
// Is JDK 1.4 Logging Available?
try {
jdk14IsAvailable = null != Class.forName("java.util.logging.Logger") &&
null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger");
} catch (Throwable t) {
jdk14IsAvailable = false;
}
// Set the default Log implementation
String name = null;
try {
name = System.getProperty("org.apache.commons.logging.log");
if (name == null) {
name = System.getProperty("org.apache.commons.logging.Log");
}
} catch (Throwable t) {
}
if (name != null) {
try {
setLogImplementation(name);
} catch (Throwable t) {
try {
setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
} catch (Throwable u) {
// ignored
}
}
} else {
try {
if (log4jIsAvailable) {
setLogImplementation("org.apache.commons.logging.impl.Log4JLogger");
} else if (jdk14IsAvailable) {
setLogImplementation("org.apache.commons.logging.impl.Jdk14Logger");
} else {
setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
}
} catch (Throwable t) {
try {
setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
} catch (Throwable u) {
// ignored
}
}
}
}
// ------------------------------------------------------------ Constructor
/** Don't allow others to create instances. */
private LogSource() {
}
// ---------------------------------------------------------- Class Methods
/**
* Set the log implementation/log implementation factory
* by the name of the class. The given class must implement {@link Log},
* and provide a constructor that takes a single {@link String} argument
* (containing the name of the log).
*/
static public void setLogImplementation(String classname)
throws LinkageError, NoSuchMethodException, SecurityException, ClassNotFoundException {
try {
Class logclass = Class.forName(classname);
Class[] argtypes = new Class[1];
argtypes[0] = "".getClass();
logImplctor = logclass.getConstructor(argtypes);
} catch (Throwable t) {
logImplctor = null;
}
}
/**
* Set the log implementation/log implementation factory by class.
* The given class must implement {@link Log}, and provide a constructor
* that takes a single {@link String} argument (containing the name of the log).
*/
static public void setLogImplementation(Class logclass)
throws LinkageError, ExceptionInInitializerError, NoSuchMethodException, SecurityException {
Class[] argtypes = new Class[1];
argtypes[0] = "".getClass();
logImplctor = logclass.getConstructor(argtypes);
}
/** Get a <code>Log</code> instance by class name. */
static public Log getInstance(String name) {
Log log = (Log) logs.get(name);
if (null == log) {
log = makeNewLogInstance(name);
logs.put(name, log);
}
return log;
}
/** Get a <code>Log</code> instance by class. */
static public Log getInstance(Class clazz) {
return getInstance(clazz.getName());
}
/**
* Create a new {@link Log} implementation, based on the given <i>name</i>.
* <p>
* The specific {@link Log} implementation returned is determined by the
* value of the <tt>org.apache.commons.logging.log</tt> property. The value
* of <tt>org.apache.commons.logging.log</tt> may be set to the fully specified
* name of a class that implements the {@link Log} interface. This class must
* also have a public constructor that takes a single {@link String} argument
* (containing the <i>name</i> of the {@link Log} to be constructed.
* <p>
* When <tt>org.apache.commons.logging.log</tt> is not set, or when no corresponding
* class can be found, this method will return a Log4JLogger if the log4j Logger
* class is available in the {@link LogSource}'s classpath, or a Jdk14Logger if we
* are on a JDK 1.4 or later system, or NoOpLog if neither of the above conditions is true.
*
* @param name the log name (or category)
*/
static public Log makeNewLogInstance(String name) {
Log log;
try {
Object[] args = { name };
log = (Log) logImplctor.newInstance(args);
} catch (Throwable t) {
log = null;
}
if (null == log) {
log = new NoOpLog(name);
}
return log;
}
/**
* Returns a {@link String} array containing the names of
* all logs known to me.
*/
static public String[] getLogNames() {
return (String[]) logs.keySet().toArray(new String[logs.size()]);
}
}

View File

@ -0,0 +1,298 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import org.apache.avalon.framework.logger.Logger;
import org.apache.commons.logging.Log;
/**
* Implementation of commons-logging Log interface that delegates all
* logging calls to the Avalon logging abstraction: the Logger interface.
* <p>
* There are two ways in which this class can be used:
* <ul>
* <li>the instance can be constructed with an Avalon logger
* (by calling {@link #AvalonLogger(Logger)}). In this case, it acts
* as a simple thin wrapping implementation over the logger. This is
* particularly useful when using a property setter.
* </li>
* <li>the {@link #setDefaultLogger} class property can be called which
* sets the ancestral Avalon logger for this class. Any <code>AvalonLogger</code>
* instances created through the <code>LogFactory</code> mechanisms will output
* to child loggers of this <code>Logger</code>.
* </li>
* </ul>
* <p>
* <strong>Note:</strong> <code>AvalonLogger</code> does not implement Serializable
* because the constructors available for it make this impossible to achieve in all
* circumstances; there is no way to "reconnect" to an underlying Logger object on
* deserialization if one was just passed in to the constructor of the original
* object. This class <i>was</i> marked Serializable in the 1.0.4 release of
* commons-logging, but this never actually worked (a NullPointerException would
* be thrown as soon as the deserialized object was used), so removing this marker
* is not considered to be an incompatible change.
*
* @version $Id: AvalonLogger.java 1435115 2013-01-18 12:40:19Z tn $
*/
public class AvalonLogger implements Log {
/** Ancestral Avalon logger. */
private static volatile Logger defaultLogger = null;
/** Avalon logger used to perform log. */
private final transient Logger logger;
/**
* Constructs an <code>AvalonLogger</code> that outputs to the given
* <code>Logger</code> instance.
*
* @param logger the Avalon logger implementation to delegate to
*/
public AvalonLogger(Logger logger) {
this.logger = logger;
}
/**
* Constructs an <code>AvalonLogger</code> that will log to a child
* of the <code>Logger</code> set by calling {@link #setDefaultLogger}.
*
* @param name the name of the avalon logger implementation to delegate to
*/
public AvalonLogger(String name) {
if (defaultLogger == null) {
throw new NullPointerException("default logger has to be specified if this constructor is used!");
}
this.logger = defaultLogger.getChildLogger(name);
}
/**
* Gets the Avalon logger implementation used to perform logging.
*
* @return avalon logger implementation
*/
public Logger getLogger() {
return logger;
}
/**
* Sets the ancestral Avalon logger from which the delegating loggers will descend.
*
* @param logger the default avalon logger,
* in case there is no logger instance supplied in constructor
*/
public static void setDefaultLogger(Logger logger) {
defaultLogger = logger;
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.debug</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#debug(Object, Throwable)
*/
public void debug(Object message, Throwable t) {
if (getLogger().isDebugEnabled()) {
getLogger().debug(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.debug</code>.
*
* @param message to log.
* @see org.apache.commons.logging.Log#debug(Object)
*/
public void debug(Object message) {
if (getLogger().isDebugEnabled()) {
getLogger().debug(String.valueOf(message));
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.error</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#error(Object, Throwable)
*/
public void error(Object message, Throwable t) {
if (getLogger().isErrorEnabled()) {
getLogger().error(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.error</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#error(Object)
*/
public void error(Object message) {
if (getLogger().isErrorEnabled()) {
getLogger().error(String.valueOf(message));
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.fatalError</code>.
*
* @param message to log.
* @param t log this cause.
* @see org.apache.commons.logging.Log#fatal(Object, Throwable)
*/
public void fatal(Object message, Throwable t) {
if (getLogger().isFatalErrorEnabled()) {
getLogger().fatalError(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.fatalError</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#fatal(Object)
*/
public void fatal(Object message) {
if (getLogger().isFatalErrorEnabled()) {
getLogger().fatalError(String.valueOf(message));
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.info</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#info(Object, Throwable)
*/
public void info(Object message, Throwable t) {
if (getLogger().isInfoEnabled()) {
getLogger().info(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.info</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#info(Object)
*/
public void info(Object message) {
if (getLogger().isInfoEnabled()) {
getLogger().info(String.valueOf(message));
}
}
/**
* Is logging to <code>org.apache.avalon.framework.logger.Logger.debug</code> enabled?
* @see org.apache.commons.logging.Log#isDebugEnabled()
*/
public boolean isDebugEnabled() {
return getLogger().isDebugEnabled();
}
/**
* Is logging to <code>org.apache.avalon.framework.logger.Logger.error</code> enabled?
* @see org.apache.commons.logging.Log#isErrorEnabled()
*/
public boolean isErrorEnabled() {
return getLogger().isErrorEnabled();
}
/**
* Is logging to <code>org.apache.avalon.framework.logger.Logger.fatalError</code> enabled?
* @see org.apache.commons.logging.Log#isFatalEnabled()
*/
public boolean isFatalEnabled() {
return getLogger().isFatalErrorEnabled();
}
/**
* Is logging to <code>org.apache.avalon.framework.logger.Logger.info</code> enabled?
* @see org.apache.commons.logging.Log#isInfoEnabled()
*/
public boolean isInfoEnabled() {
return getLogger().isInfoEnabled();
}
/**
* Is logging to <code>org.apache.avalon.framework.logger.Logger.debug</code> enabled?
* @see org.apache.commons.logging.Log#isTraceEnabled()
*/
public boolean isTraceEnabled() {
return getLogger().isDebugEnabled();
}
/**
* Is logging to <code>org.apache.avalon.framework.logger.Logger.warn</code> enabled?
* @see org.apache.commons.logging.Log#isWarnEnabled()
*/
public boolean isWarnEnabled() {
return getLogger().isWarnEnabled();
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.debug</code>.
*
* @param message to log.
* @param t log this cause.
* @see org.apache.commons.logging.Log#trace(Object, Throwable)
*/
public void trace(Object message, Throwable t) {
if (getLogger().isDebugEnabled()) {
getLogger().debug(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.debug</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#trace(Object)
*/
public void trace(Object message) {
if (getLogger().isDebugEnabled()) {
getLogger().debug(String.valueOf(message));
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.warn</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#warn(Object, Throwable)
*/
public void warn(Object message, Throwable t) {
if (getLogger().isWarnEnabled()) {
getLogger().warn(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.avalon.framework.logger.Logger.warn</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#warn(Object)
*/
public void warn(Object message) {
if (getLogger().isWarnEnabled()) {
getLogger().warn(String.valueOf(message));
}
}
}

View File

@ -0,0 +1,302 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogRecord;
import java.util.StringTokenizer;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.apache.commons.logging.Log;
/**
* Implementation of the <code>org.apache.commons.logging.Log</code>
* interface that wraps the standard JDK logging mechanisms that are
* available in SourceForge's Lumberjack for JDKs prior to 1.4.
*
* @version $Id: Jdk13LumberjackLogger.java 1432663 2013-01-13 17:24:18Z tn $
* @since 1.1
*/
public class Jdk13LumberjackLogger implements Log, Serializable {
/** Serializable version identifier. */
private static final long serialVersionUID = -8649807923527610591L;
// ----------------------------------------------------- Instance Variables
/**
* The underlying Logger implementation we are using.
*/
protected transient Logger logger = null;
protected String name = null;
private String sourceClassName = "unknown";
private String sourceMethodName = "unknown";
private boolean classAndMethodFound = false;
/**
* This member variable simply ensures that any attempt to initialise
* this class in a pre-1.4 JVM will result in an ExceptionInInitializerError.
* It must not be private, as an optimising compiler could detect that it
* is not used and optimise it away.
*/
protected static final Level dummyLevel = Level.FINE;
// ----------------------------------------------------------- Constructors
/**
* Construct a named instance of this Logger.
*
* @param name Name of the logger to be constructed
*/
public Jdk13LumberjackLogger(String name) {
this.name = name;
logger = getLogger();
}
// --------------------------------------------------------- Public Methods
private void log( Level level, String msg, Throwable ex ) {
if( getLogger().isLoggable(level) ) {
LogRecord record = new LogRecord(level, msg);
if( !classAndMethodFound ) {
getClassAndMethod();
}
record.setSourceClassName(sourceClassName);
record.setSourceMethodName(sourceMethodName);
if( ex != null ) {
record.setThrown(ex);
}
getLogger().log(record);
}
}
/**
* Gets the class and method by looking at the stack trace for the
* first entry that is not this class.
*/
private void getClassAndMethod() {
try {
Throwable throwable = new Throwable();
throwable.fillInStackTrace();
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter( stringWriter );
throwable.printStackTrace( printWriter );
String traceString = stringWriter.getBuffer().toString();
StringTokenizer tokenizer =
new StringTokenizer( traceString, "\n" );
tokenizer.nextToken();
String line = tokenizer.nextToken();
while ( line.indexOf( this.getClass().getName() ) == -1 ) {
line = tokenizer.nextToken();
}
while ( line.indexOf( this.getClass().getName() ) >= 0 ) {
line = tokenizer.nextToken();
}
int start = line.indexOf( "at " ) + 3;
int end = line.indexOf( '(' );
String temp = line.substring( start, end );
int lastPeriod = temp.lastIndexOf( '.' );
sourceClassName = temp.substring( 0, lastPeriod );
sourceMethodName = temp.substring( lastPeriod + 1 );
} catch ( Exception ex ) {
// ignore - leave class and methodname unknown
}
classAndMethodFound = true;
}
/**
* Logs a message with <code>java.util.logging.Level.FINE</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#debug(Object)
*/
public void debug(Object message) {
log(Level.FINE, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.FINE</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#debug(Object, Throwable)
*/
public void debug(Object message, Throwable exception) {
log(Level.FINE, String.valueOf(message), exception);
}
/**
* Logs a message with <code>java.util.logging.Level.SEVERE</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#error(Object)
*/
public void error(Object message) {
log(Level.SEVERE, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.SEVERE</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#error(Object, Throwable)
*/
public void error(Object message, Throwable exception) {
log(Level.SEVERE, String.valueOf(message), exception);
}
/**
* Logs a message with <code>java.util.logging.Level.SEVERE</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#fatal(Object)
*/
public void fatal(Object message) {
log(Level.SEVERE, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.SEVERE</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#fatal(Object, Throwable)
*/
public void fatal(Object message, Throwable exception) {
log(Level.SEVERE, String.valueOf(message), exception);
}
/**
* Return the native Logger instance we are using.
*/
public Logger getLogger() {
if (logger == null) {
logger = Logger.getLogger(name);
}
return logger;
}
/**
* Logs a message with <code>java.util.logging.Level.INFO</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#info(Object)
*/
public void info(Object message) {
log(Level.INFO, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.INFO</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#info(Object, Throwable)
*/
public void info(Object message, Throwable exception) {
log(Level.INFO, String.valueOf(message), exception);
}
/**
* Is debug logging currently enabled?
*/
public boolean isDebugEnabled() {
return getLogger().isLoggable(Level.FINE);
}
/**
* Is error logging currently enabled?
*/
public boolean isErrorEnabled() {
return getLogger().isLoggable(Level.SEVERE);
}
/**
* Is fatal logging currently enabled?
*/
public boolean isFatalEnabled() {
return getLogger().isLoggable(Level.SEVERE);
}
/**
* Is info logging currently enabled?
*/
public boolean isInfoEnabled() {
return getLogger().isLoggable(Level.INFO);
}
/**
* Is trace logging currently enabled?
*/
public boolean isTraceEnabled() {
return getLogger().isLoggable(Level.FINEST);
}
/**
* Is warn logging currently enabled?
*/
public boolean isWarnEnabled() {
return getLogger().isLoggable(Level.WARNING);
}
/**
* Logs a message with <code>java.util.logging.Level.FINEST</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#trace(Object)
*/
public void trace(Object message) {
log(Level.FINEST, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.FINEST</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#trace(Object, Throwable)
*/
public void trace(Object message, Throwable exception) {
log(Level.FINEST, String.valueOf(message), exception);
}
/**
* Logs a message with <code>java.util.logging.Level.WARNING</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#warn(Object)
*/
public void warn(Object message) {
log(Level.WARNING, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.WARNING</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#warn(Object, Throwable)
*/
public void warn(Object message, Throwable exception) {
log(Level.WARNING, String.valueOf(message), exception);
}
}

View File

@ -0,0 +1,273 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.Log;
/**
* Implementation of the <code>org.apache.commons.logging.Log</code>
* interface that wraps the standard JDK logging mechanisms that were
* introduced in the Merlin release (JDK 1.4).
*
* @version $Id: Jdk14Logger.java 1448063 2013-02-20 10:01:41Z tn $
*/
public class Jdk14Logger implements Log, Serializable {
/** Serializable version identifier. */
private static final long serialVersionUID = 4784713551416303804L;
/**
* This member variable simply ensures that any attempt to initialise
* this class in a pre-1.4 JVM will result in an ExceptionInInitializerError.
* It must not be private, as an optimising compiler could detect that it
* is not used and optimise it away.
*/
protected static final Level dummyLevel = Level.FINE;
// ----------------------------------------------------------- Constructors
/**
* Construct a named instance of this Logger.
*
* @param name Name of the logger to be constructed
*/
public Jdk14Logger(String name) {
this.name = name;
logger = getLogger();
}
// ----------------------------------------------------- Instance Variables
/**
* The underlying Logger implementation we are using.
*/
protected transient Logger logger = null;
/**
* The name of the logger we are wrapping.
*/
protected String name = null;
// --------------------------------------------------------- Protected Methods
protected void log( Level level, String msg, Throwable ex ) {
Logger logger = getLogger();
if (logger.isLoggable(level)) {
// Hack (?) to get the stack trace.
Throwable dummyException = new Throwable();
StackTraceElement locations[] = dummyException.getStackTrace();
// LOGGING-132: use the provided logger name instead of the class name
String cname = name;
String method = "unknown";
// Caller will be the third element
if( locations != null && locations.length > 2 ) {
StackTraceElement caller = locations[2];
method = caller.getMethodName();
}
if( ex == null ) {
logger.logp( level, cname, method, msg );
} else {
logger.logp( level, cname, method, msg, ex );
}
}
}
// --------------------------------------------------------- Public Methods
/**
* Logs a message with <code>java.util.logging.Level.FINE</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#debug(Object)
*/
public void debug(Object message) {
log(Level.FINE, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.FINE</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#debug(Object, Throwable)
*/
public void debug(Object message, Throwable exception) {
log(Level.FINE, String.valueOf(message), exception);
}
/**
* Logs a message with <code>java.util.logging.Level.SEVERE</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#error(Object)
*/
public void error(Object message) {
log(Level.SEVERE, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.SEVERE</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#error(Object, Throwable)
*/
public void error(Object message, Throwable exception) {
log(Level.SEVERE, String.valueOf(message), exception);
}
/**
* Logs a message with <code>java.util.logging.Level.SEVERE</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#fatal(Object)
*/
public void fatal(Object message) {
log(Level.SEVERE, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.SEVERE</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#fatal(Object, Throwable)
*/
public void fatal(Object message, Throwable exception) {
log(Level.SEVERE, String.valueOf(message), exception);
}
/**
* Return the native Logger instance we are using.
*/
public Logger getLogger() {
if (logger == null) {
logger = Logger.getLogger(name);
}
return logger;
}
/**
* Logs a message with <code>java.util.logging.Level.INFO</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#info(Object)
*/
public void info(Object message) {
log(Level.INFO, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.INFO</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#info(Object, Throwable)
*/
public void info(Object message, Throwable exception) {
log(Level.INFO, String.valueOf(message), exception);
}
/**
* Is debug logging currently enabled?
*/
public boolean isDebugEnabled() {
return getLogger().isLoggable(Level.FINE);
}
/**
* Is error logging currently enabled?
*/
public boolean isErrorEnabled() {
return getLogger().isLoggable(Level.SEVERE);
}
/**
* Is fatal logging currently enabled?
*/
public boolean isFatalEnabled() {
return getLogger().isLoggable(Level.SEVERE);
}
/**
* Is info logging currently enabled?
*/
public boolean isInfoEnabled() {
return getLogger().isLoggable(Level.INFO);
}
/**
* Is trace logging currently enabled?
*/
public boolean isTraceEnabled() {
return getLogger().isLoggable(Level.FINEST);
}
/**
* Is warn logging currently enabled?
*/
public boolean isWarnEnabled() {
return getLogger().isLoggable(Level.WARNING);
}
/**
* Logs a message with <code>java.util.logging.Level.FINEST</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#trace(Object)
*/
public void trace(Object message) {
log(Level.FINEST, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.FINEST</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#trace(Object, Throwable)
*/
public void trace(Object message, Throwable exception) {
log(Level.FINEST, String.valueOf(message), exception);
}
/**
* Logs a message with <code>java.util.logging.Level.WARNING</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#warn(Object)
*/
public void warn(Object message) {
log(Level.WARNING, String.valueOf(message), null);
}
/**
* Logs a message with <code>java.util.logging.Level.WARNING</code>.
*
* @param message to log
* @param exception log this cause
* @see org.apache.commons.logging.Log#warn(Object, Throwable)
*/
public void warn(Object message, Throwable exception) {
log(Level.WARNING, String.valueOf(message), exception);
}
}

View File

@ -0,0 +1,312 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.log4j.Logger;
import org.apache.log4j.Priority;
import org.apache.log4j.Level;
/**
* Implementation of {@link Log} that maps directly to a
* <strong>Logger</strong> for log4J version 1.2.
* <p>
* Initial configuration of the corresponding Logger instances should be done
* in the usual manner, as outlined in the Log4J documentation.
* <p>
* The reason this logger is distinct from the 1.3 logger is that in version 1.2
* of Log4J:
* <ul>
* <li>class Logger takes Priority parameters not Level parameters.
* <li>class Level extends Priority
* </ul>
* Log4J1.3 is expected to change Level so it no longer extends Priority, which is
* a non-binary-compatible change. The class generated by compiling this code against
* log4j 1.2 will therefore not run against log4j 1.3.
*
* @version $Id: Log4JLogger.java 1448119 2013-02-20 12:28:04Z tn $
*/
public class Log4JLogger implements Log, Serializable {
/** Serializable version identifier. */
private static final long serialVersionUID = 5160705895411730424L;
// ------------------------------------------------------------- Attributes
/** The fully qualified name of the Log4JLogger class. */
private static final String FQCN = Log4JLogger.class.getName();
/** Log to this logger */
private transient volatile Logger logger = null;
/** Logger name */
private final String name;
private static final Priority traceLevel;
// ------------------------------------------------------------
// Static Initializer.
//
// Note that this must come after the static variable declarations
// otherwise initialiser expressions associated with those variables
// will override any settings done here.
//
// Verify that log4j is available, and that it is version 1.2.
// If an ExceptionInInitializerError is generated, then LogFactoryImpl
// will treat that as meaning that the appropriate underlying logging
// library is just not present - if discovery is in progress then
// discovery will continue.
// ------------------------------------------------------------
static {
if (!Priority.class.isAssignableFrom(Level.class)) {
// nope, this is log4j 1.3, so force an ExceptionInInitializerError
throw new InstantiationError("Log4J 1.2 not available");
}
// Releases of log4j1.2 >= 1.2.12 have Priority.TRACE available, earlier
// versions do not. If TRACE is not available, then we have to map
// calls to Log.trace(...) onto the DEBUG level.
Priority _traceLevel;
try {
_traceLevel = (Priority) Level.class.getDeclaredField("TRACE").get(null);
} catch(Exception ex) {
// ok, trace not available
_traceLevel = Level.DEBUG;
}
traceLevel = _traceLevel;
}
// ------------------------------------------------------------ Constructor
public Log4JLogger() {
name = null;
}
/**
* Base constructor.
*/
public Log4JLogger(String name) {
this.name = name;
this.logger = getLogger();
}
/**
* For use with a log4j factory.
*/
public Log4JLogger(Logger logger) {
if (logger == null) {
throw new IllegalArgumentException(
"Warning - null logger in constructor; possible log4j misconfiguration.");
}
this.name = logger.getName();
this.logger = logger;
}
/**
* Logs a message with <code>org.apache.log4j.Priority.TRACE</code>.
* When using a log4j version that does not support the <code>TRACE</code>
* level, the message will be logged at the <code>DEBUG</code> level.
*
* @param message to log
* @see org.apache.commons.logging.Log#trace(Object)
*/
public void trace(Object message) {
getLogger().log(FQCN, traceLevel, message, null);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.TRACE</code>.
* When using a log4j version that does not support the <code>TRACE</code>
* level, the message will be logged at the <code>DEBUG</code> level.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#trace(Object, Throwable)
*/
public void trace(Object message, Throwable t) {
getLogger().log(FQCN, traceLevel, message, t);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.DEBUG</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#debug(Object)
*/
public void debug(Object message) {
getLogger().log(FQCN, Level.DEBUG, message, null);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.DEBUG</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#debug(Object, Throwable)
*/
public void debug(Object message, Throwable t) {
getLogger().log(FQCN, Level.DEBUG, message, t);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.INFO</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#info(Object)
*/
public void info(Object message) {
getLogger().log(FQCN, Level.INFO, message, null);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.INFO</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#info(Object, Throwable)
*/
public void info(Object message, Throwable t) {
getLogger().log(FQCN, Level.INFO, message, t);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.WARN</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#warn(Object)
*/
public void warn(Object message) {
getLogger().log(FQCN, Level.WARN, message, null);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.WARN</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#warn(Object, Throwable)
*/
public void warn(Object message, Throwable t) {
getLogger().log(FQCN, Level.WARN, message, t);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.ERROR</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#error(Object)
*/
public void error(Object message) {
getLogger().log(FQCN, Level.ERROR, message, null);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.ERROR</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#error(Object, Throwable)
*/
public void error(Object message, Throwable t) {
getLogger().log(FQCN, Level.ERROR, message, t);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.FATAL</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#fatal(Object)
*/
public void fatal(Object message) {
getLogger().log(FQCN, Level.FATAL, message, null);
}
/**
* Logs a message with <code>org.apache.log4j.Priority.FATAL</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#fatal(Object, Throwable)
*/
public void fatal(Object message, Throwable t) {
getLogger().log(FQCN, Level.FATAL, message, t);
}
/**
* Return the native Logger instance we are using.
*/
public Logger getLogger() {
Logger result = logger;
if (result == null) {
synchronized(this) {
result = logger;
if (result == null) {
logger = result = Logger.getLogger(name);
}
}
}
return result;
}
/**
* Check whether the Log4j Logger used is enabled for <code>DEBUG</code> priority.
*/
public boolean isDebugEnabled() {
return getLogger().isDebugEnabled();
}
/**
* Check whether the Log4j Logger used is enabled for <code>ERROR</code> priority.
*/
public boolean isErrorEnabled() {
return getLogger().isEnabledFor(Level.ERROR);
}
/**
* Check whether the Log4j Logger used is enabled for <code>FATAL</code> priority.
*/
public boolean isFatalEnabled() {
return getLogger().isEnabledFor(Level.FATAL);
}
/**
* Check whether the Log4j Logger used is enabled for <code>INFO</code> priority.
*/
public boolean isInfoEnabled() {
return getLogger().isInfoEnabled();
}
/**
* Check whether the Log4j Logger used is enabled for <code>TRACE</code> priority.
* When using a log4j version that does not support the TRACE level, this call
* will report whether <code>DEBUG</code> is enabled or not.
*/
public boolean isTraceEnabled() {
return getLogger().isEnabledFor(traceLevel);
}
/**
* Check whether the Log4j Logger used is enabled for <code>WARN</code> priority.
*/
public boolean isWarnEnabled() {
return getLogger().isEnabledFor(Level.WARN);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,269 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import java.io.Serializable;
import org.apache.log.Logger;
import org.apache.log.Hierarchy;
import org.apache.commons.logging.Log;
/**
* Implementation of <code>org.apache.commons.logging.Log</code>
* that wraps the <a href="http://avalon.apache.org/logkit/">avalon-logkit</a>
* logging system. Configuration of <code>LogKit</code> is left to the user.
* <p>
* <code>LogKit</code> accepts only <code>String</code> messages.
* Therefore, this implementation converts object messages into strings
* by called their <code>toString()</code> method before logging them.
*
* @version $Id: LogKitLogger.java 1448119 2013-02-20 12:28:04Z tn $
*/
public class LogKitLogger implements Log, Serializable {
/** Serializable version identifier. */
private static final long serialVersionUID = 3768538055836059519L;
// ------------------------------------------------------------- Attributes
/** Logging goes to this <code>LogKit</code> logger */
protected transient volatile Logger logger = null;
/** Name of this logger */
protected String name = null;
// ------------------------------------------------------------ Constructor
/**
* Construct <code>LogKitLogger</code> which wraps the <code>LogKit</code>
* logger with given name.
*
* @param name log name
*/
public LogKitLogger(String name) {
this.name = name;
this.logger = getLogger();
}
// --------------------------------------------------------- Public Methods
/**
* Return the underlying Logger we are using.
*/
public Logger getLogger() {
Logger result = logger;
if (result == null) {
synchronized(this) {
result = logger;
if (result == null) {
logger = result = Hierarchy.getDefaultHierarchy().getLoggerFor(name);
}
}
}
return result;
}
// ----------------------------------------------------- Log Implementation
/**
* Logs a message with <code>org.apache.log.Priority.DEBUG</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#trace(Object)
*/
public void trace(Object message) {
debug(message);
}
/**
* Logs a message with <code>org.apache.log.Priority.DEBUG</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#trace(Object, Throwable)
*/
public void trace(Object message, Throwable t) {
debug(message, t);
}
/**
* Logs a message with <code>org.apache.log.Priority.DEBUG</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#debug(Object)
*/
public void debug(Object message) {
if (message != null) {
getLogger().debug(String.valueOf(message));
}
}
/**
* Logs a message with <code>org.apache.log.Priority.DEBUG</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#debug(Object, Throwable)
*/
public void debug(Object message, Throwable t) {
if (message != null) {
getLogger().debug(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.log.Priority.INFO</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#info(Object)
*/
public void info(Object message) {
if (message != null) {
getLogger().info(String.valueOf(message));
}
}
/**
* Logs a message with <code>org.apache.log.Priority.INFO</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#info(Object, Throwable)
*/
public void info(Object message, Throwable t) {
if (message != null) {
getLogger().info(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.log.Priority.WARN</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#warn(Object)
*/
public void warn(Object message) {
if (message != null) {
getLogger().warn(String.valueOf(message));
}
}
/**
* Logs a message with <code>org.apache.log.Priority.WARN</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#warn(Object, Throwable)
*/
public void warn(Object message, Throwable t) {
if (message != null) {
getLogger().warn(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.log.Priority.ERROR</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#error(Object)
*/
public void error(Object message) {
if (message != null) {
getLogger().error(String.valueOf(message));
}
}
/**
* Logs a message with <code>org.apache.log.Priority.ERROR</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#error(Object, Throwable)
*/
public void error(Object message, Throwable t) {
if (message != null) {
getLogger().error(String.valueOf(message), t);
}
}
/**
* Logs a message with <code>org.apache.log.Priority.FATAL_ERROR</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#fatal(Object)
*/
public void fatal(Object message) {
if (message != null) {
getLogger().fatalError(String.valueOf(message));
}
}
/**
* Logs a message with <code>org.apache.log.Priority.FATAL_ERROR</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#fatal(Object, Throwable)
*/
public void fatal(Object message, Throwable t) {
if (message != null) {
getLogger().fatalError(String.valueOf(message), t);
}
}
/**
* Checks whether the <code>LogKit</code> logger will log messages of priority <code>DEBUG</code>.
*/
public boolean isDebugEnabled() {
return getLogger().isDebugEnabled();
}
/**
* Checks whether the <code>LogKit</code> logger will log messages of priority <code>ERROR</code>.
*/
public boolean isErrorEnabled() {
return getLogger().isErrorEnabled();
}
/**
* Checks whether the <code>LogKit</code> logger will log messages of priority <code>FATAL_ERROR</code>.
*/
public boolean isFatalEnabled() {
return getLogger().isFatalErrorEnabled();
}
/**
* Checks whether the <code>LogKit</code> logger will log messages of priority <code>INFO</code>.
*/
public boolean isInfoEnabled() {
return getLogger().isInfoEnabled();
}
/**
* Checks whether the <code>LogKit</code> logger will log messages of priority <code>DEBUG</code>.
*/
public boolean isTraceEnabled() {
return getLogger().isDebugEnabled();
}
/**
* Checks whether the <code>LogKit</code> logger will log messages of priority <code>WARN</code>.
*/
public boolean isWarnEnabled() {
return getLogger().isWarnEnabled();
}
}

View File

@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import java.io.Serializable;
import org.apache.commons.logging.Log;
/**
* Trivial implementation of Log that throws away all messages. No
* configurable system properties are supported.
*
* @version $Id: NoOpLog.java 1432663 2013-01-13 17:24:18Z tn $
*/
public class NoOpLog implements Log, Serializable {
/** Serializable version identifier. */
private static final long serialVersionUID = 561423906191706148L;
/** Convenience constructor */
public NoOpLog() { }
/** Base constructor */
public NoOpLog(String name) { }
/** Do nothing */
public void trace(Object message) { }
/** Do nothing */
public void trace(Object message, Throwable t) { }
/** Do nothing */
public void debug(Object message) { }
/** Do nothing */
public void debug(Object message, Throwable t) { }
/** Do nothing */
public void info(Object message) { }
/** Do nothing */
public void info(Object message, Throwable t) { }
/** Do nothing */
public void warn(Object message) { }
/** Do nothing */
public void warn(Object message, Throwable t) { }
/** Do nothing */
public void error(Object message) { }
/** Do nothing */
public void error(Object message, Throwable t) { }
/** Do nothing */
public void fatal(Object message) { }
/** Do nothing */
public void fatal(Object message, Throwable t) { }
/**
* Debug is never enabled.
*
* @return false
*/
public final boolean isDebugEnabled() { return false; }
/**
* Error is never enabled.
*
* @return false
*/
public final boolean isErrorEnabled() { return false; }
/**
* Fatal is never enabled.
*
* @return false
*/
public final boolean isFatalEnabled() { return false; }
/**
* Info is never enabled.
*
* @return false
*/
public final boolean isInfoEnabled() { return false; }
/**
* Trace is never enabled.
*
* @return false
*/
public final boolean isTraceEnabled() { return false; }
/**
* Warn is never enabled.
*
* @return false
*/
public final boolean isWarnEnabled() { return false; }
}

View File

@ -0,0 +1,136 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.LogFactory;
/**
* This class is capable of receiving notifications about the undeployment of
* a webapp, and responds by ensuring that commons-logging releases all
* memory associated with the undeployed webapp.
* <p>
* In general, the WeakHashtable support added in commons-logging release 1.1
* ensures that logging classes do not hold references that prevent an
* undeployed webapp's memory from being garbage-collected even when multiple
* copies of commons-logging are deployed via multiple classloaders (a
* situation that earlier versions had problems with). However there are
* some rare cases where the WeakHashtable approach does not work; in these
* situations specifying this class as a listener for the web application will
* ensure that all references held by commons-logging are fully released.
* <p>
* To use this class, configure the webapp deployment descriptor to call
* this class on webapp undeploy; the contextDestroyed method will tell
* every accessible LogFactory class that the entry in its map for the
* current webapp's context classloader should be cleared.
*
* @version $Id: ServletContextCleaner.java 1432580 2013-01-13 10:41:05Z tn $
* @since 1.1
*/
public class ServletContextCleaner implements ServletContextListener {
private static final Class[] RELEASE_SIGNATURE = {ClassLoader.class};
/**
* Invoked when a webapp is undeployed, this tells the LogFactory
* class to release any logging information related to the current
* contextClassloader.
*/
public void contextDestroyed(ServletContextEvent sce) {
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
Object[] params = new Object[1];
params[0] = tccl;
// Walk up the tree of classloaders, finding all the available
// LogFactory classes and releasing any objects associated with
// the tccl (ie the webapp).
//
// When there is only one LogFactory in the classpath, and it
// is within the webapp being undeployed then there is no problem;
// garbage collection works fine.
//
// When there are multiple LogFactory classes in the classpath but
// parent-first classloading is used everywhere, this loop is really
// short. The first instance of LogFactory found will
// be the highest in the classpath, and then no more will be found.
// This is ok, as with this setup this will be the only LogFactory
// holding any data associated with the tccl being released.
//
// When there are multiple LogFactory classes in the classpath and
// child-first classloading is used in any classloader, then multiple
// LogFactory instances may hold info about this TCCL; whenever the
// webapp makes a call into a class loaded via an ancestor classloader
// and that class calls LogFactory the tccl gets registered in
// the LogFactory instance that is visible from the ancestor
// classloader. However the concrete logging library it points
// to is expected to have been loaded via the TCCL, so the
// underlying logging lib is only initialised/configured once.
// These references from ancestor LogFactory classes down to
// TCCL classloaders are held via weak references and so should
// be released but there are circumstances where they may not.
// Walking up the classloader ancestry ladder releasing
// the current tccl at each level tree, though, will definitely
// clear any problem references.
ClassLoader loader = tccl;
while (loader != null) {
// Load via the current loader. Note that if the class is not accessible
// via this loader, but is accessible via some ancestor then that class
// will be returned.
try {
Class logFactoryClass = loader.loadClass("org.apache.commons.logging.LogFactory");
Method releaseMethod = logFactoryClass.getMethod("release", RELEASE_SIGNATURE);
releaseMethod.invoke(null, params);
loader = logFactoryClass.getClassLoader().getParent();
} catch(ClassNotFoundException ex) {
// Neither the current classloader nor any of its ancestors could find
// the LogFactory class, so we can stop now.
loader = null;
} catch(NoSuchMethodException ex) {
// This is not expected; every version of JCL has this method
System.err.println("LogFactory instance found which does not support release method!");
loader = null;
} catch(IllegalAccessException ex) {
// This is not expected; every ancestor class should be accessible
System.err.println("LogFactory instance found which is not accessable!");
loader = null;
} catch(InvocationTargetException ex) {
// This is not expected
System.err.println("LogFactory instance release method failed!");
loader = null;
}
}
// Just to be sure, invoke release on the LogFactory that is visible from
// this ServletContextCleaner class too. This should already have been caught
// by the above loop but just in case...
LogFactory.release(tccl);
}
/**
* Invoked when a webapp is deployed. Nothing needs to be done here.
*/
public void contextInitialized(ServletContextEvent sce) {
// do nothing
}
}

View File

@ -0,0 +1,649 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogConfigurationException;
/**
* Simple implementation of Log that sends all enabled log messages,
* for all defined loggers, to System.err. The following system properties
* are supported to configure the behavior of this logger:
* <ul>
* <li><code>org.apache.commons.logging.simplelog.defaultlog</code> -
* Default logging detail level for all instances of SimpleLog.
* Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
* If not specified, defaults to "info". </li>
* <li><code>org.apache.commons.logging.simplelog.log.xxxxx</code> -
* Logging detail level for a SimpleLog instance named "xxxxx".
* Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
* If not specified, the default logging detail level is used.</li>
* <li><code>org.apache.commons.logging.simplelog.showlogname</code> -
* Set to <code>true</code> if you want the Log instance name to be
* included in output messages. Defaults to <code>false</code>.</li>
* <li><code>org.apache.commons.logging.simplelog.showShortLogname</code> -
* Set to <code>true</code> if you want the last component of the name to be
* included in output messages. Defaults to <code>true</code>.</li>
* <li><code>org.apache.commons.logging.simplelog.showdatetime</code> -
* Set to <code>true</code> if you want the current date and time
* to be included in output messages. Default is <code>false</code>.</li>
* <li><code>org.apache.commons.logging.simplelog.dateTimeFormat</code> -
* The date and time format to be used in the output messages.
* The pattern describing the date and time format is the same that is
* used in <code>java.text.SimpleDateFormat</code>. If the format is not
* specified or is invalid, the default format is used.
* The default format is <code>yyyy/MM/dd HH:mm:ss:SSS zzz</code>.</li>
* </ul>
* <p>
* In addition to looking for system properties with the names specified
* above, this implementation also checks for a class loader resource named
* <code>"simplelog.properties"</code>, and includes any matching definitions
* from this resource (if it exists).
*
* @version $Id: SimpleLog.java 1435115 2013-01-18 12:40:19Z tn $
*/
public class SimpleLog implements Log, Serializable {
/** Serializable version identifier. */
private static final long serialVersionUID = 136942970684951178L;
// ------------------------------------------------------- Class Attributes
/** All system properties used by <code>SimpleLog</code> start with this */
static protected final String systemPrefix = "org.apache.commons.logging.simplelog.";
/** Properties loaded from simplelog.properties */
static protected final Properties simpleLogProps = new Properties();
/** The default format to use when formating dates */
static protected final String DEFAULT_DATE_TIME_FORMAT = "yyyy/MM/dd HH:mm:ss:SSS zzz";
/** Include the instance name in the log message? */
static volatile protected boolean showLogName = false;
/** Include the short name ( last component ) of the logger in the log
* message. Defaults to true - otherwise we'll be lost in a flood of
* messages without knowing who sends them.
*/
static volatile protected boolean showShortName = true;
/** Include the current time in the log message */
static volatile protected boolean showDateTime = false;
/** The date and time format to use in the log message */
static volatile protected String dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
/**
* Used to format times.
* <p>
* Any code that accesses this object should first obtain a lock on it,
* ie use synchronized(dateFormatter); this requirement was introduced
* in 1.1.1 to fix an existing thread safety bug (SimpleDateFormat.format
* is not thread-safe).
*/
static protected DateFormat dateFormatter = null;
// ---------------------------------------------------- Log Level Constants
/** "Trace" level logging. */
public static final int LOG_LEVEL_TRACE = 1;
/** "Debug" level logging. */
public static final int LOG_LEVEL_DEBUG = 2;
/** "Info" level logging. */
public static final int LOG_LEVEL_INFO = 3;
/** "Warn" level logging. */
public static final int LOG_LEVEL_WARN = 4;
/** "Error" level logging. */
public static final int LOG_LEVEL_ERROR = 5;
/** "Fatal" level logging. */
public static final int LOG_LEVEL_FATAL = 6;
/** Enable all logging levels */
public static final int LOG_LEVEL_ALL = LOG_LEVEL_TRACE - 1;
/** Enable no logging levels */
public static final int LOG_LEVEL_OFF = LOG_LEVEL_FATAL + 1;
// ------------------------------------------------------------ Initializer
private static String getStringProperty(String name) {
String prop = null;
try {
prop = System.getProperty(name);
} catch (SecurityException e) {
// Ignore
}
return prop == null ? simpleLogProps.getProperty(name) : prop;
}
private static String getStringProperty(String name, String dephault) {
String prop = getStringProperty(name);
return prop == null ? dephault : prop;
}
private static boolean getBooleanProperty(String name, boolean dephault) {
String prop = getStringProperty(name);
return prop == null ? dephault : "true".equalsIgnoreCase(prop);
}
// Initialize class attributes.
// Load properties file, if found.
// Override with system properties.
static {
// Add props from the resource simplelog.properties
InputStream in = getResourceAsStream("simplelog.properties");
if(null != in) {
try {
simpleLogProps.load(in);
in.close();
} catch(java.io.IOException e) {
// ignored
}
}
showLogName = getBooleanProperty(systemPrefix + "showlogname", showLogName);
showShortName = getBooleanProperty(systemPrefix + "showShortLogname", showShortName);
showDateTime = getBooleanProperty(systemPrefix + "showdatetime", showDateTime);
if(showDateTime) {
dateTimeFormat = getStringProperty(systemPrefix + "dateTimeFormat",
dateTimeFormat);
try {
dateFormatter = new SimpleDateFormat(dateTimeFormat);
} catch(IllegalArgumentException e) {
// If the format pattern is invalid - use the default format
dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
dateFormatter = new SimpleDateFormat(dateTimeFormat);
}
}
}
// ------------------------------------------------------------- Attributes
/** The name of this simple log instance */
protected volatile String logName = null;
/** The current log level */
protected volatile int currentLogLevel;
/** The short name of this simple log instance */
private volatile String shortLogName = null;
// ------------------------------------------------------------ Constructor
/**
* Construct a simple log with given name.
*
* @param name log name
*/
public SimpleLog(String name) {
logName = name;
// Set initial log level
// Used to be: set default log level to ERROR
// IMHO it should be lower, but at least info ( costin ).
setLevel(SimpleLog.LOG_LEVEL_INFO);
// Set log level from properties
String lvl = getStringProperty(systemPrefix + "log." + logName);
int i = String.valueOf(name).lastIndexOf(".");
while(null == lvl && i > -1) {
name = name.substring(0,i);
lvl = getStringProperty(systemPrefix + "log." + name);
i = String.valueOf(name).lastIndexOf(".");
}
if(null == lvl) {
lvl = getStringProperty(systemPrefix + "defaultlog");
}
if("all".equalsIgnoreCase(lvl)) {
setLevel(SimpleLog.LOG_LEVEL_ALL);
} else if("trace".equalsIgnoreCase(lvl)) {
setLevel(SimpleLog.LOG_LEVEL_TRACE);
} else if("debug".equalsIgnoreCase(lvl)) {
setLevel(SimpleLog.LOG_LEVEL_DEBUG);
} else if("info".equalsIgnoreCase(lvl)) {
setLevel(SimpleLog.LOG_LEVEL_INFO);
} else if("warn".equalsIgnoreCase(lvl)) {
setLevel(SimpleLog.LOG_LEVEL_WARN);
} else if("error".equalsIgnoreCase(lvl)) {
setLevel(SimpleLog.LOG_LEVEL_ERROR);
} else if("fatal".equalsIgnoreCase(lvl)) {
setLevel(SimpleLog.LOG_LEVEL_FATAL);
} else if("off".equalsIgnoreCase(lvl)) {
setLevel(SimpleLog.LOG_LEVEL_OFF);
}
}
// -------------------------------------------------------- Properties
/**
* Set logging level.
*
* @param currentLogLevel new logging level
*/
public void setLevel(int currentLogLevel) {
this.currentLogLevel = currentLogLevel;
}
/**
* Get logging level.
*/
public int getLevel() {
return currentLogLevel;
}
// -------------------------------------------------------- Logging Methods
/**
* Do the actual logging.
* <p>
* This method assembles the message and then calls <code>write()</code>
* to cause it to be written.
*
* @param type One of the LOG_LEVEL_XXX constants defining the log level
* @param message The message itself (typically a String)
* @param t The exception whose stack trace should be logged
*/
protected void log(int type, Object message, Throwable t) {
// Use a string buffer for better performance
final StringBuffer buf = new StringBuffer();
// Append date-time if so configured
if(showDateTime) {
final Date now = new Date();
String dateText;
synchronized(dateFormatter) {
dateText = dateFormatter.format(now);
}
buf.append(dateText);
buf.append(" ");
}
// Append a readable representation of the log level
switch(type) {
case SimpleLog.LOG_LEVEL_TRACE: buf.append("[TRACE] "); break;
case SimpleLog.LOG_LEVEL_DEBUG: buf.append("[DEBUG] "); break;
case SimpleLog.LOG_LEVEL_INFO: buf.append("[INFO] "); break;
case SimpleLog.LOG_LEVEL_WARN: buf.append("[WARN] "); break;
case SimpleLog.LOG_LEVEL_ERROR: buf.append("[ERROR] "); break;
case SimpleLog.LOG_LEVEL_FATAL: buf.append("[FATAL] "); break;
}
// Append the name of the log instance if so configured
if(showShortName) {
if(shortLogName == null) {
// Cut all but the last component of the name for both styles
final String slName = logName.substring(logName.lastIndexOf(".") + 1);
shortLogName = slName.substring(slName.lastIndexOf("/") + 1);
}
buf.append(String.valueOf(shortLogName)).append(" - ");
} else if(showLogName) {
buf.append(String.valueOf(logName)).append(" - ");
}
// Append the message
buf.append(String.valueOf(message));
// Append stack trace if not null
if(t != null) {
buf.append(" <");
buf.append(t.toString());
buf.append(">");
final java.io.StringWriter sw = new java.io.StringWriter(1024);
final java.io.PrintWriter pw = new java.io.PrintWriter(sw);
t.printStackTrace(pw);
pw.close();
buf.append(sw.toString());
}
// Print to the appropriate destination
write(buf);
}
/**
* Write the content of the message accumulated in the specified
* <code>StringBuffer</code> to the appropriate output destination. The
* default implementation writes to <code>System.err</code>.
*
* @param buffer A <code>StringBuffer</code> containing the accumulated
* text to be logged
*/
protected void write(StringBuffer buffer) {
System.err.println(buffer.toString());
}
/**
* Is the given log level currently enabled?
*
* @param logLevel is this level enabled?
*/
protected boolean isLevelEnabled(int logLevel) {
// log level are numerically ordered so can use simple numeric
// comparison
return logLevel >= currentLogLevel;
}
// -------------------------------------------------------- Log Implementation
/**
* Logs a message with
* <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#debug(Object)
*/
public final void debug(Object message) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
log(SimpleLog.LOG_LEVEL_DEBUG, message, null);
}
}
/**
* Logs a message with
* <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#debug(Object, Throwable)
*/
public final void debug(Object message, Throwable t) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
log(SimpleLog.LOG_LEVEL_DEBUG, message, t);
}
}
/**
* Logs a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#trace(Object)
*/
public final void trace(Object message) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
log(SimpleLog.LOG_LEVEL_TRACE, message, null);
}
}
/**
* Logs a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#trace(Object, Throwable)
*/
public final void trace(Object message, Throwable t) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
log(SimpleLog.LOG_LEVEL_TRACE, message, t);
}
}
/**
* Logs a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#info(Object)
*/
public final void info(Object message) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
log(SimpleLog.LOG_LEVEL_INFO,message,null);
}
}
/**
* Logs a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#info(Object, Throwable)
*/
public final void info(Object message, Throwable t) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
log(SimpleLog.LOG_LEVEL_INFO, message, t);
}
}
/**
* Logs a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#warn(Object)
*/
public final void warn(Object message) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
log(SimpleLog.LOG_LEVEL_WARN, message, null);
}
}
/**
* Logs a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#warn(Object, Throwable)
*/
public final void warn(Object message, Throwable t) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
log(SimpleLog.LOG_LEVEL_WARN, message, t);
}
}
/**
* Logs a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#error(Object)
*/
public final void error(Object message) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
log(SimpleLog.LOG_LEVEL_ERROR, message, null);
}
}
/**
* Logs a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#error(Object, Throwable)
*/
public final void error(Object message, Throwable t) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
log(SimpleLog.LOG_LEVEL_ERROR, message, t);
}
}
/**
* Log a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>.
*
* @param message to log
* @see org.apache.commons.logging.Log#fatal(Object)
*/
public final void fatal(Object message) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
log(SimpleLog.LOG_LEVEL_FATAL, message, null);
}
}
/**
* Logs a message with <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>.
*
* @param message to log
* @param t log this cause
* @see org.apache.commons.logging.Log#fatal(Object, Throwable)
*/
public final void fatal(Object message, Throwable t) {
if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
log(SimpleLog.LOG_LEVEL_FATAL, message, t);
}
}
/**
* Are debug messages currently enabled?
* <p>
* This allows expensive operations such as <code>String</code>
* concatenation to be avoided when the message will be ignored by the
* logger.
*/
public final boolean isDebugEnabled() {
return isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG);
}
/**
* Are error messages currently enabled?
* <p>
* This allows expensive operations such as <code>String</code>
* concatenation to be avoided when the message will be ignored by the
* logger.
*/
public final boolean isErrorEnabled() {
return isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR);
}
/**
* Are fatal messages currently enabled?
* <p>
* This allows expensive operations such as <code>String</code>
* concatenation to be avoided when the message will be ignored by the
* logger.
*/
public final boolean isFatalEnabled() {
return isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL);
}
/**
* Are info messages currently enabled?
* <p>
* This allows expensive operations such as <code>String</code>
* concatenation to be avoided when the message will be ignored by the
* logger.
*/
public final boolean isInfoEnabled() {
return isLevelEnabled(SimpleLog.LOG_LEVEL_INFO);
}
/**
* Are trace messages currently enabled?
* <p>
* This allows expensive operations such as <code>String</code>
* concatenation to be avoided when the message will be ignored by the
* logger.
*/
public final boolean isTraceEnabled() {
return isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE);
}
/**
* Are warn messages currently enabled?
* <p>
* This allows expensive operations such as <code>String</code>
* concatenation to be avoided when the message will be ignored by the
* logger.
*/
public final boolean isWarnEnabled() {
return isLevelEnabled(SimpleLog.LOG_LEVEL_WARN);
}
/**
* Return the thread context class loader if available.
* Otherwise return null.
*
* The thread context class loader is available for JDK 1.2
* or later, if certain security conditions are met.
*
* @exception LogConfigurationException if a suitable class loader
* cannot be identified.
*/
private static ClassLoader getContextClassLoader() {
ClassLoader classLoader = null;
try {
// Are we running on a JDK 1.2 or later system?
final Method method = Thread.class.getMethod("getContextClassLoader", (Class[]) null);
// Get the thread context class loader (if there is one)
try {
classLoader = (ClassLoader)method.invoke(Thread.currentThread(), (Class[]) null);
} catch (IllegalAccessException e) {
// ignore
} catch (InvocationTargetException e) {
/**
* InvocationTargetException is thrown by 'invoke' when
* the method being invoked (getContextClassLoader) throws
* an exception.
*
* getContextClassLoader() throws SecurityException when
* the context class loader isn't an ancestor of the
* calling class's class loader, or if security
* permissions are restricted.
*
* In the first case (not related), we want to ignore and
* keep going. We cannot help but also ignore the second
* with the logic below, but other calls elsewhere (to
* obtain a class loader) will trigger this exception where
* we can make a distinction.
*/
if (e.getTargetException() instanceof SecurityException) {
// ignore
} else {
// Capture 'e.getTargetException()' exception for details
// alternate: log 'e.getTargetException()', and pass back 'e'.
throw new LogConfigurationException
("Unexpected InvocationTargetException", e.getTargetException());
}
}
} catch (NoSuchMethodException e) {
// Assume we are running on JDK 1.1
// ignore
}
if (classLoader == null) {
classLoader = SimpleLog.class.getClassLoader();
}
// Return the selected class loader
return classLoader;
}
private static InputStream getResourceAsStream(final String name) {
return (InputStream)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
ClassLoader threadCL = getContextClassLoader();
if (threadCL != null) {
return threadCL.getResourceAsStream(name);
} else {
return ClassLoader.getSystemResourceAsStream(name);
}
}
});
}
}

View File

@ -0,0 +1,482 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Implementation of <code>Hashtable</code> that uses <code>WeakReference</code>'s
* to hold its keys thus allowing them to be reclaimed by the garbage collector.
* The associated values are retained using strong references.
* <p>
* This class follows the semantics of <code>Hashtable</code> as closely as
* possible. It therefore does not accept null values or keys.
* <p>
* <strong>Note:</strong>
* This is <em>not</em> intended to be a general purpose hash table replacement.
* This implementation is also tuned towards a particular purpose: for use as a replacement
* for <code>Hashtable</code> in <code>LogFactory</code>. This application requires
* good liveliness for <code>get</code> and <code>put</code>. Various tradeoffs
* have been made with this in mind.
* <p>
* <strong>Usage:</strong> typical use case is as a drop-in replacement
* for the <code>Hashtable</code> used in <code>LogFactory</code> for J2EE environments
* running 1.3+ JVMs. Use of this class <i>in most cases</i> (see below) will
* allow classloaders to be collected by the garbage collector without the need
* to call {@link org.apache.commons.logging.LogFactory#release(ClassLoader) LogFactory.release(ClassLoader)}.
* <p>
* <code>org.apache.commons.logging.LogFactory</code> checks whether this class
* can be supported by the current JVM, and if so then uses it to store
* references to the <code>LogFactory</code> implementation it loads
* (rather than using a standard Hashtable instance).
* Having this class used instead of <code>Hashtable</code> solves
* certain issues related to dynamic reloading of applications in J2EE-style
* environments. However this class requires java 1.3 or later (due to its use
* of <code>java.lang.ref.WeakReference</code> and associates).
* And by the way, this extends <code>Hashtable</code> rather than <code>HashMap</code>
* for backwards compatibility reasons. See the documentation
* for method <code>LogFactory.createFactoryStore</code> for more details.
* <p>
* The reason all this is necessary is due to a issue which
* arises during hot deploy in a J2EE-like containers.
* Each component running in the container owns one or more classloaders; when
* the component loads a LogFactory instance via the component classloader
* a reference to it gets stored in the static LogFactory.factories member,
* keyed by the component's classloader so different components don't
* stomp on each other. When the component is later unloaded, the container
* sets the component's classloader to null with the intent that all the
* component's classes get garbage-collected. However there's still a
* reference to the component's classloader from a key in the "global"
* <code>LogFactory</code>'s factories member! If <code>LogFactory.release()</code>
* is called whenever component is unloaded, the classloaders will be correctly
* garbage collected; this <i>should</i> be done by any container that
* bundles commons-logging by default. However, holding the classloader
* references weakly ensures that the classloader will be garbage collected
* without the container performing this step.
* <p>
* <strong>Limitations:</strong>
* There is still one (unusual) scenario in which a component will not
* be correctly unloaded without an explicit release. Though weak references
* are used for its keys, it is necessary to use strong references for its values.
* <p>
* If the abstract class <code>LogFactory</code> is
* loaded by the container classloader but a subclass of
* <code>LogFactory</code> [LogFactory1] is loaded by the component's
* classloader and an instance stored in the static map associated with the
* base LogFactory class, then there is a strong reference from the LogFactory
* class to the LogFactory1 instance (as normal) and a strong reference from
* the LogFactory1 instance to the component classloader via
* <code>getClass().getClassLoader()</code>. This chain of references will prevent
* collection of the child classloader.
* <p>
* Such a situation occurs when the commons-logging.jar is
* loaded by a parent classloader (e.g. a server level classloader in a
* servlet container) and a custom <code>LogFactory</code> implementation is
* loaded by a child classloader (e.g. a web app classloader).
* <p>
* To avoid this scenario, ensure
* that any custom LogFactory subclass is loaded by the same classloader as
* the base <code>LogFactory</code>. Creating custom LogFactory subclasses is,
* however, rare. The standard LogFactoryImpl class should be sufficient
* for most or all users.
*
* @version $Id: WeakHashtable.java 1435077 2013-01-18 10:51:35Z tn $
* @since 1.1
*/
public final class WeakHashtable extends Hashtable {
/** Serializable version identifier. */
private static final long serialVersionUID = -1546036869799732453L;
/**
* The maximum number of times put() or remove() can be called before
* the map will be purged of all cleared entries.
*/
private static final int MAX_CHANGES_BEFORE_PURGE = 100;
/**
* The maximum number of times put() or remove() can be called before
* the map will be purged of one cleared entry.
*/
private static final int PARTIAL_PURGE_COUNT = 10;
/* ReferenceQueue we check for gc'd keys */
private final ReferenceQueue queue = new ReferenceQueue();
/* Counter used to control how often we purge gc'd entries */
private int changeCount = 0;
/**
* Constructs a WeakHashtable with the Hashtable default
* capacity and load factor.
*/
public WeakHashtable() {}
/**
*@see Hashtable
*/
public boolean containsKey(Object key) {
// purge should not be required
Referenced referenced = new Referenced(key);
return super.containsKey(referenced);
}
/**
*@see Hashtable
*/
public Enumeration elements() {
purge();
return super.elements();
}
/**
*@see Hashtable
*/
public Set entrySet() {
purge();
Set referencedEntries = super.entrySet();
Set unreferencedEntries = new HashSet();
for (Iterator it=referencedEntries.iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
Referenced referencedKey = (Referenced) entry.getKey();
Object key = referencedKey.getValue();
Object value = entry.getValue();
if (key != null) {
Entry dereferencedEntry = new Entry(key, value);
unreferencedEntries.add(dereferencedEntry);
}
}
return unreferencedEntries;
}
/**
*@see Hashtable
*/
public Object get(Object key) {
// for performance reasons, no purge
Referenced referenceKey = new Referenced(key);
return super.get(referenceKey);
}
/**
*@see Hashtable
*/
public Enumeration keys() {
purge();
final Enumeration enumer = super.keys();
return new Enumeration() {
public boolean hasMoreElements() {
return enumer.hasMoreElements();
}
public Object nextElement() {
Referenced nextReference = (Referenced) enumer.nextElement();
return nextReference.getValue();
}
};
}
/**
*@see Hashtable
*/
public Set keySet() {
purge();
Set referencedKeys = super.keySet();
Set unreferencedKeys = new HashSet();
for (Iterator it=referencedKeys.iterator(); it.hasNext();) {
Referenced referenceKey = (Referenced) it.next();
Object keyValue = referenceKey.getValue();
if (keyValue != null) {
unreferencedKeys.add(keyValue);
}
}
return unreferencedKeys;
}
/**
*@see Hashtable
*/
public synchronized Object put(Object key, Object value) {
// check for nulls, ensuring semantics match superclass
if (key == null) {
throw new NullPointerException("Null keys are not allowed");
}
if (value == null) {
throw new NullPointerException("Null values are not allowed");
}
// for performance reasons, only purge every
// MAX_CHANGES_BEFORE_PURGE times
if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) {
purge();
changeCount = 0;
}
// do a partial purge more often
else if (changeCount % PARTIAL_PURGE_COUNT == 0) {
purgeOne();
}
Referenced keyRef = new Referenced(key, queue);
return super.put(keyRef, value);
}
/**
*@see Hashtable
*/
public void putAll(Map t) {
if (t != null) {
Set entrySet = t.entrySet();
for (Iterator it=entrySet.iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
put(entry.getKey(), entry.getValue());
}
}
}
/**
*@see Hashtable
*/
public Collection values() {
purge();
return super.values();
}
/**
*@see Hashtable
*/
public synchronized Object remove(Object key) {
// for performance reasons, only purge every
// MAX_CHANGES_BEFORE_PURGE times
if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) {
purge();
changeCount = 0;
}
// do a partial purge more often
else if (changeCount % PARTIAL_PURGE_COUNT == 0) {
purgeOne();
}
return super.remove(new Referenced(key));
}
/**
*@see Hashtable
*/
public boolean isEmpty() {
purge();
return super.isEmpty();
}
/**
*@see Hashtable
*/
public int size() {
purge();
return super.size();
}
/**
*@see Hashtable
*/
public String toString() {
purge();
return super.toString();
}
/**
* @see Hashtable
*/
protected void rehash() {
// purge here to save the effort of rehashing dead entries
purge();
super.rehash();
}
/**
* Purges all entries whose wrapped keys
* have been garbage collected.
*/
private void purge() {
final List toRemove = new ArrayList();
synchronized (queue) {
WeakKey key;
while ((key = (WeakKey) queue.poll()) != null) {
toRemove.add(key.getReferenced());
}
}
// LOGGING-119: do the actual removal of the keys outside the sync block
// to prevent deadlock scenarios as purge() may be called from
// non-synchronized methods too
final int size = toRemove.size();
for (int i = 0; i < size; i++) {
super.remove(toRemove.get(i));
}
}
/**
* Purges one entry whose wrapped key
* has been garbage collected.
*/
private void purgeOne() {
synchronized (queue) {
WeakKey key = (WeakKey) queue.poll();
if (key != null) {
super.remove(key.getReferenced());
}
}
}
/** Entry implementation */
private final static class Entry implements Map.Entry {
private final Object key;
private final Object value;
private Entry(Object key, Object value) {
this.key = key;
this.value = value;
}
public boolean equals(Object o) {
boolean result = false;
if (o != null && o instanceof Map.Entry) {
Map.Entry entry = (Map.Entry) o;
result = (getKey()==null ?
entry.getKey() == null :
getKey().equals(entry.getKey())) &&
(getValue()==null ?
entry.getValue() == null :
getValue().equals(entry.getValue()));
}
return result;
}
public int hashCode() {
return (getKey()==null ? 0 : getKey().hashCode()) ^
(getValue()==null ? 0 : getValue().hashCode());
}
public Object setValue(Object value) {
throw new UnsupportedOperationException("Entry.setValue is not supported.");
}
public Object getValue() {
return value;
}
public Object getKey() {
return key;
}
}
/** Wrapper giving correct symantics for equals and hashcode */
private final static class Referenced {
private final WeakReference reference;
private final int hashCode;
/**
*
* @throws NullPointerException if referant is <code>null</code>
*/
private Referenced(Object referant) {
reference = new WeakReference(referant);
// Calc a permanent hashCode so calls to Hashtable.remove()
// work if the WeakReference has been cleared
hashCode = referant.hashCode();
}
/**
*
* @throws NullPointerException if key is <code>null</code>
*/
private Referenced(Object key, ReferenceQueue queue) {
reference = new WeakKey(key, queue, this);
// Calc a permanent hashCode so calls to Hashtable.remove()
// work if the WeakReference has been cleared
hashCode = key.hashCode();
}
public int hashCode() {
return hashCode;
}
private Object getValue() {
return reference.get();
}
public boolean equals(Object o) {
boolean result = false;
if (o instanceof Referenced) {
Referenced otherKey = (Referenced) o;
Object thisKeyValue = getValue();
Object otherKeyValue = otherKey.getValue();
if (thisKeyValue == null) {
result = otherKeyValue == null;
// Since our hashcode was calculated from the original
// non-null referant, the above check breaks the
// hashcode/equals contract, as two cleared Referenced
// objects could test equal but have different hashcodes.
// We can reduce (not eliminate) the chance of this
// happening by comparing hashcodes.
result = result && this.hashCode() == otherKey.hashCode();
// In any case, as our c'tor does not allow null referants
// and Hashtable does not do equality checks between
// existing keys, normal hashtable operations should never
// result in an equals comparison between null referants
}
else
{
result = thisKeyValue.equals(otherKeyValue);
}
}
return result;
}
}
/**
* WeakReference subclass that holds a hard reference to an
* associated <code>value</code> and also makes accessible
* the Referenced object holding it.
*/
private final static class WeakKey extends WeakReference {
private final Referenced referenced;
private WeakKey(Object key,
ReferenceQueue queue,
Referenced referenced) {
super(key, queue);
this.referenced = referenced;
}
private Referenced getReferenced() {
return referenced;
}
}
}

View File

@ -0,0 +1,22 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<body>
<p>Concrete implementations of commons-logging wrapper APIs.</p>
</body>

View File

@ -0,0 +1,255 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<body>
<p>Simple wrapper API around multiple logging APIs.</p>
<h3>Overview</h3>
<p>This package provides an API for logging in server-based applications that
can be used around a variety of different logging implementations, including
prebuilt support for the following:</p>
<ul>
<li><a href="http://logging.apache.org/log4j/">Log4J</a> (version 1.2 or later)
from Apache's Logging project. Each named <a href="Log.html">Log</a>
instance is connected to a corresponding Log4J Logger.</li>
<li><a href="http://java.sun.com/j2se/1.4/docs/guide/util/logging/index.html">
JDK Logging API</a>, included in JDK 1.4 or later systems. Each named
<a href="Log.html">Log</a> instance is connected to a corresponding
<code>java.util.logging.Logger</code> instance.</li>
<li><a href="http://avalon.apache.org/logkit/">LogKit</a> from Apache's
Avalon project. Each named <a href="Log.html">Log</a> instance is
connected to a corresponding LogKit <code>Logger</code>.</li>
<li><a href="impl/NoOpLog.html">NoOpLog</a> implementation that simply swallows
all log output, for all named <a href="Log.html">Log</a> instances.</li>
<li><a href="impl/SimpleLog.html">SimpleLog</a> implementation that writes all
log output, for all named <a href="Log.html">Log</a> instances, to
System.err.</li>
</ul>
<h3>Quick Start Guide</h3>
<p>For those impatient to just get on with it, the following example
illustrates the typical declaration and use of a logger that is named (by
convention) after the calling class:
<pre>
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Foo {
private Log log = LogFactory.getLog(Foo.class);
public void foo() {
...
try {
if (log.isDebugEnabled()) {
log.debug("About to do something to object " + name);
}
name.bar();
} catch (IllegalStateException e) {
log.error("Something bad happened to " + name, e);
}
...
}
</pre>
<p>Unless you configure things differently, all log output will be written
to System.err. Therefore, you really will want to review the remainder of
this page in order to understand how to configure logging for your
application.</p>
<h3>Configuring the Commons Logging Package</h3>
<h4>Choosing a <code>LogFactory</code> Implementation</h4>
<p>From an application perspective, the first requirement is to retrieve an
object reference to the <code>LogFactory</code> instance that will be used
to create <code><a href="Log.html">Log</a></code> instances for this
application. This is normally accomplished by calling the static
<code>getFactory()</code> method. This method implements the following
discovery algorithm to select the name of the <code>LogFactory</code>
implementation class this application wants to use:</p>
<ul>
<li>Check for a system property named
<code>org.apache.commons.logging.LogFactory</code>.</li>
<li>Use the JDK 1.3 JAR Services Discovery mechanism (see
<a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html">
http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html</a> for
more information) to look for a resource named
<code>META-INF/services/org.apache.commons.logging.LogFactory</code>
whose first line is assumed to contain the desired class name.</li>
<li>Look for a properties file named <code>commons-logging.properties</code>
visible in the application class path, with a property named
<code>org.apache.commons.logging.LogFactory</code> defining the
desired implementation class name.</li>
<li>Fall back to a default implementation, which is described
further below.</li>
</ul>
<p>If a <code>commons-logging.properties</code> file is found, all of the
properties defined there are also used to set configuration attributes on
the instantiated <code>LogFactory</code> instance.</p>
<p>Once an implementation class name is selected, the corresponding class is
loaded from the current Thread context class loader (if there is one), or
from the class loader that loaded the <code>LogFactory</code> class itself
otherwise. This allows a copy of <code>commons-logging.jar</code> to be
shared in a multiple class loader environment (such as a servlet container),
but still allow each web application to provide its own <code>LogFactory</code>
implementation, if it so desires. An instance of this class will then be
created, and cached per class loader.
<h4>The Default <code>LogFactory</code> Implementation</h4>
<p>The Logging Package APIs include a default <code>LogFactory</code>
implementation class (<a href="impl/LogFactoryImpl.html">
org.apache.commons.logging.impl.LogFactoryImpl</a>) that is selected if no
other implementation class name can be discovered. Its primary purpose is
to create (as necessary) and return <a href="Log.html">Log</a> instances
in response to calls to the <code>getInstance()</code> method. The default
implementation uses the following rules:</p>
<ul>
<li>At most one <code>Log</code> instance of the same name will be created.
Subsequent <code>getInstance()</code> calls to the same
<code>LogFactory</code> instance, with the same name or <code>Class</code>
parameter, will return the same <code>Log</code> instance.</li>
<li>When a new <code>Log</code> instance must be created, the default
<code>LogFactory</code> implementation uses the following discovery
process:
<ul>
<li>Look for a configuration attribute of this factory named
<code>org.apache.commons.logging.Log</code> (for backwards
compatibility to pre-1.0 versions of this API, an attribute
<code>org.apache.commons.logging.log</code> is also consulted).</li>
<li>Look for a system property named
<code>org.apache.commons.logging.Log</code> (for backwards
compatibility to pre-1.0 versions of this API, a system property
<code>org.apache.commons.logging.log</code> is also consulted).</li>
<li>If the Log4J logging system is available in the application
class path, use the corresponding wrapper class
(<a href="impl/Log4JLogger.html">Log4JLogger</a>).</li>
<li>If the application is executing on a JDK 1.4 system, use
the corresponding wrapper class
(<a href="impl/Jdk14Logger.html">Jdk14Logger</a>).</li>
<li>Fall back to the default simple logging implementation
(<a href="impl/SimpleLog.html">SimpleLog</a>).</li>
</ul></li>
<li>Load the class of the specified name from the thread context class
loader (if any), or from the class loader that loaded the
<code>LogFactory</code> class otherwise.</li>
<li>Instantiate an instance of the selected <code>Log</code>
implementation class, passing the specified name as the single
argument to its constructor.</li>
</ul>
<p>See the <a href="impl/SimpleLog.html">SimpleLog</a> JavaDocs for detailed
configuration information for this default implementation.</p>
<h4>Configuring the Underlying Logging System</h4>
<p>The basic principle is that the user is totally responsible for the
configuration of the underlying logging system.
Commons-logging should not change the existing configuration.</p>
<p>Each individual <a href="Log.html">Log</a> implementation may
support its own configuration properties. These will be documented in the
class descriptions for the corresponding implementation class.</p>
<p>Finally, some <code>Log</code> implementations (such as the one for Log4J)
require an external configuration file for the entire logging environment.
This file should be prepared in a manner that is specific to the actual logging
technology being used.</p>
<h3>Using the Logging Package APIs</h3>
<p>Use of the Logging Package APIs, from the perspective of an application
component, consists of the following steps:</p>
<ol>
<li>Acquire a reference to an instance of
<a href="Log.html">org.apache.commons.logging.Log</a>, by calling the
factory method
<a href="LogFactory.html#getInstance(java.lang.String)">
LogFactory.getInstance(String name)</a>. Your application can contain
references to multiple loggers that are used for different
purposes. A typical scenario for a server application is to have each
major component of the server use its own Log instance.</li>
<li>Cause messages to be logged (if the corresponding detail level is enabled)
by calling appropriate methods (<code>trace()</code>, <code>debug()</code>,
<code>info()</code>, <code>warn()</code>, <code>error</code>, and
<code>fatal()</code>).</li>
</ol>
<p>For convenience, <code>LogFactory</code> also offers a static method
<code>getLog()</code> that combines the typical two-step pattern:</p>
<pre>
Log log = LogFactory.getFactory().getInstance(Foo.class);
</pre>
<p>into a single method call:</p>
<pre>
Log log = LogFactory.getLog(Foo.class);
</pre>
<p>For example, you might use the following technique to initialize and
use a <a href="Log.html">Log</a> instance in an application component:</p>
<pre>
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MyComponent {
protected Log log =
LogFactory.getLog(MyComponent.class);
// Called once at startup time
public void start() {
...
log.info("MyComponent started");
...
}
// Called once at shutdown time
public void stop() {
...
log.info("MyComponent stopped");
...
}
// Called repeatedly to process a particular argument value
// which you want logged if debugging is enabled
public void process(String value) {
...
// Do the string concatenation only if logging is enabled
if (log.isDebugEnabled())
log.debug("MyComponent processing " + value);
...
}
}
</pre>
</body>

View File

@ -0,0 +1,35 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<title>Overview Documentation for COMMONS-LOGGING</title>
</head>
<body bgcolor="white">
<p>The <em>Logging Wrapper Library</em> component of the Apache Commons
subproject offers wrappers around an extensible set of concrete logging
implementations, so that application code based on it does not need to be
modified in order to select a different logging implementation.</p>
<p>See the
<a href="org/apache/commons/logging/package-summary.html#package_description">
Package Description</a> for the <code>org.apache.commons.logging</code>
package for more information.</p>
</body>
</html>

BIN
src/media/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/media/logo.xcf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

64
src/site/site.xml Normal file
View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/DECORATION/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/DECORATION/1.1.0 http://maven.apache.org/xsd/decoration-1.1.0.xsd">
<bannerRight>
<name>Commons Logging</name>
<src>/images/logo.png</src>
<href>http://commons.apache.org/logging/</href>
</bannerRight>
<body>
<menu name="Commons Logging">
<item name="Overview"
href="/index.html"/>
<item name="Download"
href="/download_logging.cgi"/>
<item name="User Guide"
href="/guide.html"/>
<item name="Troubleshooting Guide"
href="/troubleshooting.html"/>
<item name="Release Notes"
href="/RELEASE-NOTES.txt"/>
<item name='JavaDoc (Latest release)'
href='/javadocs/api-release/index.html'/>
<item name='JavaDoc (v1.1.3)'
href='/javadocs/api-1.1.3/index.html'/>
<item name='JavaDoc (v1.0.4)'
href='/javadocs/api-1.0.4/index.html'/>
</menu>
<menu name="Development">
<item name="Building"
href="/building.html"/>
<item name="Mailing Lists"
href="/mail-lists.html"/>
<item name="Issue Tracking"
href="/issue-tracking.html"/>
<item name="Proposal"
href="/proposal.html"/>
<item name="Tech Guide"
href="/tech.html"/>
<item name="Wiki"
href="http://wiki.apache.org/commons/Logging"/>
<item name='JavaDoc (SVN latest)'
href='/apidocs/index.html'/>
</menu>
</body>
</project>

View File

@ -0,0 +1,74 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>Building</title>
<author email="dev@commons.apache.org">Commons Documentation Team</author>
</properties>
<body>
<!-- ================================================== -->
<section name="Overview">
<p>
Commons Logging uses <a href="http://maven.apache.org">Maven 2.0.x</a> as its
primary build system. <a href="http://ant.apache.org">Ant</a> can also be used.
</p>
</section>
<!-- ================================================== -->
<section name="Maven">
<p>
To build the full website, run
</p>
<source>mvn site</source>
<p>
The result will be in the <code>target/site</code> folder.
You must be online and using JDK 1.4 or higher to successfully complete this target.
</p>
<p>
To build the jar files, run
</p>
<source>mvn package</source>
<p>
The resulting 4 jar files will be in the <code>target</code> folder.
You must use JDK 1.4 or higher to successfully complete this target.
</p>
<p>
To create a full distribution, run
</p>
<source>mvn clean site assembly:assembly</source>
<p>
The resulting .zip and .tar.gz files will be in the <code>target</code> folder.
You must use JDK 1.4 or higher to successfully complete this target.
</p>
<p>
Further details can be found in the
<a href="http://commons.apache.org/building.html">commons build instructions</a>.
</p>
</section>
<!-- ================================================== -->
<section name="Ant">
<p>
We still use Ant to test the artifacts built my Maven.
Please follow the instructions in the file <code>build-testing.xml</code>.
</p>
<p>
<b>Note:</b> A 1.2 JDK is needed to run the tests.
</p>
</section>
<!-- ================================================== -->
</body>
</document>

View File

@ -0,0 +1,138 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
+======================================================================+
|**** ****|
|**** THIS FILE IS GENERATED BY THE COMMONS BUILD PLUGIN ****|
|**** DO NOT EDIT DIRECTLY ****|
|**** ****|
+======================================================================+
| TEMPLATE FILE: download-page-template.xml |
| commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
+======================================================================+
| |
| 1) Re-generate using: mvn commons:download-page |
| |
| 2) Set the following properties in the component's pom: |
| - commons.componentid (required, alphabetic, lower case) |
| - commons.release.version (required) |
| - commons.binary.suffix (optional) |
| (defaults to "-bin", set to "" for pre-maven2 releases) |
| |
| 3) Example Properties |
| |
| <properties> |
| <commons.componentid>math</commons.componentid> |
| <commons.release.version>1.2</commons.release.version> |
| </properties> |
| |
+======================================================================+
-->
<document>
<properties>
<title>Download Apache Commons Logging</title>
<author email="dev@commons.apache.org">Commons Documentation Team</author>
</properties>
<body>
<section name="Download Apache Commons Logging">
<subsection name="Using a Mirror">
<p>
We recommend you use a mirror to download our release
builds, but you <strong>must</strong> verify the integrity of
the downloaded files using signatures downloaded from our main
distribution directories. Recent releases (48 hours) may not yet
be available from the mirrors.
</p>
<p>
You are currently using <b>[preferred]</b>. If you
encounter a problem with this mirror, please select another
mirror. If all mirrors are failing, there are <i>backup</i>
mirrors (at the end of the mirrors list) that should be
available.
<br></br>
[if-any logo]<a href="[link]"><img align="right" src="[logo]" border="0"></img></a>[end]
</p>
<form action="[location]" method="get" id="SelectMirror">
<p>
Other mirrors:
<select name="Preferred">
[if-any http]
[for http]<option value="[http]">[http]</option>[end]
[end]
[if-any ftp]
[for ftp]<option value="[ftp]">[ftp]</option>[end]
[end]
[if-any backup]
[for backup]<option value="[backup]">[backup] (backup)</option>[end]
[end]
</select>
<input type="submit" value="Change"></input>
</p>
</form>
<p>
The <a href="http://www.apache.org/dist/commons/KEYS">KEYS</a>
link links to the code signing keys used to sign the product.
The <code>PGP</code> link downloads the OpenPGP compatible signature from our main site.
The <code>MD5</code> link downloads the checksum from the main site.
</p>
</subsection>
</section>
<section name="Apache Commons Logging 1.2 ">
<subsection name="Binaries">
<table>
<tr>
<td><a href="[preferred]/commons/logging/binaries/commons-logging-1.2-bin.tar.gz">commons-logging-1.2-bin.tar.gz</a></td>
<td><a href="http://www.apache.org/dist/commons/logging/binaries/commons-logging-1.2-bin.tar.gz.md5">md5</a></td>
<td><a href="http://www.apache.org/dist/commons/logging/binaries/commons-logging-1.2-bin.tar.gz.asc">pgp</a></td>
</tr>
<tr>
<td><a href="[preferred]/commons/logging/binaries/commons-logging-1.2-bin.zip">commons-logging-1.2-bin.zip</a></td>
<td><a href="http://www.apache.org/dist/commons/logging/binaries/commons-logging-1.2-bin.zip.md5">md5</a></td>
<td><a href="http://www.apache.org/dist/commons/logging/binaries/commons-logging-1.2-bin.zip.asc">pgp</a></td>
</tr>
</table>
</subsection>
<subsection name="Source">
<table>
<tr>
<td><a href="[preferred]/commons/logging/source/commons-logging-1.2-src.tar.gz">commons-logging-1.2-src.tar.gz</a></td>
<td><a href="http://www.apache.org/dist/commons/logging/source/commons-logging-1.2-src.tar.gz.md5">md5</a></td>
<td><a href="http://www.apache.org/dist/commons/logging/source/commons-logging-1.2-src.tar.gz.asc">pgp</a></td>
</tr>
<tr>
<td><a href="[preferred]/commons/logging/source/commons-logging-1.2-src.zip">commons-logging-1.2-src.zip</a></td>
<td><a href="http://www.apache.org/dist/commons/logging/source/commons-logging-1.2-src.zip.md5">md5</a></td>
<td><a href="http://www.apache.org/dist/commons/logging/source/commons-logging-1.2-src.zip.asc">pgp</a></td>
</tr>
</table>
</subsection>
</section>
<section name="Archives">
<p>
Older releases can be obtained from the archives.
</p>
<ul>
<li class="download"><a href="[preferred]/commons/logging/">browse download area</a></li>
<li><a href="http://archive.apache.org/dist/commons/logging/">archives...</a></li>
</ul>
</section>
</body>
</document>

850
src/site/xdoc/guide.xml Normal file
View File

@ -0,0 +1,850 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>User Guide</title>
<author email="dev@commons.apache.org">Commons Documentation Team</author>
</properties>
<body>
<section name='Contents'>
<p>
<ol>
<li><a href='#Introduction'>Introduction</a></li>
<li><a href='#Quick Start'>Quick Start</a>
<ol>
<li><a href='#Configuration'>Configuration</a></li>
<li>
<a href='#Configuring The Underlying Logging System'>Configuring The Underlying Logging System</a>
</li>
<li>
<a href='#Configuring Log4J'>Configuring Log4J</a>
</li>
</ol>
</li>
<li><a href='#Developing With JCL'>Developing With JCL</a>
<ol>
<li><a href='#Obtaining a Log Object'>Obtaining a Log Object</a></li>
<li><a href='#Logging a Message'>Logging a Message</a></li>
<li><a href='#Serialization Issues'>Serialization Issues</a></li>
</ol>
</li>
<li><a href='#Jars Included in the Standard Distribution'>Jars Included in the Standard Distribution</a>
<ol>
<li><a href='#commons-logging.jar'>commons-logging.jar</a></li>
<li><a href='#commons-logging-api.jar'>commons-logging-api.jar</a></li>
<li><a href='#commons-logging-adapters.jar'>commons-logging-adapters.jar</a></li>
</ol>
</li>
<li><a href='#JCL Best Practices'>JCL Best Practices</a></li>
<li><a href='#Best Practices (General)'>Best Practices (General)</a>
<ol>
<li><a href='#Code Guards'>Code Guards</a></li>
<li><a href='#Message Priorities/Levels'>Message Priorities/Levels</a></li>
<li><a href='#Default Message Priority/Level'>Default Message Priority/Level</a></li>
</ol>
</li>
<li><a href='#Best Practices (Enterprise)'>Best Practices (Enterprise)</a>
<ol>
<li><a href='#Logging Exceptions'>Logging Exceptions</a></li>
<li><a href='#When Info Level Instead of Debug?'>When Info Level Instead of Debug?</a></li>
<li><a href='#More Control of Enterprise Exception Logging'>More Control of Enterprise Exception Logging</a></li>
<li><a href='#National Language Support And Internationalization'>National Language Support And Internationalization</a></li>
<li><a href='#Classloader and Memory Management'>Classloader and Memory Management</a></li>
</ol>
</li>
<li><a href='#Extending Commons Logging'>Extending Commons Logging</a>
<ol>
<li><a href='#Contract'>Contract</a></li>
<li><a href='#Creating a Log Implementation'>Creating a Log Implementation</a></li>
<li><a href='#Creating A LogFactory Implementation'>Creating A LogFactory Implementation</a></li>
</ol>
</li>
<li><a href='#A%20Quick%20Guide%20To%20Simple%20Log'>A Quick Guide To Simple Log</a>
</li>
<li><a href='#Frequently Asked Questions'>Frequently Asked Questions</a>
</li>
</ol>
</p>
</section>
<section name="Introduction">
<p>
The Apache Commons Logging (JCL) provides a <code>Log</code> interface that
is intended to be both light-weight and an independent abstraction of other logging toolkits.
It provides the middleware/tooling developer with a simple
logging abstraction, that allows the user (application developer) to plug in
a specific logging implementation.
</p>
<p>JCL provides thin-wrapper <code>Log</code> implementations for
other logging tools, including
<a href="http://logging.apache.org/log4j/docs/index.html">Log4J</a>,
<a href="http://avalon.apache.org/logkit/index.html">Avalon LogKit</a>
(the Avalon Framework's logging infrastructure),
JDK 1.4, and an implementation of JDK 1.4 logging APIs (JSR-47) for pre-1.4
systems.
The interface maps closely to Log4J and LogKit.
</p>
<p>
Familiarity with high-level details of the relevant Logging implementations is presumed.
</p>
</section>
<section name="Quick Start">
<p>
As far as possible, JCL tries to be as unobtrusive as possible.
In most cases, including the (full) <code>commons-logging.jar</code> in the classpath
should result in JCL configuring itself in a reasonable manner.
There's a good chance that it'll guess (discover) your preferred logging system and you won't
need to do any configuration of JCL at all!
</p><p>
Note, however, that if you have a particular preference then providing a simple
<code>commons-logging.properties</code> file which specifies the concrete logging library to be
used is recommended, since (in this case) JCL will log only to that system
and will report any configuration problems that prevent that system being used.
</p>
<p>
When no particular logging library is specified then JCL will silently ignore any logging library
that it finds but cannot initialise and continue to look for other alternatives. This is a deliberate
design decision; no application should fail to run because a "guessed" logging library cannot be
used. To ensure an exception is reported when a particular logging library cannot be used, use one
of the available JCL configuration mechanisms to force that library to be selected (ie disable
JCL's discovery process).
</p>
<subsection name='Configuration'>
<p>
There are two base abstractions used by JCL: <code>Log</code>
(the basic logger) and <code>LogFactory</code> (which knows how to create <code>Log</code>
instances). Specifying a particular Log implementation is very useful (whether that is
one provided by commons-logging or a user-defined one). Specifying a
<code>LogFactory</code> implementation other than the default is a subject for
advanced users only, so will not be addressed here.
</p>
<p>
The default <code>LogFactory</code> implementation uses the following discovery process
to determine what type of <code>Log</code> implementation it should use
(the process terminates when the first positive match - in order - is found):
</p>
<ol>
<li>
Look for a configuration attribute of this factory named
<code>org.apache.commons.logging.Log</code> (for backwards compatibility to
pre-1.0 versions of this API, an attribute
<code>org.apache.commons.logging.log</code> is also consulted).
<p>
Configuration attributes can be set explicitly by java code, but they are more
commonly set by placing a file named commons-logging.properties in the classpath.
When such a file exists, every entry in the properties file becomes an "attribute"
of the LogFactory. When there is more than one such file in the classpath, releases
of commons-logging prior to 1.1 simply use the first one found. From release 1.1,
each file may define a <code>priority</code> key, and the file with
the highest priority is used (no priority definition implies priority of zero).
When multiple files have the same priority, the first one found is used.
</p>
<p>
Defining this property in a commons-logging.properties file is the recommended
way of explicitly selecting a Log implementation.
</p>
</li>
<li>
Look for a system property named
<code>org.apache.commons.logging.Log</code> (for backwards
compatibility to pre-1.0 versions of this API, a system property
<code>org.apache.commons.logging.log</code> is also consulted).
</li>
<li>
If the Log4J logging system is available in the application
class path, use the corresponding wrapper class
(<a href="http://commons.apache.org/logging/apidocs/org/apache/commons/logging/impl/Log4JLogger.html">Log4JLogger</a>).
</li>
<li>
If the application is executing on a JDK 1.4 system, use
the corresponding wrapper class
(<a href="http://commons.apache.org/logging/apidocs/org/apache/commons/logging/impl/Jdk14Logger.html">Jdk14Logger</a>).
</li>
<li>
Fall back to the default simple logging wrapper
(<a href="http://commons.apache.org/logging/apidocs/org/apache/commons/logging/impl/SimpleLog.html">SimpleLog</a>).
</li>
</ol>
<p>
Consult the JCL javadocs for details of the various <code>Log</code>
implementations that ship with the component. (The discovery process is also covered in more
detail there.)
</p>
</subsection>
<subsection name='Configuring The Underlying Logging System'>
<p>
The JCL SPI
can be configured to use different logging toolkits (see <a href='#Configuration'>above</a>).
JCL provides only a bridge for writing log messages. It does not (and will not) support any
sort of configuration API for the underlying logging system.
</p>
<p>
Configuration of the behavior of the JCL ultimately depends upon the
logging toolkit being used. Please consult the documentation for the chosen logging system.
</p>
<p>
JCL is NOT responsible for initialisation, configuration or shutdown of the underlying logging library.
In many cases logging libraries will automatically initialise/configure themselves when first used, and
need no explicit shutdown process. In these situations an application can simply use JCL and not depend
directly on the API of the underlying logging system in any way. However if the logging library being used
requires special initialisation, configuration or shutdown then some logging-library-specific code will
be required in the application. JCL simply forwards logging method calls to the correct underlying
implementation. When writing library code this issue is of course not relevant as the calling application
is responsible for handling such issues.
</p>
<subsection name='Configuring Log4J'>
<p>
Log4J is a very commonly used logging implementation (as well as being the JCL primary default),
so a <i>few</i> details are presented herein to get the developer/integrator going.
Please see the <a href='http://logging.apache.org/log4j/docs/index.html'>Log4J Home</a> for more details
on Log4J and it's configuration.
</p>
<p>
Configure Log4J using system properties and/or a properties file:
</p>
<ul>
<li>
<strong>log4j.configuration=<em>log4j.properties</em></strong>
Use this system property to specify the name of a Log4J configuration file.
If not specified, the default configuration file is <i>log4j.properties</i>.
</li>
<li>
<strong>log4j.rootCategory=<i>priority</i> [, <i>appender</i>]*</strong>
</li>
Set the default (root) logger priority.
<li>
<strong>log4j.logger.<i>logger.name</i>=<i>priority</i></strong>
Set the priority for the named logger
and all loggers hierarchically lower than, or below, the
named logger.
<i>logger.name</i> corresponds to the parameter of
<code>LogFactory.getLog(<i>logger.name</i>)</code>,
used to create the logger instance. Priorities are:
<code>DEBUG</code>,
<code>INFO</code>,
<code>WARN</code>,
<code>ERROR</code>,
or <code>FATAL</code>.
<br/>
Log4J understands hierarchical names,
enabling control by package or high-level qualifiers:
<code>log4j.logger.org.apache.component=DEBUG</code>
will enable debug messages for all classes in both
<code>org.apache.component</code>
and
<code>org.apache.component.sub</code>.
Likewise, setting
<code>log4j.logger.org.apache.component=DEBUG</code>
will enable debug message for all 'component' classes,
but not for other Apache projects.
</li>
<li>
<strong>log4j.appender.<i>appender</i>.Threshold=<i>priority</i></strong>
</li>
Log4J <i>appenders</i> correspond to different output devices:
console, files, sockets, and others.
If appender's <i>threshold</i>
is less than or equal to the message priority then
the message is written by that appender.
This allows different levels of detail to be appear
at different log destinations.
For example: one can capture DEBUG (and higher) level information in a logfile,
while limiting console output to INFO (and higher).
</ul>
</subsection>
</subsection>
</section>
<section name='Developing With JCL'>
<subsection name="Obtaining a Log Object">
<p>
To use the JCL SPI from a Java class,
include the following import statements:
</p>
<ul>
<code>
import org.apache.commons.logging.Log;
<br/>
import org.apache.commons.logging.LogFactory;
<br/>
</code>
</ul>
<p>
Note that some components using JCL may
either extend Log,
or provide a component-specific LogFactory implementation.
Review the component documentation for guidelines
on how commons-logging should be used in such components.
</p>
<p>
For each class definition, declare and initialize a
<code>log</code> attribute as follows:
</p>
<ul>
<source>
public class CLASS
{
private Log log = LogFactory.getLog(CLASS.class);
...
;
</source>
</ul>
<p>
Note that for application code, declaring the log member as "static" is more
efficient as one Log object is created per class, and is recommended.
However this is not safe to do for a class which may be deployed via a "shared"
classloader in a servlet or j2ee container or similar environment. If the class
may end up invoked with different thread-context-classloader values set then the
member must <i>not</i> be declared static. The use of "static" should therefore
be avoided in code within any "library" type project.
</p>
</subsection>
<subsection name="Logging a Message">
<p>
Messages are logged to a <em>logger</em>, such as <code>log</code>
by invoking a method corresponding to <em>priority</em>.
The <code>org.apache.commons.logging.Log</code> interface defines the
following methods for use
in writing log/trace messages to the log:
</p>
<ul>
<source>
log.fatal(Object message);
log.fatal(Object message, Throwable t);
log.error(Object message);
log.error(Object message, Throwable t);
log.warn(Object message);
log.warn(Object message, Throwable t);
log.info(Object message);
log.info(Object message, Throwable t);
log.debug(Object message);
log.debug(Object message, Throwable t);
log.trace(Object message);
log.trace(Object message, Throwable t);
</source>
</ul>
<p>
Semantics for these methods are such that it is expected
that the severity, from highest to lowest, of messages is ordered as above.
</p>
<p>
In addition to the logging methods, the following are provided for code guards:
</p>
<ul>
<source>
log.isFatalEnabled();
log.isErrorEnabled();
log.isWarnEnabled();
log.isInfoEnabled();
log.isDebugEnabled();
log.isTraceEnabled();
</source>
</ul>
</subsection>
<subsection name="Serialization Issues">
<p>Prior to release 1.0.4, none of the standard Log implementations were
Serializable. If you are using such a release and have a Serializable class
with a member that is of type Log then it is necessary to declare
that member to be transient and to ensure that the value is restored on
deserialization. The recommended approach is to define a custom
readObject method on the class which reinitializes that member.</p>
<p>In release 1.0.4, all standard Log implementations are Serializable. This
means that class members of type Log do <i>not</i> need to be declared transient;
on deserialization the Log object will "rebind" to the same category for the
same logging library. Note that the same underlying logging library will be
used on deserialization as was used in the original object, even if the
application the object was deserialized into is using a different logging
library. There is one exception; LogKitLogger (adapter for the Avalon LogKit
library) is not Serializable for technical reasons.</p>
<p>Custom Log implementations not distributed with commons-logging may
or may not be Serializable. If you wish your code to be compatible with
any arbitrary log adapter then you should follow the advice given above
for pre-1.0.4 releases.</p>
</subsection>
</section>
<section name="Jars Included in the Standard Distribution">
<subsection name="commons-logging.jar">
<p>
The <code>commons-logging.jar</code> file includes the JCL API, the default
<code>LogFactory</code> implementation and thin-wrapper <code>Log</code>
implementations for
<a href="http://logging.apache.org/log4j/docs/index.html">Log4J</a>,
<a href="http://avalon.apache.org/logkit/index.html">Avalon LogKit</a>,
the Avalon Framework's logging infrastructure,
JDK 1.4, as well as an implementation of JDK 1.4 logging APIs (JSR-47) for
pre-1.4 systems.
</p>
<p>
In most cases, including <code>commons-logging.jar</code> and your preferred
logging implementation in the classpath should be all that is required to
use JCL.
</p>
</subsection>
<subsection name="commons-logging-api.jar">
<p>
The <code>commons-logging-api.jar</code> file includes the JCL API and the
default <code>LogFactory</code> implementation as well as the built-in
<code>Log</code> implementations SimpleLog and NoOpLog. However it does not
include the wrapper <code>Log</code> implementations that require additional
libraries such as <code>Log4j</code>, <code>Avalon</code> and
<code>Lumberjack</code>.
</p>
<p>
This jar is intended for use by projects that recompile the commons-logging
source using alternate java environments, and cannot compile against all of
the optional libraries that the Apache release of commons-logging supports.
Because of the reduced dependencies of this jarfile, such projects should be
able to create an equivalent of this library with fewer difficulties.
</p>
<p>
This jar is also useful for build environments that automatically track
dependencies, and thus have difficulty with the concept that the main
commons-logging.jar has "optional" dependencies on various logging
implementations that can safely go unsatisfied at runtime.
</p>
</subsection>
<subsection name="commons-logging-adapters.jar">
<p>
The <code>commons-logging-adapters.jar</code> file includes only adapters
to third-party logging implementations, and none of the core commons-logging
framework. As such, it cannot be used alone; either commons-logging.jar or
commons-logging-api.jar must also be present in the classpath.
</p>
<p>
This library will not often be used; it is only intended for situations where
a container has deployed commons-logging-api.jar in a shared classpath but a
webapp wants to bind logging to one of the external logging implementations
that the api jar does not include. In this situation, deploying the
commons-logging.jar file within the webapp can cause problems as this leads to
duplicates of the core commons-logging classes (Log, LogFactory, etc) in
the classpath which in turn can cause unpleasant ClassCastException exceptions
to occur. Deploying only the adapters avoids this problem.
</p>
</subsection>
</section>
<section name='JCL Best Practices'>
<p>
Best practices for JCL are presented in two categories:
General and Enterprise.
The general principles are fairly clear.Enterprise practices are a bit more involved
and it is not always as clear as to why they are important.
</p>
<p>
Enterprise best-practice principles apply to middleware components
and tooling that is expected to execute in an "Enterprise" level
environment.
These issues relate to Logging as Internationalization,
and fault detection.
Enterprise requires more effort and planning, but are strongly encouraged (if not required)
in production level systems. Different corporate enterprises/environments have different
requirements, so being flexible always helps.
</p>
</section>
<section name='Best Practices (General)'>
<subsection name='Code Guards'>
<p>
Code guards are typically used to guard code that
only needs to execute in support of logging,
that otherwise introduces undesirable runtime overhead
in the general case (logging disabled).
Examples are multiple parameters, or expressions (e.g. string + " more") for parameters.
Use the guard methods of the form <code>log.is&lt;<i>Priority</i>&gt;()</code> to verify
that logging should be performed, before incurring the overhead of the logging method call.
Yes, the logging methods will perform the same check, but only after resolving parameters.
</p>
</subsection>
<subsection name='Message Priorities/Levels'>
<p>
It is important to ensure that log message are
appropriate in content and severity.
The following guidelines are suggested:
</p>
<ul>
<li>
<b>fatal</b> - Severe errors that cause premature termination.
Expect these to be immediately visible on a status console.
See also <a HREF="#National%20Language%20Support%20And%20Internationalization">
Internationalization</a>.
</li>
<li>
<b>error</b> - Other runtime errors or unexpected conditions.
Expect these to be immediately visible on a status console.
See also <a HREF="#National%20Language%20Support%20And%20Internationalization">
Internationalization</a>.
</li>
<li>
<b>warn</b> - Use of deprecated APIs, poor use of API, 'almost' errors,
other runtime situations that are undesirable or unexpected, but not
necessarily "wrong".
Expect these to be immediately visible on a status console.
See also <a HREF="#National%20Language%20Support%20And%20Internationalization">
Internationalization</a>.
</li>
<li>
<b>info</b> - Interesting runtime events (startup/shutdown).
Expect these to be immediately visible on a console,
so be conservative and keep to a minimum.
See also <a HREF="#National%20Language%20Support%20And%20Internationalization">
Internationalization</a>.
</li>
<li>
<b>debug</b> - detailed information on the flow through the system.
Expect these to be written to logs only.
</li>
<li>
<b>trace</b> - more detailed information.
Expect these to be written to logs only.
</li>
</ul>
</subsection>
<subsection name='Default Message Priority/Level'>
<p>
By default the message priority should be no lower than <b>info</b>.
That is, by default <b>debug</b> message should not be seen in the logs.
</p>
</subsection>
</section>
<section name='Best Practices (Enterprise)'>
<subsection name='Logging Exceptions'>
<p>
The general rule in dealing with exceptions is to assume that
the user (developer using a tooling/middleware API) isn't going
to follow the rules.
Since any problems that result are going to be assigned to you,
it's in your best interest to be prepared with the proactive
tools necessary to demonstrate that your component works correctly,
or at worst that the problem can be analyzed from your logs.
For this discussion, we must make a distinction between different types of exceptions
based on what kind of boundaries they cross:
</p>
<ul>
<li>
<b>External Boundaries - Expected Exceptions</b>.
This classification includes exceptions such as <code>FileNotFoundException</code>
that cross API/SPI boundaries, and are exposed to the user of a component/toolkit.
These are listed in the 'throws' clause of a method signature.
<br/>
Appropriate handling of these exceptions depends upon the type
of code you are developing.
API's for utility functions and tools should log these at the <b>debug</b> level,
if they are caught at all by internal code.
<br/>
For higher level frameworks and middleware components,
these exceptions should be caught immediately prior to crossing
the API/SPI interface back to user code-space,
logged with full stack trace at <b>info</b> level,
and rethrown.
The assures that the log contains a record of the root cause for
future analysis <i>in the event that the exception is not caught and resolved
as expected by the user's code</i>.
<br/>
</li>
<li>
<b>External Boundaries - Unexpected Exceptions</b>.
This classification includes exceptions such as <code>NullPointerException</code>
that cross API/SPI boundaries, and are exposed to the user of a component/toolkit.
These are runtime exceptions/error that are NOT
listed in the 'throws' clause of a method signature.
<br/>
Appropriate handling of these exceptions depends upon the type
of code you are developing.
APIs for utility functions and tools should log these at the <b>debug</b> level,
if they are caught at all.
<br/>
For higher level frameworks and middleware components,
these exceptions should be caught immediately prior to crossing
the API/SPI interface back to user code-space,
logged with full stack trace at <b>info</b> level,
and rethrown/wrapped as <code><i>Component</i>InternalError</code>.
This ensures that the log contains a record of the root cause for
future analysis <i>in the event that the exception is not caught and
logged/reported as expected by the user's code</i>.
</li>
<li>
<b>Internal Boundaries</b>.
Exceptions that occur internally and are resolved internally.
These should be logged when caught as <b>debug</b> or <b>info</b> messages,
at the programmer's discretion.
</li>
<li>
<b>Significant Internal Boundaries</b>.
This typically only applies to middleware components that span networks or runtime processes.
Exceptions that cross over significant internal component boundaries such as networks
should be logged when caught as <b>info</b> messages.
Do not assume that such a (process/network) boundary will deliver exceptions to the 'other side'.
</li>
</ul>
</subsection>
<subsection name='When Info Level Instead of Debug?'>
<p>
You want to have exception/problem information available for
first-pass problem determination in a production level
enterprise application without turning on <b>debug</b>
as a default log level. There is simply too much information
in <b>debug</b> to be appropriate for day-to-day operations.
</p>
</subsection>
<subsection name='More Control of Enterprise Exception Logging'>
<p>
If more control is desired for the level of detail of these
'enterprise' exceptions, then consider creating a special
logger just for these exceptions:
</p>
<ul>
<source>
Log log = LogFactory.getLog("org.apache.<i>component</i>.enterprise");
</source>
</ul>
<p>
This allows the 'enterprise' level information to be turned on/off explicitly
by most logger implementations.
</p>
</subsection>
<subsection name='National Language Support And Internationalization'>
<p>
NLS internationalization involves looking up messages from
a message file by a message key, and using that message for logging.
There are various tools in Java, and provided by other components,
for working with NLS messages.
</p>
<p>
NLS enabled components are particularly appreciated
(that's an open-source-correct term for 'required by corporate end-users' :-)
for <strong>tooling</strong> and <strong>middleware</strong> components.
</p>
<p>
NLS internationalization SHOULD be strongly considered for used for
<b>fatal</b>, <b>error</b>, <b>warn</b>, and <b>info</b> messages.
It is generally considered optional for <b>debug</b> and <b>trace</b> messages.
</p>
<p>
Perhaps more direct support for internationalizing log messages
can be introduced in a future or alternate version of the <code>Log</code> interface.
</p>
</subsection>
<subsection name="Classloader and Memory Management">
<p>
The <code>LogFactory</code> discovery process (see
<a href='#Configuration'>Configuration</a> above) is a fairly expensive
operation, so JCL certainly should not perform it each time user code
invokes:
</p>
<source>LogFactory.getLog()</source>
<p>
Instead JCL caches the
<code>LogFactory</code> implementation created as a result of the discovery
process and uses the cached factory to return <code>Log</code> objects.
Since in J2EE and similar multi-classloader environments, the result of the
discovery process can vary depending on the thread context classloader
(e.g. one webapp in a web container may be configured to use Log4j and
another to use JDK 1.4 logging), JCL internally caches the
<code>LogFactory</code> instances in a static hashtable, keyed by classloader.
</p>
<p>
While this approach is efficient, it can lead to memory leaks if container
implementors are not careful to call
</p>
<source>LogFactory.release()</source>
<p>
whenever a classloader that has utilized JCL is undeployed. If
<code>release()</code> is not called, a reference to the undeployed
classloader (and thus to all the classes loaded by it) will be
held in <code>LogFactory</code>'s static hashtable.
</p>
<p>
Beginning with JCL 1.1, <code>LogFactory</code> caches factory implementations in a
"WeakHashtable". This class is similar to <code>java.util.WeakHashMap</code> in
that it holds a <code>WeakReference</code> to each key (but a strong reference
to each value), thus allowing classloaders to be GC'd even if
<code>LogFactory.release()</code> is never invoked.
</p>
<p>
Because <code>WeakHashtable</code> depends on JDK 1.3+ features, it is dynamically
loaded depending on the JVM version; when commons-logging is run on java versions
prior to 1.3 the code defaults to a standard Hashtable instead.
</p>
<p>
If a custom LogFactory implementation is used, however, then a
<code>WeakHashtable</code> alone can be insufficient to allow garbage collection
of a classloader without a call to <code>release</code>. If the abstract class
<code>LogFactory</code> is loaded by a parent classloader and a concrete
subclass implementation of <code>LogFactory</code> is loaded by a child
classloader, the WeakHashtable's key is a weak reference to the TCCL (child
classloader), but the value is a strong reference to the LogFactory instance,
which in turn contains a strong reference to its class and thus loading
classloader - the child classloader. This chain of strong references prevents
the child loader from being garbage collected.
</p>
<p>
If use of a custom <code>LogFactory</code> subclass is desired, ensuring that
the custom subclass is loaded by the same classloader as <code>LogFactory</code>
will prevent problems. In normal deployments, the standard implementations
of <code>LogFactory</code> found in package <code>org.apache.commons.logging.impl</code>
will be loaded by the same classloader that loads <code>LogFactory</code>
itself, so use of the standard <code>LogFactory</code> implementation
should not pose problems. Alternatively, use the provided ServletContextCleaner
to ensure this reference is explicitly released on webapp unload.
</p>
</subsection>
</section>
<section name='Extending Commons Logging'>
<p>
JCL is designed to encourage extensions to be created that add functionality.
Typically, extensions to JCL fall into two categories:
</p>
<ul>
<li>new <code>Log</code> implementations that provide new bridges to logging systems</li>
<li>
new <code>LogFactory</code> implementations that provide alternative discovery strategies
</li>
</ul>
<subsection name='Contract'>
<p>
When creating new implementations for <code>Log</code> and <code>LogFactory</code>,
it is important to understand the implied contract between the factory
and the log implementations:
<ul>
<li><b>Life cycle</b>
<blockquote>
The JCL LogFactory implementation must assume responsibility for
either connecting/disconnecting to a logging toolkit,
or instantiating/initializing/destroying a logging toolkit.
</blockquote>
</li>
<li><b>Exception handling</b>
<blockquote>
The JCL Log interface doesn't specify any exceptions to be handled,
the implementation must catch any exceptions.
</blockquote>
</li>
<li><b>Multiple threads</b>
<blockquote>
The JCL Log and LogFactory implementations must ensure
that any synchronization required by the logging toolkit
is met.
</blockquote>
</li>
</ul>
</p>
</subsection>
<subsection name='Creating a Log Implementation'>
<p>
The minimum requirement to integrate with another logger
is to provide an implementation of the
<code>org.apache.commons.logging.Log</code> interface.
In addition, an implementation of the
<code>org.apache.commons.logging.LogFactory</code> interface
can be provided to meet
specific requirements for connecting to, or instantiating, a logger.
</p>
<p>
The default <code>LogFactory</code> provided by JCL
can be configured to instantiate a specific implementation of the
<code>org.apache.commons.logging.Log</code> interface
by setting the property of the same name (<code>org.apache.commons.logging.Log</code>).
This property can be specified as a system property,
or in the <code>commons-logging.properties</code> file,
which must exist in the CLASSPATH.
</p>
</subsection>
<subsection name='Creating A LogFactory Implementation'>
<p>
If desired, the default implementation of the
<code>org.apache.commons.logging.LogFactory</code>
interface can be overridden,
allowing the JDK 1.3 Service Provider discovery process
to locate and create a LogFactory specific to the needs of the application.
Review the Javadoc for the <code>LogFactoryImpl.java</code>
for details.
</p>
</subsection>
</section>
<section name='A Quick Guide To Simple Log'>
<p>
JCL is distributed with a very simple <code>Log</code> implementation named
<code>org.apache.commons.logging.impl.SimpleLog</code>. This is intended to be a minimal
implementation and those requiring a fully functional open source logging system are
directed to <a href='http://logging.apache.org/log4j'>Log4J</a>.
</p>
<p>
<code>SimpleLog</code> sends all (enabled) log messages,
for all defined loggers, to <code>System.err</code>. The following system properties
are supported to configure the behavior of this logger:</p>
<ul>
<li><strong>org.apache.commons.logging.simplelog.defaultlog</strong> -
Default logging detail level for all instances of SimpleLog.
Must be one of:
<ul>
<li><code>trace</code></li>
<li><code>debug</code></li>
<li><code>info</code></li>
<li><code>warn</code></li>
<li><code>error</code></li>
<li><code>fatal</code></li>
</ul>
If not specified, defaults to <code>info</code>. </li>
<li><strong>org.apache.commons.logging.simplelog.log.xxxxx</strong> -
Logging detail level for a SimpleLog instance named "xxxxx".
Must be one of:
<ul>
<li><code>trace</code></li>
<li><code>debug</code></li>
<li><code>info</code></li>
<li><code>warn</code></li>
<li><code>error</code></li>
<li><code>fatal</code></li>
</ul>
If not specified, the default logging detail level is used.</li>
<li><strong>org.apache.commons.logging.simplelog.showlogname</strong> -
Set to <code>true</code> if you want the <code>Log</code> instance name to be
included in output messages. Defaults to <code>false</code>.</li>
<li><strong>org.apache.commons.logging.simplelog.showShortLogname</strong> -
Set to <code>true</code> if you want the last component of the name to be
included in output messages. Defaults to <code>true</code>.</li>
<li><strong>org.apache.commons.logging.simplelog.showdatetime</strong> -
Set to <code>true</code> if you want the current date and time
to be included in output messages. Default is <code>false</code>.</li>
<li><strong>org.apache.commons.logging.simplelog.dateTimeFormat</strong> -
The date and time format to be used in the output messages.
The pattern describing the date and time format is the same that is
used in <code>java.text.SimpleDateFormat</code>. If the format is not
specified or is invalid, the default format is used.
The default format is <code>yyyy/MM/dd HH:mm:ss:SSS zzz</code>.</li>
</ul>
<p>
In addition to looking for system properties with the names specified
above, this implementation also checks for a class loader resource named
<code>"simplelog.properties"</code>, and includes any matching definitions
from this resource (if it exists).
</p>
</section>
<section name='Frequently Asked Questions'>
<p>
See the <a href="http://wiki.apache.org/commons/Logging/FrequentlyAskedQuestions">FAQ document</a>
on the commons-logging wiki site
</p>
</section>
</body>
</document>

144
src/site/xdoc/index.xml Normal file
View File

@ -0,0 +1,144 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>Overview</title>
<author email="dev@commons.apache.org">Commons Documentation Team</author>
</properties>
<body>
<section name="The Logging Component">
<p>When writing a library it is very useful to log information. However there
are many logging implementations out there, and a library cannot impose the use
of a particular one on the overall application that the library is a part of.</p>
<p>The Logging package is an ultra-thin bridge between different logging
implementations. A library that uses the commons-logging API can be used with
any logging implementation at runtime. Commons-logging comes with support for a
number of popular logging implementations, and writing adapters for others is a
reasonably simple task.</p>
<p>Applications (rather than libraries) may also choose to use commons-logging.
While logging-implementation independence is not as important for applications
as it is for libraries, using commons-logging does allow the application to
change to a different logging implementation without recompiling code.
</p><p>
Note that commons-logging does not attempt to initialise or terminate the underlying
logging implementation that is used at runtime; that is the responsibility of
the application. However many popular logging implementations do automatically
initialise themselves; in this case an application may be able to avoid
containing any code that is specific to the logging implementation used.</p>
</section>
<section name="Documentation">
<p>The <a href="RELEASE-NOTES.txt">
Release Notes</a> document the new features and bug fixes that have been
included in the latest release.</p>
<p>The <a href="http://commons.apache.org/logging/apidocs/index.html">
JavaDoc API documents</a> for the latest release are available online.
In particular, you should read the package overview of the <code>org.apache.commons.logging</code>
package. In addition, there is a (short)
<a href="guide.html">User Guide</a>.</p>
<p>The <a href="http://wiki.apache.org/commons/Logging">Wiki site</a> has
the latest updates, an FAQ and much other useful information.</p>
<p>
Users needing to become experts or wanting to help develop JCL should
(in addition) consult the <a href='tech.html'>Tech Guide</a>.
This gives short introductions to topics such as advanced class loading.
</p>
</section>
<section name="Releases">
<p>
Binary and source distributions are available
<a href="http://commons.apache.org/logging/download_logging.cgi">here</a>.
</p>
<subsection name='1.2 Release - July 2014'>
<p>The main purpose of the 1.2 release is to drop support for Java 1.1.</p>
<p>For a full list of changes since the 1.1.3 release, please refer to the
<a href="changes-report.html">change-report</a>.</p>
</subsection>
<subsection name='1.1.3 Release - May 2013'>
<p>The 1.1.3 release only updates the Bundle-SymbolicName in the manifest
to "org.apache.commons.logging".</p>
<p>For a full list of changes since the 1.1.1 release, please refer to the
<a href="changes-report.html">change-report</a>.</p>
</subsection>
<subsection name='1.1.2 Release - March 2013'>
<p>The 1.1.2 release is a packaging of bug fixes since release 1.1.1.</p>
<p>For the full details, see the release notes for this version.</p>
</subsection>
<subsection name='1.1.1 Release - November 2007'>
<p>
This release is a minor update to the 1.1 release that fixes a number of bugs, and
resolves packaging issues for maven 1.x and maven 2.x users.
</p>
<p>For the full details, see the release notes for this version.</p>
</subsection>
<subsection name='1.1 Release - 10 May 2006'>
<p>This release makes several changes that are intended to resolve issues that
have been encountered when using commons-logging in servlet containers or j2ee
containers where complex classpaths are present and multiple copies of
commons-logging libraries are present at different levels.</p>
<p>This release also adds support for the TRACE level added to log4j in the
1.2.12 release. In former commons-logging versions, the log.trace method
caused log4j to output the message at the DEBUG level (the lowest level
supported by log4j at that time).</p>
<p>For the full details, see the release notes for this version.</p>
</subsection>
<subsection name='1.0.5 Release (Alpha)'>
<p>
<strong>Note:</strong> the 1.0.5 release was abandoned at alpha status.
</p>
<p>
The next JCL release will be designated 1.1 since we feel this more
accurately reflects the improvements made to the codebase.</p>
</subsection>
<subsection name='1.0.4 Release - 16 Jun 2004'>
<p>The 1.0.4 release of commons-logging is a service release containing support
for both the 1.2.x and 1.3.x series of Log4J releases.</p>
</subsection>
<subsection name='1.0.3 Release - 7 Apr 2003'>
<p>The 1.0.3 release is primarily a maintenance and code cleanup release with minimal new features.</p>
</subsection>
<subsection name='1.0.2 Release - 27 September 2002'>
<p>The 1.0.2 release is a packaging of bug fixes since release 1.0.1.</p>
</subsection>
<subsection name='1.0.1 Release - 13 August 2002'>
<p>The 1.0.1 release is a packaging of bug fixes and minor enhancements since release 1.0.</p>
</subsection>
</section>
<section name="Development Builds">
<p>Regular builds of the current SVN HEAD code are made available. See the
<a href="http://wiki.apache.org/commons/Logging">wiki</a> for details.</p>
</section>
</body>
</document>

View File

@ -0,0 +1,102 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
+======================================================================+
|**** ****|
|**** THIS FILE IS GENERATED BY THE COMMONS BUILD PLUGIN ****|
|**** DO NOT EDIT DIRECTLY ****|
|**** ****|
+======================================================================+
| TEMPLATE FILE: issue-tracking-template.xml |
| commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
+======================================================================+
| |
| 1) Re-generate using: mvn commons:jira-page |
| |
| 2) Set the following properties in the component's pom: |
| - commons.jira.id (required, alphabetic, upper case) |
| - commons.jira.pid (required, numeric) |
| |
| 3) Example Properties |
| |
| <properties> |
| <commons.jira.id>MATH</commons.jira.id> |
| <commons.jira.pid>12310485</commons.jira.pid> |
| </properties> |
| |
+======================================================================+
-->
<document>
<properties>
<title>Commons Logging Issue tracking</title>
<author email="dev@commons.apache.org">Commons Documentation Team</author>
</properties>
<body>
<section name="Commons Logging Issue tracking">
<p>
Commons Logging uses <a href="http://issues.apache.org/jira/">ASF JIRA</a> for tracking issues.
See the <a href="http://issues.apache.org/jira/browse/LOGGING">Commons Logging JIRA project page</a>.
</p>
<p>
To use JIRA you may need to <a href="http://issues.apache.org/jira/secure/Signup!default.jspa">create an account</a>
(if you have previously created/updated Commons issues using Bugzilla an account will have been automatically
created and you can use the <a href="http://issues.apache.org/jira/secure/ForgotPassword!default.jspa">Forgot Password</a>
page to get a new password).
</p>
<p>
If you would like to report a bug, or raise an enhancement request with
Commons Logging please do the following:
<ol>
<li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&amp;pid=12310484&amp;sorter/field=issuekey&amp;sorter/order=DESC&amp;status=1&amp;status=3&amp;status=4">Search existing open bugs</a>.
If you find your issue listed then please add a comment with your details.</li>
<li><a href="mail-lists.html">Search the mailing list archive(s)</a>.
You may find your issue or idea has already been discussed.</li>
<li>Decide if your issue is a bug or an enhancement.</li>
<li>Submit either a <a href="http://issues.apache.org/jira/secure/CreateIssueDetails!init.jspa?pid=12310484&amp;issuetype=1&amp;priority=4&amp;assignee=-1">bug report</a>
or <a href="http://issues.apache.org/jira/secure/CreateIssueDetails!init.jspa?pid=12310484&amp;issuetype=4&amp;priority=4&amp;assignee=-1">enhancement request</a>.</li>
</ol>
</p>
<p>
Please also remember these points:
<ul>
<li>the more information you provide, the better we can help you</li>
<li>test cases are vital, particularly for any proposed enhancements</li>
<li>the developers of Commons Logging are all unpaid volunteers</li>
</ul>
</p>
<p>
For more information on subversion and creating patches see the
<a href="http://www.apache.org/dev/contributors.html">Apache Contributors Guide</a>.
</p>
<p>
You may also find these links useful:
<ul>
<li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&amp;pid=12310484&amp;sorter/field=issuekey&amp;sorter/order=DESC&amp;status=1&amp;status=3&amp;status=4">All Open Commons Logging bugs</a></li>
<li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&amp;pid=12310484&amp;sorter/field=issuekey&amp;sorter/order=DESC&amp;status=5&amp;status=6">All Resolved Commons Logging bugs</a></li>
<li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&amp;pid=12310484&amp;sorter/field=issuekey&amp;sorter/order=DESC">All Commons Logging bugs</a></li>
</ul>
</p>
</section>
</body>
</document>

View File

@ -0,0 +1,39 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>JUnit Test Results</title>
<author email="dev@commons.apache.org">Commons Documentation Team</author>
</properties>
<body>
<!-- ================================================== -->
<section name="Summary">
<p>
The Apache Commons Logging test cases make extensive use of
sophisticated classloader configurations in order to simulate the
behaviour of various containers. It is difficult to run these tests
under Maven in the default "test" phase. As a consequence the tests
are executed via the failsafe-plugin as part of the "integration-test"
phase. The reports are available <a href="failsafe-report.html">here</a>.
</p>
</section>
<!-- ================================================== -->
</body>
</document>

View File

@ -0,0 +1,202 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
+======================================================================+
|**** ****|
|**** THIS FILE IS GENERATED BY THE COMMONS BUILD PLUGIN ****|
|**** DO NOT EDIT DIRECTLY ****|
|**** ****|
+======================================================================+
| TEMPLATE FILE: mail-lists-template.xml |
| commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
+======================================================================+
| |
| 1) Re-generate using: mvn commons:mail-page |
| |
| 2) Set the following properties in the component's pom: |
| - commons.componentid (required, alphabetic, lower case) |
| |
| 3) Example Properties |
| |
| <properties> |
| <commons.componentid>math</commons.componentid> |
| </properties> |
| |
+======================================================================+
-->
<document>
<properties>
<title>Commons Logging Mailing Lists</title>
<author email="dev@commons.apache.org">Commons Documentation Team</author>
</properties>
<body>
<section name="Overview">
<p>
<a href="index.html">Commons Logging</a> shares mailing lists with all the other
<a href="http://commons.apache.org/components.html">Commons Components</a>.
To make it easier for people to only read messages related to components they are interested in,
the convention in Commons is to prefix the subject line of messages with the component's name,
for example:
<ul>
<li>[logging] Problem with the ...</li>
</ul>
</p>
<p>
Questions related to the usage of Commons Logging should be posted to the
<a href="http://mail-archives.apache.org/mod_mbox/commons-user/">User List</a>.
<br />
The <a href="http://mail-archives.apache.org/mod_mbox/commons-dev/">Developer List</a>
is for questions and discussion related to the development of Commons Logging.
<br />
Please do not cross-post; developers are also subscribed to the user list.
</p>
<p>
<strong>Note:</strong> please don't send patches or attachments to any of the mailing lists.
Patches are best handled via the <a href="issue-tracking.html">Issue Tracking</a> system.
Otherwise, please upload the file to a public server and include the URL in the mail.
</p>
</section>
<section name="Commons Logging Mailing Lists">
<p>
<strong>Please prefix the subject line of any messages for <a href="index.html">Commons Logging</a>
with <i>[logging]</i></strong> - <i>thanks!</i>
<br />
<br />
</p>
<table>
<tr>
<th>Name</th>
<th>Subscribe</th>
<th>Unsubscribe</th>
<th>Post</th>
<th>Archive</th>
<th>Other Archives</th>
</tr>
<tr>
<td>
<strong>Commons User List</strong>
<br /><br />
Questions on using Commons Logging.
<br /><br />
</td>
<td><a href="mailto:user-subscribe@commons.apache.org">Subscribe</a></td>
<td><a href="mailto:user-unsubscribe@commons.apache.org">Unsubscribe</a></td>
<td><a href="mailto:user@commons.apache.org?subject=[logging]">Post</a></td>
<td><a href="http://mail-archives.apache.org/mod_mbox/commons-user/">mail-archives.apache.org</a></td>
<td><a href="http://markmail.org/list/org.apache.commons.users/">markmail.org</a><br />
<a href="http://www.mail-archive.com/user@commons.apache.org/">www.mail-archive.com</a><br />
<a href="http://news.gmane.org/gmane.comp.jakarta.commons.devel">news.gmane.org</a>
</td>
</tr>
<tr>
<td>
<strong>Commons Developer List</strong>
<br /><br />
Discussion of development of Commons Logging.
<br /><br />
</td>
<td><a href="mailto:dev-subscribe@commons.apache.org">Subscribe</a></td>
<td><a href="mailto:dev-unsubscribe@commons.apache.org">Unsubscribe</a></td>
<td><a href="mailto:dev@commons.apache.org?subject=[logging]">Post</a></td>
<td><a href="http://mail-archives.apache.org/mod_mbox/commons-dev/">mail-archives.apache.org</a></td>
<td><a href="http://markmail.org/list/org.apache.commons.dev/">markmail.org</a><br />
<a href="http://www.mail-archive.com/dev@commons.apache.org/">www.mail-archive.com</a><br />
<a href="http://news.gmane.org/gmane.comp.jakarta.commons.devel">news.gmane.org</a>
</td>
</tr>
<tr>
<td>
<strong>Commons Issues List</strong>
<br /><br />
Only for e-mails automatically generated by the <a href="issue-tracking.html">issue tracking</a> system.
<br /><br />
</td>
<td><a href="mailto:issues-subscribe@commons.apache.org">Subscribe</a></td>
<td><a href="mailto:issues-unsubscribe@commons.apache.org">Unsubscribe</a></td>
<td><i>read only</i></td>
<td><a href="http://mail-archives.apache.org/mod_mbox/commons-issues/">mail-archives.apache.org</a></td>
<td><a href="http://markmail.org/list/org.apache.commons.issues/">markmail.org</a><br />
<a href="http://www.mail-archive.com/issues@commons.apache.org/">www.mail-archive.com</a>
</td>
</tr>
<tr>
<td>
<strong>Commons Commits List</strong>
<br /><br />
Only for e-mails automatically generated by the <a href="source-repository.html">source control</a> sytem.
<br /><br />
</td>
<td><a href="mailto:commits-subscribe@commons.apache.org">Subscribe</a></td>
<td><a href="mailto:commits-unsubscribe@commons.apache.org">Unsubscribe</a></td>
<td><i>read only</i></td>
<td><a href="http://mail-archives.apache.org/mod_mbox/commons-commits/">mail-archives.apache.org</a></td>
<td><a href="http://markmail.org/list/org.apache.commons.commits/">markmail.org</a><br />
<a href="http://www.mail-archive.com/commits@commons.apache.org/">www.mail-archive.com</a>
</td>
</tr>
</table>
</section>
<section name="Apache Mailing Lists">
<p>
Other mailing lists which you may find useful include:
</p>
<table>
<tr>
<th>Name</th>
<th>Subscribe</th>
<th>Unsubscribe</th>
<th>Post</th>
<th>Archive</th>
<th>Other Archives</th>
</tr>
<tr>
<td>
<strong>Apache Announce List</strong>
<br /><br />
General announcements of Apache project releases.
<br /><br />
</td>
<td><a class="externalLink" href="mailto:announce-subscribe@apache.org">Subscribe</a></td>
<td><a class="externalLink" href="mailto:announce-unsubscribe@apache.org">Unsubscribe</a></td>
<td><i>read only</i></td>
<td><a class="externalLink" href="http://mail-archives.apache.org/mod_mbox/www-announce/">mail-archives.apache.org</a></td>
<td><a class="externalLink" href="http://markmail.org/list/org.apache.announce/">markmail.org</a><br />
<a class="externalLink" href="http://old.nabble.com/Apache-News-and-Announce-f109.html">old.nabble.com</a><br />
<a class="externalLink" href="http://www.mail-archive.com/announce@apache.org/">www.mail-archive.com</a><br />
<a class="externalLink" href="http://news.gmane.org/gmane.comp.apache.announce">news.gmane.org</a>
</td>
</tr>
</table>
</section>
</body>
</document>

127
src/site/xdoc/proposal.xml Normal file
View File

@ -0,0 +1,127 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>Proposal for Logging Library Package</title>
</properties>
<body>
<section name="Proposal for Logging Package">
<subsection name="(0) Rationale">
<p>There is a great need for debugging and logging information inside of
Commons components such as HTTPClient and dbcp. However, there are many
logging APIs out there and it is difficult to choose among them.
</p>
<p>The Logging package will be an ultra-thin bridge between different logging
libraries. Commons components may use the Logging JAR to remove
compile-time/runtime dependencies on any particular logging package,
and contributors may write Log implementations for the library of their choice.
</p>
</subsection>
<subsection name="(1) Scope of the Package">
<p>The package shall create and maintain a package that provides extremely
basic logging functionality and bridges to other, more sophisticated logging
implementations.
</p>
<p>
The package should :
<ul>
<li>Have an API which should be as simple to use as possible</li>
<li>Provide support for log4j</li>
<li>Provide pluggable support for other logging APIs</li>
</ul>
</p>
<p>
Non-goals:
<ul>
<li>This package will not perform logging itself, except at the most basic
level.</li>
<li>We do not seek to become a "standard" API.</li>
</ul>
</p>
</subsection>
<subsection name="(1.5) Interaction With Other Packages">
<p><em>Logging</em> relies on:
</p>
<ul>
<li>Java Development Kit (Version 1.1 or later)</li>
<li>Avalon Framework (compile-time dependency only unless this Log
implementation is selected at runtime)</li>
<li>Avalon LogKit (compile-time dependency only unless this Log
implementation is selected at runtime)</li>
<li>JDK 1.4 (compile-time dependency only unless this log implementation
is selected at runtime).</li>
<li>Log4J (compile-time dependency only unless this Log
implementation is selected at runtime)</li>
<li><a href="http://sourceforge.net/projects/lumberjack/">Lumberjack</a>
(compile-time dependency only unless this Log
implementation is selected at runtime)</li>
</ul>
</subsection>
<subsection name="(2) Required Jakarta-Commons Resources">
<ul>
<li>CVS Repository - New directory <code>logging</code> in the
<code>jakarta-commons</code> CVS repository.</li>
<li>Initial Committers - The list is provided below. </li>
<li>Mailing List - Discussions will take place on the general
<em>dev@commons.apache.org</em> mailing list. To help list
subscribers identify messages of interest, it is suggested that the
message subject of messages about this component be prefixed with
[Logging].</li>
<li>Bugzilla - New component "Logging" under the "Commons" product
category, with appropriate version identifiers as needed.</li>
<li>Jyve FAQ - New category "commons-logging" (when available).</li>
</ul>
</subsection>
<subsection name="(4) Initial Committers">
<p>The initial committers on the Logging component shall be:</p>
<ul>
<li>Morgan Delagrange</li>
<li>Rodney Waldhoff</li>
<li>Craig McClanahan</li>
</ul>
</subsection>
</section>
</body>
</document>

653
src/site/xdoc/tech.xml Normal file
View File

@ -0,0 +1,653 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>Technology Guide</title>
<author email="dev@commons.apache.org">Commons Documentation Team</author>
</properties>
<body>
<section name='Overview'>
<subsection name='Contents'>
<ul>
<li>
Overview
<ul>
<li>
Contents
</li>
<li>
<a href='#Introduction'>Introduction</a>
</li>
</ul>
</li>
<li>
<a href='#A Short Introduction to Class Loading and Class Loaders'>
A Short Introduction to Class Loading and Class Loaders
</a>
<ul>
<li>
<a href='#Preamble'>
Preamble
</a>
</li>
<li>
<a href='#Resolution Of Symbolic References'>
Resolution Of Symbolic References
</a>
</li>
<li>
<a href='#Loading'>
Loading
</a>
</li>
<li>
<a href='#Linking'>
Linking
</a>
</li>
<li>
<a href='#Loading Classes'>
Loading Classes
</a>
</li>
<li>
<a href='#Bootstrap Classloader'>
Bootstrap Classloader
</a>
</li>
<li>
<a href='#Runtime Package'>
Runtime Package
</a>
</li>
<li>
<a href='#Loader Used To Resolve A Symbolic Reference'>
Loader Used To Resolve A Symbolic Reference
</a>
</li>
<li>
<a href='#Bibliography'>
Bibliography
</a>
</li>
</ul>
</li>
<li>
<a href='#A Short Guide To Hierarchical Class Loading'>
A Short Guide To Hierarchical Class Loading
</a>
<ul>
<li>
<a href='#Delegating Class Loaders'>
Delegating Class Loaders
</a>
</li>
<li>
<a href='#Parent-First And Child-First Class Loaders'>
Parent-First And Child-First Class Loaders
</a>
</li>
<li>
<a href='#Class ClassLoader'>
Class ClassLoader
</a>
</li>
<li>
<a href='#Context ClassLoader'>
Context ClassLoader
</a>
</li>
<li>
<a href='#The Context Classloader in Container Applications'>
The Context Classloader in Container Applications
</a>
</li>
<li>
<a href='#Issues with Context ClassLoaders'>
Issues with Context ClassLoaders
</a>
</li>
<li>
<a href='#Reflection And The Context ClassLoader'>
Reflection And The Context ClassLoader
</a>
</li>
<li>
<a href='#More Information'>
More Information
</a>
</li>
</ul>
</li>
<li>
<a href='#A Short Theory Guide To JCL'>
A Short Theory Guide To JCL
</a>
<ul>
<li>
<a href='#Isolation And The Context Class Loader'>
Isolation And The Context Class Loader
</a>
</li>
<li>
<a href='#Log And LogFactory'>
Log And LogFactory
</a>
</li>
<li>
<a href='#Log Implementations'>
Log Implementations
</a>
</li>
<li>
<a href='#Using Reflection To Load Log Implementations'>
Using Reflection To Load Log Implementations
</a>
</li>
</ul>
</li>
</ul>
</subsection>
<subsection name='Introduction'>
<p>
This guide is aimed at describing the technologies that JCL developers and expert users
(and users who need to become experts)
should be familiar with. The aim is to give an understanding whilst being precise but brief.
Details which are not relevant for JCL have been suppressed.
References have been included.
</p>
<p>
These topics are a little difficult and it's easy for even experienced developers to make
mistakes. We need you to help us get it right! Please submit corrections, comments, additional references
and requests for clarification
by either:
</p>
<ul>
<li>
posting to the <a href='http://commons.apache.org/mail-lists.html'>Apache Commons dev mailing list</a> or
</li>
<li>
creating an issue in <a href='http://issues.apache.org/jira/browse/LOGGING/'>JIRA</a>.
</li>
</ul>
<p>
TIA
</p>
</subsection>
</section>
<section name='A Short Introduction to Class Loading and Class Loaders'>
<subsection name='Preamble'>
<p>
This is intended to present a guide to the process by which Java bytecode uses bytecode in other classes
from the perspective of the language and virtual machine specifications. The focus will be on deciding
which bytecode will be used (rather than the mechanics of the usage). It focuses on facts and terminology.
</p>
<p>
The process is recursive: it is therefore difficult to pick a starting point.
Sun's documentation starts from the perspective of the startup of a new application.
This guide starts from the perspective of an executing application.
</p>
<p>
During this discussion, please assume that each time that <em>class</em> is mentioned,
the comments applied equally well to interfaces.
</p>
<p>
This document is targeted at Java 1.2 and above.
</p>
</subsection>
<subsection name='Resolution Of Symbolic References'>
<p>
(<a href='http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html#44524'>LangSpec 12.3.3</a>)
The bytecode representation of a class contains symbolic names for other classes referenced.
</p>
<p>
<em>
In practical development terms: If a class is imported (either explicitly in the list of imports at the top of
the source file or implicitly through a fully qualified name in the source code) it is referenced symbolically.
</em>
</p>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#73492'>VMSpec 5.4.3</a>)
Resolution of a symbolic reference occurs dynamically at runtime and is carried out by
the Java Virtual Machine. Resolution of a symbolic reference requires loading and linking of the new class.
</p>
<p>
<em>
Note: references are not statically resolved at compile time.
</em>
</p>
</subsection>
<subsection name='Loading'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#19175'>VMSpec 2.17.2</a>)
Loading is the name given to the process by which a binary form of a class is obtained
by the Java Virtual Machine.
Java classes are always loaded and linked dynamically by the Java Virtual Machine
(rather than statically by the compiler).
</p>
<p>
<em>
In practical development terms:
This means that the developer has no certain knowledge about the actual
bytecode that will be used to execute any external call (one made outside the class). This is determined only
at execution time and is affected by the way that the code is deployed.
</em>
</p>
</subsection>
<subsection name='Linking'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#22574'>VMSpec 2.17.3</a>)
Linking is the name used for combining the
binary form of a class into the Java Virtual Machine. This must happen before the class can be used.
</p>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#22574'>VMSpec 2.17.3</a>)
Linking is composed of verification, preparation and resolution (of symbolic references).
Flexibility is allowed over the timing of resolution. (Within limit) this may happen at any time after
preparation and before that reference is used.
</p>
<p>
<em>
In practical development terms: This means that different JVMs may realize that a reference cannot be
resolved at different times during execution. Consequently, the actual behaviour cannot be precisely predicted
without intimate knowledge of the JVM (on which the bytecode will be executed).
This makes it hard to give universal guidance to users.
</em>
</p>
</subsection>
<subsection name='Loading Classes'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#19175'>VMSpec 2.17.2</a>)
The loading process is performed by a <code>ClassLoader</code>.
</p>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#72007'>VMSpec 5.3</a>)
A classloader may create a class either by delegation or by defining it directly.
The classloader that initiates loading of a class is known as the initiating loader.
The classloader that defines the class is known as the defining loader.
</p>
<p>
<em>
In practical terms: understanding and appreciating this distinction is crucial when debugging issues
concerning classloaders.
</em>
</p>
</subsection>
<subsection name='Bootstrap Classloader'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#72007'>VMSPEC 5.3</a>)
The bootstrap is the base <code>ClassLoader</code> supplied by the Java Virtual Machine.
All others are user (also known as application) <code>ClassLoader</code> instances.
</p>
<p>
<em>
In practical development terms: The System classloader returned by <code>Classloader.getSystemClassLoader()</code>
will be either the bootstrap classloader or a direct descendant of the bootstrap classloader.
Only when debugging issues concerning the system classloader should there be any need to consider the detailed
differences between the bootstrap classloader and the system classloader.
</em>
</p>
</subsection>
<subsection name='Runtime Package'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#72007'>VMSpec 5.3</a>)
At runtime, a class (or interface) is determined by its fully qualified name
and by the classloader that defines it. This is known as the class's runtime package.
</p>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#75929'>VMSpec 5.4.4</a>)
Only classes in the same runtime package are mutually accessible.
</p>
<p>
<em>
In practical development terms: two classes with the same symbolic name can only be used interchangeably
if they are defined by the same classloader. A classic symptom indicative of a classloader issue is that
two classes with the same fully qualified name are found to be incompatible during a method call.
This may happen when a member is expecting an interface which is (seemingly) implemented by a class
but the class is in a different runtime package after being defined by a different classloader. This is a
fundamental java language security feature.
</em>
</p>
</subsection>
<subsection name='Loader Used To Resolve A Symbolic Reference'>
<p>
(<a href='http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html#72007'>VMSpec 5.3</a>)
The classloader which defines the class (whose reference is being resolved) is the one
used to initiate loading of the class referred to.
</p>
<p>
<em>
In practical development terms: This is very important to bear in mind when trying to solve classloader issues.
A classic misunderstanding is this: suppose class A defined by classloader C has a symbolic reference to
class B and further that when C initiates loading of B, this is delegated to classloader D which defines B.
Class B can now only resolve symbols that can be loaded by D, rather than all those which can be loaded by C.
This is a classic recipe for classloader problems.
</em>
</p>
</subsection>
<subsection name='Bibliography'>
<ul>
<li>
<a href='http://java.sun.com/docs/books/vmspec/'>VMSpec</a> <em>The Java Virtual Machine Specification, Second Edition</em>
</li>
<li>
<a href='http://java.sun.com/docs/books/jls/'>LangSpec</a> <em>The Java Language Specification, Second Edition</em>
</li>
</ul>
</subsection>
</section>
<section name='A Short Guide To Hierarchical Class Loading'>
<subsection name='Delegating Class Loaders'>
<p>
When asked to load a class, a class loader may either define the class itself or delegate.
The base <code>ClassLoader</code> class insists that every implementation has a parent class loader.
This delegation model therefore naturally forms a tree structure rooted in the bootstrap classloader.
</p>
<p>
Containers (i.e. applications such as servlet engines or application servers
that manage and provide support services for a number of "contained" applications
that run inside of them) often use complex trees to allow isolation of different applications
running within the container. This is particularly true of J2EE containers.
</p>
</subsection>
<subsection name='Parent-First And Child-First Class Loaders'>
<p>
When a classloader is asked to load a class, a question presents itself: should it immediately
delegate the loading to its parent (and thus only define those classes not defined by its parent)
or should it try to define it first itself (and only delegate to its parent those classes it does
not itself define). Classloaders which universally adopt the first approach are termed parent-first
and the second child-first.
</p>
<p>
<strong>Note:</strong> the term child-first (though commonly used) is misleading.
A better term (and one which may be encountered on the mailing list) is parent-last.
This more accurately describes the actual process of classloading performed
by such a classloader.
</p>
<p>
Parent-first loading has been the standard mechanism in the JDK
class loader, at least since Java 1.2 introduced hierarchical classloaders.
</p>
<p>
Child-first classloading has the advantage of helping to improve isolation
between containers and the applications inside them. If an application
uses a library jar that is also used by the container, but the version of
the jar used by the two is different, child-first classloading allows the
contained application to load its version of the jar without affecting the
container.
</p>
<p>
The ability for a servlet container to offer child-first classloading
is made available, as an option, by language in the servlet spec (Section
9.7.2) that allows a container to offer child-first loading with
certain restrictions, such as not allowing replacement of java.* or
javax.* classes, or the container's implementation classes.
</p>
<p>
Though child-first and parent-first are not the only strategies possible,
they are by far the most common.
All other strategies are rare.
However, it is not uncommon to be faced with a mixture of parent-first and child-first
classloaders within the same hierarchy.
</p>
</subsection>
<subsection name='Class ClassLoader'>
<p>
The class loader used to define a class is available programmatically by calling
the <code>getClassLoader</code> method
on the class in question. This is often known as the class classloader.
</p>
</subsection>
<subsection name='Context ClassLoader'>
<p>
Java 1.2 introduces a mechanism which allows code to access classloaders
which are not the class classloader or one of its parents.
A thread may have a class loader associated with it by its creator for use
by code running in the thread when loading resources and classes.
This classloader is accessed by the <code>getContextClassLoader</code>
method on <code>Thread</code>. It is therefore often known as the context classloader.
</p>
<p>
Note that the quality and appropriateness of the context classloader depends on the
care with which the thread's owner manages it.
</p>
</subsection>
<subsection name='The Context Classloader in Container Applications'>
<p>
The Javadoc for
<a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html#setContextClassLoader(java.lang.ClassLoader)">
<code>Thread.setContextClassLoader</code></a> emphasizes the setting of the
context classloader as an aspect of thread creation. However, in many
applications the context classloader is not fixed at thread creation but
rather is changed throughout the life of a thread as thread execution moves
from one context to another. This usage of the context classloader is
particularly important in container applications.
</p>
<p>
For example, in a hypothetical servlet container, a pool of threads
is created to handle HTTP requests. When created these threads have their
context classloader set to a classloader that loads container classes.
After the thread is assigned to handle a request, container code parses
the request and then determines which of the deployed web applications
should handle it. Only when the container is about to call code associated
with a particular web application (i.e. is about to cross an "application
boundary") is the context classloader set to the classloader used to load
the web app's classes. When the web application finishes handling the
request and the call returns, the context classloader is set back to the
container classloader.
</p>
<p>
In a properly managed container, changes in the context classloader are
made when code execution crosses an application boundary. When contained
application <code>A</code> is handling a request, the context classloader
should be the one used to load <code>A</code>'s resources. When application
<code>B</code> is handling a request, the context classloader should be
<code>B</code>'s.
</p>
<p>
While a contained application is handling a request, it is not
unusual for it to call system or library code loaded by the container.
For example, a contained application may wish to call a utility function
provided by a shared library. This kind of call is considered to be
within the "application boundary", so the context classloader remains
the contained application's classloader. If the system or library code
needs to load classes or other resources only visible to the contained
application's classloader, it can use the context classloader to access
these resources.
</p>
<p>
If the context classloader is properly managed, system and library code
that can be accessed by multiple applications can not only use it to load
application-specific resources, but also can use it to detect which
application is making a call and thereby provided services tailored to the
caller.
</p>
</subsection>
<subsection name='Issues with Context ClassLoaders'>
<p>
In practice, context classloaders vary in quality and issues sometimes arise
when using them.
The owner of the thread is responsible for setting the classloader.
If the context classloader is not set then it will default to the system
classloader.
Any container doing so will cause difficulties for any code using the context classloader.
</p>
<p>
The owner is also at liberty to set the classloader as they wish.
Containers may set the context classloader so that it is neither a child nor a parent
of the classloader that defines the class using that loader.
Again, this will cause difficulties.
</p>
<p>
Introduced in <a href='http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf'>Java J2EE 1.3</a>
is a requirement for vendors to appropriately set the context classloader.
Section 6.2.4.8 (1.4 text):
</p>
<source>
This specification requires that J2EE containers provide a per thread
context class loader for the use of system or library classes in
dynamically loading classes provided by the application. The EJB
specification requires that all EJB client containers provide a per
thread context class loader for dynamically loading system value classes.
The per thread context class loader is accessed using the Thread method
getContextClassLoader.
The classes used by an application will typically be loaded by a
hierarchy of class loaders. There may be a top level application class
loader, an extension class loader, and so on, down to a system class
loader. The top level application class loader delegates to the lower
class loaders as needed. Classes loaded by lower class loaders, such as
portable EJB system value classes, need to be able to discover the top
level application class loader used to dynamically load application
classes.
We require that containers provide a per thread context class loader
that can be used to load top level application classes as described
above.
</source>
<p>
This specification leaves quite a lot of freedom for vendors.
(As well as using unconventional terminology and containing the odd typo.)
It is a difficult passage (to say the least).
</p>
</subsection>
<subsection name='Reflection And The Context ClassLoader'>
<p>
Reflection cannot bypass restrictions imposed by the java language security model, but, by avoiding symbolic
references, reflection can be used to load classes which could not otherwise be loaded. Another <code>ClassLoader</code>
can be used to load a class and then reflection used to create an instance.
</p>
<p>
Recall that the runtime packaging is used to determine accessibility.
Reflection cannot be used to avoid basic java security.
Therefore, the runtime packaging becomes an issue when attempting to cast classes
created by reflection using other class loaders.
When using this strategy, various modes of failure are possible
when common class references are defined by the different class loaders.
</p>
<p>
Reflection is often used with the context classloader. In theory, this allows a class defined in
a parent classloader to load any class that is loadable by the application.
In practice, this only works well when the context classloader is set carefully.
</p>
</subsection>
<subsection name='More Information'>
<ul>
<li>
Articles On Class Loaders And Class Loading
<ul>
<li>
<a
href='http://www.onjava.com/pub/a/onjava/2001/07/25/ejb.html'>
Article on J2EE class loading
</a>
</li>
<li>
<a
href='http://www.onjava.com/pub/a/onjava/2003/11/12/classloader.html'>
Article on class loading
</a>
</li>
<li>
<a
href='http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html'>
Article on context class loaders
</a>
</li>
</ul>
</li>
<li>Specific Containers
<ul>
<li>
<a
href='http://tomcat.apache.org/tomcat-4.1-doc/class-loader-howto.html'>
Tomcat 4.1 ClassLoader Guide
</a>
</li>
<li>
<a
href='http://tomcat.apache.org/tomcat-5.0-doc/class-loader-howto.html'>
Tomcat 5.0 ClassLoader Guide
</a>
</li>
<li>
<a
href='http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/trun_classload_web.html'>
Classloading In WebSphere
</a>
</li>
</ul>
</li>
</ul>
</subsection>
</section>
<section name='A Short Theory Guide To JCL'>
<subsection name='Isolation And The Context Class Loader'>
<p>
JCL takes the view that different context class loader indicate boundaries between applications
running in a container environment. Isolation requires that JCL honours these boundaries
and therefore allows different isolated applications to configure their logging systems
independently.
</p>
</subsection>
<subsection name='Log And LogFactory'>
<p>
Performance dictates that symbolic references to these classes are present in the calling application code
(reflection would simply be too slow). Therefore, these classes must be loadable by the classloader
that loads the application code.
</p>
</subsection>
<subsection name='Log Implementations'>
<p>
Performance dictates that symbolic references to the logging systems are present in the implementation
classes (again, reflection would simply be too slow). So, for an implementation to be able to function,
it is necessary for the logging system to be loadable by the classloader that defines the implementing class.
</p>
</subsection>
<subsection name='Using Reflection To Load Log Implementations'>
<p>
However, there is actually no reason why <code>LogFactory</code> requires symbolic references to particular <code>Log</code>
implementations. Reflection can be used to load these from an appropriate classloader
without unacceptable performance degradation.
This is the strategy adopted by JCL.
</p>
<p>
JCL uses the context classloader to load the <code>Log</code> implementation.
</p>
</subsection>
</section>
</body>
</document>

View File

@ -0,0 +1,467 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>Troubleshooting Guide</title>
<author email="dev@commons.apache.org">Commons Documentation Team</author>
</properties>
<body>
<section name="Contents">
<ul>
<li>
<a href="#Contents">Contents</a>
</li>
<li>
<a href="#Using JCL Diagnostics">Using JCL Diagnostics</a>
<ul>
<li>
<a href="#When To Use Diagnostic Logging">When To Use Diagnostic Logging</a>
<ul/>
</li>
<li>
<a href="#How To Use Diagnostic logging">How To Use Diagnostic logging</a>
</li>
<li>
<a href="#OIDs">OIDs</a>
</li>
<li>
<a href="#Diagnostic Message Prefix">Diagnostic Message Prefix</a>
</li>
<li>
<a href="#ClassLoader Hierarchy Tree">ClassLoader Hierarchy Tree</a>
</li>
<li>
<a href="#LogFactory Class Bootstrap">LogFactory Class Bootstrap</a>
</li>
<li>
<a href="#Construction Of LogFactoryImpl Instances">Construction Of LogFactoryImpl Instances</a>
</li>
<li>
<a href="#Log Discovery Diagnostics">Log Discovery Diagnostics</a>
</li>
</ul>
</li>
<li>
<a href="#Containers With Custom LogFactory Implementations">Containers With Custom LogFactory Implementations</a>
<ul>
<li>
<a href="#The Incompatible LogFactory Issue">The Incompatible LogFactory Issue</a>
<ul>
<li>
<a href="#Symptoms">Symptoms</a>
</li>
<li>
<a href="#Explanation">Explanation</a>
</li>
<li>
<a href="#Fixes">Fixes</a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#Containers With Custom ClassLoading Behaviour for Logging">Containers With Custom ClassLoading Behaviour for Logging</a>
<ul>
<li>
<a href="#Apache Tomcat">Apache Tomcat</a>
<ul/>
</li>
<li>
<a href="#JBoss Application Server">JBoss Application Server</a>
<ul/>
</li>
<li>
<a href="#Other Containers">Other Containers</a>
<ul/>
</li>
</ul>
</li>
</ul>
</section>
<section name='Using JCL Diagnostics'>
<p>
Diagnostics is a feature introduced in JCL 1.1 as an aid to debugging problems
with JCL configurations. When diagnostics are switched on, messages are logged
to a stream (specified by the user) by the two main classes involved in discovery
in JCL (<code>LogFactory</code> and <code>LogFactoryImpl</code>).
</p>
<p>
Diagnostics are intended to be used in conjunction with the source. The source
contains numerous and lengthy comments. Often these are intended to help explain
the meaning of the messages.
</p>
<subsection name='When To Use Diagnostic Logging'>
<p>
Diagnostic logging is intended only to be used when debugging a problematic
configuration. It <em>should</em> be switched off for production.
</p>
</subsection>
<subsection name='How To Use Diagnostic logging'>
<p>
Diagnostic logging is controlled through the system property
<code>org.apache.commons.logging.diagnostics.dest</code>. Setting the property value
to the special strings <code>STDOUT</code> or <code>STDERR</code> (case-sensitive)
will output messages to <code>System.out</code> and <code>System.err</code> respectively.
Setting the property value to a valid file name will result in the messages being logged
to that file.
</p>
</subsection>
<subsection name='OIDs'>
<p>
Diagnostics uses the concept of an Object ID (OID). This allows the identity of objects
to be tracked without relying on useful <code>toString</code> implementations.
These are of the form:
</p>
<code><pre>
<em>classname</em>@<em>system identity hash code</em>
</pre></code>
<p>
The <em>system identity hash code</em> is found by calling <code>System.identityHashCode()</code>
which should uniquely identify a particular instance. The classname is usually the fully qualified
class name though in a few cases, <code>org.apache.commons.logging.impl.LogFactoryImpl</code> may be
shortened to <code>LogFactoryImpl</code> to increase ease of reading. For example:
</p>
<code><pre>
sun.misc.Launcher$AppClassLoader@20120943
LogFactoryImpl@1671711
</pre></code>
<p>
OIDs are intended to be used to cross-reference. They allow particular instances of classloaders
and JCL classes to be tracked in different contexts. This plays a vital role in building
up the understanding of the classloader environment required to diagnose JCL problems.
</p>
</subsection>
<subsection name='Diagnostic Message Prefix'>
<p>
Each diagnostic message is prefixed with details of the relevant class in a standard format.
This takes the form:
</p>
<code><pre>
[<em>class-identifier</em> from <em>ClassLoader OID</em>]
</pre></code>
<p>
<em>ClassLoader OID</em> is the <a href='#OIDs'>OID</a> of a classloader which loaded
the class issuing the message.
<em>class-identifier</em> identifies the object issuing the message.
</p>
<p>
In the case of
<code>LogFactory</code>, this is just <code>LogFactory</code>. For example (line split):
</p>
<code><pre>
[LogFactory
from sun.misc.Launcher$AppClassLoader@20120943] BOOTSTRAP COMPLETED
</pre></code>
<p>
In the case of
<code>LogFactoryImpl</code>, the prefix is the instance OID. This can be cross referenced
to discover the details of the TCCL used to manage this instance. For example (line split):
</p>
<code><pre>
[LogFactoryImpl@1671711
from sun.misc.Launcher$AppClassLoader@20120943] Instance created.
</pre></code>
</subsection>
<subsection name='ClassLoader Hierarchy Tree'>
<p>
Understanding the relationships between classloaders is vital when debugging JCL.
At various points, JCL will print to the diagnostic log the hierarchy for important
classloaders. This is obtained by walking the tree using <code>getParent</code>.
Each classloader is represented (visually) by an OID (to allow cross referencing)
and the relationship indicated in <code><em>child</em> --> <em>parent</em></code> fashion.
For example (line split for easy reading):
</p>
<code><pre>
ClassLoader tree:java.net.URLClassLoader@3526198
--> sun.misc.Launcher$AppClassLoader@20120943 (SYSTEM)
--> sun.misc.Launcher$ExtClassLoader@11126876
--> BOOT
</pre></code>
<p>
Represents a hierarchy with four elements ending in the boot classloader.
</p>
</subsection>
<subsection name='LogFactory Class Bootstrap'>
<p>
Whenever the <code>LogFactory</code> class is initialized, diagnostic messages about
the classloader environment are logged. The content of each of these messages is prefixed by
<code>[ENV]</code> to help distinguish them. The extension directories, application classpath,
details of the classloader (including the <a href='#OIDs'>OID</a> and <code>toString</code>
value) used to load <code>LogFactory</code> and the
<a href='#ClassLoader%20Hierarchy%20Tree'>classloader tree</a> for that classloader
are logged.
</p>
<p>
Many Sun classloaders have confusing <code>toString</code> values. For example, the OID may be
</p>
<code><pre>
sun.misc.Launcher$AppClassLoader@20120943
</pre></code>
<p>
with a <code>toString</code> value of
</p>
<code><pre>
sun.misc.Launcher$AppClassLoader@133056f
</pre></code>
<p>
Other classloader implementations may give very useful information (such as the local classpath).
</p>
<p>
Finally, once initialization is complete a <code>BOOTSTRAP COMPLETED</code> message is issued.
</p>
</subsection>
<subsection name='Construction Of LogFactoryImpl Instances'>
<p>
<code>LogFactoryImpl</code> is the standard and default <code>LogFactory</code> implementation.
This section obviously only applies to configurations using this implementation.
</p>
<p>
Before assigning a <code>Log</code> instance, <code>LogFactory</code> loads a
<code>LogFactory</code> implementation. The content is prefixed by <code>[LOOKUP]</code>
for each diagnostic message logged by this process.
</p>
<p>
The implementation used can vary per Thread context classloader (TCCL). If this is the first time
that a Log has been requested for a particular TCCL a new instance will be created.
</p>
<p>
Information of particular interest is logged at this stage. Details of the TCCL are logged
allowing the <a href='#OIDs'>OID</a> later to be cross-referenced to the <code>toString</code> value
and the <a href='#ClassLoader%20Hierarchy%20Tree'>classloader tree</a>. For example, the
following log snippet details the TCCL (lines split):
</p>
<code><pre>
[LogFactory from sun.misc.Launcher$AppClassLoader@20120943]
[LOOKUP] LogFactory implementation requested for the first time for context
classloader java.net.URLClassLoader@3526198
[LogFactory from sun.misc.Launcher$AppClassLoader@20120943]
[LOOKUP] java.net.URLClassLoader@3526198 == 'java.net.URLClassLoader@35ce36'
[LogFactory from sun.misc.Launcher$AppClassLoader@20120943]
[LOOKUP] ClassLoader tree:java.net.URLClassLoader@3526198
--> sun.misc.Launcher$AppClassLoader@20120943 (SYSTEM)
--> sun.misc.Launcher$ExtClassLoader@11126876
--> BOOT
</pre></code>
</subsection>
<subsection name='Log Discovery Diagnostics'>
<p>
The standard <code>LogFactoryImpl</code> issues many diagnostic messages when discovering
the <code>Log</code> implementation to be used.
</p>
<p>
During discovery, environment variables are loaded and values set. This content is prefixed by
<code>[ENV]</code> to make it easier to distinguish this material.
</p>
<p>
The possible messages issued during discovery are numerous. To understand them, the source
should be consulted. Attention should be paid to the classloader hierarchy trees for the
classloader used to load <code>LogFactory</code> and to the TCCL.
</p>
</subsection>
</section>
<section name='Containers With Custom LogFactory Implementations'>
<p>
Some containers use a custom <code>LogFactory</code> implementation to adapt JCL to their particular
logging system. This has some important consequences for the deployment of applications using JCL within
these containers.
</p>
<p>
Containers known to use this mechanism:
</p>
<ul>
<li><a href='http://www.ibm.com/software/websphere/'>WebSphere Application Server</a> from
<a href='http://www.ibm.com/software/websphere/'>IBM</a> (versions 5 and 6).</li>
</ul>
<p>
Containers suspected to use this mechanism:
</p>
<ul>
<li>WebSphere Application Server (other versions).</li>
</ul>
<p>
The Apache Commons team would be grateful if reports were posted to the development list
of other containers using a custom implementation.
</p>
<subsection name='The Incompatible LogFactory Issue'>
<subsection name='Symptoms'>
<p>
An exception is thrown by JCL with a message similar to:
</p>
<code><pre>
The chosen LogFactory implementation does not extend LogFactory. Please check your configuration.
(Caused by java.lang.ClassCastException: The application has specified that a custom LogFactory
implementation should be used but Class 'com.ibm.ws.commons.logging.TrLogFactory' cannot be converted
to 'org.apache.commons.logging.LogFactory'. The conflict is caused by the presence of multiple
LogFactory classes in incompatible classloaders. Background can be found in
http://commons.apache.org/logging/tech.html. If you have not explicitly specified a custom
LogFactory then it is likely that the container has set one without your knowledge.
In this case, consider using the commons-logging-adapters.jar file or specifying the standard
LogFactory from the command line. Help can be found @http://commons.apache.org/logging.
</pre></code>
<p>
This is a WebSphere example so the name of the custom LogFactory is
<code>com.ibm.ws.commons.logging.TrLogFactory</code>. For other containers, this class name will
differ.
</p>
</subsection>
<subsection name='Explanation'>
<p>
A custom <code>LogFactory</code> implementation can only be used if the implementation class loaded
dynamically at runtime can be cast to the <code>LogFactory</code> class that loaded it. There are
several ways in which this cast can fail. The most obvious is that the source code may not actually
extend <code>LogFactory</code>. The source may be compatible but if the <code>LogFactory</code> class
against which the source is compiled is not binary compatible then the cast will also fail.
</p>
<p>
There is also another more unusual way in which this cast can fail: even when the binary is compatible,
the implementation class loaded at runtime may be linked to a different instance of the
<code>LogFactory</code> class. For more information, see the <a href='tech.html'>tech guide</a>.
</p>
<p>
This situation may be encountered in containers which use a custom <code>LogFactory</code> implementation.
The implementation will typically be provided in a shared, high level classloader together with JCL.
When an application classloader contains <code>LogFactory</code>, the implementation will be loaded
from that higher level classloader. The implementation class will be linked to the <code>LogFactory</code>
class loaded by the higher level classloader. Even if the
<code>LogFactory</code> implementations are binary compatible, since they are loaded by different classloaders
the two <code>LogFactory</code> Class instances are not equal and so the cast must fail.
</p>
<p>
The policy adopted by JCL in this situation is to re-throw this exception. Additional information
is included in the message to help diagnosis. The reasoning behind this choice is that a
particular <code>LogFactory</code> implementation has been actively specified and this
choice should not be ignored. This policy has unfortunate consequences when running in
containers which have custom implementations: the above runtime exception may be thrown
under certain classloading policies without the user knowingly specifying a custom
implementation.
</p>
</subsection>
<subsection name='Fixes'>
<p>
There are various ways to fix this problem. Which fix is right depends on the circumstances.
</p>
<p>
If you are happy using another classloading policy for the application, select a
classloading policy which ensures that <code>LogFactory</code> will be loaded from the
shared classloader containing the custom implementation.
</p>
<p>
If you want to bypass the container adaption mechanism then set the appropriate system property
to the default value when the container is started:
</p>
<code><pre>
-Dorg.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
</pre></code>
<p>
If you want to continue to use the default container mechanism then:
</p>
<ul>
<li>
Find and replace the commons-logging implementation used by the container with
the most modern release
</li>
<li>
Replace the commons-logging jar in the application with the commons-logging-adapters jar.
This will ensure that application classloader will delegate to it's parent when loading
<code>LogFactory</code>.
</li>
</ul>
<p>
If you encounter difficulties when applying the fixes recommended, please turn on
<a href='#Using JCL Diagnostics'>diagnostics</a> and consult the logs.
</p>
</subsection>
</subsection>
</section>
<section name='Containers With Custom ClassLoading Behaviour for Logging'>
<p>
Because commons-logging is such a fundamental library, some containers modify the way
in which classloading behaves for commons-logging classes.
</p>
<subsection name="Apache Tomcat">
<p>
At the current date, Tomcat 5.5.16 is the current release. All releases from version
4.1.x through 5.5.16 have a startup process that places jarfile
${tomcat.home}/bin/commons-logging-api.jar in the system classpath and then
prevents any webapp from overriding the classes in that jarfile. Effectively, all
webapps behave as if "parent-first" classloading were enabled for those classes.
</p>
<p>
This has some benefits; in particular it means that there are no problems in
these Tomcat versions with having multiple copies of the commons-logging Log
interface in the classpath (which avoids the "Log does not implement Log"
problem described elsewhere).
</p>
<p>
However it also means that no webapp can override the core commons-logging
classes by including an updated commons-logging jarfile in WEB-INF/lib; any
class already loaded via the container takes priority. In particular, as
Tomcat bundles logging 1.0.4 only, the new diagnostics and memory-leak-prevention
features of the 1.1 release will not be available unless the container's
library version is updated.
</p>
<p>
Because the commons-logging-api.jar in the container does not contain any
log-library-adapter classes, updated behaviour for these <i>will</i> be
seen when logging 1.1 is bundled in WEB-INF/lib. In particular, the
support for log4j's TRACE level will take effect without having to update
the container.
</p>
<p>
If you do wish to update Tomcat's version of commons-logging, then you
<i>must</i> use the commons-logging-1.1-api jar only, not the full jar.
Classes in the webapp cannot override classes loaded from the system
classpath set up during Tomcat's startup process, and logging adapters
can only see their matching concrete logging library if that library is
available in the same classpath. Bundling the full commons-logging jarfile
(with adapters) into the system classpath therefore means that logging
libraries (eg log4j) within WEB-INF/lib are not accessible.
</p>
<p>
Note that the behaviour described here only applies if the standard Tomcat
startup process is run. When Tomcat is embedded in a larger
framework (eg run embedded within an IDE) this may not apply.
</p>
</subsection>
<subsection name="JBoss Application Server">
<p>
The JBoss Application Server can be configured to prevent deployed
code from overriding classes higher in the hierarchy, effectively
forcing "parent-first" behaviour for selected classes. By default,
commons-logging is in this list (at least for some JBoss versions
starting with 4.0.2), and therefore including an updated version
of commons-logging in WEB-INF/lib or similar will have no effect.
See the JBoss classloading documentation for more details.
</p>
</subsection>
<subsection name="Other Containers">
<p>
As more information becomes available on this topic, it may be added
to the commons-logging wiki site.
</p>
</subsection>
</section>
</body>
</document>

View File

@ -0,0 +1,94 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import junit.framework.TestCase;
/**
* Generic tests that can be applied to any log adapter by
* subclassing this class and defining method getLogObject
* appropriately.
*
* @author Sean C. Sullivan
* @version $Revision: 1432587 $
*/
public abstract class AbstractLogTest extends TestCase {
public abstract Log getLogObject();
public void testLoggingWithNullParameters()
{
Log log = this.getLogObject();
assertNotNull(log);
log.debug(null);
log.debug(null, null);
log.debug(log.getClass().getName() + ": debug statement");
log.debug(log.getClass().getName() + ": debug statement w/ null exception", new RuntimeException());
log.error(null);
log.error(null, null);
log.error(log.getClass().getName() + ": error statement");
log.error(log.getClass().getName() + ": error statement w/ null exception", new RuntimeException());
log.fatal(null);
log.fatal(null, null);
log.fatal(log.getClass().getName() + ": fatal statement");
log.fatal(log.getClass().getName() + ": fatal statement w/ null exception", new RuntimeException());
log.info(null);
log.info(null, null);
log.info(log.getClass().getName() + ": info statement");
log.info(log.getClass().getName() + ": info statement w/ null exception", new RuntimeException());
log.trace(null);
log.trace(null, null);
log.trace(log.getClass().getName() + ": trace statement");
log.trace(log.getClass().getName() + ": trace statement w/ null exception", new RuntimeException());
log.warn(null);
log.warn(null, null);
log.warn(log.getClass().getName() + ": warn statement");
log.warn(log.getClass().getName() + ": warn statement w/ null exception", new RuntimeException());
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import java.util.Hashtable;
public class AltHashtable extends Hashtable {
/**
* Generated serial version ID.
*/
private static final long serialVersionUID = 8927996458633688095L;
public static Object lastKey;
public static Object lastValue;
public Object put(Object key, Object value) {
lastKey = key;
lastValue = value;
return super.put(key, value);
}
}

View File

@ -0,0 +1,93 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import junit.framework.Test;
import junit.framework.TestCase;
/**
* Test the ability to force the LogFactory class to use some
* arbitrary Hashtable implementation to store its mapping from
* context-classloader -&gt; LogFactory object.
*/
public class AltHashtableTestCase extends TestCase {
public static Test suite() throws Exception {
Class thisClass = AltHashtableTestCase.class;
ClassLoader thisClassLoader = thisClass.getClassLoader();
PathableClassLoader loader = new PathableClassLoader(null);
loader.useExplicitLoader("junit.", thisClassLoader);
loader.addLogicalLib("testclasses");
loader.addLogicalLib("commons-logging");
Class testClass = loader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, loader);
}
/**
* Set up before each test.
* <p>
* This method ensures that the appropriate system property is defined
* to force the LogFactory class to use the AltHashtable class as its
* Hashtable implementation for storing factories in.
* <p>
* This does make the assumption that whatever JVM we are running in
* doesn't initialise classes until they are actually referenced (ie the
* LogFactory class hasn't been initialised before this method is called).
* This is true of all JVMs I know of; and if it isn't then this test will
* fail and someone will tell us.
*/
public void setUp() {
System.setProperty(
"org.apache.commons.logging.LogFactory.HashtableImpl",
AltHashtable.class.getName());
}
/**
* Verify that initialising the LogFactory class will cause it
* to instantiate an object of type specified in system property
* "org.apache.commons.logging.LogFactory.HashtableImpl".
*/
public void testType() {
// Here, the reference to the LogFactory class should cause the
// class to be loaded and initialised. It will see the property
// set and use the AltHashtable class. If other tests in this
// class have already been run within the same classloader then
// LogFactory will already have been initialised, but that
// doesn't change the effectiveness of this test.
assertTrue(LogFactory.factories instanceof AltHashtable);
}
/**
* Verify that when LogFactory sees a context-classloader for the
* first time that it creates a new entry in the LogFactory.factories
* hashmap. In particular, this checks that this process works ok when
* a system property has been used to specify an alternative Hashtable
* implementation for LogFactory to use.
*/
public void testPutCalled() throws Exception {
AltHashtable.lastKey = null;
AltHashtable.lastValue = null;
LogFactory.getLog(AltHashtableTestCase.class);
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
assertEquals(contextLoader, AltHashtable.lastKey);
assertNotNull(AltHashtable.lastValue);
}
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import junit.framework.TestCase;
import java.util.Hashtable;
/**
* Tests behaviour when the property is misconfigured.
*/
public class BadHashtablePropertyTestCase extends TestCase {
public void testType() {
assertTrue(LogFactory.factories instanceof Hashtable);
}
public void testPutCalled() throws Exception {
LogFactory.getLog(BadHashtablePropertyTestCase.class);
}
}

View File

@ -0,0 +1,119 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import junit.framework.TestCase;
/**
* Tests the basic logging operations to ensure that they all function
* without exception failure. In other words, that they do no fail by
* throwing exceptions.
* This is the minimum requirement for any well behaved logger
* and so this test should be run for each kind.
*/
public class BasicOperationsTestCase extends TestCase
{
public void testIsEnabledClassLog()
{
Log log = LogFactory.getLog(BasicOperationsTestCase.class);
executeIsEnabledTest(log);
}
public void testIsEnabledNamedLog()
{
Log log = LogFactory.getLog(BasicOperationsTestCase.class.getName());
executeIsEnabledTest(log);
}
public void executeIsEnabledTest(Log log)
{
try
{
log.isTraceEnabled();
log.isDebugEnabled();
log.isInfoEnabled();
log.isWarnEnabled();
log.isErrorEnabled();
log.isFatalEnabled();
}
catch (Throwable t)
{
t.printStackTrace();
fail("Exception thrown: " + t);
}
}
public void testMessageWithoutExceptionClassLog()
{
Log log = LogFactory.getLog(BasicOperationsTestCase.class);
executeMessageWithoutExceptionTest(log);
}
public void testMessageWithoutExceptionNamedLog()
{
Log log = LogFactory.getLog(BasicOperationsTestCase.class.getName());
executeMessageWithoutExceptionTest(log);
}
public void executeMessageWithoutExceptionTest(Log log)
{
try
{
log.trace("Hello, Mum");
log.debug("Hello, Mum");
log.info("Hello, Mum");
log.warn("Hello, Mum");
log.error("Hello, Mum");
log.fatal("Hello, Mum");
}
catch (Throwable t)
{
t.printStackTrace();
fail("Exception thrown: " + t);
}
}
public void testMessageWithExceptionClassLog()
{
Log log = LogFactory.getLog(BasicOperationsTestCase.class);
executeMessageWithExceptionTest(log);
}
public void testMessageWithExceptionNamedLog()
{
Log log = LogFactory.getLog(BasicOperationsTestCase.class.getName());
executeMessageWithExceptionTest(log);
}
public void executeMessageWithExceptionTest(Log log)
{
try
{
log.trace("Hello, Mum", new ArithmeticException());
log.debug("Hello, Mum", new ArithmeticException());
log.info("Hello, Mum", new ArithmeticException());
log.warn("Hello, Mum", new ArithmeticException());
log.error("Hello, Mum", new ArithmeticException());
log.fatal("Hello, Mum", new ArithmeticException());
}
catch (Throwable t)
{
t.printStackTrace();
fail("Exception thrown: " + t);
}
}
}

View File

@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
/**
* Dummy exception that unit tests create instances of when they want to test
* logging of an Exception object.
*/
public class DummyException extends Exception {
private static final long serialVersionUID = 1L;
public DummyException() {
// super("Dummy Exception for unit testing");
}
}

View File

@ -0,0 +1,225 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import junit.framework.TestCase;
/**
* testcase to emulate container and application isolated from container
* @author baliuka
* @version $Id: LoadTestCase.java 1432587 2013-01-13 11:11:32Z tn $
*/
public class LoadTestCase extends TestCase{
//TODO: need some way to add service provider packages
static private String LOG_PCKG[] = {"org.apache.commons.logging",
"org.apache.commons.logging.impl"};
/**
* A custom classloader which "duplicates" logging classes available
* in the parent classloader into itself.
* <p>
* When asked to load a class that is in one of the LOG_PCKG packages,
* it loads the class itself (child-first). This class doesn't need
* to be set up with a classpath, as it simply uses the same classpath
* as the classloader that loaded it.
*/
static class AppClassLoader extends ClassLoader{
java.util.Map classes = new java.util.HashMap();
AppClassLoader(ClassLoader parent){
super(parent);
}
private Class def(String name)throws ClassNotFoundException{
Class result = (Class)classes.get(name);
if(result != null){
return result;
}
try{
ClassLoader cl = this.getClass().getClassLoader();
String classFileName = name.replace('.','/') + ".class";
java.io.InputStream is = cl.getResourceAsStream(classFileName);
java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
while(is.available() > 0){
out.write(is.read());
}
byte data [] = out.toByteArray();
result = super.defineClass(name, data, 0, data.length );
classes.put(name,result);
return result;
}catch(java.io.IOException ioe){
throw new ClassNotFoundException( name + " caused by "
+ ioe.getMessage() );
}
}
// not very trivial to emulate we must implement "findClass",
// but it will delegete to junit class loder first
public Class loadClass(String name)throws ClassNotFoundException{
//isolates all logging classes, application in the same classloader too.
//filters exeptions to simlify handling in test
for(int i = 0; i < LOG_PCKG.length; i++ ){
if( name.startsWith( LOG_PCKG[i] ) &&
name.indexOf("Exception") == -1 ){
return def(name);
}
}
return super.loadClass(name);
}
}
/**
* Call the static setAllowFlawedContext method on the specified class
* (expected to be a UserClass loaded via a custom classloader), passing
* it the specified state parameter.
*/
private void setAllowFlawedContext(Class c, String state) throws Exception {
Class[] params = {String.class};
java.lang.reflect.Method m = c.getDeclaredMethod("setAllowFlawedContext", params);
m.invoke(null, new Object[] {state});
}
/**
* Test what happens when we play various classloader tricks like those
* that happen in web and j2ee containers.
* <p>
* Note that this test assumes that commons-logging.jar and log4j.jar
* are available via the system classpath.
*/
public void testInContainer()throws Exception{
//problem can be in this step (broken app container or missconfiguration)
//1. Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
//2. Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
// we expect this :
// 1. Thread.currentThread().setContextClassLoader(appLoader);
// 2. Thread.currentThread().setContextClassLoader(null);
// Context classloader is same as class calling into log
Class cls = reload();
Thread.currentThread().setContextClassLoader(cls.getClassLoader());
execute(cls);
// Context classloader is the "bootclassloader". This is technically
// bad, but LogFactoryImpl.ALLOW_FLAWED_CONTEXT defaults to true so
// this test should pass.
cls = reload();
Thread.currentThread().setContextClassLoader(null);
execute(cls);
// Context classloader is the "bootclassloader". This is same as above
// except that ALLOW_FLAWED_CONTEXT is set to false; an error should
// now be reported.
cls = reload();
Thread.currentThread().setContextClassLoader(null);
try {
setAllowFlawedContext(cls, "false");
execute(cls);
fail("Logging config succeeded when context classloader was null!");
} catch(LogConfigurationException ex) {
// expected; the boot classloader doesn't *have* JCL available
}
// Context classloader is the system classloader.
//
// This is expected to cause problems, as LogFactoryImpl will attempt
// to use the system classloader to load the Log4JLogger class, which
// will then be unable to cast that object to the Log interface loaded
// via the child classloader. However as ALLOW_FLAWED_CONTEXT defaults
// to true this test should pass.
cls = reload();
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
execute(cls);
// Context classloader is the system classloader. This is the same
// as above except that ALLOW_FLAWED_CONTEXT is set to false; an error
// should now be reported.
cls = reload();
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
try {
setAllowFlawedContext(cls, "false");
execute(cls);
fail("Error: somehow downcast a Logger loaded via system classloader"
+ " to the Log interface loaded via a custom classloader");
} catch(LogConfigurationException ex) {
// expected
}
}
/**
* Load class UserClass via a temporary classloader which is a child of
* the classloader used to load this test class.
*/
private Class reload()throws Exception{
Class testObjCls = null;
AppClassLoader appLoader = new AppClassLoader(
this.getClass().getClassLoader());
try{
testObjCls = appLoader.loadClass(UserClass.class.getName());
}catch(ClassNotFoundException cnfe){
throw cnfe;
}catch(Throwable t){
t.printStackTrace();
fail("AppClassLoader failed ");
}
assertTrue( "app isolated" ,testObjCls.getClassLoader() == appLoader );
return testObjCls;
}
private void execute(Class cls)throws Exception{
cls.newInstance();
}
public void setUp() {
// save state before test starts so we can restore it when test ends
origContextClassLoader = Thread.currentThread().getContextClassLoader();
}
public void tearDown() {
// restore original state so a test can't stuff up later tests.
Thread.currentThread().setContextClassLoader(origContextClassLoader);
}
private ClassLoader origContextClassLoader;
}

View File

@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
public class LogTestCase extends AbstractLogTest
{
public Log getLogObject()
{
/**
* Pickup whatever is found/configured!
*/
return LogFactory.getLog(this.getClass().getName());
}
}

View File

@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import junit.framework.TestCase;
/**
* Test cases for situations where getClassLoader or getContextClassLoader
* return null. This can happen when using JDK 1.1. It can also happen when
* JCL is deployed via the bootclassloader - something that could be done when
* using java in embedded systems.
*/
public class NullClassLoaderTestCase extends TestCase {
//---------------------- unit tests ---------------------------------
/**
* This tests that when getContextClassLoader returns null, the
* LogFactory.getLog(name) method still correctly returns the same
* log object when called multiple times with the same name.
*/
public void testSameLogObject() throws Exception {
// unfortunately, there just isn't any way to emulate JCL being
// accessable via the null classloader in "standard" systems, so
// we can't include this test in our standard unit tests.
}
}

View File

@ -0,0 +1,436 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* A ClassLoader which sees only specified classes, and which can be
* set to do parent-first or child-first path lookup.
* <p>
* Note that this classloader is not "industrial strength"; users
* looking for such a class may wish to look at the Tomcat sourcecode
* instead. In particular, this class may not be threadsafe.
* <p>
* Note that the ClassLoader.getResources method isn't overloaded here.
* It would be nice to ensure that when child-first lookup is set the
* resources from the child are returned earlier in the list than the
* resources from the parent. However overriding this method isn't possible
* as the java 1.4 version of ClassLoader declares this method final
* (though the java 1.5 version has removed the final qualifier). As the
* ClassLoader javadoc doesn't specify the order in which resources
* are returned, it's valid to return the resources in any order (just
* untidy) so the inherited implementation is technically ok.
*/
public class PathableClassLoader extends URLClassLoader {
private static final URL[] NO_URLS = new URL[0];
/**
* A map of package-prefix to ClassLoader. Any class which is in
* this map is looked up via the specified classloader instead of
* the classpath associated with this classloader or its parents.
* <p>
* This is necessary in order for the rest of the world to communicate
* with classes loaded via a custom classloader. As an example, junit
* testcases which are loaded via a custom classloader needs to see
* the same junit classes as the code invoking the testcase, otherwise
* they can't pass result objects back.
* <p>
* Normally, only a classloader created with a null parent needs to
* have any lookasides defined.
*/
private HashMap lookasides = null;
/**
* See setParentFirst.
*/
private boolean parentFirst = true;
/**
* Constructor.
* <p>
* Often, null is passed as the parent, ie the parent of the new
* instance is the bootloader. This ensures that the classpath is
* totally clean; nothing but the standard java library will be
* present.
* <p>
* When using a null parent classloader with a junit testcase, it *is*
* necessary for the junit library to also be visible. In this case, it
* is recommended that the following code be used:
* <pre>
* pathableLoader.useExplicitLoader(
* "junit.",
* junit.framework.Test.class.getClassLoader());
* </pre>
* Note that this works regardless of whether junit is on the system
* classpath, or whether it has been loaded by some test framework that
* creates its own classloader to run unit tests in (eg maven2's
* Surefire plugin).
*/
public PathableClassLoader(ClassLoader parent) {
super(NO_URLS, parent);
}
/**
* Allow caller to explicitly add paths. Generally this not a good idea;
* use addLogicalLib instead, then define the location for that logical
* library in the build.xml file.
*/
public void addURL(URL url) {
super.addURL(url);
}
/**
* Specify whether this classloader should ask the parent classloader
* to resolve a class first, before trying to resolve it via its own
* classpath.
* <p>
* Checking with the parent first is the normal approach for java, but
* components within containers such as servlet engines can use
* child-first lookup instead, to allow the components to override libs
* which are visible in shared classloaders provided by the container.
* <p>
* Note that the method getResources always behaves as if parentFirst=true,
* because of limitations in java 1.4; see the javadoc for method
* getResourcesInOrder for details.
* <p>
* This value defaults to true.
*/
public void setParentFirst(boolean state) {
parentFirst = state;
}
/**
* For classes with the specified prefix, get them from the system
* classpath <i>which is active at the point this method is called</i>.
* <p>
* This method is just a shortcut for
* <pre>
* useExplicitLoader(prefix, ClassLoader.getSystemClassLoader());
* </pre>
* <p>
* Of course, this assumes that the classes of interest are already
* in the classpath of the system classloader.
*/
public void useSystemLoader(String prefix) {
useExplicitLoader(prefix, ClassLoader.getSystemClassLoader());
}
/**
* Specify a classloader to use for specific java packages.
* <p>
* The specified classloader is normally a loader that is NOT
* an ancestor of this classloader. In particular, this loader
* may have the bootloader as its parent, but be configured to
* see specific other classes (eg the junit library loaded
* via the system classloader).
* <p>
* The differences between using this method, and using
* addLogicalLib are:
* <ul>
* <li>If code calls getClassLoader on a class loaded via
* "lookaside", then traces up its inheritance chain, it
* will see the "real" classloaders. When the class is remapped
* into this classloader via addLogicalLib, the classloader
* chain seen is this object plus ancestors.
* <li>If two different jars contain classes in the same
* package, then it is not possible to load both jars into
* the same "lookaside" classloader (eg the system classloader)
* then map one of those subsets from here. Of course they could
* be loaded into two different "lookaside" classloaders and
* then a prefix used to map from here to one of those classloaders.
* </ul>
*/
public void useExplicitLoader(String prefix, ClassLoader loader) {
if (lookasides == null) {
lookasides = new HashMap();
}
lookasides.put(prefix, loader);
}
/**
* Specify a collection of logical libraries. See addLogicalLib.
*/
public void addLogicalLib(String[] logicalLibs) {
for(int i=0; i<logicalLibs.length; ++i) {
addLogicalLib(logicalLibs[i]);
}
}
/**
* Specify a logical library to be included in the classpath used to
* locate classes.
* <p>
* The specified lib name is used as a key into the system properties;
* there is expected to be a system property defined with that name
* whose value is a url that indicates where that logical library can
* be found. Typically this is the name of a jar file, or a directory
* containing class files.
* <p>
* If there is no system property, but the classloader that loaded
* this class is a URLClassLoader then the set of URLs that the
* classloader uses for its classpath is scanned; any jar in the
* URL set whose name starts with the specified string is added to
* the classpath managed by this instance.
* <p>
* Using logical library names allows the calling code to specify its
* desired classpath without knowing the exact location of the necessary
* classes.
*/
public void addLogicalLib(String logicalLib) {
// first, check the system properties
String filename = System.getProperty(logicalLib);
if (filename != null) {
try {
URL libUrl = new File(filename).toURL();
addURL(libUrl);
return;
} catch(java.net.MalformedURLException e) {
throw new UnknownError(
"Invalid file [" + filename + "] for logical lib [" + logicalLib + "]");
}
}
// now check the classpath for a similar-named lib
URL libUrl = libFromClasspath(logicalLib);
if (libUrl != null) {
addURL(libUrl);
return;
}
// lib not found
throw new UnknownError(
"Logical lib [" + logicalLib + "] is not defined"
+ " as a System property.");
}
/**
* If the classloader that loaded this class has this logical lib in its
* path, then return the matching URL otherwise return null.
* <p>
* This only works when the classloader loading this class is an instance
* of URLClassLoader and thus has a getURLs method that returns the classpath
* it uses when loading classes. However in practice, the vast majority of the
* time this type is the classloader used.
* <p>
* The classpath of the classloader for this instance is scanned, and any
* jarfile in the path whose name starts with the logicalLib string is
* considered a match. For example, passing "foo" will match a url
* of <code>file:///some/where/foo-2.7.jar</code>.
* <p>
* When multiple classpath entries match the specified logicalLib string,
* the one with the shortest filename component is returned. This means that
* if "foo-1.1.jar" and "foobar-1.1.jar" are in the path, then a logicalLib
* name of "foo" will match the first entry above.
*/
private URL libFromClasspath(String logicalLib) {
ClassLoader cl = this.getClass().getClassLoader();
if (cl instanceof URLClassLoader == false) {
return null;
}
URLClassLoader ucl = (URLClassLoader) cl;
URL[] path = ucl.getURLs();
URL shortestMatch = null;
int shortestMatchLen = Integer.MAX_VALUE;
for(int i=0; i<path.length; ++i) {
URL u = path[i];
// extract the filename bit on the end of the url
String filename = u.toString();
if (!filename.endsWith(".jar")) {
// not a jarfile, ignore it
continue;
}
int lastSlash = filename.lastIndexOf('/');
if (lastSlash >= 0) {
filename = filename.substring(lastSlash+1);
}
if (filename.startsWith(logicalLib)) {
// ok, this is a candidate
if (filename.length() < shortestMatchLen) {
shortestMatch = u;
shortestMatchLen = filename.length();
}
}
}
return shortestMatch;
}
/**
* Override ClassLoader method.
* <p>
* For each explicitly mapped package prefix, if the name matches the
* prefix associated with that entry then attempt to load the class via
* that entries' classloader.
*/
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// just for performance, check java and javax
if (name.startsWith("java.") || name.startsWith("javax.")) {
return super.loadClass(name, resolve);
}
if (lookasides != null) {
for(Iterator i = lookasides.entrySet().iterator(); i.hasNext(); ) {
Map.Entry entry = (Map.Entry) i.next();
String prefix = (String) entry.getKey();
if (name.startsWith(prefix) == true) {
ClassLoader loader = (ClassLoader) entry.getValue();
Class clazz = Class.forName(name, resolve, loader);
return clazz;
}
}
}
if (parentFirst) {
return super.loadClass(name, resolve);
} else {
// Implement child-first.
//
// It appears that the findClass method doesn't check whether the
// class has already been loaded. This seems odd to me, but without
// first checking via findLoadedClass we can get java.lang.LinkageError
// with message "duplicate class definition" which isn't good.
try {
Class clazz = findLoadedClass(name);
if (clazz == null) {
clazz = super.findClass(name);
}
if (resolve) {
resolveClass(clazz);
}
return clazz;
} catch(ClassNotFoundException e) {
return super.loadClass(name, resolve);
}
}
}
/**
* Same as parent class method except that when parentFirst is false
* the resource is looked for in the local classpath before the parent
* loader is consulted.
*/
public URL getResource(String name) {
if (parentFirst) {
return super.getResource(name);
} else {
URL local = super.findResource(name);
if (local != null) {
return local;
}
return super.getResource(name);
}
}
/**
* Emulate a proper implementation of getResources which respects the
* setting for parentFirst.
* <p>
* Note that it's not possible to override the inherited getResources, as
* it's declared final in java1.4 (thought that's been removed for 1.5).
* The inherited implementation always behaves as if parentFirst=true.
*/
public Enumeration getResourcesInOrder(String name) throws IOException {
if (parentFirst) {
return super.getResources(name);
} else {
Enumeration localUrls = super.findResources(name);
ClassLoader parent = getParent();
if (parent == null) {
// Alas, there is no method to get matching resources
// from a null (BOOT) parent classloader. Calling
// ClassLoader.getSystemClassLoader isn't right. Maybe
// calling Class.class.getResources(name) would do?
//
// However for the purposes of unit tests, we can
// simply assume that no relevant resources are
// loadable from the parent; unit tests will never be
// putting any of their resources in a "boot" classloader
// path!
return localUrls;
}
Enumeration parentUrls = parent.getResources(name);
ArrayList localItems = toList(localUrls);
ArrayList parentItems = toList(parentUrls);
localItems.addAll(parentItems);
return Collections.enumeration(localItems);
}
}
/**
*
* Clean implementation of list function of
* {@link java.utils.Collection} added in JDK 1.4
* @param en <code>Enumeration</code>, possibly null
* @return <code>ArrayList</code> containing the enumerated
* elements in the enumerated order, not null
*/
private ArrayList toList(Enumeration en) {
ArrayList results = new ArrayList();
if (en != null) {
while (en.hasMoreElements()){
Object element = en.nextElement();
results.add(element);
}
}
return results;
}
/**
* Same as parent class method except that when parentFirst is false
* the resource is looked for in the local classpath before the parent
* loader is consulted.
*/
public InputStream getResourceAsStream(String name) {
if (parentFirst) {
return super.getResourceAsStream(name);
} else {
URL local = super.findResource(name);
if (local != null) {
try {
return local.openStream();
} catch(IOException e) {
// TODO: check if this is right or whether we should
// fall back to trying parent. The javadoc doesn't say...
return null;
}
}
return super.getResourceAsStream(name);
}
}
}

View File

@ -0,0 +1,147 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import java.util.Properties;
import junit.framework.Test;
import junit.framework.TestResult;
import junit.framework.TestSuite;
/**
* Custom TestSuite class that can be used to control the context classloader
* in operation when a test runs.
* <p>
* For tests that need to control exactly what the classloader hierarchy is
* like when the test is run, something like the following is recommended:
* <pre>
* class SomeTestCase extends TestCase {
* public static Test suite() throws Exception {
* PathableClassLoader parent = new PathableClassLoader(null);
* parent.useSystemLoader("junit.");
*
* PathableClassLoader child = new PathableClassLoader(parent);
* child.addLogicalLib("testclasses");
* child.addLogicalLib("log4j12");
* child.addLogicalLib("commons-logging");
*
* Class testClass = child.loadClass(SomeTestCase.class.getName());
* ClassLoader contextClassLoader = child;
*
* PathableTestSuite suite = new PathableTestSuite(testClass, child);
* return suite;
* }
*
* // test methods go here
* }
* </pre>
* Note that if the suite method throws an exception then this will be handled
* reasonable gracefully by junit; it will report that the suite method for
* a test case failed with exception yyy.
* <p>
* The use of PathableClassLoader is not required to use this class, but it
* is expected that using the two classes together is common practice.
* <p>
* This class will run each test methods within the specified TestCase using
* the specified context classloader and system classloader. If different
* tests within the same class require different context classloaders,
* then the context classloader passed to the constructor should be the
* "lowest" one available, and tests that need the context set to some parent
* of this "lowest" classloader can call
* <pre>
* // NB: pseudo-code only
* setContextClassLoader(getContextClassLoader().getParent());
* </pre>
* This class ensures that any context classloader changes applied by a test
* is undone after the test is run, so tests don't need to worry about
* restoring the context classloader on exit. This class also ensures that
* the system properties are restored to their original settings after each
* test, so tests that manipulate those don't need to worry about resetting them.
* <p>
* This class does not provide facilities for manipulating system properties;
* tests that need specific system properties can simply set them in the
* fixture or at the start of a test method.
* <p>
* <b>Important!</b> When the test case is run, "this.getClass()" refers of
* course to the Class object passed to the constructor of this class - which
* is different from the class whose suite() method was executed to determine
* the classpath. This means that the suite method cannot communicate with
* the test cases simply by setting static variables (for example to make the
* custom classloaders available to the test methods or setUp/tearDown fixtures).
* If this is really necessary then it is possible to use reflection to invoke
* static methods on the class object passed to the constructor of this class.
* <p>
* <h2>Limitations</h2>
* <p>
* This class cannot control the system classloader (ie what method
* ClassLoader.getSystemClassLoader returns) because Java provides no
* mechanism for setting the system classloader. In this case, the only
* option is to invoke the unit test in a separate JVM with the appropriate
* settings.
* <p>
* The effect of using this approach in a system that uses junit's
* "reloading classloader" behaviour is unknown. This junit feature is
* intended for junit GUI apps where a test may be run multiple times
* within the same JVM - and in particular, when the .class file may
* be modified between runs of the test. How junit achieves this is
* actually rather weird (the whole junit code is rather weird in fact)
* and it is not clear whether this approach will work as expected in
* such situations.
*/
public class PathableTestSuite extends TestSuite {
/**
* The classloader that should be set as the context classloader
* before each test in the suite is run.
*/
private final ClassLoader contextLoader;
/**
* Constructor.
*
* @param testClass is the TestCase that is to be run, as loaded by
* the appropriate ClassLoader.
*
* @param contextClassLoader is the loader that should be returned by
* calls to Thread.currentThread.getContextClassLoader from test methods
* (or any method called by test methods).
*/
public PathableTestSuite(Class testClass, ClassLoader contextClassLoader) {
super(testClass);
contextLoader = contextClassLoader;
}
/**
* This method is invoked once for each Test in the current TestSuite.
* Note that a Test may itself be a TestSuite object (ie a collection
* of tests).
* <p>
* The context classloader and system properties are saved before each
* test, and restored after the test completes to better isolate tests.
*/
public void runTest(Test test, TestResult result) {
ClassLoader origContext = Thread.currentThread().getContextClassLoader();
Properties oldSysProps = (Properties) System.getProperties().clone();
try {
Thread.currentThread().setContextClassLoader(contextLoader);
test.run(result);
} finally {
System.setProperties(oldSysProps);
Thread.currentThread().setContextClassLoader(origContext);
}
}
}

View File

@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import org.apache.commons.logging.impl.SimpleLog;
public class SimpleLogTestCase extends AbstractLogTest
{
public Log getLogObject()
{
return new SimpleLog(this.getClass().getName());
}
}

View File

@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.impl.LogFactoryImpl;
public class UserClass {
/**
* Set the ALLOW_FLAWED_CONTEXT feature on the LogFactoryImpl object
* associated with this class' classloader.
* <p>
* Don't forget to set the context classloader to whatever it will be
* when an instance of this class is actually created <i>before</i> calling
* this method!
*/
public static void setAllowFlawedContext(String state) {
LogFactory f = LogFactory.getFactory();
f.setAttribute(LogFactoryImpl.ALLOW_FLAWED_CONTEXT_PROPERTY, state);
}
public UserClass() {
Log log = LogFactory.getLog(LoadTestCase.class);
}
}

View File

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.avalon;
import org.apache.avalon.framework.logger.NullLogger;
import org.apache.commons.logging.impl.AvalonLogger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.AbstractLogTest;
import junit.framework.Test;
import junit.framework.TestSuite;
/**
* @author <a href="mailto:neeme@apache.org">Neeme Praks</a>
* @version $Revision: 1432587 $ $Date: 2013-01-13 12:11:32 +0100 (Sun, 13 Jan 2013) $
*/
public class AvalonLoggerTestCase extends AbstractLogTest {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(AvalonLoggerTestCase.class);
return suite;
}
public Log getLogObject() {
// Output does not seem to be used, so don't display it.
Log log = new AvalonLogger(new NullLogger());
return log;
}
}

View File

@ -0,0 +1,125 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.config;
import java.net.URL;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests that verify that the process of configuring logging on startup
* works correctly by selecting the file with the highest priority.
* <p>
* This test sets up a classpath where:
* <ul>
* <li> first file found has priority=20
* <li> second file found has priority=10
* </ul>
* The result should be that the first file is used.
*/
public class FirstPriorityConfigTestCase extends TestCase {
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
Class thisClass = FirstPriorityConfigTestCase.class;
// Determine the URL to this .class file, so that we can then
// append the priority dirs to it. For tidiness, load this
// class through a dummy loader though this is not absolutely
// necessary...
PathableClassLoader dummy = new PathableClassLoader(null);
dummy.useExplicitLoader("junit.", Test.class.getClassLoader());
dummy.addLogicalLib("testclasses");
dummy.addLogicalLib("commons-logging");
String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
URL baseUrl = dummy.findResource(thisClassPath);
// Now set up the desired classloader hierarchy. We'll put JCL
// in the container path, the testcase in a webapp path, and
// both config files into the webapp path too.
PathableClassLoader containerLoader = new PathableClassLoader(null);
containerLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
containerLoader.addLogicalLib("commons-logging");
PathableClassLoader webappLoader = new PathableClassLoader(containerLoader);
webappLoader.addLogicalLib("testclasses");
URL pri20URL = new URL(baseUrl, "priority20/");
webappLoader.addURL(pri20URL);
URL pri10URL = new URL(baseUrl, "priority10/");
webappLoader.addURL(pri10URL);
// load the test class via webapp loader, and use the webapp loader
// as the tccl loader too.
Class testClass = webappLoader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, webappLoader);
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
LogFactory.releaseAll();
}
// ----------------------------------------------------------- Test Methods
/**
* Verify that the config file being used is the one containing
* the desired configId value.
*/
public void testPriority() throws Exception {
LogFactory instance = LogFactory.getFactory();
ClassLoader thisClassLoader = this.getClass().getClassLoader();
ClassLoader lfClassLoader = instance.getClass().getClassLoader();
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
// context classloader should be thisClassLoader
assertEquals(thisClassLoader, contextClassLoader);
// lfClassLoader should be parent of this classloader
assertEquals(lfClassLoader, thisClassLoader.getParent());
assertEquals(PathableClassLoader.class.getName(),
lfClassLoader.getClass().getName());
String id = (String) instance.getAttribute("configId");
assertEquals("Correct config file loaded", "priority20", id );
}
}

View File

@ -0,0 +1,130 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.config;
import java.net.URL;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests that verify that the process of configuring logging on startup
* works correctly by selecting the file with the highest priority.
* <p>
* This test sets up a classpath where:
* <ul>
* <li> first file (in parent loader) has priority=10 (parentFirst=true)
* <li> second file found has no priority set
* <li> third file found has priority=20
* <li> fourth file found also has priority=20
* </ul>
* The result should be that the third file is used.
* <p>
* Note that parentFirst=true is used in this test because method
* <code>PathableClassLoader.getResources</code> always behaves as if
* parentFirst=true; see the PathableClassLoader javadoc for details.
*/
public class PriorityConfigTestCase extends TestCase {
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
Class thisClass = PriorityConfigTestCase.class;
// Determine the URL to this .class file, so that we can then
// append the priority dirs to it. For tidiness, load this
// class through a dummy loader though this is not absolutely
// necessary...
PathableClassLoader dummy = new PathableClassLoader(null);
dummy.useExplicitLoader("junit.", Test.class.getClassLoader());
dummy.addLogicalLib("testclasses");
dummy.addLogicalLib("commons-logging");
String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
URL baseUrl = dummy.findResource(thisClassPath);
// Now set up the desired classloader hierarchy. We'll put a config
// file of priority=10 in the container path, and ones of both
// "no priority" and priority=20 in the webapp path.
//
// A second properties file with priority=20 is also added,
// so we can check that the first one in the classpath is
// used.
PathableClassLoader containerLoader = new PathableClassLoader(null);
containerLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
containerLoader.addLogicalLib("commons-logging");
URL pri10URL = new URL(baseUrl, "priority10/");
containerLoader.addURL(pri10URL);
PathableClassLoader webappLoader = new PathableClassLoader(containerLoader);
webappLoader.setParentFirst(true);
webappLoader.addLogicalLib("testclasses");
URL noPriorityURL = new URL(baseUrl, "nopriority/");
webappLoader.addURL(noPriorityURL);
URL pri20URL = new URL(baseUrl, "priority20/");
webappLoader.addURL(pri20URL);
URL pri20aURL = new URL(baseUrl, "priority20a/");
webappLoader.addURL(pri20aURL);
// load the test class via webapp loader, and use the webapp loader
// as the tccl loader too.
Class testClass = webappLoader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, webappLoader);
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
LogFactory.releaseAll();
}
// ----------------------------------------------------------- Test Methods
/**
* Verify that the config file being used is the one containing
* the desired configId value.
*/
public void testPriority() throws Exception {
LogFactory instance = LogFactory.getFactory();
String id = (String) instance.getAttribute("configId");
assertEquals("Correct config file loaded", "priority20", id );
}
}

View File

@ -0,0 +1,313 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.impl;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import junit.framework.TestCase;
public class WeakHashtableTestCase extends TestCase {
private static final int WAIT_FOR_THREAD_COMPLETION = 5000; // 5 seconds
private static final int RUN_LOOPS = 3000;
private static final int OUTER_LOOP = 400;
private static final int THREAD_COUNT = 10;
private static WeakHashtable hashtable;
/** Maximum number of iterations before our test fails */
private static final int MAX_GC_ITERATIONS = 50;
private WeakHashtable weakHashtable;
private Long keyOne;
private Long keyTwo;
private Long keyThree;
private Long valueOne;
private Long valueTwo;
private Long valueThree;
public WeakHashtableTestCase(String testName) {
super(testName);
}
protected void setUp() throws Exception {
super.setUp();
weakHashtable = new WeakHashtable();
keyOne = new Long(1);
keyTwo = new Long(2);
keyThree = new Long(3);
valueOne = new Long(100);
valueTwo = new Long(200);
valueThree = new Long(300);
weakHashtable.put(keyOne, valueOne);
weakHashtable.put(keyTwo, valueTwo);
weakHashtable.put(keyThree, valueThree);
}
/** Tests public boolean contains(Object value) */
public void testContains() throws Exception {
assertFalse(weakHashtable.contains(new Long(1)));
assertFalse(weakHashtable.contains(new Long(2)));
assertFalse(weakHashtable.contains(new Long(3)));
assertTrue(weakHashtable.contains(new Long(100)));
assertTrue(weakHashtable.contains(new Long(200)));
assertTrue(weakHashtable.contains(new Long(300)));
assertFalse(weakHashtable.contains(new Long(400)));
}
/** Tests public boolean containsKey(Object key) */
public void testContainsKey() throws Exception {
assertTrue(weakHashtable.containsKey(new Long(1)));
assertTrue(weakHashtable.containsKey(new Long(2)));
assertTrue(weakHashtable.containsKey(new Long(3)));
assertFalse(weakHashtable.containsKey(new Long(100)));
assertFalse(weakHashtable.containsKey(new Long(200)));
assertFalse(weakHashtable.containsKey(new Long(300)));
assertFalse(weakHashtable.containsKey(new Long(400)));
}
/** Tests public boolean containsValue(Object value) */
public void testContainsValue() throws Exception {
assertFalse(weakHashtable.containsValue(new Long(1)));
assertFalse(weakHashtable.containsValue(new Long(2)));
assertFalse(weakHashtable.containsValue(new Long(3)));
assertTrue(weakHashtable.containsValue(new Long(100)));
assertTrue(weakHashtable.containsValue(new Long(200)));
assertTrue(weakHashtable.containsValue(new Long(300)));
assertFalse(weakHashtable.containsValue(new Long(400)));
}
/** Tests public Enumeration elements() */
public void testElements() throws Exception {
ArrayList elements = new ArrayList();
for (Enumeration e = weakHashtable.elements(); e.hasMoreElements();) {
elements.add(e.nextElement());
}
assertEquals(3, elements.size());
assertTrue(elements.contains(valueOne));
assertTrue(elements.contains(valueTwo));
assertTrue(elements.contains(valueThree));
}
/** Tests public Set entrySet() */
public void testEntrySet() throws Exception {
Set entrySet = weakHashtable.entrySet();
for (Iterator it = entrySet.iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
Object key = entry.getKey();
if (keyOne.equals(key)) {
assertEquals(valueOne, entry.getValue());
} else if (keyTwo.equals(key)) {
assertEquals(valueTwo, entry.getValue());
} else if (keyThree.equals(key)) {
assertEquals(valueThree, entry.getValue());
} else {
fail("Unexpected key");
}
}
}
/** Tests public Object get(Object key) */
public void testGet() throws Exception {
assertEquals(valueOne, weakHashtable.get(keyOne));
assertEquals(valueTwo, weakHashtable.get(keyTwo));
assertEquals(valueThree, weakHashtable.get(keyThree));
assertNull(weakHashtable.get(new Long(50)));
}
/** Tests public Enumeration keys() */
public void testKeys() throws Exception {
ArrayList keys = new ArrayList();
for (Enumeration e = weakHashtable.keys(); e.hasMoreElements();) {
keys.add(e.nextElement());
}
assertEquals(3, keys.size());
assertTrue(keys.contains(keyOne));
assertTrue(keys.contains(keyTwo));
assertTrue(keys.contains(keyThree));
}
/** Tests public Set keySet() */
public void testKeySet() throws Exception {
Set keySet = weakHashtable.keySet();
assertEquals(3, keySet.size());
assertTrue(keySet.contains(keyOne));
assertTrue(keySet.contains(keyTwo));
assertTrue(keySet.contains(keyThree));
}
/** Tests public Object put(Object key, Object value) */
public void testPut() throws Exception {
Long anotherKey = new Long(2004);
weakHashtable.put(anotherKey, new Long(1066));
assertEquals(new Long(1066), weakHashtable.get(anotherKey));
// Test compliance with the hashtable API re nulls
Exception caught = null;
try {
weakHashtable.put(null, new Object());
}
catch (Exception e) {
caught = e;
}
assertNotNull("did not throw an exception adding a null key", caught);
caught = null;
try {
weakHashtable.put(new Object(), null);
}
catch (Exception e) {
caught = e;
}
assertNotNull("did not throw an exception adding a null value", caught);
}
/** Tests public void putAll(Map t) */
public void testPutAll() throws Exception {
Map newValues = new HashMap();
Long newKey = new Long(1066);
Long newValue = new Long(1415);
newValues.put(newKey, newValue);
Long anotherNewKey = new Long(1645);
Long anotherNewValue = new Long(1815);
newValues.put(anotherNewKey, anotherNewValue);
weakHashtable.putAll(newValues);
assertEquals(5, weakHashtable.size());
assertEquals(newValue, weakHashtable.get(newKey));
assertEquals(anotherNewValue, weakHashtable.get(anotherNewKey));
}
/** Tests public Object remove(Object key) */
public void testRemove() throws Exception {
weakHashtable.remove(keyOne);
assertEquals(2, weakHashtable.size());
assertNull(weakHashtable.get(keyOne));
}
/** Tests public Collection values() */
public void testValues() throws Exception {
Collection values = weakHashtable.values();
assertEquals(3, values.size());
assertTrue(values.contains(valueOne));
assertTrue(values.contains(valueTwo));
assertTrue(values.contains(valueThree));
}
/**
* Disabled this test as it makes wrong assumptions wrt the GC.
* This test especially fails with:
*
* Java(TM) SE Runtime Environment (build pxi3260sr12-20121025_01(SR12))
* IBM J9 VM (build 2.4, JRE 1.6.0 IBM J9 2.4 Linux x86-32 jvmxi3260sr12-20121024_1
*/
public void xxxIgnoretestRelease() throws Exception {
assertNotNull(weakHashtable.get(new Long(1)));
ReferenceQueue testQueue = new ReferenceQueue();
WeakReference weakKeyOne = new WeakReference(keyOne, testQueue);
// lose our references
keyOne = null;
keyTwo = null;
keyThree = null;
valueOne = null;
valueTwo = null;
valueThree = null;
int iterations = 0;
int bytz = 2;
while(true) {
System.gc();
if(iterations++ > MAX_GC_ITERATIONS){
fail("Max iterations reached before resource released.");
}
if(weakHashtable.get(new Long(1)) == null) {
break;
} else {
// create garbage:
byte[] b = new byte[bytz];
bytz = bytz * 2;
}
}
// some JVMs seem to take a little time to put references on
// the reference queue once the reference has been collected
// need to think about whether this is enough to justify
// stepping through the collection each time...
while(testQueue.poll() == null) {}
// Test that the released objects are not taking space in the table
assertEquals("underlying table not emptied", 0, weakHashtable.size());
}
public static class StupidThread extends Thread {
public StupidThread(String name) {
super(name);
}
public void run() {
for (int i = 0; i < RUN_LOOPS; i++) {
hashtable.put("key" + ":" + i%10, Boolean.TRUE);
if(i%50 == 0) {
yield();
}
}
}
}
public void testLOGGING_119() throws Exception {
Thread [] t = new Thread[THREAD_COUNT];
for (int j=1; j <= OUTER_LOOP; j++) {
hashtable = new WeakHashtable();
for (int i = 0; i < t.length; i++) {
t[i] = new StupidThread("Thread:" + i);
t[i].setDaemon(true); // Otherwise we cannot exit
t[i].start();
}
for (int i = 0; i < t.length; i++) {
t[i].join(WAIT_FOR_THREAD_COMPLETION);
if (t[i].isAlive()) {
break; // at least one thread is stuck
}
}
int active=0;
for (int i = 0; i < t.length; i++) {
if (t[i].isAlive()) {
active++;
}
}
if (active > 0) {
fail("Attempt: " + j + " Stuck threads: " + active);
}
}
}
}

View File

@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.jdk14;
import junit.framework.Test;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* TestCase for Jdk14 logging when the commons-logging-api jar file is in
* the parent classpath and commons-logging.jar is in the child.
*/
public class CustomConfigAPITestCase extends CustomConfigTestCase {
public CustomConfigAPITestCase(String name) {
super(name);
}
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader parent = new PathableClassLoader(null);
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
// the TestHandler class must be accessable from the System classloader
// in order for java.util.logging.LogManager.readConfiguration to
// be able to instantiate it. And this test case must see the same
// class in order to be able to access its data. Yes this is ugly
// but the whole jdk14 API is a ******* mess anyway.
ClassLoader scl = ClassLoader.getSystemClassLoader();
loadTestHandler(HANDLER_NAME, scl);
parent.useExplicitLoader(HANDLER_NAME, scl);
parent.addLogicalLib("commons-logging-api");
PathableClassLoader child = new PathableClassLoader(parent);
child.addLogicalLib("testclasses");
child.addLogicalLib("commons-logging");
Class testClass = child.loadClass(CustomConfigAPITestCase.class.getName());
return new PathableTestSuite(testClass, child);
}
}

View File

@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.jdk14;
import junit.framework.Test;
import org.apache.commons.logging.PathableTestSuite;
import org.apache.commons.logging.PathableClassLoader;
/**
* TestCase for Jdk14 logging when the commons-logging jar file is in
* the parent classpath.
*/
public class CustomConfigFullTestCase extends CustomConfigTestCase {
public CustomConfigFullTestCase(String name) {
super(name);
}
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader parent = new PathableClassLoader(null);
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
// the TestHandler class must be accessable from the System classloader
// in order for java.util.logging.LogManager.readConfiguration to
// be able to instantiate it. And this test case must see the same
// class in order to be able to access its data. Yes this is ugly
// but the whole jdk14 API is a ******* mess anyway.
ClassLoader scl = ClassLoader.getSystemClassLoader();
loadTestHandler(HANDLER_NAME, scl);
parent.useExplicitLoader(HANDLER_NAME, scl);
parent.addLogicalLib("commons-logging");
PathableClassLoader child = new PathableClassLoader(parent);
child.addLogicalLib("testclasses");
Class testClass = child.loadClass(CustomConfigFullTestCase.class.getName());
return new PathableTestSuite(testClass, child);
}
}

View File

@ -0,0 +1,395 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.jdk14;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import junit.framework.Test;
import org.apache.commons.logging.DummyException;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* <p>TestCase for JDK 1.4 logging when running on a JDK 1.4 system with
* custom configuration, so that JDK 1.4 should be selected and an appropriate
* logger configured per the configuration properties.</p>
*
* @author Craig R. McClanahan
* @version $Revision: 1448063 $ $Date: 2013-02-20 11:01:41 +0100 (Wed, 20 Feb 2013) $
*/
public class CustomConfigTestCase extends DefaultConfigTestCase {
protected static final String HANDLER_NAME = "org.apache.commons.logging.jdk14.TestHandler";
// ----------------------------------------------------------- Constructors
/**
* <p>Construct a new instance of this test case.</p>
*
* @param name Name of the test case
*/
public CustomConfigTestCase(String name) {
super(name);
}
// ----------------------------------------------------- Instance Variables
/**
* <p>The customized <code>Handler</code> we will be using.</p>
*/
protected TestHandler handler = null;
/**
* <p>The underlying <code>Handler</code>s we will be using.</p>
*/
protected Handler handlers[] = null;
/**
* <p>The underlying <code>Logger</code> we will be using.</p>
*/
protected Logger logger = null;
/**
* <p>The underlying <code>LogManager</code> we will be using.</p>
*/
protected LogManager manager = null;
/**
* <p>The message levels that should have been logged.</p>
*/
protected Level testLevels[] =
{ Level.FINE, Level.INFO, Level.WARNING, Level.SEVERE, Level.SEVERE };
/**
* <p>The message strings that should have been logged.</p>
*/
protected String testMessages[] =
{ "debug", "info", "warn", "error", "fatal" };
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Given the name of a class that is somewhere in the classpath of the provided
* classloader, return the contents of the corresponding .class file.
*/
protected static byte[] readClass(String name, ClassLoader srcCL) throws Exception {
String resName = name.replace('.', '/') + ".class";
System.err.println("Trying to load resource [" + resName + "]");
InputStream is = srcCL.getResourceAsStream(resName);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.err.println("Reading resource [" + resName + "]");
byte[] buf = new byte[1000];
for(;;) {
int read = is.read(buf);
if (read <= 0) {
break;
}
baos.write(buf, 0, read);
}
is.close();
return baos.toByteArray();
}
/**
* Make a class available in the system classloader even when its classfile is
* not present in the classpath configured for that classloader. This only
* works for classes for which all dependencies are already loaded in
* that classloader.
*/
protected static void loadTestHandler(String className, ClassLoader targetCL) {
try {
targetCL.loadClass(className);
// fail("Class already in target classloader");
return;
} catch(ClassNotFoundException ex) {
// ok, go ahead and load it
}
try {
ClassLoader srcCL = CustomConfigAPITestCase.class.getClassLoader();
byte[] classData = readClass(className, srcCL);
Class[] params = new Class[] { String.class, classData.getClass(), Integer.TYPE, Integer.TYPE };
Method m = ClassLoader.class.getDeclaredMethod("defineClass", params);
Object[] args = new Object[4];
args[0] = className;
args[1] = classData;
args[2] = new Integer(0);
args[3] = new Integer(classData.length);
m.setAccessible(true);
m.invoke(targetCL, args);
} catch(Exception e) {
e.printStackTrace();
fail("Unable to load class " + className);
}
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
setUpManager
("org/apache/commons/logging/jdk14/CustomConfig.properties");
setUpLogger(this.getClass().getName());
setUpHandlers();
setUpFactory();
setUpLog(this.getClass().getName());
}
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader cl = new PathableClassLoader(null);
cl.useExplicitLoader("junit.", Test.class.getClassLoader());
// the TestHandler class must be accessable from the System classloader
// in order for java.util.logging.LogManager.readConfiguration to
// be able to instantiate it. And this test case must see the same
// class in order to be able to access its data. Yes this is ugly
// but the whole jdk14 API is a ******* mess anyway.
ClassLoader scl = ClassLoader.getSystemClassLoader();
loadTestHandler(HANDLER_NAME, scl);
cl.useExplicitLoader(HANDLER_NAME, scl);
cl.addLogicalLib("commons-logging");
cl.addLogicalLib("testclasses");
Class testClass = cl.loadClass(CustomConfigTestCase.class.getName());
return new PathableTestSuite(testClass, cl);
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
super.tearDown();
handlers = null;
logger = null;
manager = null;
}
// ----------------------------------------------------------- Test Methods
// Test logging message strings with exceptions
public void testExceptionMessages() throws Exception {
logExceptionMessages();
checkLogRecords(true);
}
// Test logging plain message strings
public void testPlainMessages() throws Exception {
logPlainMessages();
checkLogRecords(false);
}
// Test pristine Handlers instances
public void testPristineHandlers() {
assertNotNull(handlers);
assertEquals(1, handlers.length);
assertTrue(handlers[0] instanceof TestHandler);
assertNotNull(handler);
}
// Test pristine Logger instance
public void testPristineLogger() {
assertNotNull("Logger exists", logger);
assertEquals("Logger name", this.getClass().getName(), logger.getName());
// Assert which logging levels have been enabled
assertTrue(logger.isLoggable(Level.SEVERE));
assertTrue(logger.isLoggable(Level.WARNING));
assertTrue(logger.isLoggable(Level.INFO));
assertTrue(logger.isLoggable(Level.CONFIG));
assertTrue(logger.isLoggable(Level.FINE));
assertTrue(!logger.isLoggable(Level.FINER));
assertTrue(!logger.isLoggable(Level.FINEST));
}
// Test Serializability of Log instance
public void testSerializable() throws Exception {
super.testSerializable();
testExceptionMessages();
}
// -------------------------------------------------------- Support Methods
// Check the log instance
protected void checkLog() {
assertNotNull("Log exists", log);
assertEquals("Log class",
"org.apache.commons.logging.impl.Jdk14Logger",
log.getClass().getName());
// Assert which logging levels have been enabled
assertTrue(log.isFatalEnabled());
assertTrue(log.isErrorEnabled());
assertTrue(log.isWarnEnabled());
assertTrue(log.isInfoEnabled());
assertTrue(log.isDebugEnabled());
assertTrue(!log.isTraceEnabled());
}
// Check the recorded messages
protected void checkLogRecords(boolean thrown) {
Iterator records = handler.records();
for (int i = 0; i < testMessages.length; i++) {
assertTrue(records.hasNext());
LogRecord record = (LogRecord) records.next();
assertEquals("LogRecord level",
testLevels[i], record.getLevel());
assertEquals("LogRecord message",
testMessages[i], record.getMessage());
assertTrue("LogRecord class",
record.getSourceClassName().startsWith(
"org.apache.commons.logging.jdk14.CustomConfig"));
if (thrown) {
assertEquals("LogRecord method",
"logExceptionMessages",
record.getSourceMethodName());
} else {
assertEquals("LogRecord method",
"logPlainMessages",
record.getSourceMethodName());
}
if (thrown) {
assertNotNull("LogRecord thrown", record.getThrown());
assertTrue("LogRecord thrown type",
record.getThrown() instanceof DummyException);
} else {
assertNull("LogRecord thrown",
record.getThrown());
}
}
assertTrue(!records.hasNext());
handler.flush();
}
// Log the messages with exceptions
protected void logExceptionMessages() {
Throwable t = new DummyException();
log.trace("trace", t); // Should not actually get logged
log.debug("debug", t);
log.info("info", t);
log.warn("warn", t);
log.error("error", t);
log.fatal("fatal", t);
}
// Log the plain messages
protected void logPlainMessages() {
log.trace("trace"); // Should not actually get logged
log.debug("debug");
log.info("info");
log.warn("warn");
log.error("error");
log.fatal("fatal");
}
// Set up handlers instance
protected void setUpHandlers() throws Exception {
Logger parent = logger;
while (parent.getParent() != null) {
parent = parent.getParent();
}
handlers = parent.getHandlers();
// The CustomConfig.properties file explicitly defines one handler class
// to be attached to the root logger, so if it isn't there then
// something is badly wrong...
//
// Yes this testing is also done in testPristineHandlers but
// unfortunately:
// * we need to set up the handlers variable here,
// * we don't want that to be set up incorrectly, as that can
// produce weird error messages in other tests, and
// * we can't rely on testPristineHandlers being the first
// test to run.
// so we need to test things here too.
assertNotNull("No Handlers defined for JDK14 logging", handlers);
assertEquals("Unexpected number of handlers for JDK14 logging", 1, handlers.length);
assertNotNull("Handler is null", handlers[0]);
assertTrue("Handler not of expected type", handlers[0] instanceof TestHandler);
handler = (TestHandler) handlers[0];
}
// Set up logger instance
protected void setUpLogger(String name) throws Exception {
logger = Logger.getLogger(name);
}
// Set up LogManager instance
protected void setUpManager(String config) throws Exception {
manager = LogManager.getLogManager();
InputStream is =
this.getClass().getClassLoader().getResourceAsStream(config);
manager.readConfiguration(is);
is.close();
}
}

View File

@ -0,0 +1,191 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.jdk14;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* <p>TestCase for JDK 1.4 logging when running on a JDK 1.4 system with
* zero configuration, and with Log4J not present (so JDK 1.4 logging
* should be automatically configured.</p>
*
* @author Craig R. McClanahan
* @version $Revision: 1432587 $ $Date: 2013-01-13 12:11:32 +0100 (Sun, 13 Jan 2013) $
*/
public class DefaultConfigTestCase extends TestCase {
// ----------------------------------------------------------- Constructors
/**
* <p>Construct a new instance of this test case.</p>
*
* @param name Name of the test case
*/
public DefaultConfigTestCase(String name) {
super(name);
}
// ----------------------------------------------------- Instance Variables
/**
* <p>The {@link LogFactory} implementation we have selected.</p>
*/
protected LogFactory factory = null;
/**
* <p>The {@link Log} implementation we have selected.</p>
*/
protected Log log = null;
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
setUpFactory();
setUpLog("TestLogger");
}
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader loader = new PathableClassLoader(null);
loader.useExplicitLoader("junit.", Test.class.getClassLoader());
loader.addLogicalLib("testclasses");
loader.addLogicalLib("commons-logging");
Class testClass = loader.loadClass(DefaultConfigTestCase.class.getName());
return new PathableTestSuite(testClass, loader);
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
log = null;
factory = null;
LogFactory.releaseAll();
}
// ----------------------------------------------------------- Test Methods
// Test pristine Log instance
public void testPristineLog() {
checkLog();
}
// Test pristine LogFactory instance
public void testPristineFactory() {
assertNotNull("LogFactory exists", factory);
assertEquals("LogFactory class",
"org.apache.commons.logging.impl.LogFactoryImpl",
factory.getClass().getName());
String names[] = factory.getAttributeNames();
assertNotNull("Names exists", names);
assertEquals("Names empty", 0, names.length);
}
// Test Serializability of Log instance
public void testSerializable() throws Exception {
// Serialize and deserialize the instance
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(log);
oos.close();
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
log = (Log) ois.readObject();
ois.close();
// Check the characteristics of the resulting object
checkLog();
}
// -------------------------------------------------------- Support Methods
// Check the log instance
protected void checkLog() {
assertNotNull("Log exists", log);
assertEquals("Log class",
"org.apache.commons.logging.impl.Jdk14Logger",
log.getClass().getName());
// Can we call level checkers with no exceptions?
log.isDebugEnabled();
log.isErrorEnabled();
log.isFatalEnabled();
log.isInfoEnabled();
log.isTraceEnabled();
log.isWarnEnabled();
}
// Set up factory instance
protected void setUpFactory() throws Exception {
factory = LogFactory.getFactory();
}
// Set up log instance
protected void setUpLog(String name) throws Exception {
log = LogFactory.getLog(name);
}
}

View File

@ -0,0 +1,70 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.jdk14;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
/**
* <p>Test implementation of <code>java.util.logging.Handler</code>.</p>
*
* @author Craig R. McClanahan
* @version $Revision: 1432587 $ $Date: 2013-01-13 12:11:32 +0100 (Sun, 13 Jan 2013) $
*/
public class TestHandler extends Handler {
// ----------------------------------------------------- Instance Variables
// The set of logged records for this handler
private final List records = new ArrayList();
// --------------------------------------------------------- Public Methods
public Iterator records() {
return records.iterator();
}
// -------------------------------------------------------- Handler Methods
public void close() {
}
public void flush() {
records.clear();
}
public void publish(LogRecord record) {
records.add(record);
}
}

View File

@ -0,0 +1,216 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.log4j;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.apache.commons.logging.DummyException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Abstract set of tests that can be executed with various classpaths set.
* <p>
* The tests verify that when running on a system with Log4J present,
* Log4J is selected and that the logger basically works.
*/
public abstract class StandardTests extends TestCase {
/**
* Simple structure to store information about messages that actually get
* logged by the underlying logging library.
*/
public static class LogEvent {
public String msg;
public String level;
public Throwable throwable;
}
// -------------------------------------------------------------------
// JUnit Infrastructure Methods
// -------------------------------------------------------------------
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
LogFactory.releaseAll();
}
// -----------------------------------------------------------
// abstract methods
// -----------------------------------------------------------
/**
* Modify log4j's setup so that all messages actually logged get redirected
* into the specified list.
* <p>
* This method also sets the logging level to INFO so that we
* can test whether messages are getting properly filtered.
*/
public abstract void setUpTestAppender(List logEvents) throws Exception;
// ----------------------------------------------------------- Test Methods
/**
* Test that a LogFactory gets created as expected.
*/
public void testCreateFactory() {
LogFactory factory = LogFactory.getFactory();
assertNotNull("LogFactory exists", factory);
assertEquals("LogFactory class",
"org.apache.commons.logging.impl.LogFactoryImpl",
factory.getClass().getName());
String names[] = factory.getAttributeNames();
assertNotNull("Names exists", names);
assertEquals("Names empty", 0, names.length);
}
/**
* Verify that we can log messages without exceptions.
*/
public void testPlainMessages() throws Exception {
List logEvents = new ArrayList();
setUpTestAppender(logEvents);
Log log = LogFactory.getLog("test-category");
logPlainMessages(log);
checkLoggingEvents(logEvents, false);
}
/**
* Verify that we can log exception messages.
*/
public void testExceptionMessages() throws Exception {
List logEvents = new ArrayList();
setUpTestAppender(logEvents);
Log log = LogFactory.getLog("test-category");
logExceptionMessages(log);
checkLoggingEvents(logEvents, true);
}
/**
* Test Serializability of Log instance
*/
public void testSerializable() throws Exception {
List logEvents = new ArrayList();
setUpTestAppender(logEvents);
Log log = LogFactory.getLog("test-category");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(log);
oos.close();
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Log newLog = (Log) ois.readObject();
ois.close();
// Check the characteristics of the resulting object
logExceptionMessages(newLog);
checkLoggingEvents(logEvents, true);
}
// -------------------------------------------------------- Support Methods
/**
* Verify that the TestAppender has received the expected
* number of messages. This assumes that:
* <ul>
* <li>setUpTestAppender has been called
* <li>logPlainMessages or logExceptionMessages has been
* called to log a known number of messages at known levels.
* </ul>
*
* @param logEvents is the list of log events received.
*
* @param thrown False if logPlainMessages was called
* (ie the TestAppender is expected to have received
* logevents with no associated exception info). True if
* logExceptionMessages was called.
*/
private void checkLoggingEvents(List logEvents, boolean thrown) {
LogEvent ev;
assertEquals("Unexpected number of log events", 4, logEvents.size());
ev = (LogEvent) logEvents.get(0);
assertEquals("Info message expected", "info", ev.msg);
assertEquals("Info level expected", "INFO", ev.level);
assertEquals("Exception data incorrect", ev.throwable!=null, thrown);
ev = (LogEvent) logEvents.get(1);
assertEquals("Warn message expected", "warn", ev.msg);
assertEquals("Warn level expected", "WARN", ev.level);
assertEquals("Exception data incorrect", ev.throwable!=null, thrown);
ev = (LogEvent) logEvents.get(2);
assertEquals("Error message expected", "error", ev.msg);
assertEquals("Error level expected", "ERROR", ev.level);
assertEquals("Exception data incorrect", ev.throwable!=null, thrown);
ev = (LogEvent) logEvents.get(3);
assertEquals("Fatal message expected", "fatal", ev.msg);
assertEquals("Fatal level expected", "FATAL", ev.level);
assertEquals("Exception data incorrect", ev.throwable!=null, thrown);
}
/**
* Log plain messages.
*/
private void logPlainMessages(Log log) {
log.trace("trace"); // Should not actually get logged
log.debug("debug"); // Should not actually get logged
log.info("info");
log.warn("warn");
log.error("error");
log.fatal("fatal");
}
/**
* Log messages with exceptions
*/
private void logExceptionMessages(Log log) {
Throwable t = new DummyException();
log.trace("trace", t); // Should not actually get logged
log.debug("debug", t); // Should not actually get logged
log.info("info", t);
log.warn("warn", t);
log.error("error", t);
log.fatal("fatal", t);
}
}

View File

@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.log4j.log4j12;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests for Log4J logging that emulate a webapp running within
* a container where the commons-logging-api jar file is in
* the parent classpath and commons-logging.jar is in the child.
*/
public class ApiClasspathStandardTestCase extends TestCase {
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader parent = new PathableClassLoader(null);
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
parent.addLogicalLib("commons-logging-api");
PathableClassLoader child = new PathableClassLoader(parent);
child.addLogicalLib("log4j12");
child.addLogicalLib("commons-logging");
child.addLogicalLib("testclasses");
Class testClass = child.loadClass(
"org.apache.commons.logging.log4j.log4j12.Log4j12StandardTests");
return new PathableTestSuite(testClass, child);
}
}

View File

@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.log4j.log4j12;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests for Log4J logging when there is only one classloader and everything
* is in it, as would be the situation for a standalone application.
*/
public class AppClasspathStandardTestCase extends TestCase {
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader loader = new PathableClassLoader(null);
loader.useExplicitLoader("junit.", Test.class.getClassLoader());
loader.addLogicalLib("testclasses");
loader.addLogicalLib("log4j12");
loader.addLogicalLib("commons-logging");
Class testClass = loader.loadClass(
"org.apache.commons.logging.log4j.log4j12.Log4j12StandardTests");
return new PathableTestSuite(testClass, loader);
}
}

View File

@ -0,0 +1,50 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.log4j.log4j12;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests for Log4J logging that emulate a webapp running within
* a container where all the necessary libs are in the child.
*/
public class ChildClasspathStandardTestCase extends TestCase {
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader parent = new PathableClassLoader(null);
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
PathableClassLoader child = new PathableClassLoader(parent);
child.addLogicalLib("testclasses");
child.addLogicalLib("log4j12");
child.addLogicalLib("commons-logging");
Class testClass = child.loadClass(
"org.apache.commons.logging.log4j.log4j12.Log4j12StandardTests");
return new PathableTestSuite(testClass, child);
}
}

View File

@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.log4j.log4j12;
import java.util.List;
import org.apache.commons.logging.log4j.StandardTests;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
/**
* A concrete class that runs the standard tests, and is compiled
* specifically against log4j12. The parent class can't call any
* log4j methods at all as that would mean it has to be compiled
* against a particular version of log4j.
*/
public class Log4j12StandardTests extends StandardTests {
public void setUpTestAppender(List logEvents) {
TestAppender appender = new TestAppender(logEvents);
Logger rootLogger = Logger.getRootLogger();
rootLogger.removeAllAppenders();
rootLogger.addAppender(appender);
rootLogger.setLevel(Level.INFO);
}
}

View File

@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.log4j.log4j12;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests for Log4J logging that emulate a webapp running within
* a container where all the necessary libs are in the parent.
*/
public class ParentClasspathStandardTestCase extends TestCase {
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader parent = new PathableClassLoader(null);
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
parent.addLogicalLib("commons-logging");
parent.addLogicalLib("log4j12");
PathableClassLoader child = new PathableClassLoader(parent);
child.addLogicalLib("testclasses");
Class testClass = child.loadClass(
"org.apache.commons.logging.log4j.log4j12.Log4j12StandardTests");
return new PathableTestSuite(testClass, child);
}
}

View File

@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.log4j.log4j12;
import java.util.List;
import org.apache.commons.logging.log4j.StandardTests;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
/**
* A custom implementation of <code>org.apache.log4j.Appender</code> which
* converts the log4j-specific log event record into a representation that
* doesn't have a dependency on log4j and stores that new representation into
* an external list.
*/
public class TestAppender extends AppenderSkeleton {
/**
* Constructor.
*/
public TestAppender(List logEvents) {
events = logEvents;
}
// ----------------------------------------------------- Instance Variables
// The set of logged events for this appender
private final List events;
// ------------------------------------------------------- Appender Methods
protected void append(LoggingEvent event) {
StandardTests.LogEvent lev = new StandardTests.LogEvent();
lev.level = event.getLevel().toString();
if (event.getMessage() == null) {
lev.msg = null;
} else {
lev.msg = event.getMessage().toString();
}
if (event.getThrowableInformation() == null) {
lev.throwable = null;
} else {
lev.throwable = event.getThrowableInformation().getThrowable();
}
events.add(lev);
}
public void close() {
}
public boolean requiresLayout() {
return false;
}
}

View File

@ -0,0 +1,166 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.logkit;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import junit.framework.Test;
import org.apache.commons.logging.AbstractLogTest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
import org.apache.commons.logging.impl.LogKitLogger;
/**
* Basic tests for Avalon LogKit logger adapter.
*/
public class StandardTestCase extends AbstractLogTest {
// ----------------------------------------------------- Instance Variables
/**
* <p>The {@link LogFactory} implementation we have selected.</p>
*/
protected LogFactory factory = null;
/**
* <p>The {@link Log} implementation we have selected.</p>
*/
protected Log log = null;
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
Class thisClass = StandardTestCase.class;
PathableClassLoader loader = new PathableClassLoader(null);
loader.useExplicitLoader("junit.", Test.class.getClassLoader());
loader.addLogicalLib("testclasses");
loader.addLogicalLib("commons-logging");
loader.addLogicalLib("logkit");
Class testClass = loader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, loader);
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
System.setProperty(
"org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.LogKitLogger");
factory = LogFactory.getFactory();
log = LogFactory.getLog("TestLogger");
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
log = null;
factory = null;
LogFactory.releaseAll();
}
// ----------------------------------------------------------- Test Methods
/**
* Override the abstract method from the parent class so that the
* inherited tests can access the right Log object type.
*/
public Log getLogObject()
{
return new LogKitLogger(this.getClass().getName());
}
// Test pristine LogFactory instance
public void testPristineFactory() {
assertNotNull("LogFactory exists", factory);
assertEquals("LogFactory class",
"org.apache.commons.logging.impl.LogFactoryImpl",
factory.getClass().getName());
String names[] = factory.getAttributeNames();
assertNotNull("Names exists", names);
assertEquals("Names empty", 0, names.length);
}
// Test pristine Log instance
public void testPristineLog() {
checkStandard();
}
// Test Serializability of standard instance
public void testSerializable() throws Exception {
checkStandard();
// Serialize and deserialize the instance
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(log);
oos.close();
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
log = (Log) ois.readObject();
ois.close();
checkStandard();
}
// -------------------------------------------------------- Support Methods
// Check the standard log instance
protected void checkStandard() {
assertNotNull("Log exists", log);
assertEquals("Log class",
"org.apache.commons.logging.impl.LogKitLogger",
log.getClass().getName());
// Can we call level checkers with no exceptions?
// Note that by default *everything* is enabled for LogKit
assertTrue(log.isTraceEnabled());
assertTrue(log.isDebugEnabled());
assertTrue(log.isInfoEnabled());
assertTrue(log.isWarnEnabled());
assertTrue(log.isErrorEnabled());
assertTrue(log.isFatalEnabled());
}
}

View File

@ -0,0 +1,103 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.noop;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.impl.NoOpLog;
import org.apache.commons.logging.AbstractLogTest;
/**
* Tests for NoOpLog logging adapter.
* <p>
* This simply applies the tests defined in AbstractLogTest to this class.
*/
public class NoOpLogTestCase extends AbstractLogTest
{
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
System.setProperty(
"org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.NoOpLog");
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
LogFactory.releaseAll();
System.getProperties().remove("org.apache.commons.logging.Log");
}
/**
* Override the abstract method from the parent class so that the
* inherited tests can access the right Log object type.
*/
public Log getLogObject()
{
return new NoOpLog(this.getClass().getName());
}
// Test Serializability of standard instance
public void testSerializable() throws Exception {
Log log = LogFactory.getLog(this.getClass().getName());
checkLog(log);
// Serialize and deserialize the instance
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(log);
oos.close();
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
log = (Log) ois.readObject();
ois.close();
checkLog(log);
}
// -------------------------------------------------------- Support Methods
private void checkLog(Log log) {
assertNotNull("Log exists", log);
assertEquals("Log class",
"org.apache.commons.logging.impl.NoOpLog",
log.getClass().getName());
// Can we call level checkers with no exceptions?
// Note that *everything* is permanently disabled for NoOpLog
assertFalse(log.isTraceEnabled());
assertFalse(log.isDebugEnabled());
assertFalse(log.isInfoEnabled());
assertFalse(log.isWarnEnabled());
assertFalse(log.isErrorEnabled());
assertFalse(log.isFatalEnabled());
}
}

View File

@ -0,0 +1,317 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.pathable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests for the PathableTestSuite and PathableClassLoader functionality,
* where lookup order for the PathableClassLoader is child-first.
* <p>
* These tests assume:
* <ul>
* <li>junit is in system classpath
* <li>nothing else is in system classpath
* </ul>
*/
public class ChildFirstTestCase extends TestCase {
/**
* Set up a custom classloader hierarchy for this test case.
* The hierarchy is:
* <ul>
* <li> contextloader: child-first.
* <li> childloader: child-first, used to load test case.
* <li> parentloader: child-first, parent is the bootclassloader.
* </ul>
*/
public static Test suite() throws Exception {
Class thisClass = ChildFirstTestCase.class;
ClassLoader thisClassLoader = thisClass.getClassLoader();
// Make the parent a direct child of the bootloader to hide all
// other classes in the system classpath
PathableClassLoader parent = new PathableClassLoader(null);
parent.setParentFirst(false);
// Make the junit classes visible as a special case, as junit
// won't be able to call this class at all without this. The
// junit classes must be visible from the classloader that loaded
// this class, so use that as the source for future access to classes
// from the junit package.
parent.useExplicitLoader("junit.", thisClassLoader);
// Make the commons-logging.jar classes visible via the parent
parent.addLogicalLib("commons-logging");
// Create a child classloader to load the test case through
PathableClassLoader child = new PathableClassLoader(parent);
child.setParentFirst(false);
// Obviously, the child classloader needs to have the test classes
// in its path!
child.addLogicalLib("testclasses");
child.addLogicalLib("commons-logging-adapters");
// Create a third classloader to be the context classloader.
PathableClassLoader context = new PathableClassLoader(child);
context.setParentFirst(false);
// reload this class via the child classloader
Class testClass = child.loadClass(thisClass.getName());
// and return our custom TestSuite class
return new PathableTestSuite(testClass, context);
}
/**
* Utility method to return the set of all classloaders in the
* parent chain starting from the one that loaded the class for
* this object instance.
*/
private Set getAncestorCLs() {
Set s = new HashSet();
ClassLoader cl = this.getClass().getClassLoader();
while (cl != null) {
s.add(cl);
cl = cl.getParent();
}
return s;
}
/**
* Test that the classloader hierarchy is as expected, and that
* calling loadClass() on various classloaders works as expected.
* Note that for this test case, parent-first classloading is
* in effect.
*/
public void testPaths() throws Exception {
// the context classloader is not expected to be null
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
assertNotNull("Context classloader is null", contextLoader);
assertEquals("Context classloader has unexpected type",
PathableClassLoader.class.getName(),
contextLoader.getClass().getName());
// the classloader that loaded this class is obviously not null
ClassLoader thisLoader = this.getClass().getClassLoader();
assertNotNull("thisLoader is null", thisLoader);
assertEquals("thisLoader has unexpected type",
PathableClassLoader.class.getName(),
thisLoader.getClass().getName());
// the suite method specified that the context classloader's parent
// is the loader that loaded this test case.
assertSame("Context classloader is not child of thisLoader",
thisLoader, contextLoader.getParent());
// thisLoader's parent should be available
ClassLoader parentLoader = thisLoader.getParent();
assertNotNull("Parent classloader is null", parentLoader);
assertEquals("Parent classloader has unexpected type",
PathableClassLoader.class.getName(),
parentLoader.getClass().getName());
// parent should have a parent of null
assertNull("Parent classloader has non-null parent", parentLoader.getParent());
// getSystemClassloader is not a PathableClassLoader; it's of a
// built-in type. This also verifies that system classloader is none of
// (context, child, parent).
ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
assertNotNull("System classloader is null", systemLoader);
assertFalse("System classloader has unexpected type",
PathableClassLoader.class.getName().equals(
systemLoader.getClass().getName()));
// junit classes should be visible; their classloader is not
// in the hierarchy of parent classloaders for this class,
// though it is accessable due to trickery in the PathableClassLoader.
Class junitTest = contextLoader.loadClass("junit.framework.Test");
Set ancestorCLs = getAncestorCLs();
assertFalse("Junit not loaded by ancestor classloader",
ancestorCLs.contains(junitTest.getClassLoader()));
// jcl api classes should be visible only via the parent
Class logClass = contextLoader.loadClass("org.apache.commons.logging.Log");
assertSame("Log class not loaded via parent",
logClass.getClassLoader(), parentLoader);
// jcl adapter classes should be visible via both parent and child. However
// as the classloaders are child-first we should see the child one.
Class log4jClass = contextLoader.loadClass("org.apache.commons.logging.impl.Log4JLogger");
assertSame("Log4JLogger not loaded via child",
log4jClass.getClassLoader(), thisLoader);
// test classes should be visible via the child only
Class testClass = contextLoader.loadClass("org.apache.commons.logging.PathableTestSuite");
assertSame("PathableTestSuite not loaded via child",
testClass.getClassLoader(), thisLoader);
// test loading of class that is not available
try {
Class noSuchClass = contextLoader.loadClass("no.such.class");
fail("Class no.such.class is unexpectedly available");
assertNotNull(noSuchClass); // silence warning about unused var
} catch(ClassNotFoundException ex) {
// ok
}
// String class classloader is null
Class stringClass = contextLoader.loadClass("java.lang.String");
assertNull("String class classloader is not null!",
stringClass.getClassLoader());
}
/**
* Test that the various flavours of ClassLoader.getResource work as expected.
*/
public void testResource() {
URL resource;
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
ClassLoader childLoader = contextLoader.getParent();
// getResource where it doesn't exist
resource = childLoader.getResource("nosuchfile");
assertNull("Non-null URL returned for invalid resource name", resource);
// getResource where it is accessable only to parent classloader
resource = childLoader.getResource("org/apache/commons/logging/Log.class");
assertNotNull("Unable to locate Log.class resource", resource);
// getResource where it is accessable only to child classloader
resource = childLoader.getResource("org/apache/commons/logging/PathableTestSuite.class");
assertNotNull("Unable to locate PathableTestSuite.class resource", resource);
// getResource where it is accessable to both classloaders. The one visible
// to the child should be returned. The URL returned will be of form
// jar:file:/x/y.jar!path/to/resource. The filename part should include the jarname
// of form commons-logging-adapters-nnnn.jar, not commons-logging-nnnn.jar
resource = childLoader.getResource("org/apache/commons/logging/impl/Log4JLogger.class");
assertNotNull("Unable to locate Log4JLogger.class resource", resource);
assertTrue("Incorrect source for Log4JLogger class",
resource.toString().indexOf("/commons-logging-adapters-1.") > 0);
}
/**
* Test that the various flavours of ClassLoader.getResources work as expected.
*/
public void testResources() throws Exception {
Enumeration resources;
URL[] urls;
// verify the classloader hierarchy
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
ClassLoader childLoader = contextLoader.getParent();
ClassLoader parentLoader = childLoader.getParent();
ClassLoader bootLoader = parentLoader.getParent();
assertNull("Unexpected classloader hierarchy", bootLoader);
// getResources where no instances exist
resources = childLoader.getResources("nosuchfile");
urls = toURLArray(resources);
assertEquals("Non-null URL returned for invalid resource name", 0, urls.length);
// getResources where the resource only exists in the parent
resources = childLoader.getResources("org/apache/commons/logging/Log.class");
urls = toURLArray(resources);
assertEquals("Unexpected number of Log.class resources found", 1, urls.length);
// getResources where the resource only exists in the child
resources = childLoader.getResources("org/apache/commons/logging/PathableTestSuite.class");
urls = toURLArray(resources);
assertEquals("Unexpected number of PathableTestSuite.class resources found", 1, urls.length);
// getResources where the resource exists in both.
// resources should be returned in order (child-resource, parent-resource).
//
// IMPORTANT: due to the fact that in java 1.4 and earlier method
// ClassLoader.getResources is final it isn't possible for PathableClassLoader
// to override this. So even when child-first is enabled the resource order
// is still (parent-resources, child-resources). This test verifies the expected
// behaviour - even though it's not the desired behaviour.
resources = childLoader.getResources("org/apache/commons/logging/impl/Log4JLogger.class");
urls = toURLArray(resources);
assertEquals("Unexpected number of Log4JLogger.class resources found", 2, urls.length);
// There is no guarantee about the ordering of results returned from getResources
// To make this test portable across JVMs, sort the string to give them a known order
String[] urlsToStrings = new String[2];
urlsToStrings[0] = urls[0].toString();
urlsToStrings[1] = urls[1].toString();
Arrays.sort(urlsToStrings);
assertTrue("Incorrect source for Log4JLogger class",
urlsToStrings[0].indexOf("/commons-logging-1.") > 0);
assertTrue("Incorrect source for Log4JLogger class",
urlsToStrings[1].indexOf("/commons-logging-adapters-1.") > 0);
}
/**
* Utility method to convert an enumeration-of-URLs into an array of URLs.
*/
private static URL[] toURLArray(Enumeration e) {
ArrayList l = new ArrayList();
while (e.hasMoreElements()) {
URL u = (URL) e.nextElement();
l.add(u);
}
URL[] tmp = new URL[l.size()];
return (URL[]) l.toArray(tmp);
}
/**
* Test that getResourceAsStream works.
*/
public void testResourceAsStream() throws Exception {
java.io.InputStream is;
// verify the classloader hierarchy
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
ClassLoader childLoader = contextLoader.getParent();
ClassLoader parentLoader = childLoader.getParent();
ClassLoader bootLoader = parentLoader.getParent();
assertNull("Unexpected classloader hierarchy", bootLoader);
// getResourceAsStream where no instances exist
is = childLoader.getResourceAsStream("nosuchfile");
assertNull("Invalid resource returned non-null stream", is);
// getResourceAsStream where resource does exist
is = childLoader.getResourceAsStream("org/apache/commons/logging/Log.class");
assertNotNull("Null returned for valid resource", is);
is.close();
// It would be nice to test parent-first ordering here, but that would require
// having a resource with the same name in both the parent and child loaders,
// but with different contents. That's a little tricky to set up so we'll
// skip that for now.
}
}

View File

@ -0,0 +1,120 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.pathable;
import java.net.URL;
import java.net.URLClassLoader;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests for the PathableTestSuite class.
*/
public class GeneralTestCase extends TestCase {
/**
* Set up a custom classloader hierarchy for this test case.
*/
public static Test suite() throws Exception {
Class thisClass = GeneralTestCase.class;
ClassLoader thisClassLoader = thisClass.getClassLoader();
PathableClassLoader loader = new PathableClassLoader(null);
loader.useExplicitLoader("junit.", thisClassLoader);
loader.addLogicalLib("testclasses");
// reload this class via the child classloader
Class testClass = loader.loadClass(thisClass.getName());
// and return our custom TestSuite class
return new PathableTestSuite(testClass, loader);
}
/**
* Verify that a certain system property is not set, then set it.
*/
private static void checkAndSetProperties() {
String prop = System.getProperty("no.such.property");
assertNull("no.such.property is unexpectedly defined", prop);
System.setProperty("no.such.property", "dummy value");
prop = System.getProperty("no.such.property");
assertNotNull("no.such.property is unexpectedly undefined", prop);
}
/**
* Verify that when a test method modifies the system properties they are
* reset before the next test is run.
* <p>
* This method works in conjunction with testResetProps2. There is no
* way of knowing which test method junit will run first, but it doesn't
* matter; whichever one of them runs first will modify the system properties.
* If the PathableTestSuite isn't resetting the system properties then whichever
* of them runs second will fail. Of course if other methods are run in-between
* then those methods might also fail...
*/
public void testResetProps1() {
checkAndSetProperties();
}
/**
* See testResetProps1.
*/
public void testResetProps2() {
checkAndSetProperties();
}
/**
* Verify that the context classloader is a custom one, then reset it to
* a non-custom one.
*/
private static void checkAndSetContext() {
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
assertEquals("ContextLoader is of unexpected type",
contextLoader.getClass().getName(),
PathableClassLoader.class.getName());
URL[] noUrls = new URL[0];
Thread.currentThread().setContextClassLoader(new URLClassLoader(noUrls));
}
/**
* Verify that when a test method modifies the context classloader it is
* reset before the next test is run.
* <p>
* This method works in conjunction with testResetContext2. There is no
* way of knowing which test method junit will run first, but it doesn't
* matter; whichever one of them runs first will modify the contextClassloader.
* If the PathableTestSuite isn't resetting the contextClassLoader then whichever
* of them runs second will fail. Of course if other methods are run in-between
* then those methods might also fail...
*/
public void testResetContext1() {
checkAndSetContext();
}
/**
* See testResetContext1.
*/
public void testResetContext2() {
checkAndSetContext();
}
}

View File

@ -0,0 +1,308 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.pathable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests for the PathableTestSuite and PathableClassLoader functionality,
* where lookup order for the PathableClassLoader is parent-first.
* <p>
* These tests assume:
* <ul>
* <li>junit is in system classpath
* <li>nothing else is in system classpath
* </ul>
*/
public class ParentFirstTestCase extends TestCase {
/**
* Set up a custom classloader hierarchy for this test case.
* The hierarchy is:
* <ul>
* <li> contextloader: parent-first.
* <li> childloader: parent-first, used to load test case.
* <li> parentloader: parent-first, parent is the bootclassloader.
* </ul>
*/
public static Test suite() throws Exception {
Class thisClass = ParentFirstTestCase.class;
ClassLoader thisClassLoader = thisClass.getClassLoader();
// Make the parent a direct child of the bootloader to hide all
// other classes in the system classpath
PathableClassLoader parent = new PathableClassLoader(null);
// Make the junit classes visible as a special case, as junit
// won't be able to call this class at all without this. The
// junit classes must be visible from the classloader that loaded
// this class, so use that as the source for future access to classes
// from the junit package.
parent.useExplicitLoader("junit.", thisClassLoader);
// make the commons-logging.jar classes visible via the parent
parent.addLogicalLib("commons-logging");
// create a child classloader to load the test case through
PathableClassLoader child = new PathableClassLoader(parent);
// obviously, the child classloader needs to have the test classes
// in its path!
child.addLogicalLib("testclasses");
child.addLogicalLib("commons-logging-adapters");
// create a third classloader to be the context classloader.
PathableClassLoader context = new PathableClassLoader(child);
// reload this class via the child classloader
Class testClass = child.loadClass(thisClass.getName());
// and return our custom TestSuite class
return new PathableTestSuite(testClass, context);
}
/**
* Utility method to return the set of all classloaders in the
* parent chain starting from the one that loaded the class for
* this object instance.
*/
private Set getAncestorCLs() {
Set s = new HashSet();
ClassLoader cl = this.getClass().getClassLoader();
while (cl != null) {
s.add(cl);
cl = cl.getParent();
}
return s;
}
/**
* Test that the classloader hierarchy is as expected, and that
* calling loadClass() on various classloaders works as expected.
* Note that for this test case, parent-first classloading is
* in effect.
*/
public void testPaths() throws Exception {
// the context classloader is not expected to be null
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
assertNotNull("Context classloader is null", contextLoader);
assertEquals("Context classloader has unexpected type",
PathableClassLoader.class.getName(),
contextLoader.getClass().getName());
// the classloader that loaded this class is obviously not null
ClassLoader thisLoader = this.getClass().getClassLoader();
assertNotNull("thisLoader is null", thisLoader);
assertEquals("thisLoader has unexpected type",
PathableClassLoader.class.getName(),
thisLoader.getClass().getName());
// the suite method specified that the context classloader's parent
// is the loader that loaded this test case.
assertSame("Context classloader is not child of thisLoader",
thisLoader, contextLoader.getParent());
// thisLoader's parent should be available
ClassLoader parentLoader = thisLoader.getParent();
assertNotNull("Parent classloader is null", parentLoader);
assertEquals("Parent classloader has unexpected type",
PathableClassLoader.class.getName(),
parentLoader.getClass().getName());
// parent should have a parent of null
assertNull("Parent classloader has non-null parent", parentLoader.getParent());
// getSystemClassloader is not a PathableClassLoader; it's of a
// built-in type. This also verifies that system classloader is none of
// (context, child, parent).
ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
assertNotNull("System classloader is null", systemLoader);
assertFalse("System classloader has unexpected type",
PathableClassLoader.class.getName().equals(
systemLoader.getClass().getName()));
// junit classes should be visible; their classloader is not
// in the hierarchy of parent classloaders for this class,
// though it is accessable due to trickery in the PathableClassLoader.
Class junitTest = contextLoader.loadClass("junit.framework.Test");
Set ancestorCLs = getAncestorCLs();
assertFalse("Junit not loaded by ancestor classloader",
ancestorCLs.contains(junitTest.getClassLoader()));
// jcl api classes should be visible only via the parent
Class logClass = contextLoader.loadClass("org.apache.commons.logging.Log");
assertSame("Log class not loaded via parent",
logClass.getClassLoader(), parentLoader);
// jcl adapter classes should be visible via both parent and child. However
// as the classloaders are parent-first we should see the parent one.
Class log4jClass = contextLoader.loadClass("org.apache.commons.logging.impl.Log4JLogger");
assertSame("Log4JLogger not loaded via parent",
log4jClass.getClassLoader(), parentLoader);
// test classes should be visible via the child only
Class testClass = contextLoader.loadClass("org.apache.commons.logging.PathableTestSuite");
assertSame("PathableTestSuite not loaded via child",
testClass.getClassLoader(), thisLoader);
// test loading of class that is not available
try {
Class noSuchClass = contextLoader.loadClass("no.such.class");
fail("Class no.such.class is unexpectedly available");
assertNotNull(noSuchClass); // silence warning about unused var
} catch(ClassNotFoundException ex) {
// ok
}
// String class classloader is null
Class stringClass = contextLoader.loadClass("java.lang.String");
assertNull("String class classloader is not null!",
stringClass.getClassLoader());
}
/**
* Test that the various flavours of ClassLoader.getResource work as expected.
*/
public void testResource() {
URL resource;
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
ClassLoader childLoader = contextLoader.getParent();
// getResource where it doesn't exist
resource = childLoader.getResource("nosuchfile");
assertNull("Non-null URL returned for invalid resource name", resource);
// getResource where it is accessable only to parent classloader
resource = childLoader.getResource("org/apache/commons/logging/Log.class");
assertNotNull("Unable to locate Log.class resource", resource);
// getResource where it is accessable only to child classloader
resource = childLoader.getResource("org/apache/commons/logging/PathableTestSuite.class");
assertNotNull("Unable to locate PathableTestSuite.class resource", resource);
// getResource where it is accessable to both classloaders. The one visible
// to the parent should be returned. The URL returned will be of form
// jar:file:/x/y.jar!path/to/resource. The filename part should include the jarname
// of form commons-logging-nnnn.jar, not commons-logging-adapters-nnnn.jar
resource = childLoader.getResource("org/apache/commons/logging/impl/Log4JLogger.class");
assertNotNull("Unable to locate Log4JLogger.class resource", resource);
assertTrue("Incorrect source for Log4JLogger class",
resource.toString().indexOf("/commons-logging-1.") > 0);
}
/**
* Test that the various flavours of ClassLoader.getResources work as expected.
*/
public void testResources() throws Exception {
Enumeration resources;
URL[] urls;
// verify the classloader hierarchy
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
ClassLoader childLoader = contextLoader.getParent();
ClassLoader parentLoader = childLoader.getParent();
ClassLoader bootLoader = parentLoader.getParent();
assertNull("Unexpected classloader hierarchy", bootLoader);
// getResources where no instances exist
resources = childLoader.getResources("nosuchfile");
urls = toURLArray(resources);
assertEquals("Non-null URL returned for invalid resource name", 0, urls.length);
// getResources where the resource only exists in the parent
resources = childLoader.getResources("org/apache/commons/logging/Log.class");
urls = toURLArray(resources);
assertEquals("Unexpected number of Log.class resources found", 1, urls.length);
// getResources where the resource only exists in the child
resources = childLoader.getResources("org/apache/commons/logging/PathableTestSuite.class");
urls = toURLArray(resources);
assertEquals("Unexpected number of PathableTestSuite.class resources found", 1, urls.length);
// getResources where the resource exists in both.
// resources should be returned in order (parent-resource, child-resource)
resources = childLoader.getResources("org/apache/commons/logging/impl/Log4JLogger.class");
urls = toURLArray(resources);
assertEquals("Unexpected number of Log4JLogger.class resources found", 2, urls.length);
// There is no gaurantee about the ordering of results returned from getResources
// To make this test portable across JVMs, sort the string to give them a known order
String[] urlsToStrings = new String[2];
urlsToStrings[0] = urls[0].toString();
urlsToStrings[1] = urls[1].toString();
Arrays.sort(urlsToStrings);
assertTrue("Incorrect source for Log4JLogger class",
urlsToStrings[0].indexOf("/commons-logging-1.") > 0);
assertTrue("Incorrect source for Log4JLogger class",
urlsToStrings[1].indexOf("/commons-logging-adapters-1.") > 0);
}
/**
* Utility method to convert an enumeration-of-URLs into an array of URLs.
*/
private static URL[] toURLArray(Enumeration e) {
ArrayList l = new ArrayList();
while (e.hasMoreElements()) {
URL u = (URL) e.nextElement();
l.add(u);
}
URL[] tmp = new URL[l.size()];
return (URL[]) l.toArray(tmp);
}
/**
* Test that getResourceAsStream works.
*/
public void testResourceAsStream() throws Exception {
java.io.InputStream is;
// verify the classloader hierarchy
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
ClassLoader childLoader = contextLoader.getParent();
ClassLoader parentLoader = childLoader.getParent();
ClassLoader bootLoader = parentLoader.getParent();
assertNull("Unexpected classloader hierarchy", bootLoader);
// getResourceAsStream where no instances exist
is = childLoader.getResourceAsStream("nosuchfile");
assertNull("Invalid resource returned non-null stream", is);
// getResourceAsStream where resource does exist
is = childLoader.getResourceAsStream("org/apache/commons/logging/Log.class");
assertNotNull("Null returned for valid resource", is);
is.close();
// It would be nice to test parent-first ordering here, but that would require
// having a resource with the same name in both the parent and child loaders,
// but with different contents. That's a little tricky to set up so we'll
// skip that for now.
}
}

View File

@ -0,0 +1,21 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
* file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
* to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.apache.commons.logging.security;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class DummyClass {
public DummyClass() {
Log log = LogFactory.getLog(DummyClass.class);
log.info("Some log message");
}
}

View File

@ -0,0 +1,149 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.security;
import java.io.FilePermission;
import java.security.Permission;
import java.security.Permissions;
/**
* Custom implementation of a security manager, so we can control the
* security environment for tests in this package.
*/
public class MockSecurityManager extends SecurityManager {
private final Permissions permissions = new Permissions();
private static final Permission setSecurityManagerPerm =
new RuntimePermission("setSecurityManager");
private int untrustedCodeCount = 0;
public MockSecurityManager() {
permissions.add(setSecurityManagerPerm);
}
/**
* Define the set of permissions to be granted to classes in the o.a.c.l package,
* but NOT to unit-test classes in o.a.c.l.security package.
*/
public void addPermission(Permission p) {
permissions.add(p);
}
/**
* This returns the number of times that a check of a permission failed
* due to stack-walking tracing up into untrusted code. Any non-zero
* value indicates a bug in JCL, ie a situation where code was not
* correctly wrapped in an AccessController block. The result of such a
* bug is that signing JCL is not sufficient to allow JCL to perform
* the operation; the caller would need to be signed too.
*/
public int getUntrustedCodeCount() {
return untrustedCodeCount;
}
public void checkPermission(Permission p) throws SecurityException {
if (setSecurityManagerPerm.implies(p)) {
// ok, allow this; we don't want to block any calls to setSecurityManager
// otherwise this custom security manager cannot be reset to the original.
// System.out.println("setSecurityManager: granted");
return;
}
// Allow read-only access to files, as this is needed to load classes!
// Ideally, we would limit this to just .class and .jar files.
if (p instanceof FilePermission) {
FilePermission fp = (FilePermission) p;
if (fp.getActions().equals("read")) {
// System.out.println("Permit read of files");
return;
}
}
System.out.println("\n\ntesting permission:" + p.getClass() + ":"+ p);
Exception e = new Exception();
e.fillInStackTrace();
StackTraceElement[] stack = e.getStackTrace();
// scan the call stack from most recent to oldest.
// start at 1 to skip the entry in the stack for this method
for(int i=1; i<stack.length; ++i) {
String cname = stack[i].getClassName();
System.out.println("" + i + ":" + stack[i].getClassName() +
"." + stack[i].getMethodName() + ":" + stack[i].getLineNumber());
if (cname.equals("java.util.logging.Handler") && stack[i].getMethodName().equals("setLevel")) {
// LOGGING CODE CAUSES ACCESSCONTROLEXCEPTION
// http://www-01.ibm.com/support/docview.wss?uid=swg1IZ51152
return;
}
if (cname.equals("java.util.logging.Level") && stack[i].getMethodName().equals("getLocalizedLevelName")) {
// LOGGING-156: OpenJDK 1.7 JULI code (java.util.logging.Level#getLocalizedLevelName)
// calls ResourceBundle#getBundle() without using AccessController#doPrivileged()
// requiring RuntimePermission: "accessClassInPackage.sun.util.logging.resources"
return;
}
if (cname.equals("java.security.AccessController")) {
// Presumably method name equals "doPrivileged"
//
// The previous iteration of this loop verified that the
// PrivilegedAction.run method associated with this
// doPrivileged method call had the right permissions,
// so we just return here. Effectively, the method invoking
// doPrivileged asserted that it checked the input params
// and found them safe, and that code is trusted, so we
// don't need to check the trust level of code higher in
// the call stack.
System.out.println("Access controller found: returning");
return;
} else if (cname.startsWith("java.")
|| cname.startsWith("javax.")
|| cname.startsWith("junit.")
|| cname.startsWith("org.apache.tools.ant.")
|| cname.startsWith("sun.")) {
// Code in these packages is trusted if the caller is trusted.
//
// TODO: maybe check class is loaded via system loader or similar rather
// than checking name? Trusted domains may be different in alternative
// jvms..
} else if (cname.startsWith("org.apache.commons.logging.security")) {
// this is the unit test code; treat this like an untrusted client
// app that is using JCL
++untrustedCodeCount;
System.out.println("Untrusted code [testcase] found");
throw new SecurityException("Untrusted code [testcase] found");
} else if (cname.startsWith("org.apache.commons.logging.")) {
if (permissions.implies(p)) {
// Code here is trusted if the caller is trusted
System.out.println("Permission in allowed set for JCL class");
} else {
System.out.println("Permission refused:" + p.getClass() + ":" + p);
throw new SecurityException("Permission refused:" + p.getClass() + ":" + p);
}
} else {
// we found some code that is not trusted to perform this operation.
System.out.println("Unexpected code: permission refused:" + p.getClass() + ":" + p);
throw new SecurityException("Unexpected code: permission refused:" + p.getClass() + ":" + p);
}
}
}
}

View File

@ -0,0 +1,140 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.security;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AllPermission;
import java.util.Hashtable;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests for logging with a security policy that allows JCL access to everything.
* <p>
* This class has only one unit test, as we are (in part) checking behaviour in
* the static block of the LogFactory class. As that class cannot be unloaded after
* being loaded into a classloader, the only workaround is to use the
* PathableClassLoader approach to ensure each test is run in its own
* classloader, and use a separate testcase class for each test.
*/
public class SecurityAllowedTestCase extends TestCase
{
private SecurityManager oldSecMgr;
// Dummy special hashtable, so we can tell JCL to use this instead of
// the standard one.
public static class CustomHashtable extends Hashtable {
/**
* Generated serial version ID.
*/
private static final long serialVersionUID = 8941017300059246720L;
}
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader parent = new PathableClassLoader(null);
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
parent.addLogicalLib("commons-logging");
parent.addLogicalLib("testclasses");
Class testClass = parent.loadClass(
"org.apache.commons.logging.security.SecurityAllowedTestCase");
return new PathableTestSuite(testClass, parent);
}
public void setUp() {
// save security manager so it can be restored in tearDown
oldSecMgr = System.getSecurityManager();
}
public void tearDown() {
// Restore, so other tests don't get stuffed up if a test
// sets a custom security manager.
System.setSecurityManager(oldSecMgr);
}
/**
* Test what happens when JCL is run with all permissions enabled. Custom
* overrides should take effect.
*/
public void testAllAllowed() {
System.setProperty(
LogFactory.HASHTABLE_IMPLEMENTATION_PROPERTY,
CustomHashtable.class.getName());
MockSecurityManager mySecurityManager = new MockSecurityManager();
mySecurityManager.addPermission(new AllPermission());
System.setSecurityManager(mySecurityManager);
try {
// Use reflection so that we can control exactly when the static
// initialiser for the LogFactory class is executed.
Class c = this.getClass().getClassLoader().loadClass(
"org.apache.commons.logging.LogFactory");
Method m = c.getMethod("getLog", new Class[] {Class.class});
Log log = (Log) m.invoke(null, new Object[] {this.getClass()});
// Check whether we had any security exceptions so far (which were
// caught by the code). We should not, as every secure operation
// should be wrapped in an AccessController. Any security exceptions
// indicate a path that is missing an appropriate AccessController.
//
// We don't wait until after the log.info call to get this count
// because java.util.logging tries to load a resource bundle, which
// requires permission accessClassInPackage. JCL explicitly does not
// wrap calls to log methods in AccessControllers because writes to
// a log file *should* only be permitted if the original caller is
// trusted to access that file.
int untrustedCodeCount = mySecurityManager.getUntrustedCodeCount();
log.info("testing");
// check that the default map implementation was loaded, as JCL was
// forbidden from reading the HASHTABLE_IMPLEMENTATION_PROPERTY property.
System.setSecurityManager(null);
Field factoryField = c.getDeclaredField("factories");
factoryField.setAccessible(true);
Object factoryTable = factoryField.get(null);
assertNotNull(factoryTable);
assertEquals(CustomHashtable.class.getName(), factoryTable.getClass().getName());
// we better compare that we have no security exception during the call to log
// IBM JVM tries to load bundles during the invoke call, which increase the count
assertEquals("Untrusted code count", untrustedCodeCount, mySecurityManager.getUntrustedCodeCount());
} catch(Throwable t) {
// Restore original security manager so output can be generated; the
// PrintWriter constructor tries to read the line.separator
// system property.
System.setSecurityManager(oldSecMgr);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
fail("Unexpected exception:" + t.getMessage() + ":" + sw.toString());
}
}
}

View File

@ -0,0 +1,191 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.security;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Hashtable;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests for logging with a security policy that forbids JCL access to anything.
* <p>
* Performing tests with security permissions disabled is tricky, as building error
* messages on failure requires certain security permissions. If the security manager
* blocks these, then the test can fail without the error messages being output.
* <p>
* This class has only one unit test, as we are (in part) checking behaviour in
* the static block of the LogFactory class. As that class cannot be unloaded after
* being loaded into a classloader, the only workaround is to use the
* PathableClassLoader approach to ensure each test is run in its own
* classloader, and use a separate testcase class for each test.
*/
public class SecurityForbiddenTestCase extends TestCase
{
private SecurityManager oldSecMgr;
private ClassLoader otherClassLoader;
// Dummy special hashtable, so we can tell JCL to use this instead of
// the standard one.
public static class CustomHashtable extends Hashtable {
/**
* Generated serial version ID.
*/
private static final long serialVersionUID = 7224652794746236024L;
}
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
PathableClassLoader parent = new PathableClassLoader(null);
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
parent.addLogicalLib("commons-logging");
parent.addLogicalLib("testclasses");
Class testClass = parent.loadClass(
"org.apache.commons.logging.security.SecurityForbiddenTestCase");
return new PathableTestSuite(testClass, parent);
}
public void setUp() {
// save security manager so it can be restored in tearDown
oldSecMgr = System.getSecurityManager();
PathableClassLoader classLoader = new PathableClassLoader(null);
classLoader.addLogicalLib("commons-logging");
classLoader.addLogicalLib("testclasses");
otherClassLoader = classLoader;
}
public void tearDown() {
// Restore, so other tests don't get stuffed up if a test
// sets a custom security manager.
System.setSecurityManager(oldSecMgr);
}
/**
* Test what happens when JCL is run with absolutely no security
* privileges at all, including reading system properties. Everything
* should fall back to the built-in defaults.
*/
public void testAllForbidden() {
System.setProperty(
LogFactory.HASHTABLE_IMPLEMENTATION_PROPERTY,
CustomHashtable.class.getName());
MockSecurityManager mySecurityManager = new MockSecurityManager();
System.setSecurityManager(mySecurityManager);
try {
// Use reflection so that we can control exactly when the static
// initialiser for the LogFactory class is executed.
Class c = this.getClass().getClassLoader().loadClass(
"org.apache.commons.logging.LogFactory");
Method m = c.getMethod("getLog", new Class[] {Class.class});
Log log = (Log) m.invoke(null, new Object[] {this.getClass()});
log.info("testing");
// check that the default map implementation was loaded, as JCL was
// forbidden from reading the HASHTABLE_IMPLEMENTATION_PROPERTY property.
//
// The default is either the java Hashtable class (java < 1.2) or the
// JCL WeakHashtable (java >= 1.3).
System.setSecurityManager(oldSecMgr);
Field factoryField = c.getDeclaredField("factories");
factoryField.setAccessible(true);
Object factoryTable = factoryField.get(null);
assertNotNull(factoryTable);
String ftClassName = factoryTable.getClass().getName();
assertTrue("Custom hashtable unexpectedly used",
!CustomHashtable.class.getName().equals(ftClassName));
assertEquals(0, mySecurityManager.getUntrustedCodeCount());
} catch(Throwable t) {
// Restore original security manager so output can be generated; the
// PrintWriter constructor tries to read the line.separator
// system property.
System.setSecurityManager(oldSecMgr);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
fail("Unexpected exception:" + t.getMessage() + ":" + sw.toString());
}
}
/**
* Test what happens when JCL is run with absolutely no security
* privileges at all and a class loaded with a different classloader
* than the context classloader of the current thread tries to log something.
*/
public void testContextClassLoader() {
System.setProperty(
LogFactory.HASHTABLE_IMPLEMENTATION_PROPERTY,
CustomHashtable.class.getName());
MockSecurityManager mySecurityManager = new MockSecurityManager();
System.setSecurityManager(mySecurityManager);
try {
// load a dummy class with another classloader
// to force a SecurityException when the LogFactory calls
// Thread.getCurrentThread().getContextClassLoader()
loadClass("org.apache.commons.logging.security.DummyClass", otherClassLoader);
System.setSecurityManager(oldSecMgr);
assertEquals(0, mySecurityManager.getUntrustedCodeCount());
} catch(Throwable t) {
// Restore original security manager so output can be generated; the
// PrintWriter constructor tries to read the line.separator
// system property.
System.setSecurityManager(oldSecMgr);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
fail("Unexpected exception:" + t.getMessage() + ":" + sw.toString());
}
}
/**
* Loads a class with the given classloader.
*/
private Object loadClass(String name, ClassLoader classLoader) {
try {
Class clazz = classLoader.loadClass(name);
Object obj = clazz.newInstance();
return obj;
} catch ( Exception e ) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
fail("Unexpected exception:" + e.getMessage() + ":" + sw.toString());
}
return null;
}
}

View File

@ -0,0 +1,72 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.servlet;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
import org.apache.commons.logging.impl.ServletContextCleaner;
/**
* Tests for ServletContextCleaner utility class.
*/
public class BasicServletTestCase extends TestCase {
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
// LogFactory in parent
// LogFactory in child (loads test)
// LogFactory in tccl
//
// Having the test loaded via a loader above the tccl emulates the situation
// where a web.xml file specifies ServletContextCleaner as a listener, and
// that class is deployed via a shared classloader.
PathableClassLoader parent = new PathableClassLoader(null);
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
parent.addLogicalLib("commons-logging");
parent.addLogicalLib("servlet-api");
PathableClassLoader child = new PathableClassLoader(parent);
child.setParentFirst(false);
child.addLogicalLib("commons-logging");
child.addLogicalLib("testclasses");
PathableClassLoader tccl = new PathableClassLoader(child);
tccl.setParentFirst(false);
tccl.addLogicalLib("commons-logging");
Class testClass = child.loadClass(BasicServletTestCase.class.getName());
return new PathableTestSuite(testClass, tccl);
}
/**
* Test that calling ServletContextCleaner.contextDestroyed doesn't crash.
* Testing anything else is rather difficult...
*/
public void testBasics() {
ServletContextCleaner scc = new ServletContextCleaner();
scc.contextDestroyed(null);
}
}

View File

@ -0,0 +1,277 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.simple;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.framework.Test;
import org.apache.commons.logging.DummyException;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
import org.apache.commons.logging.impl.SimpleLog;
/**
* <p>TestCase for simple logging when running with custom configuration
* properties.</p>
*
* @author Craig R. McClanahan
* @version $Revision: 1432587 $ $Date: 2013-01-13 12:11:32 +0100 (Sun, 13 Jan 2013) $
*/
public class CustomConfigTestCase extends DefaultConfigTestCase {
// ----------------------------------------------------- Instance Variables
/**
* <p>The expected log records.</p>
*/
protected List expected;
/**
* <p>The message levels that should have been logged.</p>
*/
/*
protected Level testLevels[] =
{ Level.FINE, Level.INFO, Level.WARNING, Level.SEVERE, Level.SEVERE };
*/
/**
* <p>The message strings that should have been logged.</p>
*/
protected String testMessages[] =
{ "debug", "info", "warn", "error", "fatal" };
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Set system properties that will control the LogFactory/Log objects
* when they are created. Subclasses can override this method to
* define properties that suit them.
*/
public void setProperties() {
System.setProperty(
"org.apache.commons.logging.Log",
"org.apache.commons.logging.simple.DecoratedSimpleLog");
System.setProperty(
"org.apache.commons.logging.simplelog.defaultlog",
"debug");
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
setProperties();
expected = new ArrayList();
setUpFactory();
setUpLog("DecoratedLogger");
}
/**
* Return the tests included in this test suite.
* <p>
* We need to use a PathableClassLoader here because the SimpleLog class
* is a pile of junk and chock-full of static variables. Any other test
* (like simple.CustomConfigTestCase) that has used the SimpleLog class
* will already have caused it to do once-only initialisation that we
* can't reset, even by calling LogFactory.releaseAll, because of those
* ugly statics. The only clean solution is to load a clean copy of
* commons-logging including SimpleLog via a nice clean classloader.
* Or we could fix SimpleLog to be sane...
*/
public static Test suite() throws Exception {
Class thisClass = CustomConfigTestCase.class;
PathableClassLoader loader = new PathableClassLoader(null);
loader.useExplicitLoader("junit.", Test.class.getClassLoader());
loader.addLogicalLib("testclasses");
loader.addLogicalLib("commons-logging");
Class testClass = loader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, loader);
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
super.tearDown();
expected = null;
}
// ----------------------------------------------------------- Test Methods
// Test logging message strings with exceptions
public void testExceptionMessages() throws Exception {
((DecoratedSimpleLog) log).clearCache();
logExceptionMessages();
checkExpected();
}
// Test logging plain message strings
public void testPlainMessages() throws Exception {
((DecoratedSimpleLog) log).clearCache();
logPlainMessages();
checkExpected();
}
// Test Serializability of standard instance
public void testSerializable() throws Exception {
((DecoratedSimpleLog) log).clearCache();
logPlainMessages();
super.testSerializable();
logExceptionMessages();
checkExpected();
}
// -------------------------------------------------------- Support Methods
// Check the decorated log instance
protected void checkDecorated() {
assertNotNull("Log exists", log);
assertEquals("Log class",
"org.apache.commons.logging.simple.DecoratedSimpleLog",
log.getClass().getName());
// Can we call level checkers with no exceptions?
assertTrue(log.isDebugEnabled());
assertTrue(log.isErrorEnabled());
assertTrue(log.isFatalEnabled());
assertTrue(log.isInfoEnabled());
assertTrue(!log.isTraceEnabled());
assertTrue(log.isWarnEnabled());
// Can we retrieve the current log level?
assertEquals(SimpleLog.LOG_LEVEL_DEBUG, ((SimpleLog) log).getLevel());
// Can we validate the extra exposed properties?
checkDecoratedDateTime();
assertEquals("DecoratedLogger",
((DecoratedSimpleLog) log).getLogName());
checkShowDateTime();
assertTrue(((DecoratedSimpleLog) log).getShowShortName());
}
/** Hook for subclassses */
protected void checkShowDateTime() {
assertTrue(!((DecoratedSimpleLog) log).getShowDateTime());
}
/** Hook for subclasses */
protected void checkDecoratedDateTime() {
assertEquals("yyyy/MM/dd HH:mm:ss:SSS zzz",
((DecoratedSimpleLog) log).getDateTimeFormat());
}
// Check the actual log records against the expected ones
protected void checkExpected() {
List acts = ((DecoratedSimpleLog) log).getCache();
Iterator exps = expected.iterator();
int n = 0;
while (exps.hasNext()) {
LogRecord exp = (LogRecord) exps.next();
LogRecord act = (LogRecord) acts.get(n++);
assertEquals("Row " + n + " type", exp.type, act.type);
assertEquals("Row " + n + " message", exp.message, act.message);
assertEquals("Row " + n + " throwable", exp.t, act.t);
}
}
// Check the standard log instance
protected void checkStandard() {
checkDecorated();
}
// Log the messages with exceptions
protected void logExceptionMessages() {
// Generate log records
Throwable t = new DummyException();
log.trace("trace", t); // Should not actually get logged
log.debug("debug", t);
log.info("info", t);
log.warn("warn", t);
log.error("error", t);
log.fatal("fatal", t);
// Record the log records we expect
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_DEBUG, "debug", t));
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_INFO, "info", t));
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_WARN, "warn", t));
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_ERROR, "error", t));
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_FATAL, "fatal", t));
}
// Log the plain messages
protected void logPlainMessages() {
// Generate log records
log.trace("trace"); // Should not actually get logged
log.debug("debug");
log.info("info");
log.warn("warn");
log.error("error");
log.fatal("fatal");
// Record the log records we expect
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_DEBUG, "debug", null));
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_INFO, "info", null));
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_WARN, "warn", null));
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_ERROR, "error", null));
expected.add(new LogRecord(SimpleLog.LOG_LEVEL_FATAL, "fatal", null));
}
}

View File

@ -0,0 +1,105 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.simple;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import junit.framework.Test;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Tests custom date time format configuration
*/
public class DateTimeCustomConfigTestCase extends CustomConfigTestCase {
// ----------------------------------------------------------- Constructors
/**
* Return the tests included in this test suite.
* <p>
* We need to use a PathableClassLoader here because the SimpleLog class
* is a pile of junk and chock-full of static variables. Any other test
* (like simple.CustomConfigTestCase) that has used the SimpleLog class
* will already have caused it to do once-only initialisation that we
* can't reset, even by calling LogFactory.releaseAll, because of those
* ugly statics. The only clean solution is to load a clean copy of
* commons-logging including SimpleLog via a nice clean classloader.
* Or we could fix SimpleLog to be sane...
*/
public static Test suite() throws Exception {
Class thisClass = DateTimeCustomConfigTestCase.class;
PathableClassLoader loader = new PathableClassLoader(null);
loader.useExplicitLoader("junit.", Test.class.getClassLoader());
loader.addLogicalLib("testclasses");
loader.addLogicalLib("commons-logging");
Class testClass = loader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, loader);
}
/**
* Set up system properties required by this unit test. Here, we
* set up the props defined in the parent class setProperties method,
* and add a few to configure the SimpleLog class date/time output.
*/
public void setProperties() {
super.setProperties();
System.setProperty(
"org.apache.commons.logging.simplelog.dateTimeFormat",
"dd.mm.yyyy");
System.setProperty(
"org.apache.commons.logging.simplelog.showdatetime",
"true");
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
super.setUp();
}
// ----------------------------------------------------------- Methods
/** Checks that the date time format has been successfully set */
protected void checkDecoratedDateTime() {
assertEquals("Expected date format to be set", "dd.mm.yyyy",
((DecoratedSimpleLog) log).getDateTimeFormat());
// try the formatter
Date now = new Date();
DateFormat formatter = ((DecoratedSimpleLog) log).getDateTimeFormatter();
SimpleDateFormat sampleFormatter = new SimpleDateFormat("dd.mm.yyyy");
assertEquals("Date should be formatters to pattern dd.mm.yyyy",
sampleFormatter.format(now), formatter.format(now));
}
/** Hook for subclassses */
protected void checkShowDateTime() {
assertTrue(((DecoratedSimpleLog) log).getShowDateTime());
}
}

View File

@ -0,0 +1,106 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.simple;
import java.util.ArrayList;
import java.util.List;
import java.text.DateFormat;
import org.apache.commons.logging.impl.SimpleLog;
/**
* <p>Decorated instance of SimpleLog to expose internal state and
* support buffered output.</p>
*/
public class DecoratedSimpleLog extends SimpleLog {
// ------------------------------------------------------------ Constructor
/**
* Generated serial version ID.
*/
private static final long serialVersionUID = 196544280770017153L;
public DecoratedSimpleLog(String name) {
super(name);
}
// ------------------------------------------------------------- Properties
public DateFormat getDateTimeFormatter() {
return dateFormatter;
}
public String getDateTimeFormat() {
return dateTimeFormat;
}
public String getLogName() {
return logName;
}
public boolean getShowDateTime() {
return showDateTime;
}
public boolean getShowShortName() {
return showShortName;
}
// ------------------------------------------------------- Protected Methods
// Cache logged messages
protected void log(int type, Object message, Throwable t) {
super.log(type, message, t);
cache.add(new LogRecord(type, message, t));
}
// ---------------------------------------------------------- Public Methods
// Cache of logged records
protected ArrayList cache = new ArrayList();
// Clear cache
public void clearCache() {
cache.clear();
}
// Return cache
public List getCache() {
return this.cache;
}
}

View File

@ -0,0 +1,249 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.simple;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
import org.apache.commons.logging.impl.SimpleLog;
/**
* <p>TestCase for simple logging when running with zero configuration
* other than selecting the SimpleLog implementation.</p>
*
* @author Craig R. McClanahan
* @version $Revision: 1432587 $ $Date: 2013-01-13 12:11:32 +0100 (Sun, 13 Jan 2013) $
*/
public class DefaultConfigTestCase extends TestCase {
// ----------------------------------------------------- Instance Variables
/**
* <p>The {@link LogFactory} implementation we have selected.</p>
*/
protected LogFactory factory = null;
/**
* <p>The {@link Log} implementation we have selected.</p>
*/
protected Log log = null;
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Return the tests included in this test suite.
* <p>
* We need to use a PathableClassLoader here because the SimpleLog class
* is a pile of junk and chock-full of static variables. Any other test
* (like simple.CustomConfigTestCase) that has used the SimpleLog class
* will already have caused it to do once-only initialisation that we
* can't reset, even by calling LogFactory.releaseAll, because of those
* ugly statics. The only clean solution is to load a clean copy of
* commons-logging including SimpleLog via a nice clean classloader.
* Or we could fix SimpleLog to be sane...
*/
public static Test suite() throws Exception {
Class thisClass = DefaultConfigTestCase.class;
PathableClassLoader loader = new PathableClassLoader(null);
loader.useExplicitLoader("junit.", Test.class.getClassLoader());
loader.addLogicalLib("testclasses");
loader.addLogicalLib("commons-logging");
Class testClass = loader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, loader);
}
/**
* Set system properties that will control the LogFactory/Log objects
* when they are created. Subclasses can override this method to
* define properties that suit them.
*/
public void setProperties() {
System.setProperty(
"org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.SimpleLog");
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
setProperties();
setUpFactory();
setUpLog("TestLogger");
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
log = null;
factory = null;
LogFactory.releaseAll();
}
// ----------------------------------------------------------- Test Methods
// Test pristine DecoratedSimpleLog instance
public void testPristineDecorated() {
setUpDecorated("DecoratedLogger");
checkDecorated();
}
// Test pristine Log instance
public void testPristineLog() {
checkStandard();
}
// Test pristine LogFactory instance
public void testPristineFactory() {
assertNotNull("LogFactory exists", factory);
assertEquals("LogFactory class",
"org.apache.commons.logging.impl.LogFactoryImpl",
factory.getClass().getName());
String names[] = factory.getAttributeNames();
assertNotNull("Names exists", names);
assertEquals("Names empty", 0, names.length);
}
// Test Serializability of standard instance
public void testSerializable() throws Exception {
// Serialize and deserialize the instance
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(log);
oos.close();
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
log = (Log) ois.readObject();
ois.close();
// Check the characteristics of the resulting object
checkStandard();
}
// -------------------------------------------------------- Support Methods
// Check the decorated log instance
protected void checkDecorated() {
assertNotNull("Log exists", log);
assertEquals("Log class",
"org.apache.commons.logging.simple.DecoratedSimpleLog",
log.getClass().getName());
// Can we call level checkers with no exceptions?
assertTrue(!log.isDebugEnabled());
assertTrue(log.isErrorEnabled());
assertTrue(log.isFatalEnabled());
assertTrue(log.isInfoEnabled());
assertTrue(!log.isTraceEnabled());
assertTrue(log.isWarnEnabled());
// Can we retrieve the current log level?
assertEquals(SimpleLog.LOG_LEVEL_INFO, ((SimpleLog) log).getLevel());
// Can we validate the extra exposed properties?
assertEquals("yyyy/MM/dd HH:mm:ss:SSS zzz",
((DecoratedSimpleLog) log).getDateTimeFormat());
assertEquals("DecoratedLogger",
((DecoratedSimpleLog) log).getLogName());
assertTrue(!((DecoratedSimpleLog) log).getShowDateTime());
assertTrue(((DecoratedSimpleLog) log).getShowShortName());
}
// Check the standard log instance
protected void checkStandard() {
assertNotNull("Log exists", log);
assertEquals("Log class",
"org.apache.commons.logging.impl.SimpleLog",
log.getClass().getName());
// Can we call level checkers with no exceptions?
assertTrue(!log.isDebugEnabled());
assertTrue(log.isErrorEnabled());
assertTrue(log.isFatalEnabled());
assertTrue(log.isInfoEnabled());
assertTrue(!log.isTraceEnabled());
assertTrue(log.isWarnEnabled());
// Can we retrieve the current log level?
assertEquals(SimpleLog.LOG_LEVEL_INFO, ((SimpleLog) log).getLevel());
}
// Set up decorated log instance
protected void setUpDecorated(String name) {
log = new DecoratedSimpleLog(name);
}
// Set up factory instance
protected void setUpFactory() throws Exception {
factory = LogFactory.getFactory();
}
// Set up log instance
protected void setUpLog(String name) throws Exception {
log = LogFactory.getLog(name);
}
}

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.simple;
import java.io.Serializable;
public class LogRecord implements Serializable {
/**
* Generated serial version ID.
*/
private static final long serialVersionUID = -5254831759209770665L;
public LogRecord(int type, Object message, Throwable t) {
this.type = type;
this.message = message;
this.t = t;
}
public int type;
public Object message;
public Throwable t;
}

View File

@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.tccl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
import junit.framework.Test;
import junit.framework.TestCase;
/**
* Simulates the case when TCCL is badly set and cannot load JCL.
*/
public class BadTCCLTestCase extends TestCase {
public static Test suite() throws Exception {
PathableClassLoader contextClassLoader = new PathableClassLoader(null);
contextClassLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
PathableTestSuite suite = new PathableTestSuite(BadTCCLTestCase.class, contextClassLoader);
return suite;
}
// test methods
/**
* This test just tests that a log implementation can be found
* by the LogFactory.
*/
public void testGetLog() {
Log log = LogFactory.getLog(BadTCCLTestCase.class);
log.debug("Hello, Mum");
}
}

View File

@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.tccl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableTestSuite;
import junit.framework.Test;
import junit.framework.TestCase;
/**
* Simulates the case when TCCL is set to NULL.
*/
public class NullTCCLTestCase extends TestCase {
public static Test suite() throws Exception {
PathableTestSuite suite = new PathableTestSuite(NullTCCLTestCase.class, null);
return suite;
}
// test methods
/**
* This test just tests that a log implementation can be found
* by the LogFactory.
*/
public void testGetLog() {
Log log = LogFactory.getLog(NullTCCLTestCase.class);
log.debug("Hello, Mum");
}
}

View File

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.tccl.custom;
import org.apache.commons.logging.Log;
public class MyLog implements Log {
public MyLog(String category) {}
public boolean isDebugEnabled() { return false; }
public boolean isErrorEnabled() { return false; }
public boolean isFatalEnabled() { return false; }
public boolean isInfoEnabled() { return false; }
public boolean isTraceEnabled() { return false; }
public boolean isWarnEnabled() { return false; }
public void trace(Object message) {}
public void trace(Object message, Throwable t) {}
public void debug(Object message) {}
public void debug(Object message, Throwable t) {}
public void info(Object message) {}
public void info(Object message, Throwable t) {}
public void warn(Object message) {}
public void warn(Object message, Throwable t) {}
public void error(Object message) {}
public void error(Object message, Throwable t) {}
public void fatal(Object message) {}
public void fatal(Object message, Throwable t) {}
}

View File

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.tccl.custom;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MyLogFactoryImpl extends LogFactory {
public Object getAttribute(String name) { return null; }
public String[] getAttributeNames() { return null; }
public Log getInstance(Class clazz) { return null; }
public Log getInstance(String name) { return null; }
public void release() {}
public void removeAttribute(String name) {}
public void setAttribute(String name, Object value) {}
}

View File

@ -0,0 +1,160 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.tccl.log;
import java.net.URL;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogConfigurationException;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Verify that by default LogFactoryImpl is loaded from the tccl classloader.
*/
public class TcclDisabledTestCase extends TestCase {
public static final String MY_LOG_PKG =
"org.apache.commons.logging.tccl.custom";
public static final String MY_LOG_IMPL =
MY_LOG_PKG + ".MyLog";
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
Class thisClass = TcclDisabledTestCase.class;
// Determine the URL to this .class file, so that we can then
// append the priority dirs to it. For tidiness, load this
// class through a dummy loader though this is not absolutely
// necessary...
PathableClassLoader dummy = new PathableClassLoader(null);
dummy.useExplicitLoader("junit.", Test.class.getClassLoader());
dummy.addLogicalLib("testclasses");
dummy.addLogicalLib("commons-logging");
String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
URL baseUrl = dummy.findResource(thisClassPath);
// Now set up the desired classloader hierarchy. Everything goes into
// the parent classpath, but we exclude the custom Log class.
//
// We then create a tccl classloader that can see the custom
// Log class. Therefore if that class can be found, then the
// TCCL must have been used to load it.
PathableClassLoader emptyLoader = new PathableClassLoader(null);
PathableClassLoader parentLoader = new PathableClassLoader(null);
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
parentLoader.addLogicalLib("commons-logging");
parentLoader.addLogicalLib("testclasses");
// hack to ensure that the testcase classloader can't see
// the custom MyLog
parentLoader.useExplicitLoader(MY_LOG_PKG + ".", emptyLoader);
URL propsEnableUrl = new URL(baseUrl, "props_disable_tccl/");
parentLoader.addURL(propsEnableUrl);
PathableClassLoader tcclLoader = new PathableClassLoader(parentLoader);
tcclLoader.addLogicalLib("testclasses");
Class testClass = parentLoader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, tcclLoader);
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
LogFactory.releaseAll();
}
// ----------------------------------------------------------- Test Methods
/**
* Verify that MyLog is only loadable via the tccl.
*/
public void testLoader() throws Exception {
ClassLoader thisClassLoader = this.getClass().getClassLoader();
ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
// the tccl loader should NOT be the same as the loader that loaded this test class.
assertNotSame("tccl not same as test classloader", thisClassLoader, tcclLoader);
// MyLog should not be loadable via parent loader
try {
Class clazz = thisClassLoader.loadClass(MY_LOG_IMPL);
fail("Unexpectedly able to load MyLog via test class classloader");
assertNotNull(clazz); // silence warnings about unused var
} catch(ClassNotFoundException ex) {
// ok, expected
}
// MyLog should be loadable via tccl loader
try {
Class clazz = tcclLoader.loadClass(MY_LOG_IMPL);
assertNotNull(clazz);
} catch(ClassNotFoundException ex) {
fail("Unexpectedly unable to load MyLog via tccl classloader");
}
}
/**
* Verify that the custom Log implementation which is only accessable
* via the TCCL has NOT been loaded. Because this is only accessable via the
* TCCL, and we've use a commons-logging.properties that disables TCCL loading,
* we should see the default Log rather than the custom one.
*/
public void testTcclLoading() throws Exception {
LogFactory instance = LogFactory.getFactory();
assertEquals(
"Correct LogFactory loaded",
"org.apache.commons.logging.impl.LogFactoryImpl",
instance.getClass().getName());
try {
Log log = instance.getInstance("test");
fail("Unexpectedly succeeded in loading a custom Log class"
+ " that is only accessable via the tccl.");
assertNotNull(log); // silence compiler warning about unused var
} catch(LogConfigurationException ex) {
// ok, expected
int index = ex.getMessage().indexOf(MY_LOG_IMPL);
assertTrue("MyLog not found", index >= 0);
}
}
}

View File

@ -0,0 +1,155 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.tccl.log;
import java.net.URL;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Verify that by default the standard LogFactoryImpl class loads a
* custom Log implementation via the TCCL.
*/
public class TcclEnabledTestCase extends TestCase {
public static final String MY_LOG_PKG =
"org.apache.commons.logging.tccl.custom";
public static final String MY_LOG_IMPL =
MY_LOG_PKG + ".MyLog";
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
Class thisClass = TcclEnabledTestCase.class;
// Determine the URL to this .class file, so that we can then
// append the priority dirs to it. For tidiness, load this
// class through a dummy loader though this is not absolutely
// necessary...
PathableClassLoader dummy = new PathableClassLoader(null);
dummy.useExplicitLoader("junit.", Test.class.getClassLoader());
dummy.addLogicalLib("testclasses");
dummy.addLogicalLib("commons-logging");
String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
URL baseUrl = dummy.findResource(thisClassPath);
// Now set up the desired classloader hierarchy. Everything goes into
// the parent classpath, but we exclude the custom Log class.
//
// We then create a tccl classloader that can see the custom
// Log class. Therefore if that class can be found, then the
// TCCL must have been used to load it.
PathableClassLoader emptyLoader = new PathableClassLoader(null);
PathableClassLoader parentLoader = new PathableClassLoader(null);
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
parentLoader.addLogicalLib("commons-logging");
parentLoader.addLogicalLib("testclasses");
// hack to ensure that the testcase classloader can't see
// the custom MyLogFactoryImpl
parentLoader.useExplicitLoader(MY_LOG_PKG + ".", emptyLoader);
URL propsEnableUrl = new URL(baseUrl, "props_enable_tccl/");
parentLoader.addURL(propsEnableUrl);
PathableClassLoader tcclLoader = new PathableClassLoader(parentLoader);
tcclLoader.addLogicalLib("testclasses");
Class testClass = parentLoader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, tcclLoader);
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
LogFactory.releaseAll();
}
// ----------------------------------------------------------- Test Methods
/**
* Verify that MyLogFactoryImpl is only loadable via the tccl.
*/
public void testLoader() throws Exception {
ClassLoader thisClassLoader = this.getClass().getClassLoader();
ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
// the tccl loader should NOT be the same as the loader that loaded this test class.
assertNotSame("tccl not same as test classloader", thisClassLoader, tcclLoader);
// MyLog should not be loadable via parent loader
try {
Class clazz = thisClassLoader.loadClass(MY_LOG_IMPL);
fail("Unexpectedly able to load MyLog via test class classloader");
assertNotNull(clazz); // silence warnings about unused var
} catch(ClassNotFoundException ex) {
// ok, expected
}
// MyLog should be loadable via tccl loader
try {
Class clazz = tcclLoader.loadClass(MY_LOG_IMPL);
assertNotNull(clazz);
} catch(ClassNotFoundException ex) {
fail("Unexpectedly unable to load MyLog via tccl classloader");
}
}
/**
* Verify that the custom Log implementation which is only accessable
* via the TCCL has successfully been loaded as specified in the config file.
* This proves that the TCCL was used to load that class.
*/
public void testTcclLoading() throws Exception {
LogFactory instance = LogFactory.getFactory();
assertEquals(
"Correct LogFactory loaded",
"org.apache.commons.logging.impl.LogFactoryImpl",
instance.getClass().getName());
Log log = instance.getInstance("test");
assertEquals(
"Correct Log loaded",
MY_LOG_IMPL,
log.getClass().getName());
}
}

View File

@ -0,0 +1,156 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.tccl.logfactory;
import java.net.URL;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Verify that a commons-logging.properties file can prevent a custom
* LogFactoryImpl being loaded from the tccl classloader.
*/
public class TcclDisabledTestCase extends TestCase {
public static final String MY_LOG_FACTORY_PKG =
"org.apache.commons.logging.tccl.custom";
public static final String MY_LOG_FACTORY_IMPL =
MY_LOG_FACTORY_PKG + ".MyLogFactoryImpl";
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
Class thisClass = TcclDisabledTestCase.class;
// Determine the URL to this .class file, so that we can then
// append the priority dirs to it. For tidiness, load this
// class through a dummy loader though this is not absolutely
// necessary...
PathableClassLoader dummy = new PathableClassLoader(null);
dummy.useExplicitLoader("junit.", Test.class.getClassLoader());
dummy.addLogicalLib("testclasses");
dummy.addLogicalLib("commons-logging");
String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
URL baseUrl = dummy.findResource(thisClassPath);
// Now set up the desired classloader hierarchy. Everything goes into
// the parent classpath, but we exclude the custom LogFactoryImpl
// class.
//
// We then create a tccl classloader that can see the custom
// LogFactory class. Therefore if that class can be found, then the
// TCCL must have been used to load it.
PathableClassLoader emptyLoader = new PathableClassLoader(null);
PathableClassLoader parentLoader = new PathableClassLoader(null);
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
parentLoader.addLogicalLib("commons-logging");
parentLoader.addLogicalLib("testclasses");
// hack to ensure that the testcase classloader can't see
// the custom MyLogFactoryImpl
parentLoader.useExplicitLoader(
MY_LOG_FACTORY_PKG + ".", emptyLoader);
URL propsEnableUrl = new URL(baseUrl, "props_disable_tccl/");
parentLoader.addURL(propsEnableUrl);
PathableClassLoader tcclLoader = new PathableClassLoader(parentLoader);
tcclLoader.addLogicalLib("testclasses");
Class testClass = parentLoader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, tcclLoader);
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
LogFactory.releaseAll();
}
// ----------------------------------------------------------- Test Methods
/**
* Verify that MyLogFactoryImpl is only loadable via the tccl.
*/
public void testLoader() throws Exception {
ClassLoader thisClassLoader = this.getClass().getClassLoader();
ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
// the tccl loader should NOT be the same as the loader that loaded this test class.
assertNotSame("tccl not same as test classloader", thisClassLoader, tcclLoader);
// MyLogFactoryImpl should not be loadable via parent loader
try {
Class clazz = thisClassLoader.loadClass(MY_LOG_FACTORY_IMPL);
fail("Unexpectedly able to load MyLogFactoryImpl via test class classloader");
assertNotNull(clazz); // silence warning about unused var
} catch(ClassNotFoundException ex) {
// ok, expected
}
// MyLogFactoryImpl should be loadable via tccl loader
try {
Class clazz = tcclLoader.loadClass(MY_LOG_FACTORY_IMPL);
assertNotNull(clazz);
} catch(ClassNotFoundException ex) {
fail("Unexpectedly unable to load MyLogFactoryImpl via tccl classloader");
}
}
/**
* Verify that the custom LogFactory implementation which is only accessable
* via the TCCL has NOT been loaded. Because this is only accessable via the
* TCCL, and we've use a commons-logging.properties that disables TCCL loading,
* we should see the default LogFactoryImpl rather than the custom one.
*/
public void testTcclLoading() throws Exception {
try {
LogFactory instance = LogFactory.getFactory();
fail("Unexpectedly succeeded in loading custom factory, though TCCL disabled.");
assertNotNull(instance); // silence warning about unused var
} catch(org.apache.commons.logging.LogConfigurationException ex) {
// ok, custom MyLogFactoryImpl as specified in props_disable_tccl
// could not be found.
int index = ex.getMessage().indexOf(MY_LOG_FACTORY_IMPL);
assertTrue("MylogFactoryImpl not found", index >= 0);
}
}
}

View File

@ -0,0 +1,147 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.logging.tccl.logfactory;
import java.net.URL;
import junit.framework.Test;
import junit.framework.TestCase;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.PathableClassLoader;
import org.apache.commons.logging.PathableTestSuite;
/**
* Verify that by default a custom LogFactoryImpl is loaded from the
* tccl classloader.
*/
public class TcclEnabledTestCase extends TestCase {
// ------------------------------------------- JUnit Infrastructure Methods
/**
* Return the tests included in this test suite.
*/
public static Test suite() throws Exception {
Class thisClass = TcclEnabledTestCase.class;
// Determine the URL to this .class file, so that we can then
// append the priority dirs to it. For tidiness, load this
// class through a dummy loader though this is not absolutely
// necessary...
PathableClassLoader dummy = new PathableClassLoader(null);
dummy.useExplicitLoader("junit.", Test.class.getClassLoader());
dummy.addLogicalLib("testclasses");
dummy.addLogicalLib("commons-logging");
String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
URL baseUrl = dummy.findResource(thisClassPath);
// Now set up the desired classloader hierarchy. Everything goes into
// the parent classpath, but we exclude the custom LogFactoryImpl
// class.
//
// We then create a tccl classloader that can see the custom
// LogFactory class. Therefore if that class can be found, then the
// TCCL must have been used to load it.
PathableClassLoader emptyLoader = new PathableClassLoader(null);
PathableClassLoader parentLoader = new PathableClassLoader(null);
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
parentLoader.addLogicalLib("commons-logging");
parentLoader.addLogicalLib("testclasses");
// hack to ensure that the testcase classloader can't see
// the cust MyLogFactoryImpl
parentLoader.useExplicitLoader(
"org.apache.commons.logging.tccl.custom.", emptyLoader);
URL propsEnableUrl = new URL(baseUrl, "props_enable_tccl/");
parentLoader.addURL(propsEnableUrl);
PathableClassLoader tcclLoader = new PathableClassLoader(parentLoader);
tcclLoader.addLogicalLib("testclasses");
Class testClass = parentLoader.loadClass(thisClass.getName());
return new PathableTestSuite(testClass, tcclLoader);
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
LogFactory.releaseAll();
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
LogFactory.releaseAll();
}
// ----------------------------------------------------------- Test Methods
/**
* Verify that MyLogFactoryImpl is only loadable via the tccl.
*/
public void testLoader() throws Exception {
ClassLoader thisClassLoader = this.getClass().getClassLoader();
ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
// the tccl loader should NOT be the same as the loader that loaded this test class.
assertNotSame("tccl not same as test classloader", thisClassLoader, tcclLoader);
// MyLogFactoryImpl should not be loadable via parent loader
try {
Class clazz = thisClassLoader.loadClass(
"org.apache.commons.logging.tccl.custom.MyLogFactoryImpl");
fail("Unexpectedly able to load MyLogFactoryImpl via test class classloader");
assertNotNull(clazz); // silence warning about unused var
} catch(ClassNotFoundException ex) {
// ok, expected
}
// MyLogFactoryImpl should be loadable via tccl loader
try {
Class clazz = tcclLoader.loadClass(
"org.apache.commons.logging.tccl.custom.MyLogFactoryImpl");
assertNotNull(clazz);
} catch(ClassNotFoundException ex) {
fail("Unexpectedly unable to load MyLogFactoryImpl via tccl classloader");
}
}
/**
* Verify that the custom LogFactory implementation which is only accessable
* via the TCCL has successfully been loaded as specified in the config file.
* This proves that the TCCL was used to load that class.
*/
public void testTcclLoading() throws Exception {
LogFactory instance = LogFactory.getFactory();
assertEquals(
"Correct LogFactory loaded",
"org.apache.commons.logging.tccl.custom.MyLogFactoryImpl",
instance.getClass().getName());
}
}

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