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.log;
19  
20  import java.net.URL;
21  
22  import junit.framework.Test;
23  import junit.framework.TestCase;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogConfigurationException;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.commons.logging.PathableClassLoader;
29  import org.apache.commons.logging.PathableTestSuite;
30  
31  /**
32   * Verifies that by default LogFactoryImpl is loaded from the TCCL class loader.
33   */
34  public class TcclDisabledTestCase extends TestCase {
35  
36      public static final String MY_LOG_PKG =
37          "org.apache.commons.logging.tccl.custom";
38  
39      public static final String MY_LOG_IMPL =
40          MY_LOG_PKG + ".MyLog";
41  
42      /**
43       * Returns the tests included in this test suite.
44       */
45      public static Test suite() throws Exception {
46          final Class<TcclDisabledTestCase> 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 Log class.
62          //
63          // We then create a TCCL class loader that can see the custom
64          // Log 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 MyLog
74          parentLoader.useExplicitLoader(MY_LOG_PKG + ".", emptyLoader);
75  
76          final URL propsEnableUrl = new URL(baseUrl, "props_disable_tccl/");
77          parentLoader.addURL(propsEnableUrl);
78  
79          final PathableClassLoader tcclLoader = new PathableClassLoader(parentLoader);
80          tcclLoader.addLogicalLib("testclasses");
81  
82          final Class<?> testClass = parentLoader.loadClass(thisClass.getName());
83          return new PathableTestSuite(testClass, tcclLoader);
84      }
85  
86      /**
87       * Sets up instance variables required by this test case.
88       */
89      @Override
90      public void setUp() throws Exception {
91          LogFactory.releaseAll();
92      }
93  
94      /**
95       * Tears down instance variables required by this test case.
96       */
97      @Override
98      public void tearDown() {
99          LogFactory.releaseAll();
100     }
101 
102     /**
103      * Verifies that MyLog is only loadable via the TCCL.
104      */
105     public void testLoader() throws Exception {
106 
107         final ClassLoader thisClassLoader = this.getClass().getClassLoader();
108         final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
109 
110         // the TCCL loader should NOT be the same as the loader that loaded this test class.
111         assertNotSame("TCCL not same as test class loader", thisClassLoader, tcclLoader);
112 
113         // MyLog should not be loadable via parent loader
114         try {
115             final Class<?> clazz = thisClassLoader.loadClass(MY_LOG_IMPL);
116             fail("Unexpectedly able to load MyLog via test class class loader");
117             assertNotNull(clazz); // silence warnings about unused var
118         } catch (final ClassNotFoundException ex) {
119             // ok, expected
120         }
121 
122         // MyLog should be loadable via TCCL loader
123         try {
124             final Class<?> clazz = tcclLoader.loadClass(MY_LOG_IMPL);
125             assertNotNull(clazz);
126         } catch (final ClassNotFoundException ex) {
127             fail("Unexpectedly unable to load MyLog via TCCL class loader");
128         }
129     }
130 
131     /**
132      * Verifies that the custom Log implementation which is only accessible
133      * via the TCCL has NOT been loaded. Because this is only accessible via the
134      * TCCL, and we've use a commons-logging.properties that disables TCCL loading,
135      * we should see the default Log rather than the custom one.
136      */
137     public void testTcclLoading() throws Exception {
138         final LogFactory instance = LogFactory.getFactory();
139         assertEquals(
140                 "Correct LogFactory loaded",
141                 "org.apache.commons.logging.impl.LogFactoryImpl",
142                 instance.getClass().getName());
143 
144         try {
145             final Log log = instance.getInstance("test");
146             fail("Unexpectedly succeeded in loading a custom Log class"
147                 + " that is only accessible via the TCCL.");
148             assertNotNull(log); // silence compiler warning about unused var
149         } catch (final LogConfigurationException ex) {
150             // ok, expected
151             assertTrue("MyLog not found", ex.getMessage().contains(MY_LOG_IMPL));
152         }
153     }
154 }