Move test classes to src/test/java
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/logging/trunk@1432695 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -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$
|
||||
*/
|
||||
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());
|
||||
}
|
||||
}
|
||||
32
src/test/java/org/apache/commons/logging/AltHashtable.java
Normal file
32
src/test/java/org/apache/commons/logging/AltHashtable.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.commons.logging;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class AltHashtable extends Hashtable {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/test/java/org/apache/commons/logging/DummyException.java
Normal file
28
src/test/java/org/apache/commons/logging/DummyException.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.logging;
|
||||
|
||||
/**
|
||||
* Dummy exception that unit tests create instances of when they want to test
|
||||
* logging of an Exception object.
|
||||
*/
|
||||
public class DummyException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public DummyException() {
|
||||
// super("Dummy Exception for unit testing");
|
||||
}
|
||||
}
|
||||
225
src/test/java/org/apache/commons/logging/LoadTestCase.java
Normal file
225
src/test/java/org/apache/commons/logging/LoadTestCase.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.logging;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* testcase to emulate container and application isolated from container
|
||||
* @author baliuka
|
||||
* @version $Id$
|
||||
*/
|
||||
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;
|
||||
}
|
||||
31
src/test/java/org/apache/commons/logging/LogTestCase.java
Normal file
31
src/test/java/org/apache/commons/logging/LogTestCase.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.logging;
|
||||
|
||||
|
||||
public class LogTestCase extends AbstractLogTest
|
||||
{
|
||||
|
||||
public Log getLogObject()
|
||||
{
|
||||
/**
|
||||
* Pickup whatever is found/configured!
|
||||
*/
|
||||
return LogFactory.getLog(this.getClass().getName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
147
src/test/java/org/apache/commons/logging/PathableTestSuite.java
Normal file
147
src/test/java/org/apache/commons/logging/PathableTestSuite.java
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.logging;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestResult;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Custom TestSuite class that can be used to control the context classloader
|
||||
* in operation when a test runs.
|
||||
* <p>
|
||||
* For tests that need to control exactly what the classloader hierarchy is
|
||||
* like when the test is run, something like the following is recommended:
|
||||
* <pre>
|
||||
* class SomeTestCase extends TestCase {
|
||||
* public static Test suite() throws Exception {
|
||||
* PathableClassLoader parent = new PathableClassLoader(null);
|
||||
* parent.useSystemLoader("junit.");
|
||||
*
|
||||
* PathableClassLoader child = new PathableClassLoader(parent);
|
||||
* child.addLogicalLib("testclasses");
|
||||
* child.addLogicalLib("log4j12");
|
||||
* child.addLogicalLib("commons-logging");
|
||||
*
|
||||
* Class testClass = child.loadClass(SomeTestCase.class.getName());
|
||||
* ClassLoader contextClassLoader = child;
|
||||
*
|
||||
* PathableTestSuite suite = new PathableTestSuite(testClass, child);
|
||||
* return suite;
|
||||
* }
|
||||
*
|
||||
* // test methods go here
|
||||
* }
|
||||
* </pre>
|
||||
* Note that if the suite method throws an exception then this will be handled
|
||||
* reasonable gracefully by junit; it will report that the suite method for
|
||||
* a test case failed with exception yyy.
|
||||
* <p>
|
||||
* The use of PathableClassLoader is not required to use this class, but it
|
||||
* is expected that using the two classes together is common practice.
|
||||
* <p>
|
||||
* This class will run each test methods within the specified TestCase using
|
||||
* the specified context classloader and system classloader. If different
|
||||
* tests within the same class require different context classloaders,
|
||||
* then the context classloader passed to the constructor should be the
|
||||
* "lowest" one available, and tests that need the context set to some parent
|
||||
* of this "lowest" classloader can call
|
||||
* <pre>
|
||||
* // NB: pseudo-code only
|
||||
* setContextClassLoader(getContextClassLoader().getParent());
|
||||
* </pre>
|
||||
* This class ensures that any context classloader changes applied by a test
|
||||
* is undone after the test is run, so tests don't need to worry about
|
||||
* restoring the context classloader on exit. This class also ensures that
|
||||
* the system properties are restored to their original settings after each
|
||||
* test, so tests that manipulate those don't need to worry about resetting them.
|
||||
* <p>
|
||||
* This class does not provide facilities for manipulating system properties;
|
||||
* tests that need specific system properties can simply set them in the
|
||||
* fixture or at the start of a test method.
|
||||
* <p>
|
||||
* <b>Important!</b> When the test case is run, "this.getClass()" refers of
|
||||
* course to the Class object passed to the constructor of this class - which
|
||||
* is different from the class whose suite() method was executed to determine
|
||||
* the classpath. This means that the suite method cannot communicate with
|
||||
* the test cases simply by setting static variables (for example to make the
|
||||
* custom classloaders available to the test methods or setUp/tearDown fixtures).
|
||||
* If this is really necessary then it is possible to use reflection to invoke
|
||||
* static methods on the class object passed to the constructor of this class.
|
||||
* <p>
|
||||
* <h2>Limitations</h2>
|
||||
* <p>
|
||||
* This class cannot control the system classloader (ie what method
|
||||
* ClassLoader.getSystemClassLoader returns) because Java provides no
|
||||
* mechanism for setting the system classloader. In this case, the only
|
||||
* option is to invoke the unit test in a separate JVM with the appropriate
|
||||
* settings.
|
||||
* <p>
|
||||
* The effect of using this approach in a system that uses junit's
|
||||
* "reloading classloader" behaviour is unknown. This junit feature is
|
||||
* intended for junit GUI apps where a test may be run multiple times
|
||||
* within the same JVM - and in particular, when the .class file may
|
||||
* be modified between runs of the test. How junit achieves this is
|
||||
* actually rather weird (the whole junit code is rather weird in fact)
|
||||
* and it is not clear whether this approach will work as expected in
|
||||
* such situations.
|
||||
*/
|
||||
public class PathableTestSuite extends TestSuite {
|
||||
|
||||
/**
|
||||
* The classloader that should be set as the context classloader
|
||||
* before each test in the suite is run.
|
||||
*/
|
||||
private final ClassLoader contextLoader;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param testClass is the TestCase that is to be run, as loaded by
|
||||
* the appropriate ClassLoader.
|
||||
*
|
||||
* @param contextClassLoader is the loader that should be returned by
|
||||
* calls to Thread.currentThread.getContextClassLoader from test methods
|
||||
* (or any method called by test methods).
|
||||
*/
|
||||
public PathableTestSuite(Class testClass, ClassLoader contextClassLoader) {
|
||||
super(testClass);
|
||||
contextLoader = contextClassLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked once for each Test in the current TestSuite.
|
||||
* Note that a Test may itself be a TestSuite object (ie a collection
|
||||
* of tests).
|
||||
* <p>
|
||||
* The context classloader and system properties are saved before each
|
||||
* test, and restored after the test completes to better isolate tests.
|
||||
*/
|
||||
public void runTest(Test test, TestResult result) {
|
||||
ClassLoader origContext = Thread.currentThread().getContextClassLoader();
|
||||
Properties oldSysProps = (Properties) System.getProperties().clone();
|
||||
try {
|
||||
Thread.currentThread().setContextClassLoader(contextLoader);
|
||||
test.run(result);
|
||||
} finally {
|
||||
System.setProperties(oldSysProps);
|
||||
Thread.currentThread().setContextClassLoader(origContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
41
src/test/java/org/apache/commons/logging/UserClass.java
Normal file
41
src/test/java/org/apache/commons/logging/UserClass.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.logging;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.commons.logging.impl.LogFactoryImpl;
|
||||
|
||||
public class UserClass {
|
||||
|
||||
/**
|
||||
* Set the ALLOW_FLAWED_CONTEXT feature on the LogFactoryImpl object
|
||||
* associated with this class' classloader.
|
||||
* <p>
|
||||
* Don't forget to set the context classloader to whatever it will be
|
||||
* when an instance of this class is actually created <i>before</i> calling
|
||||
* this method!
|
||||
*/
|
||||
public static void setAllowFlawedContext(String state) {
|
||||
LogFactory f = LogFactory.getFactory();
|
||||
f.setAttribute(LogFactoryImpl.ALLOW_FLAWED_CONTEXT_PROPERTY, state);
|
||||
}
|
||||
|
||||
public UserClass() {
|
||||
Log log = LogFactory.getLog(LoadTestCase.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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$ $Date$
|
||||
*/
|
||||
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,18 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
configId=nopriority
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
priority=10.5
|
||||
configId=priority10
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
priority=20.6
|
||||
configId=priority20
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
priority=20.6
|
||||
configId=priority20a
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT 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 WeakHashtableTest 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 WeakHashtableTest(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));
|
||||
}
|
||||
|
||||
public void testRelease() 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,25 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT 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 is the custom configuration properties for the JDK 1.4 logger tests
|
||||
# in CustomConfigTestCase.
|
||||
|
||||
# Configure the Handler so we can examine the logged messages
|
||||
handlers = org.apache.commons.logging.jdk14.TestHandler
|
||||
|
||||
# Configre the default logging level to be FINE so we should get
|
||||
# everything except trace messages
|
||||
.level = FINE
|
||||
@@ -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$ $Date$
|
||||
*/
|
||||
|
||||
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("TestLogger");
|
||||
setUpHandlers();
|
||||
setUpFactory();
|
||||
setUpLog("TestLogger");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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", "TestLogger", 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$ $Date$
|
||||
*/
|
||||
|
||||
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$ $Date$
|
||||
*/
|
||||
|
||||
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,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.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());
|
||||
|
||||
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,133 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT 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 {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
|
||||
assertEquals(0, untrustedCodeCount);
|
||||
} 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,128 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT 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;
|
||||
|
||||
// Dummy special hashtable, so we can tell JCL to use this instead of
|
||||
// the standard one.
|
||||
public static class CustomHashtable extends Hashtable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
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
|
||||
* priveleges 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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$ $Date$
|
||||
*/
|
||||
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,101 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.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
|
||||
|
||||
|
||||
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$ $Date$
|
||||
*/
|
||||
|
||||
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,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.apache.commons.logging.simple;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
public class LogRecord implements Serializable {
|
||||
|
||||
|
||||
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,20 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
use_tccl=false
|
||||
org.apache.commons.logging.Log=org.apache.commons.logging.tccl.custom.MyLog
|
||||
org.apache.commons.logging.diagnostics.dest=STDERR
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
org.apache.commons.logging.Log=org.apache.commons.logging.tccl.custom.MyLog
|
||||
org.apache.commons.logging.diagnostics.dest=STDERR
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
use_tccl=false
|
||||
org.apache.commons.logging.LogFactory=org.apache.commons.logging.tccl.custom.MyLogFactoryImpl
|
||||
@@ -0,0 +1,18 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
org.apache.commons.logging.LogFactory=org.apache.commons.logging.tccl.custom.MyLogFactoryImpl
|
||||
Reference in New Issue
Block a user