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.LogFactory;
27  import org.apache.commons.logging.PathableClassLoader;
28  import org.apache.commons.logging.PathableTestSuite;
29  
30  /**
31   * Verifies that by default the standard LogFactoryImpl class loads a
32   * custom Log implementation via the TCCL.
33   */
34  public class TcclEnabledTestCase 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<TcclEnabledTestCase> thisClass = TcclEnabledTestCase.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 MyLogFactoryImpl
74          parentLoader.useExplicitLoader(MY_LOG_PKG + ".", emptyLoader);
75  
76          final URL propsEnableUrl = new URL(baseUrl, "props_enable_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 MyLogFactoryImpl 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 successfully been loaded as specified in the config file.
134      * This proves that the TCCL was used to load that class.
135      */
136     public void testTcclLoading() throws Exception {
137         final LogFactory instance = LogFactory.getFactory();
138 
139         assertEquals(
140             "Correct LogFactory loaded",
141             "org.apache.commons.logging.impl.LogFactoryImpl",
142             instance.getClass().getName());
143 
144         final Log log = instance.getInstance("test");
145         assertEquals(
146             "Correct Log loaded",
147             MY_LOG_IMPL,
148             log.getClass().getName());
149     }
150 }