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 org.apache.commons.logging.LogFactory;
23  import org.apache.commons.logging.PathableClassLoader;
24  import org.apache.commons.logging.PathableTestSuite;
25  
26  import junit.framework.Test;
27  import junit.framework.TestCase;
28  
29  /**
30   * Verify that a commons-logging.properties file can prevent a custom
31   * LogFactoryImpl being loaded from the tccl class loader.
32   */
33  
34  public class TcclDisabledTestCase extends TestCase {
35  
36      public static final String MY_LOG_FACTORY_PKG =
37          "org.apache.commons.logging.tccl.custom";
38  
39      public static final String MY_LOG_FACTORY_IMPL =
40          MY_LOG_FACTORY_PKG + ".MyLogFactoryImpl";
41  
42      /**
43       * Return the tests included in this test suite.
44       */
45      public static Test suite() throws Exception {
46          final Class thisClass = TcclDisabledTestCase.class;
47  
48          // Determine the URL to this .class file, so that we can then
49          // append the priority dirs to it. For tidiness, load this
50          // class through a dummy loader though this is not absolutely
51          // necessary...
52          final PathableClassLoader dummy = new PathableClassLoader(null);
53          dummy.useExplicitLoader("junit.", Test.class.getClassLoader());
54          dummy.addLogicalLib("testclasses");
55          dummy.addLogicalLib("commons-logging");
56  
57          final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
58          final URL baseUrl = dummy.findResource(thisClassPath);
59  
60          // Now set up the desired class loader hierarchy. Everything goes into
61          // the parent classpath, but we exclude the custom LogFactoryImpl
62          // class.
63          //
64          // We then create a tccl class loader that can see the custom
65          // LogFactory class. Therefore if that class can be found, then the
66          // TCCL must have been used to load it.
67          final PathableClassLoader emptyLoader = new PathableClassLoader(null);
68  
69          final PathableClassLoader parentLoader = new PathableClassLoader(null);
70          parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
71          parentLoader.addLogicalLib("commons-logging");
72          parentLoader.addLogicalLib("testclasses");
73          // hack to ensure that the test class loader can't see
74          // the custom MyLogFactoryImpl
75          parentLoader.useExplicitLoader(
76              MY_LOG_FACTORY_PKG + ".", emptyLoader);
77  
78          final URL propsEnableUrl = new URL(baseUrl, "props_disable_tccl/");
79          parentLoader.addURL(propsEnableUrl);
80  
81          final PathableClassLoader tcclLoader = new PathableClassLoader(parentLoader);
82          tcclLoader.addLogicalLib("testclasses");
83  
84          final Class testClass = parentLoader.loadClass(thisClass.getName());
85          return new PathableTestSuite(testClass, tcclLoader);
86      }
87  
88      /**
89       * Sets up instance variables required by this test case.
90       */
91      @Override
92      public void setUp() throws Exception {
93          LogFactory.releaseAll();
94      }
95  
96      /**
97       * Tear down instance variables required by this test case.
98       */
99      @Override
100     public void tearDown() {
101         LogFactory.releaseAll();
102     }
103 
104     /**
105      * Verify that MyLogFactoryImpl is only loadable via the tccl.
106      */
107     public void testLoader() throws Exception {
108 
109         final ClassLoader thisClassLoader = this.getClass().getClassLoader();
110         final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
111 
112         // the tccl loader should NOT be the same as the loader that loaded this test class.
113         assertNotSame("tccl not same as test class loader", thisClassLoader, tcclLoader);
114 
115         // MyLogFactoryImpl should not be loadable via parent loader
116         try {
117             final Class clazz = thisClassLoader.loadClass(MY_LOG_FACTORY_IMPL);
118             fail("Unexpectedly able to load MyLogFactoryImpl via test class class loader");
119             assertNotNull(clazz); // silence warning about unused var
120         } catch (final ClassNotFoundException ex) {
121             // ok, expected
122         }
123 
124         // MyLogFactoryImpl should be loadable via tccl loader
125         try {
126             final Class clazz = tcclLoader.loadClass(MY_LOG_FACTORY_IMPL);
127             assertNotNull(clazz);
128         } catch (final ClassNotFoundException ex) {
129             fail("Unexpectedly unable to load MyLogFactoryImpl via tccl class loader");
130         }
131     }
132 
133     /**
134      * Verify that the custom LogFactory implementation which is only accessible
135      * via the TCCL has NOT been loaded. Because this is only accessible via the
136      * TCCL, and we've use a commons-logging.properties that disables TCCL loading,
137      * we should see the default LogFactoryImpl rather than the custom one.
138      */
139     public void testTcclLoading() throws Exception {
140         try {
141             final LogFactory instance = LogFactory.getFactory();
142             fail("Unexpectedly succeeded in loading custom factory, though TCCL disabled.");
143             assertNotNull(instance); // silence warning about unused var
144         } catch (final org.apache.commons.logging.LogConfigurationException ex) {
145             // ok, custom MyLogFactoryImpl as specified in props_disable_tccl
146             // could not be found.
147             final int index = ex.getMessage().indexOf(MY_LOG_FACTORY_IMPL);
148             assertTrue("MylogFactoryImpl not found", index >= 0);
149         }
150     }
151 }