View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.logging.tccl.logfactory;
19  
20  import java.net.URL;
21  
22  import junit.framework.Test;
23  import junit.framework.TestCase;
24  
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.commons.logging.PathableClassLoader;
27  import org.apache.commons.logging.PathableTestSuite;
28  
29  /**
30   * Verifies that a commons-logging.properties file can prevent a custom
31   * LogFactoryImpl being loaded from the TCCL class loader.
32   */
33  public class TcclDisabledTestCase extends TestCase {
34  
35      public static final String MY_LOG_FACTORY_PKG =
36          "org.apache.commons.logging.tccl.custom";
37  
38      public static final String MY_LOG_FACTORY_IMPL =
39          MY_LOG_FACTORY_PKG + ".MyLogFactoryImpl";
40  
41      /**
42       * Returns the tests included in this test suite.
43       */
44      public static Test suite() throws Exception {
45          final Class<TcclDisabledTestCase> thisClass = TcclDisabledTestCase.class;
46  
47          // Determine the URL to this .class file, so that we can then
48          // append the priority dirs to it. For tidiness, load this
49          // class through a dummy loader though this is not absolutely
50          // necessary...
51          final PathableClassLoader dummy = new PathableClassLoader(null);
52          dummy.useExplicitLoader("junit.", Test.class.getClassLoader());
53          dummy.addLogicalLib("testclasses");
54          dummy.addLogicalLib("commons-logging");
55  
56          final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
57          final URL baseUrl = dummy.findResource(thisClassPath);
58  
59          // Now set up the desired class loader hierarchy. Everything goes into
60          // the parent classpath, but we exclude the custom LogFactoryImpl
61          // class.
62          //
63          // We then create a TCCL class loader that can see the custom
64          // LogFactory class. Therefore if that class can be found, then the
65          // TCCL must have been used to load it.
66          final PathableClassLoader emptyLoader = new PathableClassLoader(null);
67  
68          final PathableClassLoader parentLoader = new PathableClassLoader(null);
69          parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
70          parentLoader.addLogicalLib("commons-logging");
71          parentLoader.addLogicalLib("testclasses");
72          // hack to ensure that the test class loader can't see
73          // the custom MyLogFactoryImpl
74          parentLoader.useExplicitLoader(
75              MY_LOG_FACTORY_PKG + ".", emptyLoader);
76  
77          final URL propsEnableUrl = new URL(baseUrl, "props_disable_tccl/");
78          parentLoader.addURL(propsEnableUrl);
79  
80          final PathableClassLoader tcclLoader = new PathableClassLoader(parentLoader);
81          tcclLoader.addLogicalLib("testclasses");
82  
83          final Class<?> testClass = parentLoader.loadClass(thisClass.getName());
84          return new PathableTestSuite(testClass, tcclLoader);
85      }
86  
87      /**
88       * Sets up instance variables required by this test case.
89       */
90      @Override
91      public void setUp() throws Exception {
92          LogFactory.releaseAll();
93      }
94  
95      /**
96       * Tears down instance variables required by this test case.
97       */
98      @Override
99      public void tearDown() {
100         LogFactory.releaseAll();
101     }
102 
103     /**
104      * Verifies that MyLogFactoryImpl is only loadable via the TCCL.
105      */
106     public void testLoader() throws Exception {
107 
108         final ClassLoader thisClassLoader = this.getClass().getClassLoader();
109         final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
110 
111         // the tccl loader should NOT be the same as the loader that loaded this test class.
112         assertNotSame("TCCL not same as test class loader", thisClassLoader, tcclLoader);
113 
114         // MyLogFactoryImpl should not be loadable via parent loader
115         try {
116             final Class<?> clazz = thisClassLoader.loadClass(MY_LOG_FACTORY_IMPL);
117             fail("Unexpectedly able to load MyLogFactoryImpl via test class class loader");
118             assertNotNull(clazz); // silence warning about unused var
119         } catch (final ClassNotFoundException ex) {
120             // OK, expected
121         }
122 
123         // MyLogFactoryImpl should be loadable via TCCL loader
124         try {
125             final Class<?> clazz = tcclLoader.loadClass(MY_LOG_FACTORY_IMPL);
126             assertNotNull(clazz);
127         } catch (final ClassNotFoundException ex) {
128             fail("Unexpectedly unable to load MyLogFactoryImpl via TCCL class loader");
129         }
130     }
131 
132     /**
133      * Verifies that the custom LogFactory implementation which is only accessible
134      * via the TCCL has NOT been loaded. Because this is only accessible via the
135      * TCCL, and we've use a commons-logging.properties that disables TCCL loading,
136      * we should see the default LogFactoryImpl rather than the custom one.
137      */
138     public void testTcclLoading() throws Exception {
139         try {
140             final LogFactory instance = LogFactory.getFactory();
141             fail("Unexpectedly succeeded in loading custom factory, though TCCL disabled.");
142             assertNotNull(instance); // silence warning about unused var
143         } catch (final org.apache.commons.logging.LogConfigurationException ex) {
144             // OK, custom MyLogFactoryImpl as specified in props_disable_tccl
145             // could not be found.
146             assertTrue("MylogFactoryImpl not found", ex.getMessage().contains(MY_LOG_FACTORY_IMPL));
147         }
148     }
149 }