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