Import Upstream version 1.2
This commit is contained in:
commit
e8a71d016c
|
@ -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.
|
|
@ -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/).
|
||||||
|
|
|
@ -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>
|
|
@ -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!
|
||||||
|
|
|
@ -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/
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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.
|
||||||
|
*/
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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}
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
@ -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()]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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; }
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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<<i>Priority</i>>()</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>
|
|
@ -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>
|
|
@ -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&pid=12310484&sorter/field=issuekey&sorter/order=DESC&status=1&status=3&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&issuetype=1&priority=4&assignee=-1">bug report</a>
|
||||||
|
or <a href="http://issues.apache.org/jira/secure/CreateIssueDetails!init.jspa?pid=12310484&issuetype=4&priority=4&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&pid=12310484&sorter/field=issuekey&sorter/order=DESC&status=1&status=3&status=4">All Open Commons Logging bugs</a></li>
|
||||||
|
<li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&pid=12310484&sorter/field=issuekey&sorter/order=DESC&status=5&status=6">All Resolved Commons Logging bugs</a></li>
|
||||||
|
<li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&pid=12310484&sorter/field=issuekey&sorter/order=DESC">All Commons Logging bugs</a></li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</document>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 -> 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) {}
|
||||||
|
}
|
|
@ -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) {}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
Loading…
Reference in New Issue