master dbf68c5fc129 cached
153 files
329.3 KB
87.3k tokens
488 symbols
1 requests
Download .txt
Showing preview only (390K chars total). Download the full file or copy to clipboard to get everything.
Repository: mjiderhamn/classloader-leak-prevention
Branch: master
Commit: dbf68c5fc129
Files: 153
Total size: 329.3 KB

Directory structure:
gitextract_ovazmkyr/

├── .gitignore
├── .mvn/
│   └── wrapper/
│       ├── MavenWrapperDownloader.java
│       └── maven-wrapper.properties
├── .travis.yml
├── LICENSE.txt
├── README.md
├── classloader-leak-prevention/
│   ├── classloader-leak-prevention-core/
│   │   ├── README.md
│   │   ├── pom.xml
│   │   └── src/
│   │       ├── main/
│   │       │   └── java/
│   │       │       └── se/
│   │       │           └── jiderhamn/
│   │       │               └── classloader/
│   │       │                   └── leak/
│   │       │                       └── prevention/
│   │       │                           ├── ClassLoaderLeakPreventor.java
│   │       │                           ├── ClassLoaderLeakPreventorFactory.java
│   │       │                           ├── ClassLoaderPreMortemCleanUp.java
│   │       │                           ├── JULLogger.java
│   │       │                           ├── Logger.java
│   │       │                           ├── MustBeAfter.java
│   │       │                           ├── PreClassLoaderInitiator.java
│   │       │                           ├── ReplaceDOMNormalizerSerializerAbortException.java
│   │       │                           ├── StdLogger.java
│   │       │                           ├── cleanup/
│   │       │                           │   ├── ApacheCommonsLoggingCleanUp.java
│   │       │                           │   ├── BeanELResolverCleanUp.java
│   │       │                           │   ├── BeanIntrospectorCleanUp.java
│   │       │                           │   ├── BeanValidationCleanUp.java
│   │       │                           │   ├── DefaultAuthenticatorCleanUp.java
│   │       │                           │   ├── DriverManagerCleanUp.java
│   │       │                           │   ├── GeoToolsCleanUp.java
│   │       │                           │   ├── IIOServiceProviderCleanUp.java
│   │       │                           │   ├── IntrospectionUtilsCleanUp.java
│   │       │                           │   ├── JDK8151486CleanUp.java
│   │       │                           │   ├── JacksonCleanUp.java
│   │       │                           │   ├── JavaServerFaces2746CleanUp.java
│   │       │                           │   ├── JavaUtilLoggingLevelCleanUp.java
│   │       │                           │   ├── JavaxSecurityAuthLoginConfigurationCleanUp.java
│   │       │                           │   ├── JceSecurityCleanUp.java
│   │       │                           │   ├── KeepAliveTimerCacheCleanUp.java
│   │       │                           │   ├── MBeanCleanUp.java
│   │       │                           │   ├── MXBeanNotificationListenersCleanUp.java
│   │       │                           │   ├── MoxyCleanUp.java
│   │       │                           │   ├── MultiThreadedHttpConnectionManagerCleanUp.java
│   │       │                           │   ├── ObjectStreamClassCleanup.java
│   │       │                           │   ├── PropertyEditorCleanUp.java
│   │       │                           │   ├── ProxySelectorCleanUp.java
│   │       │                           │   ├── ReactorNettyHttpResourcesCleanUp.java
│   │       │                           │   ├── ResourceBundleCleanUp.java
│   │       │                           │   ├── RmiTargetsCleanUp.java
│   │       │                           │   ├── SAAJEnvelopeFactoryParserPoolCleanUp.java
│   │       │                           │   ├── SecurityProviderCleanUp.java
│   │       │                           │   ├── ShutdownHookCleanUp.java
│   │       │                           │   ├── StopThreadsCleanUp.java
│   │       │                           │   ├── ThreadGroupCleanUp.java
│   │       │                           │   ├── ThreadGroupContextCleanUp.java
│   │       │                           │   ├── ThreadLocalCleanUp.java
│   │       │                           │   ├── WarningThreadLocalCleanUp.java
│   │       │                           │   └── X509TrustManagerImplUnparseableExtensionCleanUp.java
│   │       │                           └── preinit/
│   │       │                               ├── AwtToolkitInitiator.java
│   │       │                               ├── DatatypeConverterImplInitiator.java
│   │       │                               ├── DocumentBuilderFactoryInitiator.java
│   │       │                               ├── JarUrlConnectionInitiator.java
│   │       │                               ├── Java2dDisposerInitiator.java
│   │       │                               ├── Java2dRenderQueueInitiator.java
│   │       │                               ├── JavaxSecurityLoginConfigurationInitiator.java
│   │       │                               ├── JdbcDriversInitiator.java
│   │       │                               ├── LdapPoolManagerInitiator.java
│   │       │                               ├── OracleJdbcThreadInitiator.java
│   │       │                               ├── SecurityPolicyInitiator.java
│   │       │                               ├── SecurityProvidersInitiator.java
│   │       │                               ├── SunAwtAppContextInitiator.java
│   │       │                               └── SunGCInitiator.java
│   │       └── test/
│   │           ├── java/
│   │           │   └── se/
│   │           │       └── jiderhamn/
│   │           │           └── classloader/
│   │           │               └── leak/
│   │           │                   └── prevention/
│   │           │                       ├── ClassLoaderLeakPreventorFactoryTest.java
│   │           │                       ├── PreventionsTestBase.java
│   │           │                       ├── StopThreadsCleanUp_TimerTest.java
│   │           │                       ├── cleanup/
│   │           │                       │   ├── BeanELResolverCleanUpTest.java
│   │           │                       │   ├── BeanIntrospectorCleanUpTest.java
│   │           │                       │   ├── BeanValidationCleanUpTest.java
│   │           │                       │   ├── ClassLoaderPreMortemCleanUpTestBase.java
│   │           │                       │   ├── DefaultAuthenticatorCleanUpTest.java
│   │           │                       │   ├── DriverManagerCleanUpTest.java
│   │           │                       │   ├── GeoToolsCleanUpTest.java
│   │           │                       │   ├── IIOServiceProviderCleanUpTest.java
│   │           │                       │   ├── ImageIOMockImageInputStreamSPI.java
│   │           │                       │   ├── JDK8151486CleanUpTest.java
│   │           │                       │   ├── JacksonCleanUpTest.java
│   │           │                       │   ├── JavaServerFaces2746CleanUpTest.java
│   │           │                       │   ├── JavaUtilLoggingLevelCleanUpTest.java
│   │           │                       │   ├── JavaxSecurityAuthLoginConfigurationCleanUpTest.java
│   │           │                       │   ├── JceSecurityCleanUpTest.java
│   │           │                       │   ├── MBeanCleanUpTest.java
│   │           │                       │   ├── MXBeanNotificationListenersCleanUpTest.java
│   │           │                       │   ├── MXBeanNotificationListenersCleanUp_ListenerWrapperTest.java
│   │           │                       │   ├── MoxyCleanUpTest.java
│   │           │                       │   ├── MultiThreadedHttpConnectionManagerCleanUpTest.java
│   │           │                       │   ├── ObjectStreamClassCleanupTest.java
│   │           │                       │   ├── PropertyEditorCleanUpTest.java
│   │           │                       │   ├── ProxySelectorCleanUpTest.java
│   │           │                       │   ├── ReplaceDOMNormalizerSerializerAbortExceptionCleanUpTest.java
│   │           │                       │   ├── SAAJEnvelopeFactoryParserPoolCleanUpTest.java
│   │           │                       │   ├── SecurityProviderCleanUpTest.java
│   │           │                       │   ├── ShutdownHookCleanUpTest.java
│   │           │                       │   ├── StopThreadsCleanUp_MultiThreadedHttpConnectionManagerTest.java
│   │           │                       │   ├── StopThreadsCleanUp_PostgresqlJdbcTest.java
│   │           │                       │   ├── StopThreadsCleanUp_Runnable.java
│   │           │                       │   ├── StopThreadsClenup_ExecutorTest.java
│   │           │                       │   ├── ThreadGroupCleanUpTest.java
│   │           │                       │   ├── ThreadLocalCleanUpTest.java
│   │           │                       │   ├── ThreadLocalWithNestedRefValueCleanUpTest.java
│   │           │                       │   ├── ThreadLocalWithRefValueCleanUpTest.java
│   │           │                       │   ├── X509TrustManagerImplUnparseableExtensionCleanUpTest.java
│   │           │                       │   └── package-info.java
│   │           │                       ├── package-info.java
│   │           │                       └── preinit/
│   │           │                           ├── AwtToolkitInitiatorTest.java
│   │           │                           ├── DatatypeConverterImplInitiatorTest.java
│   │           │                           ├── DocumentBuilderFactoryInitiatorTest.java
│   │           │                           ├── Java2dDisposerInitiatorTest.java
│   │           │                           ├── Java2dRenderQueueInitiatorTest.java
│   │           │                           ├── JavaxSecurityLoginConfigurationInitiatorTest.java
│   │           │                           ├── JdbcDriversInitiatorTest.java
│   │           │                           ├── LdapPoolManagerInitiatorTest.java
│   │           │                           ├── OracleJdbcThreadInitiatorTest.java
│   │           │                           ├── PreClassLoaderInitiatorTestBase.java
│   │           │                           ├── ReplaceDOMNormalizerSerializerAbortExceptionInitiatorTest.java
│   │           │                           ├── SecurityPolicyInitiatorTest.java
│   │           │                           ├── SecurityProvidersInitiatorTest.java
│   │           │                           ├── SunAwtAppContextInitiatorTest.java
│   │           │                           └── SunGCInitiatorTest.java
│   │           └── resources/
│   │               ├── META-INF/
│   │               │   └── services/
│   │               │       └── javax.imageio.spi.ImageInputStreamSpi
│   │               ├── spi-cacert-2008.crt
│   │               └── spi-cacert-2008.keystore
│   ├── classloader-leak-prevention-servlet/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           └── java/
│   │               └── se/
│   │                   └── jiderhamn/
│   │                       └── classloader/
│   │                           └── leak/
│   │                               └── prevention/
│   │                                   └── ClassLoaderLeakPreventorListener.java
│   ├── classloader-leak-prevention-servlet3/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── se/
│   │           │       └── jiderhamn/
│   │           │           └── classloader/
│   │           │               └── leak/
│   │           │                   └── prevention/
│   │           │                       └── ClassLoaderLeakPreventionContainerInitializer.java
│   │           └── resources/
│   │               └── META-INF/
│   │                   ├── services/
│   │                   │   └── javax.servlet.ServletContainerInitializer
│   │                   └── web-fragment.xml
│   └── pom.xml
├── classloader-leak-test-framework/
│   ├── README.md
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── se/
│       │           └── jiderhamn/
│       │               ├── HeapDumper.java
│       │               └── classloader/
│       │                   ├── PackagesLoadedOutsideClassLoader.java
│       │                   ├── RedefiningClassLoader.java
│       │                   ├── ZombieMarker.java
│       │                   └── leak/
│       │                       ├── JUnitClassloaderRunner.java
│       │                       ├── LeakPreventor.java
│       │                       └── Leaks.java
│       └── test/
│           └── java/
│               ├── com/
│               │   └── classloader/
│               │       └── test/
│               │           └── CustomClass.java
│               └── se/
│                   └── jiderhamn/
│                       └── classloader/
│                           ├── RedefiningClassLoaderTest.java
│                           └── leak/
│                               ├── JUnitClassloaderRunnerTest.java
│                               ├── NonLeakingTest.java
│                               ├── accused/
│                               │   ├── CustomThreadLocalTest.java
│                               │   └── package-info.java
│                               └── known/
│                                   ├── CustomThreadLocalCustomValueTest.java
│                                   ├── JEditorPaneTest.java
│                                   └── package-info.java
├── mvnw
├── mvnw.cmd
└── pom.xml

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
target
.classpath
.project
.settings
.mvn/wrapper/maven-wrapper.jar


================================================
FILE: .mvn/wrapper/MavenWrapperDownloader.java
================================================
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.Properties;

public final class MavenWrapperDownloader
{
    private static final String WRAPPER_VERSION = "3.1.1";

    private static final boolean VERBOSE = Boolean.parseBoolean( System.getenv( "MVNW_VERBOSE" ) );

    /**
     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
     */
    private static final String DEFAULT_DOWNLOAD_URL =
        "https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/" + WRAPPER_VERSION
            + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";

    /**
     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to use instead of the
     * default one.
     */
    private static final String MAVEN_WRAPPER_PROPERTIES_PATH = ".mvn/wrapper/maven-wrapper.properties";

    /**
     * Path where the maven-wrapper.jar will be saved to.
     */
    private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar";

    /**
     * Name of the property which should be used to override the default download url for the wrapper.
     */
    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";

    public static void main( String[] args )
    {
        if ( args.length == 0 )
        {
            System.err.println( " - ERROR projectBasedir parameter missing" );
            System.exit( 1 );
        }

        log( " - Downloader started" );
        final String dir = args[0].replace( "..", "" ); // Sanitize path
        final Path projectBasedir = Paths.get( dir ).toAbsolutePath().normalize();
        if ( !Files.isDirectory( projectBasedir, LinkOption.NOFOLLOW_LINKS ) )
        {
            System.err.println( " - ERROR projectBasedir not exists: " + projectBasedir );
            System.exit( 1 );
        }

        log( " - Using base directory: " + projectBasedir );

        // If the maven-wrapper.properties exists, read it and check if it contains a custom
        // wrapperUrl parameter.
        Path mavenWrapperPropertyFile = projectBasedir.resolve( MAVEN_WRAPPER_PROPERTIES_PATH );
        String url = readWrapperUrl( mavenWrapperPropertyFile );

        try
        {
            Path outputFile = projectBasedir.resolve( MAVEN_WRAPPER_JAR_PATH );
            createDirectories( outputFile.getParent() );
            downloadFileFromURL( url, outputFile );
            log( "Done" );
            System.exit( 0 );
        }
        catch ( IOException e )
        {
            System.err.println( "- Error downloading" );
            e.printStackTrace();
            System.exit( 1 );
        }
    }

    private static void downloadFileFromURL( String urlString, Path destination ) throws IOException
    {
        log( " - Downloading to: " + destination );
        if ( System.getenv( "MVNW_USERNAME" ) != null && System.getenv( "MVNW_PASSWORD" ) != null )
        {
            final String username = System.getenv( "MVNW_USERNAME" );
            final char[] password = System.getenv( "MVNW_PASSWORD" ).toCharArray();
            Authenticator.setDefault( new Authenticator()
            {
                @Override
                protected PasswordAuthentication getPasswordAuthentication()
                {
                    return new PasswordAuthentication( username, password );
                }
            } );
        }
        URL website = new URL( urlString );
        try ( InputStream inStream = website.openStream() ) {
            Files.copy( inStream, destination, StandardCopyOption.REPLACE_EXISTING );
        }
        log( " - Downloader complete" );
    }

    private static void createDirectories(Path outputPath) throws IOException
    {
        if ( !Files.isDirectory( outputPath, LinkOption.NOFOLLOW_LINKS ) ) {
            Path createDirectories = Files.createDirectories( outputPath );
            log( " - Directories created: " + createDirectories );
        }
    }

    private static String readWrapperUrl( Path mavenWrapperPropertyFile )
    {
        String url = DEFAULT_DOWNLOAD_URL;
        if ( Files.exists( mavenWrapperPropertyFile, LinkOption.NOFOLLOW_LINKS ) )
        {
            log( " - Reading property file: " + mavenWrapperPropertyFile );
            try ( InputStream in = Files.newInputStream( mavenWrapperPropertyFile, StandardOpenOption.READ ) )
            {
                Properties mavenWrapperProperties = new Properties();
                mavenWrapperProperties.load( in );
                url = mavenWrapperProperties.getProperty( PROPERTY_NAME_WRAPPER_URL, DEFAULT_DOWNLOAD_URL );
            }
            catch ( IOException e )
            {
                System.err.println( " - ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'" );
            }
        }
        log( " - Downloading from: " + url );
        return url;
    }

    private static void log( String msg )
    {
        if ( VERBOSE )
        {
            System.out.println( msg );
        }
    }

}


================================================
FILE: .mvn/wrapper/maven-wrapper.properties
================================================
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar


================================================
FILE: .travis.yml
================================================
dist: trusty

language: java

jdk:
  - oraclejdk8
  - openjdk11

# Uncomment to upload heapdumps to S3 bucket; https://docs.travis-ci.com/user/uploading-artifacts/
#addons:
#  artifacts:
#    paths:
#      - $(ls $HOME/build/mjiderhamn/classloader-leak-prevention/classloader-leak-prevention/classloader-leak-prevention-core/target/surefire-reports/*.hprof | tr "\n" ":")

cache:
  directories:
  - $HOME/.m2


================================================
FILE: LICENSE.txt
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# Classloader Leak Prevention library
[![Build Status](https://travis-ci.org/mjiderhamn/classloader-leak-prevention.svg?branch=master)](http://travis-ci.org/mjiderhamn/classloader-leak-prevention)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/se.jiderhamn.classloader-leak-prevention/classloader-leak-prevention-servlet3/badge.svg)](https://maven-badges.herokuapp.com/maven-central/se.jiderhamn.classloader-leak-prevention/classloader-leak-prevention-servlet3/)
[![License](https://img.shields.io/badge/license-Apache2-blue.svg?style=flat)](https://github.com/mjiderhamn/classloader-leak-prevention/blob/master/LICENSE.txt)

If you want to avoid the dreaded `java.lang.OutOfMemoryError: Metaspace` / `PermGen space`, 
just include this library into your Java EE application and it should take care of the rest!

To learn more about classloader leaks, their causes, types, ways to find them and known offenders, see blog series here: http://java.jiderhamn.se/category/classloader-leaks/

## Servlet 3.0+
In a Servlet 3.0+ environment, all you need to do is include this Maven 
dependency in your `.war`:
```xml
<dependency>
  <groupId>se.jiderhamn.classloader-leak-prevention</groupId>
  <artifactId>classloader-leak-prevention-servlet3</artifactId>
  <version>2.7.0</version>
</dependency>
```

If you run into problems with the Servlet 3.0 module, try the Servlet 2.5 alternative below.
Since the [Servlet spec does not guarantee the order of `ServletContainerInitializer`s](https://java.net/jira/browse/SERVLET_SPEC-79),
it means this library may not initialize first and clean up last in case you have other Servlet 3.0 dependencies, which
could lead to unexpected behaviour.

## Servlet 2.5 (and earlier)
For Servlet 2.5 (and earlier) environments, you need to use a different
Maven dependency (notice the difference in `artifactId`):
```xml
<dependency>
  <groupId>se.jiderhamn.classloader-leak-prevention</groupId>
  <artifactId>classloader-leak-prevention-servlet</artifactId>
  <version>2.7.0</version>
</dependency>
```

You also have to add this to your `web.xml`:
```xml
<listener>
  <listener-class>se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventorListener</listener-class>
</listener>
```
_Note that the name of the listener class has changed since 1.x!_

It makes sense to keep this listener "outermost" (initializing first, 
destroying last), so you should normally declare it before any other 
listeners in `web.xml`.

## Configuration
The context listener used in both cases has a number of settings that can be configured with context parameters in `web.xml`:
 
```xml
<context-param>
  <param-name>ClassLoaderLeakPreventor.stopThreads</param-name>
  <param-value>false</param-value>
</context-param>
```
 
 The available settings are
 <table border="1">
   <tr>
     <th>Parameter name</th>
     <th>Default value</th>
     <th>Description</th>
   </tr>
   <tr>
     <td><code>ClassLoaderLeakPreventor.stopThreads</code></td>
     <td><code>true</code></td>
     <td>Should threads tied to the web app classloader be forced to stop at application shutdown?</td>
   </tr>
   <tr>
     <td><code>ClassLoaderLeakPreventor.stopTimerThreads</code></td>
     <td><code>true</code></td>
     <td>Should Timer threads tied to the web app classloader be forced to stop at application shutdown?</td>
   </tr>
   <tr>
     <td><code>ClassLoaderLeakPreventor.executeShutdownHooks</td>
     <td><code>true</code></td>
     <td>Should shutdown hooks registered from the application be executed at application shutdown?</td>
   </tr>
   <tr>
     <td><code>ClassLoaderLeakPreventor.startOracleTimeoutThread</td>
     <td><code>true</code></td>
     <td>
       Should the <code>oracle.jdbc.driver.OracleTimeoutPollingThread</code> thread be forced to start with system ClassLoader,
       in case Oracle JDBC driver is present? This is normally a good idea, but can be disabled in case the Oracle JDBC
       driver is not used even though it is on the classpath.
     </td>
   </tr>
   <tr>
     <td><code>ClassLoaderLeakPreventor.threadWaitMs</td>
     <td nowrap="nowrap"><code>5000</code><br />(5 seconds)</td>
     <td>No of milliseconds to wait for threads to finish execution, before stopping them.</td>
   </tr>
   <tr>
     <td><code>ClassLoaderLeakPreventor.shutdownHookWaitMs</code></td>
     <td nowrap="nowrap"><code>10000</code><br />(10 seconds)</td>
     <td>
       No of milliseconds to wait for shutdown hooks to finish execution, before stopping them.
       If set to -1 there will be no waiting at all, but Thread is allowed to run until finished.
     </td>
   </tr>
 </table>

## Classloader leak detection / test framework

The test framework has its own Maven module and its own documentation, see [classloader-leak-test-framework](classloader-leak-test-framework).

## Integration

For non-servlet environments, please see the documentation for the [core module](classloader-leak-prevention/classloader-leak-prevention-core).

## License

This project is licensed under the [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0), which allows you to include modified versions of the code in your distributed software, without having to release your source code.


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/README.md
================================================
# Classloader Leak Prevention library integration

_This document is about using the Classloader Leak Prevention library in
a non-servlet environment. For general information and use in servlet 
environments, please see the [root README.md](../../README.md)_

Version 2.x of the Classloader Leak Prevention library has been refactored
to allow for use outside a servlet environment, or by all means in a
servlet container (Java EE application server).

# Setting up
What you will want to do is first create a [ClassLoaderLeakPreventorFactory](src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorFactory.java)
instance, either by using the default constructor that will configure the system
`ClassLoader` (`ClassLoader.getSystemClassLoader()`) to be used for pre-inits,
or provide your own leak safe `ClassLoader` to the constructor.

Make any configurations on the factory instance, i.e. add or remove any
[cleanup](src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderPreMortemCleanUp.java)
or [pre-init](https://github.com/mjiderhamn/classloader-leak-prevention/blob/master/classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/PreClassLoaderInitiator.java)
plugins, or change parameters of any of the default plugins.

# Protect ClassLoader
Then for every `ClassLoader` that needs leak protection, create a new
[ClassLoaderLeakPreventor](src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventor.java)
using
```java
classLoaderLeakPreventor = classLoaderLeakPreventorFactory.newLeakPreventor(classLoader);
```
 
Before letting any code execute inside the `ClassLoader` (or at least as
soon as possible), invoke
```java
classLoaderLeakPreventor.runPreClassLoaderInitiators();
```
 
You can reuse the same `ClassLoaderLeakPreventorFactory` for multiple
`ClassLoaders`, but please be aware that any configuration changes made
to plugins of the factory will affect all `ClassLoaderLeakPreventor`s 
created by the factory - both future and existing. If however you add
or remove plugins, that will only affect new `ClassLoaderLeakPreventor`s. 

# Shutting down
When you believe the `ClassLoader` should no longer be used, but be ready
for Garbage Collection, invoke 
```java
classLoaderLeakPreventor.runCleanUps();
```
on the `ClassLoaderLeakPreventor` that corresponds to the `ClassLoader`.

# Example
For an example how to use the framework, feel free to study the
[ClassLoaderLeakPreventorListener](../classloader-leak-prevention-servlet/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorListener.java)
in the `classloader-leak-prevention-servlet` module.

# Maven
The module is available in Maven as
```xml
<dependency>
  <groupId>se.jiderhamn.classloader-leak-prevention</groupId>
  <artifactId>classloader-leak-prevention-core</artifactId>
  <version>2.7.0</version>
</dependency>
```

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/pom.xml
================================================
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>se.jiderhamn.classloader-leak-prevention</groupId>
    <artifactId>classloader-leak-prevention-parent</artifactId>
    <version>2.7.1-SNAPSHOT</version>
  </parent>

  <artifactId>classloader-leak-prevention-core</artifactId>
  <packaging>jar</packaging>
  <name>ClassLoader Leak Prevention library</name>
  <description>Library that prevents ClassLoader leaks / java.lang.OutOfMemoryError: PermGen space</description>
  <url>https://github.com/mjiderhamn/classloader-leak-prevention</url>
  
  <dependencies>
    <!-- Dependency on test framework -->
    <dependency>
      <groupId>se.jiderhamn</groupId>
      <artifactId>classloader-leak-test-framework</artifactId>
      <version>1.1.2</version>
      <scope>test</scope>
    </dependency>
    <!-- Required by some of the tested APIs --> 
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1.3</version>
      <scope>test</scope>
    </dependency>
    <!-- Validation API needed for testing leak -->
    <dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>1.0.0.GA</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>4.2.0.Final</version>
      <scope>test</scope>
    </dependency>
    <!-- Apache Axis 1.4 for leak test -->
    <dependency>
      <groupId>org.apache.axis</groupId>
      <artifactId>axis</artifactId>
      <version>1.4</version>
      <scope>test</scope>
    </dependency>
    <!-- Required by Axis -->
    <dependency>
      <groupId>commons-discovery</groupId>
      <artifactId>commons-discovery</artifactId>
      <version>0.5</version>
      <scope>test</scope>
    </dependency>
    <!-- JDBC driver for DriverManager test -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.18</version>
      <scope>test</scope>
    </dependency>
    <!-- Test leak in EL implementation cache -->
    <dependency>
      <groupId>javax.el</groupId>
      <artifactId>el-api</artifactId>
      <version>2.2.1-b04</version>
      <scope>test</scope>
    </dependency>
    <!-- MultiThreadedHttpConnectionManagerCleanUpTest --> 
    <dependency>
      <groupId>com.sun.jersey.contribs</groupId>
      <artifactId>jersey-apache-client</artifactId>
      <version>1.19</version>
      <scope>test</scope>
    </dependency> 
    
    <!-- Test leak in CXF custom authenticator -->
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-transports-http</artifactId>
      <version>2.6.10</version>
      <scope>test</scope>
    </dependency>
    <!-- Test that GeoTools leaks are prevented -->
    <dependency>
      <groupId>org.geotools</groupId>
      <artifactId>gt-metadata</artifactId>
      <version>2.6.2</version>
      <scope>test</scope>
    </dependency>
    <!-- Test leak in JSF api -->
    <dependency>
      <groupId>com.sun.faces</groupId>
      <artifactId>jsf-api</artifactId>
      <version>2.1.19</version>
      <scope>test</scope>
    </dependency>
    <!-- Could be removed if Mockito was used to mock ELContext -->
    <dependency>
      <groupId>com.sun.faces</groupId>
      <artifactId>jsf-impl</artifactId>
      <version>2.1.19</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>9.4-1201-jdbc41</version>
      <scope>test</scope>
    </dependency>
    <!-- Test that MOXy leaks are prevented -->
    <dependency>
      <groupId>org.eclipse.persistence</groupId>
      <artifactId>org.eclipse.persistence.moxy</artifactId>
      <version>2.7.0</version>
      <scope>test</scope>
    </dependency>
    <!-- Test that Jackson leaks are prevented -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.2</version>
      <scope>test</scope>
    </dependency>
    
    <!-- Example dependency for test Oracle JDBC -->
    <!--
    <dependency>
      <groupId>com.oracle</groupId>
      <artifactId>ojdbc</artifactId>
      <version>12.2.0.1</version>
      <scope>test</scope>
    </dependency>
    -->

    <!-- Internal APIs that have been removed from the JDK in java 11. -->
    <!-- Used for testing SAAJEnvelopeFactoryParserPoolCleanUp. -->
    <dependency>
      <groupId>com.sun.xml.messaging.saaj</groupId>
      <artifactId>saaj-impl</artifactId>
      <version>1.4.0</version>
      <scope>provided</scope>
    </dependency>
    
    <!-- Internal APIs that have been removed from the JDK in java 11. Used for MoxyCleanUpTest -->
    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>2.2.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-core</artifactId>
      <version>2.2.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
      <version>2.2.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>javax.activation</groupId>
      <artifactId>activation</artifactId>
      <version>1.1.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <!-- Create artifact (jar) with test classes https://maven.apache.org/guides/mini/guide-attached-tests.html -->
  <build>
    <plugins>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-jar-plugin</artifactId>
       <version>3.0.2</version>
       <executions>
         <execution>
           <goals>
             <goal>test-jar</goal>
           </goals>
         </execution>
       </executions>
     </plugin>
    </plugins>
  </build>
</project>

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventor.java
================================================
package se.jiderhamn.classloader.leak.prevention;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * This class helps prevent classloader leaks.
 * @author Mattias Jiderhamn
 */
@SuppressWarnings("WeakerAccess")
public class ClassLoaderLeakPreventor {

  /** Default no of milliseconds to wait for threads to finish execution */
  public static final int THREAD_WAIT_MS_DEFAULT = 5 * 1000; // 5 seconds
  
  private static final ProtectionDomain[] NO_DOMAINS = new ProtectionDomain[0];

  private static final AccessControlContext NO_DOMAINS_ACCESS_CONTROL_CONTEXT = new AccessControlContext(NO_DOMAINS);

  /** {@link ClassLoader#isAncestor(ClassLoader)} */
  private final Method java_lang_ClassLoader_isAncestor;
  
  /** {@link ClassLoader#isAncestorOf(ClassLoader)} of IBM JRE */
  private final Method java_lang_ClassLoader_isAncestorOf;
  
  private final Field java_security_AccessControlContext$combiner;
  
  private final Field java_security_AccessControlContext$parent;
  
  private final Field java_security_AccessControlContext$privilegedContext;

  /** 
   * {@link ClassLoader} to be used when invoking the {@link PreClassLoaderInitiator}s.
   * This will normally be the {@link ClassLoader#getSystemClassLoader()}, but could be any other framework or 
   * app server classloader. Normally, but not necessarily, a parent of {@link #classLoader}.
   */
  private final ClassLoader leakSafeClassLoader;
  
  /** The {@link ClassLoader} we want to avoid leaking */
  private final ClassLoader classLoader;
  
  private final Logger logger;
  
  private final Collection<PreClassLoaderInitiator> preClassLoaderInitiators;
  
  private final Collection<ClassLoaderPreMortemCleanUp> cleanUps;
  
  /** {@link DomainCombiner} that filters any {@link ProtectionDomain}s loaded by our classloader */
  private final DomainCombiner domainCombiner;

  public ClassLoaderLeakPreventor(ClassLoader leakSafeClassLoader, ClassLoader classLoader, Logger logger,
                           Collection<PreClassLoaderInitiator> preClassLoaderInitiators,
                           Collection<ClassLoaderPreMortemCleanUp> cleanUps) {
    this.leakSafeClassLoader = leakSafeClassLoader;
    this.classLoader = classLoader;
    this.logger = logger;
    this.preClassLoaderInitiators = preClassLoaderInitiators;
    this.cleanUps = cleanUps;

    final String javaVendor = System.getProperty("java.vendor");
    if(javaVendor != null && javaVendor.startsWith("IBM")) { // IBM
      java_lang_ClassLoader_isAncestor = null;
      java_lang_ClassLoader_isAncestorOf = findMethod(ClassLoader.class, "isAncestorOf", ClassLoader.class);
    }
    else { // Oracle
      java_lang_ClassLoader_isAncestor = findMethod(ClassLoader.class, "isAncestor", ClassLoader.class);
      java_lang_ClassLoader_isAncestorOf = null;
    }
    NestedProtectionDomainCombinerException.class.getName(); // Should be loaded before switching to leak safe classloader
    
    this.domainCombiner = createDomainCombiner();

    // Reflection inits
    java_security_AccessControlContext$combiner = findField(AccessControlContext.class, "combiner");
    java_security_AccessControlContext$parent = findField(AccessControlContext.class, "parent");
    java_security_AccessControlContext$privilegedContext = findField(AccessControlContext.class, "privilegedContext");

  }
  
  /** Invoke all the registered {@link PreClassLoaderInitiator}s in the {@link #leakSafeClassLoader} */
  public void runPreClassLoaderInitiators() {
    info("Initializing by loading some known offenders with leak safe classloader"); 
    
    doInLeakSafeClassLoader(new Runnable() {
      @Override
      public void run() {
        for(PreClassLoaderInitiator preClassLoaderInitiator : preClassLoaderInitiators) {
          preClassLoaderInitiator.doOutsideClassLoader(ClassLoaderLeakPreventor.this);
        }
      }
    });
  }
  
  /**
   * Perform action in the provided ClassLoader (normally system ClassLoader, that may retain references to the 
   * {@link Thread#contextClassLoader}. 
   * The motive for the custom {@link AccessControlContext} is to avoid spawned threads from inheriting all the 
   * {@link java.security.ProtectionDomain}s of the running code, since that may include the classloader we want to 
   * avoid leaking. This however means the {@link AccessControlContext} will have a {@link DomainCombiner} referencing the 
   * classloader, which will be taken care of in {@link #runCleanUps()}.
   */
   protected void doInLeakSafeClassLoader(final Runnable runnable) {
     final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
     
     try {
       Thread.currentThread().setContextClassLoader(leakSafeClassLoader);
 
       // Use doPrivileged() not to perform secured actions, but to avoid threads spawned inheriting the 
       // AccessControlContext of the current thread, since among the ProtectionDomains there will be one
       // (the top one) whose classloader is the web app classloader
       AccessController.doPrivileged(new PrivilegedAction<Object>() {
         @Override
         public Object run() {
           runnable.run();
           return null; // Nothing to return
         }
       }, createAccessControlContext());
     }
     finally {
       // Reset original classloader
       Thread.currentThread().setContextClassLoader(contextClassLoader);
     }
   }
   
   /** 
    * Create {@link AccessControlContext} that is used in {@link #doInLeakSafeClassLoader(Runnable)}.
    * The motive is to avoid spawned threads from inheriting all the {@link java.security.ProtectionDomain}s of the 
    * running code, since that will include the web app classloader.
    */
   public AccessControlContext createAccessControlContext() {
     try { // Try the normal way
       return new AccessControlContext(NO_DOMAINS_ACCESS_CONTROL_CONTEXT, domainCombiner);
     }
     catch (SecurityException e) { // createAccessControlContext not granted
       try { // Try reflection
         Constructor<AccessControlContext> constructor = 
             AccessControlContext.class.getDeclaredConstructor(ProtectionDomain[].class, DomainCombiner.class);
         constructor.setAccessible(true);
         return constructor.newInstance(NO_DOMAINS, domainCombiner);
       }
       catch (Exception e1) {
         logger.error("createAccessControlContext not granted and AccessControlContext could not be created via reflection");
         return AccessController.getContext();
       }
     }
   } 
   
   /** {@link DomainCombiner} that filters any {@link ProtectionDomain}s loaded by our classloader */
   private DomainCombiner createDomainCombiner() {
     return new DomainCombiner() {
       
       /** Flag to detected recursive calls */
       private final ThreadLocal<Boolean> isExecuting = new ThreadLocal<Boolean>();
       
       @Override
       public ProtectionDomain[] combine(ProtectionDomain[] currentDomains, ProtectionDomain[] assignedDomains) {
         if(assignedDomains != null && assignedDomains.length > 0) {
           logger.error("Unexpected assignedDomains - please report to developer of this library!");
         }
 
         if(isExecuting.get() == Boolean.TRUE)
           throw new NestedProtectionDomainCombinerException();
           
         try {
           isExecuting.set(Boolean.TRUE); // Throw NestedProtectionDomainCombinerException on nested calls

           // Keep all ProtectionDomain not involving the web app classloader 
           final List<ProtectionDomain> output = new ArrayList<ProtectionDomain>();
           for(ProtectionDomain protectionDomain : currentDomains) {
             if(protectionDomain.getClassLoader() == null ||
                 ! isClassLoaderOrChild(protectionDomain.getClassLoader())) {
               output.add(protectionDomain);
             }
           }
           return output.toArray(new ProtectionDomain[output.size()]);
         }
         finally {
           isExecuting.remove();
         }
       }
     };
   }  
  
  /** 
   * Recursively unset our custom {@link DomainCombiner} (loaded in the web app) from the {@link AccessControlContext} 
   * and any parents or privilegedContext thereof.
   */
  @Deprecated
  public void removeDomainCombiner(Thread thread, AccessControlContext accessControlContext) {
    removeDomainCombiner("thread " + thread, accessControlContext);
  }
  
  /** 
   * Recursively unset our custom {@link DomainCombiner} (loaded in the web app) from the {@link AccessControlContext} 
   * and any parents or privilegedContext thereof.
   */
  public void removeDomainCombiner(String owner, AccessControlContext accessControlContext) {
    if(accessControlContext != null && java_security_AccessControlContext$combiner != null) {
      if(getFieldValue(java_security_AccessControlContext$combiner, accessControlContext) == this.domainCombiner) {
        warn(AccessControlContext.class.getSimpleName() + " of " + owner + " used custom combiner - unsetting");
        try {
          java_security_AccessControlContext$combiner.set(accessControlContext, null);
        }
        catch (Exception e) {
          error(e);
        }
      }
      
      // Recurse
      if(java_security_AccessControlContext$parent != null) {
        removeDomainCombiner(owner, (AccessControlContext) getFieldValue(java_security_AccessControlContext$parent, accessControlContext));
      }
      if(java_security_AccessControlContext$privilegedContext != null) {
        removeDomainCombiner(owner, (AccessControlContext) getFieldValue(java_security_AccessControlContext$privilegedContext, accessControlContext));
      }
    }
  }
  
  
  /** Invoke all the registered {@link ClassLoaderPreMortemCleanUp}s */
  public void runCleanUps() {
    if(isJvmShuttingDown()) {
      info("JVM is shutting down - skip cleanup");
      // Don't do anything more
    }
    else {
      final Field inheritedAccessControlContext = this.findField(Thread.class, "inheritedAccessControlContext");
      if(inheritedAccessControlContext != null) {
        // Check if threads have been started in doInLeakSafeClassLoader() and need fixed ACC
        for(Thread thread : getAllThreads()) { // (We actually only need to do this for threads not running in web app, as per StopThreadsCleanUp) 
          final AccessControlContext accessControlContext = getFieldValue(inheritedAccessControlContext, thread);
          removeDomainCombiner("thread " + thread , accessControlContext);
        }
      }
      
      for(ClassLoaderPreMortemCleanUp cleanUp : cleanUps) {
        cleanUp.cleanUp(this);
      }
    }
  }
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Utility methods

  public ClassLoader getClassLoader() {
    return classLoader;
  }

  /**
   * Get {@link ClassLoader} to be used when invoking the {@link PreClassLoaderInitiator}s.
   * This will normally be the {@link ClassLoader#getSystemClassLoader()}, but could be any other framework or 
   * app server classloader. Normally, but not necessarily, a parent of {@link #classLoader}.
   */
  public ClassLoader getLeakSafeClassLoader() {
    return leakSafeClassLoader;
  }

  /** Test if provided object is loaded by {@link #classLoader} */
  public boolean isLoadedInClassLoader(Object o) {
    return (o instanceof Class) && isLoadedByClassLoader((Class<?>)o) || // Object is a java.lang.Class instance 
        o != null && isLoadedByClassLoader(o.getClass());
  }

  /** Test if provided class is loaded wby {@link #classLoader} */
  public boolean isLoadedByClassLoader(Class<?> clazz) {
    return clazz != null && isClassLoaderOrChild(clazz.getClassLoader());
  }

  /** Test if provided ClassLoader is the {@link #classLoader}, or a child thereof */
  public boolean isClassLoaderOrChild(ClassLoader cl) {
    if(cl == null) {
      return false;
    }
    else if(cl == classLoader) {
      return true;
    }
    else { // It could be a child of the webapp classloader
      if(java_lang_ClassLoader_isAncestor != null) { // Primarily use ClassLoader.isAncestor()
        try {
          return (Boolean) java_lang_ClassLoader_isAncestor.invoke(cl, classLoader);
        }
        catch (Exception e) {
          error(e);
        }
      }

      if(java_lang_ClassLoader_isAncestorOf != null) { // Secondarily use IBM ClassLoader.isAncestorOf()
        try {
          return (Boolean) java_lang_ClassLoader_isAncestorOf.invoke(classLoader, cl);
        }
        catch (Exception e) {
          error(e);
        }
      }

      // We were unable to use ClassLoader.isAncestor() or isAncestorOf()
      try {
        while(cl != null) {
          if(cl == classLoader)
            return true;

          cl = cl.getParent();
        }
      }
      catch (NestedProtectionDomainCombinerException e) {
        return false; // Since we needed permission to call getParent(), it is unlikely it is a descendant
      }
      return false;
    }
  }

  /**
   * Is the {@link Thread} ties do the protected classloader, either by being a custom {@link Thread} class, having a 
   * custom {@link ThreadGroup} or having the protected classloader as its {@link Thread#contextClassLoader}?
   */
  public boolean isThreadInClassLoader(Thread thread) {
    return isLoadedInClassLoader(thread) || // Custom Thread class in classloader
       isLoadedInClassLoader(thread.getThreadGroup()) || // Custom ThreadGroup class in classloader 
       isClassLoaderOrChild(thread.getContextClassLoader()); // Running in classloader
  }
  
  /**
   * Make the provided Thread stop sleep(), wait() or join() and then give it the provided no of milliseconds to finish
   * executing. 
   * @param thread The thread to wake up and wait for
   * @param waitMs The no of milliseconds to wait. If <= 0 this method does nothing.
   * @param interrupt Should {@link Thread#interrupt()} be called first, to make thread stop sleep(), wait() or join()?               
   */
  public void waitForThread(Thread thread, long waitMs, boolean interrupt) {
    if(waitMs > 0) {
      if(interrupt) {
        try {
          thread.interrupt(); // Make Thread stop waiting in sleep(), wait() or join()
        }
        catch (SecurityException e) {
          error(e);
        }
      }

      try {
        thread.join(waitMs); // Wait for thread to run
      }
      catch (InterruptedException e) {
        // Do nothing
      }
    }
  }
  
  /** Get current stack trace or provided thread as string. Returns {@code "unavailable"} if stack trace could not be acquired. */
  public String getStackTrace(Thread thread) {
    try {
      final StackTraceElement[] stackTrace = thread.getStackTrace();
      if(stackTrace.length == 0)
        return "Thread state: " + thread.getState();

      final StringBuilder output = new StringBuilder("Thread stack trace: ");
      for(StackTraceElement stackTraceElement : stackTrace) {
        // if(output.length() > 0) // Except first
          output.append("\n\tat ");
        output.append(stackTraceElement.toString());
      }
      return output.toString().trim(); // 
    }
    catch (Throwable t) { // SecurityException
      return "Thread details unavailable";
    }
  }
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  
  public <E> E getStaticFieldValue(Class<?> clazz, String fieldName) {
    Field staticField = findField(clazz, fieldName);
    return (staticField != null) ? (E) getStaticFieldValue(staticField) : null;
  }

  public <E> E getStaticFieldValue(String className, String fieldName) {
    return (E) getStaticFieldValue(className, fieldName, false);
  }
  
  public <E> E getStaticFieldValue(String className, String fieldName, boolean trySystemCL) {
    Field staticField = findFieldOfClass(className, fieldName, trySystemCL);
    return (staticField != null) ? (E) getStaticFieldValue(staticField) : null;
  }
  
  public Field findFieldOfClass(String className, String fieldName) {
    return findFieldOfClass(className, fieldName, false);
  }
  
  public Field findFieldOfClass(String className, String fieldName, boolean trySystemCL) {
    Class<?> clazz = findClass(className, trySystemCL);
    if(clazz != null) {
      return findField(clazz, fieldName);
    }
    else
      return null;
  }
  
  public Class<?> findClass(String className) {
    return findClass(className, false);
  }
  
  public Class<?> findClass(String className, boolean trySystemCL) {
    try {
      return Class.forName(className);
    }
//    catch (NoClassDefFoundError e) {
//      // Silently ignore
//      return null;
//    }
    catch (ClassNotFoundException e) {
      if (trySystemCL) {
        try {
          return Class.forName(className, true, ClassLoader.getSystemClassLoader());
        } catch (ClassNotFoundException e1) {
          // Silently ignore
          return null;
        }
      }
      // Silently ignore
      return null;
    }
    catch (Exception ex) { // Example SecurityException
      warn(ex);
      return null;
    }
  }
  
  public Field findField(Class<?> clazz, String fieldName) {
    if(clazz == null)
      return null;

    try {
      final Field field = clazz.getDeclaredField(fieldName);
      field.setAccessible(true); // (Field is probably private) 
      return field;
    }
    catch (NoSuchFieldException ex) {
      // Silently ignore
      return null;
    }
    catch (Exception ex) { // Example SecurityException
      warn(ex);
      return null;
    }
  }
  
  public <T> T getStaticFieldValue(Field field) {
    try {
      if(! Modifier.isStatic(field.getModifiers())) {
        warn(field.toString() + " is not static");
        return null;
      }
      
      return (T) field.get(null);
    }
    catch (Exception ex) {
      warn(ex);
      // Silently ignore
      return null;
    }
  }
  
  public <T> T getFieldValue(Object obj, String fieldName) {
    final Field field = findField(obj.getClass(), fieldName);
    return (T) getFieldValue(field, obj);
  }
  
  public <T> T getFieldValue(Field field, Object obj) {
    try {
      return (T) field.get(obj);
    }
    catch (Exception ex) {
      warn(ex);
      // Silently ignore
      return null;
    }
  }
  
  public void setFinalStaticField(Field field, Object newValue) {
    // Allow modification of final field 
    try {
      Field modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);
      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    }
    catch (NoSuchFieldException e) {
      warn("Unable to get 'modifiers' field of java.lang.Field");
    }
    catch (IllegalAccessException e) {
      warn("Unable to set 'modifiers' field of java.lang.Field");
    }
    catch (Throwable t) {
      warn(t);
    }

    // Update the field
    try {
      field.set(null, newValue);
    }
    catch (Throwable e) {
      error("Error setting value of " + field + " to " + newValue);
    }
  }
  
  public Method findMethod(String className, String methodName, Class... parameterTypes) {
    Class<?> clazz = findClass(className);
    if(clazz != null) {
      return findMethod(clazz, methodName, parameterTypes);
    }
    else 
      return null;
  }
  
  public Method findMethod(Class<?> clazz, String methodName, Class... parameterTypes) {
    if(clazz == null)
      return null;

    try {
      final Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
      method.setAccessible(true);
      return method;
    }
    catch (NoSuchMethodException ex) {
      warn(ex);
      // Silently ignore
      return null;
    }
  }

  /** Get a Collection with all Threads. 
   * This method is heavily inspired by org.apache.catalina.loader.WebappClassLoader.getThreads() */
  public Collection<Thread> getAllThreads() {
    // This is some orders of magnitude slower...
    // return Thread.getAllStackTraces().keySet();
    
    // Find root ThreadGroup
    ThreadGroup tg = Thread.currentThread().getThreadGroup();
    while(tg.getParent() != null)
      tg = tg.getParent();
    
    // Note that ThreadGroup.enumerate() silently ignores all threads that does not fit into array
    int guessThreadCount = tg.activeCount() + 50;
    Thread[] threads = new Thread[guessThreadCount];
    int actualThreadCount = tg.enumerate(threads);
    while(actualThreadCount == guessThreadCount) { // Map was filled, there may be more
      guessThreadCount *= 2;
      threads = new Thread[guessThreadCount];
      actualThreadCount = tg.enumerate(threads);
    }
    
    // Filter out nulls
    final List<Thread> output = new ArrayList<Thread>();
    for(Thread t : threads) {
      if(t != null) {
        output.add(t);
      }
    }
    return output;
  }
  
  /**
   * Override this method if you want to customize how we determine if we're running in
   * JBoss WildFly (a.k.a JBoss AS).
   */
  public boolean isJBoss() {
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    
    try {
      // If package org.jboss is found, we may be running under JBoss
      return (contextClassLoader.getResource("org/jboss") != null);
    }
    catch(Exception ex) {
      return false;
    }
  }
  
  /**
   * Are we running in the Oracle/Sun Java Runtime Environment?
   * Override this method if you want to customize how we determine if this is a Oracle/Sun
   * Java Runtime Environment.
   */
  public boolean isOracleJRE() {
    String javaVendor = System.getProperty("java.vendor");
    
    return javaVendor.startsWith("Oracle") || javaVendor.startsWith("Sun");
  }

  /**
   * Unlike <code>{@link System#gc()}</code> this method guarantees that garbage collection has been performed before
   * returning.
   */
  public static void gc() {
    if (isDisableExplicitGCEnabled()) {
      System.err.println(ClassLoaderLeakPreventor.class.getSimpleName() + ": "
          + "Skipping GC call since -XX:+DisableExplicitGC is supplied as VM option.");
      return;
    }
    
    Object obj = new Object();
    WeakReference<Object> ref = new WeakReference<Object>(obj);
    //noinspection UnusedAssignment
    obj = null;
    while(ref.get() != null) {
      System.gc();
    }
  }
  
  /**
   * Check is "-XX:+DisableExplicitGC" enabled.
   *
   * @return true is "-XX:+DisableExplicitGC" is set als vm argument, false otherwise.
   */
  private static boolean isDisableExplicitGCEnabled() {
    RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
    List<String> aList = bean.getInputArguments();

    return aList.contains("-XX:+DisableExplicitGC");
  }  

  /** Is the JVM currently shutting down? */
  public boolean isJvmShuttingDown() {
    try {
      final Thread dummy = new Thread(); // Will never be started
      Runtime.getRuntime().removeShutdownHook(dummy);
      return false;
    }
    catch (IllegalStateException isex) {
      return true; // Shutting down
    }
    catch (Throwable t) { // Any other Exception, assume we are not shutting down
      return false;
    }
  }

  /**
   * Exception thrown when {@link DomainCombiner#combine(ProtectionDomain[], ProtectionDomain[])} is called recursively
   * during the execution of that same method.
   */
  private static class NestedProtectionDomainCombinerException extends RuntimeException {

  }

  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Delegate methods for Logger


  public void debug(String msg) {
    logger.debug(msg);
  }

  public void warn(Throwable t) {
    logger.warn(t);
  }

  public void error(Throwable t) {
    logger.error(t);
  }

  public void warn(String msg) {
    logger.warn(msg);
  }

  public void error(String msg) {
    logger.error(msg);
  }

  public void info(String msg) {
    logger.info(msg);
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorFactory.java
================================================
package se.jiderhamn.classloader.leak.prevention;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

import se.jiderhamn.classloader.leak.prevention.cleanup.*;
import se.jiderhamn.classloader.leak.prevention.preinit.*;

import static java.util.Collections.synchronizedMap;

/**
 * Orchestrator class responsible for invoking the preventative and cleanup measures.
 * Contains the configuration and can be reused for multiple classloaders (assume it is not itself loaded by the
 * classloader which we want to avoid leaking). In that case, the {@link #logger} may need to be thread safe.
 * @author Mattias Jiderhamn
 */
public class ClassLoaderLeakPreventorFactory {
  
  /** 
   * {@link ClassLoader} to be used when invoking the {@link PreClassLoaderInitiator}s.
   * Defaults to {@link ClassLoader#getSystemClassLoader()}, but could be any other framework or 
   * app server classloader.
   */
  protected final ClassLoader leakSafeClassLoader;
  
  /** 
   * The {@link Logger} that will be passed on to the different {@link PreClassLoaderInitiator}s and 
   * {@link ClassLoaderPreMortemCleanUp}s 
   */
  protected Logger logger = new JULLogger();

  /** 
   * Map from name to {@link PreClassLoaderInitiator}s with all the actions to invoke in the 
   * {@link #leakSafeClassLoader}. Maintains insertion order. Thread safe.
   */
  protected final Map<String, PreClassLoaderInitiator> preInitiators =
      synchronizedMap(new LinkedHashMap<String, PreClassLoaderInitiator>());

  /** 
   * Map from name to {@link ClassLoaderPreMortemCleanUp}s with all the actions to invoke to make a 
   * {@link ClassLoader} ready for Garbage Collection. Maintains insertion order. Thread safe.
   */
  protected final Map<String, ClassLoaderPreMortemCleanUp> cleanUps = 
      synchronizedMap(new LinkedHashMap<String, ClassLoaderPreMortemCleanUp>());

  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Constructors
  
  /** 
   * Create new {@link ClassLoaderLeakPreventorFactory} with {@link ClassLoader#getSystemClassLoader()} as the 
   * {@link #leakSafeClassLoader} and default {@link PreClassLoaderInitiator}s and {@link ClassLoaderPreMortemCleanUp}s. 
   */
  public ClassLoaderLeakPreventorFactory() {
    this(ClassLoader.getSystemClassLoader());
  }

  /** 
   * Create new {@link ClassLoaderLeakPreventorFactory} with supplied {@link ClassLoader} as the 
   * {@link #leakSafeClassLoader} and default {@link PreClassLoaderInitiator}s and {@link ClassLoaderPreMortemCleanUp}s.  
   */
  public ClassLoaderLeakPreventorFactory(ClassLoader leakSafeClassLoader) {
    this.leakSafeClassLoader = leakSafeClassLoader;
    configureDefaults();
  }
  
  /** Configure default {@link PreClassLoaderInitiator}s and {@link ClassLoaderPreMortemCleanUp}s */
  public void configureDefaults() {
    // The pre-initiators part is heavily inspired by Tomcats JreMemoryLeakPreventionListener  
    // See http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java?view=markup
    this.addPreInitiator(new AwtToolkitInitiator());
    // initSecurityProviders()
    this.addPreInitiator(new JdbcDriversInitiator());
    this.addPreInitiator(new SunAwtAppContextInitiator());
    this.addPreInitiator(new SecurityPolicyInitiator());
    this.addPreInitiator(new SecurityProvidersInitiator());
    this.addPreInitiator(new DocumentBuilderFactoryInitiator());
    this.addPreInitiator(new ReplaceDOMNormalizerSerializerAbortException());
    this.addPreInitiator(new DatatypeConverterImplInitiator());
    this.addPreInitiator(new JavaxSecurityLoginConfigurationInitiator());
    this.addPreInitiator(new JarUrlConnectionInitiator());
    // Load Sun specific classes that may cause leaks
    this.addPreInitiator(new LdapPoolManagerInitiator());
    this.addPreInitiator(new Java2dDisposerInitiator());
    this.addPreInitiator(new Java2dRenderQueueInitiator());
    this.addPreInitiator(new SunGCInitiator());
    this.addPreInitiator(new OracleJdbcThreadInitiator());

    this.addCleanUp(new BeanIntrospectorCleanUp());
    this.addCleanUp(new ObjectStreamClassCleanup());
    
    // Apache Commons Pool can leave unfinished threads. Anything specific we can do?
    this.addCleanUp(new BeanELResolverCleanUp());
    this.addCleanUp(new BeanValidationCleanUp());
    this.addCleanUp(new JacksonCleanUp());
    this.addCleanUp(new JavaServerFaces2746CleanUp());
    this.addCleanUp(new GeoToolsCleanUp());
    // Can we do anything about Google Guice ?
    // Can we do anything about Groovy http://jira.codehaus.org/browse/GROOVY-4154 ?
    this.addCleanUp(new IntrospectionUtilsCleanUp());
    // Can we do anything about Logback http://jira.qos.ch/browse/LBCORE-205 ?
    this.addCleanUp(new IIOServiceProviderCleanUp()); // clear ImageIO registry
    this.addCleanUp(new MoxyCleanUp());
    this.addCleanUp(new ReactorNettyHttpResourcesCleanUp());
    this.addCleanUp(new ThreadGroupContextCleanUp());
    this.addCleanUp(new X509TrustManagerImplUnparseableExtensionCleanUp());
    this.addCleanUp(new SAAJEnvelopeFactoryParserPoolCleanUp());
    
    ////////////////////
    // Fix generic leaks
    this.addCleanUp(new DriverManagerCleanUp());
    
    this.addCleanUp(new DefaultAuthenticatorCleanUp());

    this.addCleanUp(new MBeanCleanUp());
    this.addCleanUp(new MXBeanNotificationListenersCleanUp());
    
    this.addCleanUp(new ShutdownHookCleanUp());
    this.addCleanUp(new PropertyEditorCleanUp());
    this.addCleanUp(new SecurityProviderCleanUp());
    this.addCleanUp(new JceSecurityCleanUp()); // (Probably best to do after deregistering the providers)
    this.addCleanUp(new ProxySelectorCleanUp());
    this.addCleanUp(new RmiTargetsCleanUp());
    this.addCleanUp(new StopThreadsCleanUp());
    this.addCleanUp(new ThreadGroupCleanUp());
    this.addCleanUp(new ThreadLocalCleanUp()); // This must be done after threads have been stopped, or new ThreadLocals may be added by those threads
    this.addCleanUp(new KeepAliveTimerCacheCleanUp());
    this.addCleanUp(new ResourceBundleCleanUp());
    this.addCleanUp(new JDK8151486CleanUp());
    this.addCleanUp(new JavaUtilLoggingLevelCleanUp()); // Do this last, in case other shutdown procedures want to log something.
    this.addCleanUp(new ApacheCommonsLoggingCleanUp()); // Do this last, in case other shutdown procedures want to log something.
    
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Factory methods
  
  /** 
   * Create new {@link ClassLoaderLeakPreventor} used to prevent the provided {@link Thread#contextClassLoader} of the
   * {@link Thread#currentThread()} from leaking.
   * 
   * Please be aware that {@link ClassLoaderLeakPreventor}s created by the same factory share the same 
   * {@link PreClassLoaderInitiator} and {@link ClassLoaderPreMortemCleanUp} instances, in case their config is changed. 
   */
  public ClassLoaderLeakPreventor newLeakPreventor() {
    return newLeakPreventor(Thread.currentThread().getContextClassLoader());
  }
  
  /** Create new {@link ClassLoaderLeakPreventor} used to prevent the provided {@link ClassLoader} from leaking */
  public ClassLoaderLeakPreventor newLeakPreventor(ClassLoader classLoader) {
    return new ClassLoaderLeakPreventor(leakSafeClassLoader, classLoader, logger,
        new ArrayList<PreClassLoaderInitiator>(preInitiators.values()), // Snapshot
        new ArrayList<ClassLoaderPreMortemCleanUp>(cleanUps.values())); // Snapshot
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Methods for configuring the factory 
  
  /** Set logger */
  public void setLogger(Logger logger) {
    this.logger = logger;
  }
  
  /** Add a new {@link PreClassLoaderInitiator}, using the class name as name */
  public void addPreInitiator(PreClassLoaderInitiator preClassLoaderInitiator) {
    addConsideringOrder(this.preInitiators, preClassLoaderInitiator);
  }

  /** Add a new {@link ClassLoaderPreMortemCleanUp}, using the class name as name */
  public void addCleanUp(ClassLoaderPreMortemCleanUp classLoaderPreMortemCleanUp) {
    addConsideringOrder(this.cleanUps, classLoaderPreMortemCleanUp);
  }
  
  /** Add new {@link I} entry to {@code map}, taking {@link MustBeAfter} into account */
  private <I> void addConsideringOrder(Map<String, I> map, I newEntry) {
    for(Map.Entry<String, I> entry : map.entrySet()) {
      if(entry.getValue() instanceof MustBeAfter<?>) {
        final Class<? extends ClassLoaderPreMortemCleanUp>[] existingMustBeAfter = 
            ((MustBeAfter<ClassLoaderPreMortemCleanUp>)entry.getValue()).mustBeBeforeMe();
        for(Class<? extends ClassLoaderPreMortemCleanUp> clazz : existingMustBeAfter) {
          if(clazz.isAssignableFrom(newEntry.getClass())) { // Entry needs to be after new entry
            // TODO Resolve order automatically #51
            throw new IllegalStateException(clazz.getName() + " must be added after " + newEntry.getClass());
          }
        }
      }
    }
    
    map.put(newEntry.getClass().getName(), newEntry);
  }

  /** Add a new named {@link ClassLoaderPreMortemCleanUp} */
  public void addCleanUp(String name, ClassLoaderPreMortemCleanUp classLoaderPreMortemCleanUp) {
    this.cleanUps.put(name, classLoaderPreMortemCleanUp);
  }
  
  /** Remove all the currently configured {@link PreClassLoaderInitiator}s */
  public void clearPreInitiators() {
    this.preInitiators.clear();
  }

  /** Remove all the currently configured {@link ClassLoaderPreMortemCleanUp}s */
  public void clearCleanUps() {
    this.cleanUps.clear();
  }
  
  /** 
   * Get instance of {@link PreClassLoaderInitiator} for further configuring.
   * 
   * Please be aware that {@link ClassLoaderLeakPreventor}s created by the same factory share the same 
   * {@link PreClassLoaderInitiator} and {@link ClassLoaderPreMortemCleanUp} instances, in case their config is changed. 
   */
  public <C extends PreClassLoaderInitiator> C getPreInitiator(Class<C> clazz) {
    return (C) this.preInitiators.get(clazz.getName());
  }

  /** 
   * Get instance of {@link ClassLoaderPreMortemCleanUp} for further configuring.
   * 
   * Please be aware that {@link ClassLoaderLeakPreventor}s created by the same factory share the same 
   * {@link PreClassLoaderInitiator} and {@link ClassLoaderPreMortemCleanUp} instances, in case their config is changed. 
   */
  public <C extends ClassLoaderPreMortemCleanUp> C getCleanUp(Class<C> clazz) {
    return (C) this.cleanUps.get(clazz.getName());
  }

  /** Get instance of {@link PreClassLoaderInitiator} for further configuring */
  public <C extends PreClassLoaderInitiator> void removePreInitiator(Class<C> clazz) {
    this.preInitiators.remove(clazz.getName());
  }

  /** Get instance of {@link ClassLoaderPreMortemCleanUp} for further configuring */
  public <C extends ClassLoaderPreMortemCleanUp> void removeCleanUp(Class<C> clazz) {
    this.cleanUps.remove(clazz.getName());
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderPreMortemCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention;

/**
 * Interface for cleanup actions that should be performed as part of the preparations to make a {@link ClassLoader} available
 * for garbage collection.
 * @author Mattias Jiderhamn
 */
public interface ClassLoaderPreMortemCleanUp {
  
  /** 
   * Perform cleanup actions needed to make provided {@link ClassLoaderLeakPreventor#classLoader} 
   * ready for garbage collection.
   */
  void cleanUp(ClassLoaderLeakPreventor preventor);
  
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/JULLogger.java
================================================
package se.jiderhamn.classloader.leak.prevention;

import java.util.logging.Level;

/**
 * Implementation of {@link Logger} interface, that uses {@link java.util.logging}.
 * 
 * @author Mattias Jiderhamn
 */
public class JULLogger implements Logger {
  
  private static final java.util.logging.Logger LOG = 
      java.util.logging.Logger.getLogger(ClassLoaderLeakPreventor.class.getName());
  
  @Override
  public void debug(String msg) {
    LOG.config(msg);
  } 

  @Override
  public void info(String msg) {
    LOG.info(msg);
  } 

  @Override
  public void warn(String msg) {
    LOG.warning(msg);
  } 

  @Override
  public void warn(Throwable t) {
    LOG.log(Level.WARNING, t.getMessage(), t);
  } 

  @Override
  public void error(String msg) {
    LOG.severe(msg);
  } 

  @Override
  public void error(Throwable t) {
    LOG.log(Level.SEVERE, t.getMessage(), t);
  }
  
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/Logger.java
================================================
package se.jiderhamn.classloader.leak.prevention;

/**
 * Interface for logging, with similarities to common logging frameworks. If you want to plug in the leak preventor
 * into an existing architecture (such as an application server), you may want to use a custom implementation of this 
 * interface.
 * 
 * If the {@link ClassLoaderLeakPreventorFactory} is beeing reused, the {@link Logger} implementation may need to be 
 * thread safe.
 * 
 * @author Mattias Jiderhamn
 */
public interface Logger {

  /** Log debug level message */
  void debug(String msg);

  /** Log info level message */
  void info(String msg);

  /** Log a warning message */
  void warn(String msg);

  /** Log a {@link Throwable} as a warning message */
  void warn(Throwable t);

  /** Log an error message */
  void error(String msg);
  
  /** Log a {@link Throwable} as an error message */
  void error(Throwable t);
}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/MustBeAfter.java
================================================
package se.jiderhamn.classloader.leak.prevention;

/**
 * Interface to be implemented by {@link PreClassLoaderInitiator}s and {@link ClassLoaderPreMortemCleanUp}s when order
 * is important. The class implementing this interface will define what other implementations it needs to be invoked
 * *after* for correct behaviour. It is the responsibility of {@link ClassLoaderLeakPreventorFactory} to make sure
 * the implementations are ordered correctly. Currently an {@link IllegalStateException} will be thrown (TODO #51)
 * @param <I> The interface that both this class and the dependent classes implements, 
 * i.e. either {@link PreClassLoaderInitiator} or {@link ClassLoaderPreMortemCleanUp}. 
 * 
 * @author Mattias Jiderhamn
 */
public interface MustBeAfter<I> {
  
  /** 
   * Returns an array of classes that, if part of they or any subclass of them are part of the list of 
   * {@link PreClassLoaderInitiator}s/{@link ClassLoaderPreMortemCleanUp}s, needs to be prior to this element in the list.
   */
  Class<? extends I>[] mustBeBeforeMe();
}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/PreClassLoaderInitiator.java
================================================
package se.jiderhamn.classloader.leak.prevention;

/**
 * Interface for preventative actions that should be executed in the system (or other parent) classloader before they 
 * may be triggered within the classloader that is about to be launched, and thereby may trigger leaks.
 * @author Mattias Jiderhamn
 */
public interface PreClassLoaderInitiator {
  
  /** 
   * Perform action that needs to be done outside the leak susceptible classloader, i.e. in the system or other parent
   * classloader. Assume that the system or parent classloader is the {@link Thread#contextClassLoader} of the current 
   * thread when method is invoked.
   * Must NOT have modified {@link Thread#contextClassLoader} of the current thread when returning.
   */
  void doOutsideClassLoader(ClassLoaderLeakPreventor preventor);
  
}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ReplaceDOMNormalizerSerializerAbortException.java
================================================
package se.jiderhamn.classloader.leak.prevention;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * As reported at https://github.com/mjiderhamn/classloader-leak-prevention/issues/36, invoking
 * {@code DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().normalizeDocument();} or 
 * <code>
 *   Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
 *   DOMImplementationLS implementation = (DOMImplementationLS)document.getImplementation();
 *   implementation.createLSSerializer().writeToString(document);
 * </code> may trigger leaks caused by the static fields {@link com.sun.org.apache.xerces.internal.dom.DOMNormalizer#abort} and
 * {@link com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl#abort} respectively keeping stacktraces/backtraces
 * that may include references to classes loaded by our web application.
 * 
 * Since the {@link java.lang.Throwable#backtrace} itself cannot be accessed via reflection (see 
 * http://bugs.java.com/view_bug.do?bug_id=4496456) we need to replace the with new one without any stack trace.
 * 
 * This can be done either as a {@link PreClassLoaderInitiator} (recommended) or {@link ClassLoaderPreMortemCleanUp}.
 * 
 * @author Mattias Jiderhamn
 */
public class ReplaceDOMNormalizerSerializerAbortException implements PreClassLoaderInitiator, ClassLoaderPreMortemCleanUp {

  @Override
  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {
    replaceDOMNormalizerSerializerAbortException(preventor);
  }

  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    replaceDOMNormalizerSerializerAbortException(preventor);
  }

  @SuppressWarnings("WeakerAccess")
  protected void replaceDOMNormalizerSerializerAbortException(ClassLoaderLeakPreventor preventor) {
    final RuntimeException abort = constructRuntimeExceptionWithoutStackTrace(preventor, "abort", null);
    if(abort != null) {
      final Field normalizerAbort = preventor.findFieldOfClass("com.sun.org.apache.xerces.internal.dom.DOMNormalizer", "abort");
      if(normalizerAbort != null)
        preventor.setFinalStaticField(normalizerAbort, abort);

      final Field serializerAbort = preventor.findFieldOfClass("com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl", "abort");
      if(serializerAbort != null)
        preventor.setFinalStaticField(serializerAbort, abort);
    }
  }

  /** Construct a new {@link RuntimeException} without any stack trace, in order to avoid any references back to this class */
  @SuppressWarnings("WeakerAccess")
  public static RuntimeException constructRuntimeExceptionWithoutStackTrace(ClassLoaderLeakPreventor preventor,
                                                                        String message, Throwable cause) {
    try {
      final Constructor<RuntimeException> constructor = 
          RuntimeException.class.getDeclaredConstructor(String.class, Throwable.class, Boolean.TYPE, Boolean.TYPE);
      constructor.setAccessible(true);
      return constructor.newInstance(message, cause, true, false /* disable stack trace */);
    }
    catch (Throwable e) { // InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
      preventor.warn("Unable to construct RuntimeException without stack trace. The likely reason is that you are using Java <= 1.6. " +
          "No worries, except there might be some leaks you're not protected from (https://github.com/mjiderhamn/classloader-leak-prevention/issues/36 , " +
          "https://github.com/mjiderhamn/classloader-leak-prevention/issues/69). " + 
          "If you are already on Java 1.7+, please report issue to developer of this library!");
      preventor.warn(e);
      return null;
    }
  }
  
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/StdLogger.java
================================================
package se.jiderhamn.classloader.leak.prevention;

/**
 * Implementation of {@link Logger} interface, that uses {@link System#out} and {@link System#err}.
 * Because log frameworks may themselves cause leaks, we may want to avoid them altogether.
 * 
 * To "turn off" a log level, override the corresponding method(s) with an empty implementation.
 * @author Mattias Jiderhamn
 */
public class StdLogger implements Logger {
  
  /** Get prefix to use when logging to {@link System#out}/{@link System#err} */
  protected String getLogPrefix() {
    return "ClassLoader Leak Preventor: ";
  }
  
  @Override
  public void debug(String msg) {
    System.out.println(getLogPrefix() + msg);
  } 

  @Override
  public void info(String s) {
    System.out.println(getLogPrefix() + s);
  } 

  @Override
  public void warn(String s) {
    System.err.println(getLogPrefix() + s);
  } 

  @Override
  public void warn(Throwable t) {
    t.printStackTrace(System.err);
  } 

  @Override
  public void error(String s) {
    System.err.println(getLogPrefix() + s);
  } 

  @Override
  public void error(Throwable t) {
    t.printStackTrace(System.err);
  }
  
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ApacheCommonsLoggingCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.security.CodeSource;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Release this classloader from Apache Commons Logging (ACL) by calling 
 * {@code LogFactory.release(getCurrentClassLoader());}
 * Use reflection in case ACL is not present.
 * Tip: Do this last, in case other shutdown procedures want to log something.
 * 
 * @author Mattias Jiderhamn
 */
public class ApacheCommonsLoggingCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Class<?> logFactory = preventor.findClass("org.apache.commons.logging.LogFactory");
    if(logFactory != null) { // Apache Commons Logging present
      try {
        final CodeSource codeSource = logFactory.getProtectionDomain().getCodeSource();
        final String codeSourceStr = codeSource != null ? codeSource.toString() : "";
        if (codeSourceStr.contains("spring-jcl")) {
          preventor.info("ignore ApacheCommonsLoggingCleanUp for spring-jcl at " + codeSource);
          return;
        }
      } catch (SecurityException ex) {
        preventor.error(ex);
      }
      preventor.info("Releasing web app classloader from Apache Commons Logging");
      try {
        logFactory.getMethod("release", java.lang.ClassLoader.class)
            .invoke(null, preventor.getClassLoader());
      }
      catch (Exception ex) {
        preventor.error(ex);
      }
    }
    
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanELResolverCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clean for the cache of {@link javax.el.BeanELResolver}, which leaks prior to version 2.2.4.
 * @author Mattias Jiderhamn
 */
public class BeanELResolverCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    java.beans.Introspector.flushCaches(); // This must also be done          

    final Class<?> beanElResolverClass = preventor.findClass("javax.el.BeanELResolver");
    if(beanElResolverClass != null) {
      boolean cleared = false;
      try {
        final Method purgeBeanClasses = beanElResolverClass.getDeclaredMethod("purgeBeanClasses", ClassLoader.class);
        purgeBeanClasses.setAccessible(true);
        purgeBeanClasses.invoke(beanElResolverClass.newInstance(), preventor.getClassLoader());
        cleared = true;
      }
      catch (NoSuchMethodException e) {
        // Version of javax.el probably > 2.2; no real need to clear
      }
      catch (Exception e) {
        preventor.error(e);
      }
      
      if(! cleared) {
        // Fallback, if purgeBeanClasses() could not be called
        final Field propertiesField = preventor.findField(beanElResolverClass, "properties");
        if(propertiesField != null) {
          try {
            final Map<?, ?> properties = (Map<?, ?>) propertiesField.get(null);
            properties.clear();
          }
          catch (Exception e) {
            preventor.error(e);
          }
        }
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanIntrospectorCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clear {@link java.beans.Introspector} cache
 * @author Mattias Jiderhamn
 */
public class BeanIntrospectorCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    java.beans.Introspector.flushCaches(); // Clear cache of strong references
    clearClassInfoCache(preventor);
  }

  /**
   * Clears the BeanInfo SoftReference-based cache introduced in JDK 9
   *
   * References:
   * * Clear explanation of the root cause: https://bugs.openjdk.java.net/browse/JDK-8207331
   * * Issue which triggered the JDK fix: https://bugs.openjdk.java.net/browse/JDK-8231454
   * * Fix commit (JDK16+ only as of now): https://github.com/openjdk/jdk/commit/2ee2b4ae
   */
  private void clearClassInfoCache(ClassLoaderLeakPreventor preventor) {
      try {
          final Class<?> classInfoClass = preventor.findClass("com.sun.beans.introspect.ClassInfo");
          if (classInfoClass == null) {
            return;
          }

          Field cacheField = preventor.findField(classInfoClass, "CACHE");
          if (cacheField == null) {
            return;  // Either pre-JDK9 or exception occurred (should have been logged as warn at this point)
          }

          Object cacheInstance = cacheField.get(null);
          if (cacheInstance == null) {
            return;
          }
          Method clearMethod = cacheInstance.getClass().getSuperclass().getDeclaredMethod("clear");
          clearMethod.invoke(cacheInstance);
      }
      catch (Exception e) {
          preventor.warn(e);
      }
  }

}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanValidationCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.util.Map;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clean up leak caused by cache in {@link javax.validation.Validation}
 * @author Mattias Jiderhamn
 */
public class BeanValidationCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Class<?> offendingClass = 
        preventor.findClass("javax.validation.Validation$DefaultValidationProviderResolver");
    if(offendingClass != null) { // Class is present on class path
      Field offendingField = preventor.findField(offendingClass, "providersPerClassloader");
      if(offendingField != null) {
        final Object providersPerClassloader = preventor.getStaticFieldValue(offendingField);
        if(providersPerClassloader instanceof Map) { // Map<ClassLoader, List<ValidationProvider<?>>> in offending code
          //noinspection SynchronizationOnLocalVariableOrMethodParameter
          synchronized (providersPerClassloader) {
            // Fix the leak!
            ((Map<?, ?>)providersPerClassloader).remove(preventor.getClassLoader());
          }
        }
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/DefaultAuthenticatorCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.ref.Reference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.Authenticator;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clear the default {@link java.net.Authenticator} (in case current one is loaded by protected ClassLoader). 
 * Includes special workaround for CXF issue https://issues.apache.org/jira/browse/CXF-5442
 * @author Mattias Jiderhamn
 */
public class DefaultAuthenticatorCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Authenticator defaultAuthenticator = getDefaultAuthenticator(preventor);
    if(defaultAuthenticator == null || // Can both mean not set, or error retrieving, so unset anyway to be safe 
        preventor.isLoadedInClassLoader(defaultAuthenticator)) {
      if(defaultAuthenticator != null) // Log warning only if a default was actually found
        preventor.warn("Unsetting default " + Authenticator.class.getName() + ": " + defaultAuthenticator);
      Authenticator.setDefault(null);
    }
    else {
      if("org.apache.cxf.transport.http.ReferencingAuthenticator".equals(defaultAuthenticator.getClass().getName())) {
        /*
         Needed since org.apache.cxf.transport.http.ReferencingAuthenticator is loaded by dummy classloader that
         references protected classloader via AccessControlContext + ProtectionDomain.
         See https://issues.apache.org/jira/browse/CXF-5442
        */

        final Class<?> cxfAuthenticator = preventor.findClass("org.apache.cxf.transport.http.CXFAuthenticator");
        if(cxfAuthenticator != null && preventor.isLoadedByClassLoader(cxfAuthenticator)) { // CXF loaded in this application
          final Object cxfAuthenticator$instance = preventor.getStaticFieldValue(cxfAuthenticator, "instance");
          if(cxfAuthenticator$instance != null) { // CXF authenticator has been initialized in protected ClassLoader
            final Object authReference = preventor.getFieldValue(defaultAuthenticator, "auth");
            if(authReference instanceof Reference) { // WeakReference 
              final Reference<?> reference = (Reference<?>) authReference;
              final Object referencedAuth = reference.get();
              if(referencedAuth == cxfAuthenticator$instance) { // References CXFAuthenticator of this classloader 
                preventor.warn("Default " + Authenticator.class.getName() + " was " + defaultAuthenticator + " that referenced " +
                    cxfAuthenticator$instance + " loaded by protected ClassLoader");

                // Let CXF unwrap in it's own way (in case there are multiple CXF webapps in the container)
                reference.clear(); // Remove the weak reference before calling check()
                try {
                  final Method check = defaultAuthenticator.getClass().getMethod("check");
                  check.setAccessible(true);
                  check.invoke(defaultAuthenticator);
                }
                catch (Exception e) {
                  preventor.error(e);
                }
              }
            }
          }
        }
      }
      
      removeWrappedAuthenticators(preventor, defaultAuthenticator);
      
      preventor.info("Default " + Authenticator.class.getName() + " not loaded by protected ClassLoader: " + defaultAuthenticator);
    }
  }
  
  /** Find default {@link Authenticator} */
  @SuppressWarnings("WeakerAccess")
  protected Authenticator getDefaultAuthenticator(ClassLoaderLeakPreventor preventor) {
    // Normally Corresponds to getStaticFieldValue(Authenticator.class, "theAuthenticator");
    for(final Field f : Authenticator.class.getDeclaredFields()) {
      if (f.getType().equals(Authenticator.class)) { // Supposedly "theAuthenticator"
        try {
          f.setAccessible(true);
          return (Authenticator)f.get(null);
        } catch (Exception e) {
          preventor.error(e);
        }
      }
    }
    return null;
  }

  /**
   * Recursively removed wrapped {@link Authenticator} loaded in protected ClassLoader.
   * May be needed in case there are multiple CXF applications within the same container.
   */
  @SuppressWarnings("WeakerAccess")
  protected void removeWrappedAuthenticators(final ClassLoaderLeakPreventor preventor,
                                             final Authenticator authenticator) {
    if(authenticator == null)
      return;

    try {
      Class<?> authenticatorClass = authenticator.getClass();
      do {
        for(final Field f : authenticator.getClass().getDeclaredFields()) {
          if(Authenticator.class.isAssignableFrom(f.getType())) {
            try {
              final boolean isStatic = Modifier.isStatic(f.getModifiers()); // In CXF case this should be false
              final Authenticator owner = isStatic ? null : authenticator;
              f.setAccessible(true);
              final Authenticator wrapped = (Authenticator)f.get(owner);
              if(preventor.isLoadedInClassLoader(wrapped)) {
                preventor.warn(Authenticator.class.getName() + ": " + wrapped + ", wrapped by " + authenticator + 
                    ", is loaded by protected ClassLoader");
                f.set(owner, null); // For added safety
              }
              else {
                removeWrappedAuthenticators(preventor, wrapped); // Recurse
              }
            } catch (Exception e) {
              preventor.error(e);
            }
          }
        }
        authenticatorClass = authenticatorClass.getSuperclass();
      } while (authenticatorClass != null && authenticatorClass != Object.class);
    }
    catch (Exception e) { // Should never happen
      preventor.error(e);
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/DriverManagerCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Deregister JDBC drivers loaded by classloader
 * @author Mattias Jiderhamn
 */
public class DriverManagerCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final List<Driver> driversToDeregister = new ArrayList<Driver>();
    final Enumeration<Driver> allDrivers = DriverManager.getDrivers();
    while(allDrivers.hasMoreElements()) {
      final Driver driver = allDrivers.nextElement();
      if(preventor.isLoadedInClassLoader(driver)) // Should be true for all returned by DriverManager.getDrivers()
        driversToDeregister.add(driver);
    }
    
    for(Driver driver : driversToDeregister) {
      try {
        preventor.warn("JDBC driver loaded by protected ClassLoader deregistered: " + driver.getClass());
        DriverManager.deregisterDriver(driver);
      }
      catch (SQLException e) {
        preventor.error(e);
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/GeoToolsCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Shutdown GeoTools cleaner thread as of https://osgeo-org.atlassian.net/browse/GEOT-2742
 * @author Mattias Jiderhamn
 */
public class GeoToolsCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Class<?> weakCollectionCleanerClass = preventor.findClass("org.geotools.util.WeakCollectionCleaner");
    if(weakCollectionCleanerClass != null) {
      try {
        final Field DEFAULT = preventor.findField(weakCollectionCleanerClass, "DEFAULT");
        weakCollectionCleanerClass.getMethod("exit").invoke(DEFAULT.get(null));
      }
      catch (Exception ex) {
        preventor.error(ex);
      }
    }
    
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/IIOServiceProviderCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.security.AccessControlContext;
import java.util.*;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.IIOServiceProvider;
import javax.imageio.spi.ServiceRegistry;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Unregister ImageIO Service Provider loaded by the protected ClassLoader
 * @author Thomas Scheffler (1.x version)
 * @author Mattias Jiderhamn
 */
public class IIOServiceProviderCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(final ClassLoaderLeakPreventor preventor) {
    final IIORegistry registry = IIORegistry.getDefaultInstance();
    Iterator<Class<?>> categories = registry.getCategories();
    ServiceRegistry.Filter classLoaderFilter = new ServiceRegistry.Filter() {
      @Override
      public boolean filter(Object provider) {
        //remove all service provider loaded by the current ClassLoader
        return preventor.isLoadedInClassLoader(provider);
      }
    };
    while (categories.hasNext()) {
      @SuppressWarnings("unchecked")
      Class<IIOServiceProvider> category = (Class<IIOServiceProvider>) categories.next();
      Iterator<IIOServiceProvider> serviceProviders = registry.getServiceProviders(
          category,
          classLoaderFilter, true);
      if (serviceProviders.hasNext()) {
        //copy to list
        List<IIOServiceProvider> serviceProviderList = new ArrayList<IIOServiceProvider>();
        while (serviceProviders.hasNext()) {
          serviceProviderList.add(serviceProviders.next());
        }
        for (IIOServiceProvider serviceProvider : serviceProviderList) {
          preventor.warn("ImageIO " + category.getSimpleName() + " service provider deregistered: "
            + serviceProvider.getDescription(Locale.ROOT));
          registry.deregisterServiceProvider(serviceProvider);
        }
      }
    }

    // Leak as of Java 1.8u141, see https://github.com/mjiderhamn/classloader-leak-prevention/issues/71
    // The providers are probably registered by SunAwtAppContextInitiator
    final Field accMapField = preventor.findFieldOfClass("javax.imageio.spi.SubRegistry", "accMap");
    if(accMapField != null) {
      final Field categoryMapField = preventor.findField(ServiceRegistry.class, "categoryMap");
      if(categoryMapField != null) {
        final Map categoryMap = preventor.getFieldValue(categoryMapField, registry);
        if(categoryMap != null) {
          for(/*SubRegistry*/ Object subRegistry : categoryMap.values()) {
            final Map<Class<?>, AccessControlContext> accMap = preventor.getFieldValue(accMapField, subRegistry);
            if(accMap != null) {
              for(AccessControlContext acc : accMap.values()) {
                preventor.removeDomainCombiner(IIORegistry.class.getName(), acc);
              }
            }
          }
        }
      }
    }
    
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/IntrospectionUtilsCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clear IntrospectionUtils caches of Tomcat and Apache Commons Modeler
 * @author Mattias Jiderhamn
 */
public class IntrospectionUtilsCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    // Tomcat
    final Class<?> tomcatIntrospectionUtils = preventor.findClass("org.apache.tomcat.util.IntrospectionUtils");
    if(tomcatIntrospectionUtils != null) {
      try {
        tomcatIntrospectionUtils.getMethod("clear").invoke(null);
      }
      catch (Exception ex) {
        if(! preventor.isJBoss()) // JBoss includes this class, but no cache and no clear() method
          preventor.error(ex);
      }
    }

    // Apache Commons Modeler
    final Class<?> modelIntrospectionUtils = preventor.findClass("org.apache.commons.modeler.util.IntrospectionUtils");
    if(modelIntrospectionUtils != null && ! preventor.isClassLoaderOrChild(modelIntrospectionUtils.getClassLoader())) { // Loaded outside protected ClassLoader
      try {
        modelIntrospectionUtils.getMethod("clear").invoke(null);
      }
      catch (Exception ex) {
        preventor.warn("org.apache.commons.modeler.util.IntrospectionUtils needs to be cleared but there was an error, " +
            "consider upgrading Apache Commons Modeler");
        preventor.error(ex);
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JDK8151486CleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

import java.lang.reflect.Field;
import java.util.Set;

/**
 * Clear the "domains" field of the parent ClassLoader.
 *
 * See <a href="https://bugs.openjdk.java.net/browse/JDK-8151486">JDK-8151486</a>
 */
public class JDK8151486CleanUp implements ClassLoaderPreMortemCleanUp {
    @Override
    public void cleanUp(ClassLoaderLeakPreventor preventor) {
        Field field = preventor.findField(ClassLoader.class, "domains");
        if (field == null) {
            // field only exists in JDK versions [8u25, 9u140)
            return;
        }

        for (ClassLoader cl = preventor.getClassLoader().getParent(); cl != null; cl = cl.getParent()) {
            Set<?> domains = preventor.getFieldValue(field, cl);
            if (domains != null) {
                domains.clear();
            }
        }
    }
}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JacksonCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Method;
import java.util.Map;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clear Jackson TypeFactory cache as per https://github.com/FasterXML/jackson-databind/issues/1363
 * @author Mattias Jiderhamn
 */
public class JacksonCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Class<?> typeFactoryClass = preventor.findClass("com.fasterxml.jackson.databind.type.TypeFactory");
    if(typeFactoryClass != null && ! preventor.isLoadedInClassLoader(typeFactoryClass)) {
      try {
        final Method defaultInstance = preventor.findMethod(typeFactoryClass, "defaultInstance");
        if(defaultInstance != null) {
          final Object defaultTypeFactory = defaultInstance.invoke(null);
          if(defaultTypeFactory != null) {
            final Method clearCache = preventor.findMethod(typeFactoryClass, "clearCache");
            if(clearCache != null) { 
              clearCache.invoke(defaultTypeFactory);
            }
            else { // Version < 2.4.1
              final Object typeCache = preventor.getFieldValue(defaultTypeFactory, "_typeCache");
              if(typeCache instanceof Map) {
                //noinspection SynchronizationOnLocalVariableOrMethodParameter
                synchronized (typeCache) {
                  ((Map) typeCache).clear();
                }
              }
            }
          }
        }
      }
      catch (Exception e) {
        preventor.error(e);
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaServerFaces2746CleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.util.HashSet;
import java.util.Set;
import java.util.WeakHashMap;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Workaround for leak caused by Mojarra JSF implementation if included in the container.
 * See <a href="http://java.net/jira/browse/JAVASERVERFACES-2746">JAVASERVERFACES-2746</a>
 * @author Mattias Jiderhamn
 */
public class JavaServerFaces2746CleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    /*
     Note that since a WeakHashMap is used, it is not the map key that is the problem. However the value is a
     Map with java.beans.PropertyDescriptor as value, and java.beans.PropertyDescriptor has a Hashtable in which
     a class is put with "type" as key. This class may have been loaded by the protected ClassLoader.

     One example case is the class org.primefaces.component.menubutton.MenuButton that points to a Map with a key 
     "model" whose PropertyDescriptor.table has key "type" with the class org.primefaces.model.MenuModel as its value.

     For performance reasons however, we'll only look at the top level key and remove any that has been loaded by 
     protected ClassLoader.     
     */
    
    Object o = preventor.getStaticFieldValue("javax.faces.component.UIComponentBase", "descriptors"); // Non-static as of JSF 2.2.5
    if(o instanceof WeakHashMap) {
      WeakHashMap<?, ?> descriptors = (WeakHashMap<?, ?>) o;
      final Set<Class<?>> toRemove = new HashSet<Class<?>>();
      for(Object key : descriptors.keySet()) {
        if(key instanceof Class && preventor.isLoadedByClassLoader((Class<?>)key)) {
          // For performance reasons, remove all classes loaded by protected ClassLoader
          toRemove.add((Class<?>) key);
          
          // This would be more correct, but presumably slower
          /*
          Map<String, PropertyDescriptor> m = (Map<String, PropertyDescriptor>) descriptors.get(key);
          for(Map.Entry<String,PropertyDescriptor> entry : m.entrySet()) {
            Object type = entry.getValue().getValue("type"); // Key constant javax.el.ELResolver.TYPE
            if(type instanceof Class && isLoadedByWebApplication((Class)type)) {
              toRemove.add((Class) key); 
            }
          }
          */
        }
      }
      
      if(! toRemove.isEmpty()) {
        preventor.info("Removing " + toRemove.size() + " classes from Mojarra descriptors cache");
        for(Class<?> clazz : toRemove) {
          descriptors.remove(clazz);
        }
      }
    }    
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaUtilLoggingLevelCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.util.*;
import java.util.logging.Level;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Cleanup for removing custom {@link java.util.logging.Level}s loaded within the protected class loader.
 * @author Mattias Jiderhamn
 */
public class JavaUtilLoggingLevelCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Class<?> knownLevelClass = preventor.findClass("java.util.logging.Level$KnownLevel");
    if(knownLevelClass != null) {
      final Field levelObjectField = preventor.findField(knownLevelClass, "levelObject");
      if(levelObjectField != null) {

        //noinspection SynchronizationOnLocalVariableOrMethodParameter
        synchronized (knownLevelClass) {
          final Map<?, List/*<KnownLevel>*/> nameToLevels = preventor.getStaticFieldValue(knownLevelClass, "nameToLevels");
          final Map<?, List/*<KnownLevel>*/> intToLevels = preventor.getStaticFieldValue(knownLevelClass, "intToLevels");
          if(nameToLevels != null) {
            final Set/*<KnownLevel>*/ removed = process(preventor, knownLevelClass, levelObjectField, nameToLevels);
            if(intToLevels != null) {
              for(List/*<KnownLevel>*/ knownLevels : intToLevels.values()) {
                knownLevels.removeAll(removed);
              }
            }
          }
          else if(intToLevels != null) { // Use intToLevels as fallback; both should contain same values
            process(preventor, knownLevelClass, levelObjectField, intToLevels);
          }
        }
      }
      else 
        preventor.warn("Found " + knownLevelClass + " but not levelObject field");
    }
  }

  private Set/*<KnownLevel>*/ process(ClassLoaderLeakPreventor preventor, Class<?> knownLevelClass, 
                                      Field levelObjectField, Map<?, List/*<KnownLevel>*/> levelsMaps) {
    final Set/*<KnownLevel>*/ output = new HashSet<Object>();
    for(List/*<KnownLevel>*/ knownLevels : levelsMaps.values()) {
      for(Iterator/*<KnownLevel>*/ iter = knownLevels.listIterator(); iter.hasNext(); ) {
        final Object /* KnownLevel */ knownLevel = iter.next();
        final Level levelObject = preventor.getFieldValue(levelObjectField, knownLevel);
        if(preventor.isLoadedInClassLoader(levelObject)) {
          preventor.warn(Level.class.getName() + " subclass loaded by protected ClassLoader: " +
              levelObject.getClass() + "; removing from " + knownLevelClass);
          iter.remove();
          output.add(knownLevel);
        }
      }
    }
    return output;
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaxSecurityAuthLoginConfigurationCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import javax.security.auth.login.Configuration;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Cleanup for removing custom {@link javax.security.auth.login.Configuration}s loaded within the protected class loader.
 * @author Nikos Epping
 */
public class JavaxSecurityAuthLoginConfigurationCleanUp implements ClassLoaderPreMortemCleanUp {

  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    if (preventor.isLoadedInClassLoader(Configuration.getConfiguration())) {
      Configuration.setConfiguration(null);
    }
  }
}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JceSecurityCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.net.URL;
import java.security.Provider;
import java.util.Map;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clean up for the static caches of {@link javax.crypto.JceSecurity}
 * @author Mattias Jiderhamn
 */
public class JceSecurityCleanUp implements ClassLoaderPreMortemCleanUp {
  
  @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Class<?> javax_crypto_JceSecurity = preventor.findClass("javax.crypto.JceSecurity");
    if(javax_crypto_JceSecurity != null) {
      synchronized (javax_crypto_JceSecurity) { // synchronized methods are used for querying and updating the caches
        final Map<Provider, Object> verificationResults = preventor.getStaticFieldValue(javax_crypto_JceSecurity, "verificationResults");
        final Map<Provider, Object> verifyingProviders = preventor.getStaticFieldValue(javax_crypto_JceSecurity, "verifyingProviders");
        final Map<Class<?>, URL> codeBaseCacheRef = preventor.getStaticFieldValue(javax_crypto_JceSecurity, "codeBaseCacheRef");
        
        if(verificationResults != null) {
          verificationResults.clear();
        }
        if(verifyingProviders != null) {
          verifyingProviders.clear();
        }
        if(codeBaseCacheRef != null) {
          codeBaseCacheRef.clear();
        }
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/KeepAliveTimerCacheCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;
import se.jiderhamn.classloader.leak.prevention.MustBeAfter;

/**
 * Since Keep-Alive-Timer thread may have terminated, but still be referenced, we need to make sure it does not
 * reference this classloader.
 * @author Mattias Jiderhamn
 */
public class KeepAliveTimerCacheCleanUp implements ClassLoaderPreMortemCleanUp, MustBeAfter<ClassLoaderPreMortemCleanUp> {

  /** Needs to be done after {@link StopThreadsCleanUp}, since in there the Keep-Alive-Timer may be stopped. */
  @Override
  public Class<? extends ClassLoaderPreMortemCleanUp>[] mustBeBeforeMe() {
    return new Class[] {StopThreadsCleanUp.class};
  }

  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    Object keepAliveCache = preventor.getStaticFieldValue("sun.net.www.http.HttpClient", "kac", true);
    if(keepAliveCache != null) {
      final Thread keepAliveTimer = preventor.getFieldValue(keepAliveCache, "keepAliveTimer");
      if(keepAliveTimer != null) {
        if(preventor.isClassLoaderOrChild(keepAliveTimer.getContextClassLoader())) {
          keepAliveTimer.setContextClassLoader(preventor.getLeakSafeClassLoader());
          preventor.error("ContextClassLoader of sun.net.www.http.HttpClient cached Keep-Alive-Timer set to " + preventor.getLeakSafeClassLoader());
        }
      }
    }
    
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MBeanCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Unregister MBeans loaded by the protected class loader
 * @author Mattias Jiderhamn
 * @author rapla
 */
public class MBeanCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    try {
      final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
      final Set<ObjectName> allMBeanNames = mBeanServer.queryNames(new ObjectName("*:*"), null);

      // Special treatment for Jetty, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=423255
      JettyJMXRemover jettyJMXRemover = null;
      if(isJettyWithJMX(preventor)) {
        try {
          jettyJMXRemover = new JettyJMXRemover(preventor);
        }
        catch (Exception ex) {
          preventor.error(ex);
        }
      }
      
      // Look for custom MBeans
      for(ObjectName objectName : allMBeanNames) {
        try {
          if (jettyJMXRemover != null && jettyJMXRemover.unregisterJettyJMXBean(objectName)) {
        	  continue;
          }
          
          final ClassLoader mBeanClassLoader = mBeanServer.getClassLoaderFor(objectName);
          if(preventor.isClassLoaderOrChild(mBeanClassLoader)) { // MBean loaded by protected ClassLoader
            preventor.warn("MBean '" + objectName + "' was loaded by protected ClassLoader; unregistering");
            mBeanServer.unregisterMBean(objectName);
          }
          /* 
          else if(... instanceof NotificationBroadcasterSupport) {
            unregisterNotificationListeners((NotificationBroadcasterSupport) ...);
          }
          */
        }
        catch(Exception e) { // MBeanRegistrationException / InstanceNotFoundException
          preventor.error(e);
        }
      }
    }
    catch (Exception e) { // MalformedObjectNameException
      preventor.error(e);
    }
    
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Methods and classes for Jetty, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=423255 
  
  /** Are we running in Jetty with JMX enabled? */
  @SuppressWarnings("WeakerAccess")
  protected boolean isJettyWithJMX(ClassLoaderLeakPreventor preventor) {
    final ClassLoader classLoader = preventor.getClassLoader();
    try {
      // If package org.eclipse.jetty is found, we may be running under jetty
      if (classLoader.getResource("org/eclipse/jetty") == null) {
        return false;
      }

      Class.forName("org.eclipse.jetty.jmx.MBeanContainer", false, classLoader.getParent()); // JMX enabled?
      Class.forName("org.eclipse.jetty.webapp.WebAppContext", false, classLoader.getParent());
    }
    catch(Exception ex) { // For example ClassNotFoundException
      return false;
    }
    
    // Seems we are running in Jetty with JMX enabled
    return true;
  }
  
  /** 
   * Inner utility class that helps dealing with Jetty MBeans class.
   * If you enable JMX support in Jetty 8 or 9 some MBeans (e.g. for the ServletHolder or SessionManager) are
   * instantiated in the web application thread and a reference to the WebappClassloader is stored in a private
   * ObjectMBean._loader which is unfortunately not the classloader that loaded the class. Therefore we need to access 
   * the MBeanContainer class of the Jetty container and unregister the MBeans.
   */
  private class JettyJMXRemover {
    
    private final ClassLoaderLeakPreventor preventor;

    /** List of objects that may be wrapped in MBean by Jetty. Should be allowed to contain null. */
    private List<Object> objectsWrappedWithMBean;

    /** The org.eclipse.jetty.jmx.MBeanContainer instance */
    private Object beanContainer;

    /** org.eclipse.jetty.jmx.MBeanContainer.findBean() */
    private Method findBeanMethod;

    /** org.eclipse.jetty.jmx.MBeanContainer.removeBean() */
    private Method removeBeanMethod;

    @SuppressWarnings("WeakerAccess")
    public JettyJMXRemover(ClassLoaderLeakPreventor preventor) throws Exception {
      this.preventor = preventor;
      
      // First we need access to the MBeanContainer to access the beans
      // WebAppContext webappContext = (WebAppContext)servletContext;
      final Object webappContext = findJettyClass("org.eclipse.jetty.webapp.WebAppClassLoader")
              .getMethod("getContext").invoke(preventor.getClassLoader());
      if(webappContext == null)
        return;
      
      // Server server = (Server)webappContext.getServer();
      final Class<?> webAppContextClass = findJettyClass("org.eclipse.jetty.webapp.WebAppContext");
      final Object server = webAppContextClass.getMethod("getServer").invoke(webappContext);
      if(server == null)
        return;

      // MBeanContainer beanContainer = (MBeanContainer)server.getBean(MBeanContainer.class);
	  
      final Class<?> mBeanContainerClass = findJettyClass("org.eclipse.jetty.jmx.MBeanContainer");
      beanContainer = findJettyClass("org.eclipse.jetty.server.Server")
              .getMethod("getBean", Class.class).invoke(server, mBeanContainerClass);
      // Now we store all objects that belong to the web application and that will be wrapped by MBeans in a list
      if (beanContainer != null) {
        findBeanMethod = mBeanContainerClass.getMethod("findBean", ObjectName.class);
        try {
          removeBeanMethod = mBeanContainerClass.getMethod("removeBean", Object.class);
        } catch (NoSuchMethodException e) {
          preventor.warn("MBeanContainer.removeBean() method can not be found. giving up");
          return;
        }

        objectsWrappedWithMBean = new ArrayList<Object>();
        // SessionHandler sessionHandler = webappContext.getSessionHandler();
        final Object sessionHandler = webAppContextClass.getMethod("getSessionHandler").invoke(webappContext);
        if(sessionHandler != null) {
          objectsWrappedWithMBean.add(sessionHandler);
  
          // SessionManager sessionManager = sessionHandler.getSessionManager();
          final Object sessionManager = findJettyClass("org.eclipse.jetty.server.session.SessionHandler")
                  .getMethod("getSessionManager").invoke(sessionHandler);
          if(sessionManager != null) {
            objectsWrappedWithMBean.add(sessionManager);

            // SessionIdManager sessionIdManager = sessionManager.getSessionIdManager();
            final Object sessionIdManager = findJettyClass("org.eclipse.jetty.server.SessionManager")
                    .getMethod("getSessionIdManager").invoke(sessionManager);
            objectsWrappedWithMBean.add(sessionIdManager);
          }
        }

        // SecurityHandler securityHandler = webappContext.getSecurityHandler();
        objectsWrappedWithMBean.add(webAppContextClass.getMethod("getSecurityHandler").invoke(webappContext));

        // ServletHandler servletHandler = webappContext.getServletHandler();
        final Object servletHandler = webAppContextClass.getMethod("getServletHandler").invoke(webappContext);
        if(servletHandler != null) {
          objectsWrappedWithMBean.add(servletHandler);

          final Class<?> servletHandlerClass = findJettyClass("org.eclipse.jetty.servlet.ServletHandler");
          // Object[] servletMappings = servletHandler.getServletMappings();
          objectsWrappedWithMBean.add(Arrays.asList((Object[]) servletHandlerClass.getMethod("getServletMappings").invoke(servletHandler)));

          // Object[] servlets = servletHandler.getServlets();
          objectsWrappedWithMBean.add(Arrays.asList((Object[]) servletHandlerClass.getMethod("getServlets").invoke(servletHandler)));
        }
      }
    }

    /**
     * Test if objectName denotes a wrapping Jetty MBean and if so unregister it.
     * @return {@code true} if Jetty MBean was unregistered, otherwise {@code false}
     */
    boolean unregisterJettyJMXBean(ObjectName objectName) {
      if (objectsWrappedWithMBean == null || ! objectName.getDomain().contains("org.eclipse.jetty")) {
        return false;
      }
      else { // Possibly a Jetty MBean that needs to be unregistered
        try {
		      final Object bean = findBeanMethod.invoke(beanContainer, objectName);
          if(bean == null)
            return false;
          
		      // Search suspect list
		      for (Object wrapped : objectsWrappedWithMBean) {
		        if (wrapped == bean) {
              preventor.warn("Jetty MBean '" + objectName + "' is a suspect in causing memory leaks; unregistering");
			        removeBeanMethod.invoke(beanContainer, bean); // Remove it via the MBeanContainer
			        return true;
            }
		      }
  		  }
        catch (Exception ex)  {
          preventor.error(ex);
		    }
		    return false;
	    }
    }

    Class findJettyClass(String className) throws ClassNotFoundException {
      try {
        return Class.forName(className, false, preventor.getClassLoader());
      } catch (ClassNotFoundException e1) {
        try {
          return Class.forName(className);
        } catch (ClassNotFoundException e2) {
          e2.addSuppressed(e1);
          throw e2;
        }
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.management.ManagementFactory;
import java.lang.management.PlatformManagedObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;

import javax.management.*;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Unregister MBeans, MXBean {@link NotificationListener}s/{@link NotificationFilter}s/handbacks loaded by the 
 * protected class loader
 * @author Mattias Jiderhamn
 */
public class MXBeanNotificationListenersCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Class<?> notificationEmitterSupportClass = preventor.findClass("sun.management.NotificationEmitterSupport");
    final Field listenerListField = preventor.findField(notificationEmitterSupportClass, "listenerList");
    final Class<?> listenerInfoClass = preventor.findClass("sun.management.NotificationEmitterSupport$ListenerInfo");
    final Field listenerField = preventor.findField(listenerInfoClass, "listener");
    final Field filterField = preventor.findField(listenerInfoClass, "filter");
    final Field handbackField = preventor.findField(listenerInfoClass, "handback");

    final Class<?> listenerWrapperClass = preventor.findClass("com.sun.jmx.interceptor.DefaultMBeanServerInterceptor$ListenerWrapper");

    final boolean canProcessNotificationEmitterSupport = listenerListField != null && listenerInfoClass != null && listenerField != null && filterField != null && handbackField != null;

    if (!canProcessNotificationEmitterSupport) {
      preventor.warn("Unable to unregister NotificationEmitterSupport listeners, because details could not be found using reflection");
    }

    final Set<Class<? extends PlatformManagedObject>> platformInterfaces = ManagementFactory.getPlatformManagementInterfaces();

    if (platformInterfaces != null) {
      for (Class<? extends PlatformManagedObject> platformInterface : platformInterfaces) {
        for (Object mxBean : ManagementFactory.getPlatformMXBeans(platformInterface)) {
          if (mxBean instanceof NotificationEmitter) { // The MXBean may have NotificationListeners
            if (canProcessNotificationEmitterSupport && notificationEmitterSupportClass.isAssignableFrom(mxBean.getClass())) {
              final List<? /* NotificationEmitterSupport.ListenerInfo */> listenerList = preventor.getFieldValue(listenerListField, mxBean);
              if (listenerList != null) {
                for (Object listenerInfo : listenerList) { // Loop all listeners
                  final NotificationListener listener = preventor.getFieldValue(listenerField, listenerInfo);
                  final NotificationListener rawListener = unwrap(preventor, listenerWrapperClass, listener);
                  final NotificationFilter filter = preventor.getFieldValue(filterField, listenerInfo);
                  final Object handback = preventor.getFieldValue(handbackField, listenerInfo);

                  if (preventor.isLoadedInClassLoader(rawListener) || preventor.isLoadedInClassLoader(filter) || preventor.isLoadedInClassLoader(handback)) {
                    preventor.warn(((listener == rawListener) ? "Listener '" : "Wrapped listener '") + listener + 
                    "' (or its filter or handback) of MXBean " + mxBean + 
                    " of PlatformManagedObject " + platformInterface + " was loaded in protected ClassLoader; removing");
                    // This is safe, as the implementation (as of this writing) works with a copy,
                    // not altering the original
                    try {
                      ((NotificationEmitter) mxBean).removeNotificationListener(listener, filter, handback);
                    }
                    catch (ListenerNotFoundException e) { // Should never happen
                      preventor.error(e);
                    }
                  }
                }
              }
            }
            else if(mxBean instanceof NotificationBroadcasterSupport) { // Unlikely case
              unregisterNotificationListeners(preventor, (NotificationBroadcasterSupport) mxBean, listenerWrapperClass);
            }
          }
        }
      }
    }  
  }

  /** 
   * Unregister {@link NotificationListener}s from subclass of {@link NotificationBroadcasterSupport}, if listener,
   * filter or handback is loaded by the protected ClassLoader.
   */
  protected void unregisterNotificationListeners(ClassLoaderLeakPreventor preventor, NotificationBroadcasterSupport mBean,
                                                 final Class<?> listenerWrapperClass) {
    final Field listenerListField = preventor.findField(NotificationBroadcasterSupport.class, "listenerList");
    if(listenerListField != null) {
      final Class<?> listenerInfoClass = preventor.findClass("javax.management.NotificationBroadcasterSupport$ListenerInfo");

      final List<? /*javax.management.NotificationBroadcasterSupport.ListenerInfo*/> listenerList =
          preventor.getFieldValue(listenerListField, mBean);

      if(listenerList != null) {
        final Field listenerField = preventor.findField(listenerInfoClass, "listener");
        final Field filterField = preventor.findField(listenerInfoClass, "filter");
        final Field handbackField = preventor.findField(listenerInfoClass, "handback");
        for(Object listenerInfo : listenerList) {
          final NotificationListener listener = preventor.getFieldValue(listenerField, listenerInfo);
          final NotificationListener rawListener = unwrap(preventor, listenerWrapperClass, listener);
          final NotificationFilter filter = preventor.getFieldValue(filterField, listenerInfo);
          final Object handback = preventor.getFieldValue(handbackField, listenerInfo);
          
          if(preventor.isLoadedInClassLoader(rawListener) || preventor.isLoadedInClassLoader(filter) || preventor.isLoadedInClassLoader(handback)) {
            preventor.warn(((listener == rawListener) ? "Listener '" : "Wrapped listener '") + listener + 
                "' (or its filter or handback) of MBean " + mBean + 
                " was loaded in protected ClassLoader; removing");
            // This is safe, as the implementation works with a copy, not altering the original
            try {
              mBean.removeNotificationListener(listener, filter, handback);
            }
            catch (ListenerNotFoundException e) { // Should never happen
              preventor.error(e);
            }
          }
        }
      }
    }
  }

  /** Unwrap {@link NotificationListener} wrapped by {@link com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.ListenerWrapper} */
  private NotificationListener unwrap(ClassLoaderLeakPreventor preventor, Class<?> listenerWrapperClass, NotificationListener listener) {
    if(listenerWrapperClass != null && listenerWrapperClass.isInstance(listener)) {
      return preventor.getFieldValue(listener, "listener"); // Unwrap
    }
    else 
      return listener;
  }

}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MoxyCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ConcurrentModificationException;
import java.util.Map;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Cleanup for leak caused by EclipseLink MOXy
 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=529270
 * @author Mattias Jiderhamn
 */
public class MoxyCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Class<?> helperClass = findClass(preventor, "org.eclipse.persistence.jaxb.javamodel.Helper");
    if(helperClass != null) {
      unsetField(preventor, helperClass, "COLLECTION_CLASS");
      unsetField(preventor, helperClass, "LIST_CLASS");
      unsetField(preventor, helperClass, "SET_CLASS");
      unsetField(preventor, helperClass, "MAP_CLASS");
      unsetField(preventor, helperClass, "JAXBELEMENT_CLASS");
      unsetField(preventor, helperClass, "OBJECT_CLASS");
    }

    final Class<?> propertyClass = findClass(preventor, "org.eclipse.persistence.jaxb.compiler.Property");
    if(propertyClass != null) {
      unsetField(preventor, propertyClass, "OBJECT_CLASS");
      unsetField(preventor, propertyClass, "XML_ADAPTER_CLASS");
    }
  }
  
  public Class<?> findClass(ClassLoaderLeakPreventor preventor, String className) {
    try {
      return Class.forName(className, true, preventor.getLeakSafeClassLoader());
    }
    catch (ClassNotFoundException e) {
      // Silently ignore
      return null;
    }
    catch (Exception ex) { // Example SecurityException
      preventor.warn(ex);
      return null;
    }
  }

  private void unsetField(ClassLoaderLeakPreventor preventor,
                          Class<?> clazz, String fieldName) {
    final Field field = preventor.findField(clazz, fieldName);
    if(field != null) {
      try {
        final Object /* org.eclipse.persistence.jaxb.javamodel.reflection.JavaClassImpl */ javaClass = field.get(null);
        if(javaClass != null) {
          final Object /* org.eclipse.persistence.jaxb.javamodel.reflection.JavaModelImpl */ javaModelImpl = 
              preventor.getFieldValue(javaClass, "javaModelImpl");
          if(javaModelImpl != null) {
            final Method getClassLoader = preventor.findMethod(javaModelImpl.getClass(), "getClassLoader");
            if(getClassLoader != null) {
              final ClassLoader classLoader = (ClassLoader) getClassLoader.invoke(javaModelImpl);
              if(preventor.isClassLoaderOrChild(classLoader)) {
                preventor.info("Changing ClassLoader of " + field);
                preventor.findMethod(javaModelImpl.getClass(), "setClassLoader", ClassLoader.class)
                    .invoke(javaModelImpl, preventor.getLeakSafeClassLoader());
                final Field isJaxbClassLoader = preventor.findField(javaModelImpl.getClass(), "isJaxbClassLoader");
                if(isJaxbClassLoader != null) {
                  isJaxbClassLoader.set(javaModelImpl, false);
                }
              }
            }
            else
              preventor.error("Cannot get ClassLoader of " + javaModelImpl);
            
            // Clear cachedJavaClasses
            final Map cachedJavaClasses = preventor.getFieldValue(javaModelImpl, "cachedJavaClasses");
            if(cachedJavaClasses != null) {
              try {
                cachedJavaClasses.clear();
              }
              catch (ConcurrentModificationException e) {
                preventor.error("Unable to clear " + javaModelImpl + ".cachedJavaClasses");
              }
            }
          }
          else {
            preventor.error("Cannot get javaModelImpl of " + javaClass);
            field.set(null, null);
          }
        }
      }
      catch (Exception e) {
        preventor.warn(e);
      }
    }
    else 
      preventor.warn("Unable to find field " + fieldName + " of class " + clazz);
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MultiThreadedHttpConnectionManagerCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Invokes static method org.apache.commons.httpclient.MultiThreadedHttpConnectionManager.shutdownAll() to close connections left out by com.sun.jersey.client.apache.ApacheHttpClient.  
 *
 * @author Marian Petrik
 */
public class MultiThreadedHttpConnectionManagerCleanUp implements ClassLoaderPreMortemCleanUp {

	@Override
	public void cleanUp(ClassLoaderLeakPreventor preventor) {
		final Class<?> connManager = preventor.findClass("org.apache.commons.httpclient.MultiThreadedHttpConnectionManager");
		if(connManager != null && preventor.isLoadedByClassLoader(connManager)) {
			try {
				connManager.getMethod("shutdownAll").invoke(null);
			}
			catch (Throwable t) {
				preventor.warn(t);
			}
		}
	}

}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ObjectStreamClassCleanup.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.util.concurrent.ConcurrentHashMap;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clean up for the static caches of {@link java.io.ObjectStreamClass}
 */
public class ObjectStreamClassCleanup implements ClassLoaderPreMortemCleanUp {

    @Override
    public void cleanUp(ClassLoaderLeakPreventor preventor) {
        try {
            final Class<?> cacheClass = preventor.findClass("java.io.ObjectStreamClass$Caches");
            if (cacheClass == null) { return; }

            Object localDescsCache = preventor.getStaticFieldValue(cacheClass, "localDescs");
            clearIfConcurrentHashMap(localDescsCache, preventor);

            Object reflectorsCache = preventor.getStaticFieldValue(cacheClass, "reflectors");
            clearIfConcurrentHashMap(reflectorsCache, preventor);
        }
        catch (Exception e) {
            preventor.error(e);
        }
    }

    protected void clearIfConcurrentHashMap(Object object, ClassLoaderLeakPreventor preventor) {
        if (!(object instanceof ConcurrentHashMap)) { return; }
        ConcurrentHashMap<?,?> map = (ConcurrentHashMap<?,?>) object;
        int nbOfEntries=map.size();
        map.clear();
        preventor.info("Detected and fixed leak situation for java.io.ObjectStreamClass ("+nbOfEntries+" entries were flushed).");
    }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/PropertyEditorCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.beans.PropertyEditorManager;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Deregister custom property editors.
 * This has been fixed in Java 7.
 * @author Mattias Jiderhamn
 */
public class PropertyEditorCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Field registryField = preventor.findField(PropertyEditorManager.class, "registry");
    if(registryField == null) { // We're probably on a newer JDK
      preventor.info("Internal registry of " + PropertyEditorManager.class.getName() + " not found");
    }
    else {
      try {
        synchronized (PropertyEditorManager.class) {
          final Map<Class<?>, Class<?>> registry = (Map<Class<?>, Class<?>>) registryField.get(null);
          if(registry != null) { // Initialized
            final Set<Class<?>> toRemove = new HashSet<Class<?>>();
            
            for(Map.Entry<Class<?>, Class<?>> entry : registry.entrySet()) {
              if(preventor.isLoadedByClassLoader(entry.getKey()) ||
                 preventor.isLoadedByClassLoader(entry.getValue())) { // More likely
                toRemove.add(entry.getKey());
              }
            }
            
            for(Class<?> clazz : toRemove) {
              preventor.warn("Property editor for type " + clazz +  " = " + registry.get(clazz) + " needs to be deregistered");
              PropertyEditorManager.registerEditor(clazz, null); // Deregister
            }
          }
        }
      }
      catch (Exception e) { // Such as IllegalAccessException
        preventor.error(e);
      }
    }
  }
}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ProxySelectorCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.net.ProxySelector;
import java.security.AccessController;
import java.security.PrivilegedAction;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * If default {@link java.net.ProxySelector} is loaded by protected ClassLoader it needs to be unset
 * @author Mattias Jiderhamn
 */
public class ProxySelectorCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(final ClassLoaderLeakPreventor preventor) {
    AccessController.doPrivileged(new PrivilegedAction<Void>() {
      @Override
      public Void run() {
        ProxySelector selector = ProxySelector.getDefault();
        if(preventor.isLoadedInClassLoader(selector)) {
          ProxySelector.setDefault(null);
          preventor.warn("Removing default java.net.ProxySelector: " + selector);
        }
        return null;
      }
    });
    
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ReactorNettyHttpResourcesCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Method;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;


/**
 * Clean up Reactor Netty resources
 * @author Mattias Jiderhamn
 */
public class ReactorNettyHttpResourcesCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    Class<?> clazz = preventor.findClass("reactor.ipc.netty.http.HttpResources");
    if(preventor.isLoadedByClassLoader(clazz)) {
      final Method shutdown = preventor.findMethod(clazz, "shutdown");
      if(shutdown != null) {
        try {
          shutdown.invoke(null);
        }
        catch (Throwable e) {
          preventor.warn(e);
        }
      }
    }
    clazz = preventor.findClass("reactor.netty.http.HttpResources");
    if(preventor.isLoadedByClassLoader(clazz)) {
      final Method shutdown = preventor.findMethod(clazz, "shutdown");
      if(shutdown != null) {
        try {
          shutdown.invoke(null);
        }
        catch (Throwable e) {
          preventor.warn(e);
        }
      }
    }
  }
}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ResourceBundleCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clean up caches in {@link ResourceBundle}
 * @author Mattias Jiderhamn
 */
public class ResourceBundleCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    try {
      try { // First try Java 1.6 method
        final Method clearCache16 = ResourceBundle.class.getMethod("clearCache", ClassLoader.class);
        preventor.debug("Since Java 1.6+ is used, we can call " + clearCache16);
        clearCache16.invoke(null, preventor.getClassLoader());
      }
      catch (NoSuchMethodException e) {
        // Not Java 1.6+, we have to clear manually
        final Map<?,?> cacheList = preventor.getStaticFieldValue(ResourceBundle.class, "cacheList"); // Java 5: SoftCache extends AbstractMap
        final Iterator<?> iter = cacheList.keySet().iterator();
        Field loaderRefField = null;
        while(iter.hasNext()) {
          Object key = iter.next(); // CacheKey
          
          if(loaderRefField == null) { // First time
            loaderRefField = key.getClass().getDeclaredField("loaderRef");
            loaderRefField.setAccessible(true);
          }
          WeakReference<ClassLoader> loaderRef = (WeakReference<ClassLoader>) loaderRefField.get(key); // LoaderReference extends WeakReference
          ClassLoader classLoader = loaderRef.get();
          
          if(preventor.isClassLoaderOrChild(classLoader)) {
            preventor.info("Removing ResourceBundle from cache: " + key);
            iter.remove();
          }
          
        }
      }
    }
    catch(Exception ex) {
      preventor.error(ex);
    }
    
    // (CacheKey of java.util.ResourceBundle.NONEXISTENT_BUNDLE will point to first referring classloader...)
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/RmiTargetsCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Heavily inspired by org.apache.catalina.loader.WebappClassLoader.clearReferencesRmiTargets()
 * @author Mattias Jiderhamn
 */
public class RmiTargetsCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    try {
      final Class<?> objectTableClass = preventor.findClass("sun.rmi.transport.ObjectTable");
      if(objectTableClass != null) {
        clearRmiTargetsMap(preventor, (Map<?, ?>) preventor.getStaticFieldValue(objectTableClass, "objTable"));
        clearRmiTargetsMap(preventor, (Map<?, ?>) preventor.getStaticFieldValue(objectTableClass, "implTable"));
      }
    }
    catch (Exception ex) {
      preventor.error(ex);
    }
  }

  /** Iterate RMI Targets Map and remove entries loaded by protected ClassLoader */
  @SuppressWarnings("WeakerAccess")
  protected void clearRmiTargetsMap(ClassLoaderLeakPreventor preventor, Map<?, ?> rmiTargetsMap) {
    try {
      final Field cclField = preventor.findFieldOfClass("sun.rmi.transport.Target", "ccl");
      preventor.debug("Looping " + rmiTargetsMap.size() + " RMI Targets to find leaks");
      for(Iterator<?> iter = rmiTargetsMap.values().iterator(); iter.hasNext(); ) {
        Object target = iter.next(); // sun.rmi.transport.Target
        ClassLoader ccl = (ClassLoader) cclField.get(target);
        if(preventor.isClassLoaderOrChild(ccl)) {
          preventor.warn("Removing RMI Target: " + target);
          iter.remove();
        }
      }
    }
    catch (Exception ex) {
      preventor.error(ex);
    }
  }

}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/SAAJEnvelopeFactoryParserPoolCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.util.Map;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clean up leak caused by {@link javax.xml.parsers.SAXParser} attribute/property being loaded by protected class loader
 * and cached in {@link com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory#parserPool}.
 * See <a href="https://issues.apache.org/jira/browse/XALANJ-2600">here</a>.
 * @author Mattias Jiderhamn
 */
public class SAAJEnvelopeFactoryParserPoolCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    // Internal class from the JDK (Removed in JDK11)
    cleanupWithFactoryClass(preventor, preventor.findClass("com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory"));
    // Maven dependency
    cleanupWithFactoryClass(preventor, preventor.findClass("com.sun.xml.messaging.saaj.soap.EnvelopeFactory"));
  }

  private void cleanupWithFactoryClass(final ClassLoaderLeakPreventor preventor, Class<?> factoryClass) {
    final Object parserPool = preventor.getStaticFieldValue(factoryClass, "parserPool");
    
    if(parserPool != null) {
      final Field CACHE = preventor.findField(parserPool.getClass().getSuperclass(), "CACHE");
      if(CACHE != null) {
        final Object cache = preventor.getFieldValue(CACHE, parserPool);
        if(cache instanceof Map) { // WeakHashMap
          ((Map) cache).remove(preventor.getClassLoader());
        }
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/SecurityProviderCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.util.HashSet;
import java.util.Set;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Deregister custom security providers
 * @author Mattias Jiderhamn
 */
public class SecurityProviderCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Set<String> providersToRemove = new HashSet<String>();
    for(java.security.Provider provider : java.security.Security.getProviders()) {
      if(preventor.isLoadedInClassLoader(provider)) {
        providersToRemove.add(provider.getName());
      }
    }
    
    if(! providersToRemove.isEmpty()) {
      preventor.warn("Removing security providers loaded by protected ClassLoader: " + providersToRemove);
      for(String providerName : providersToRemove) {
        java.security.Security.removeProvider(providerName);
      }
    }
    
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ShutdownHookCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.util.ArrayList;
import java.util.Map;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Find and deregister shutdown hooks. Will by default execute the hooks immediately after removing them.
 * @author Mattias Jiderhamn
 */
public class ShutdownHookCleanUp implements ClassLoaderPreMortemCleanUp {

  /** Default no of milliseconds to wait for shutdown hook to finish execution */
  public static final int SHUTDOWN_HOOK_WAIT_MS_DEFAULT = 10 * 1000; // 10 seconds

  /** Should shutdown hooks registered from the application be executed at application shutdown? */
  @SuppressWarnings("WeakerAccess")
  protected boolean executeShutdownHooks = true;

  /** 
   * No of milliseconds to wait for shutdown hooks to finish execution, before stopping them.
   * If set to -1 there will be no waiting at all, but Thread is allowed to run until finished.
   */
  @SuppressWarnings("WeakerAccess")
  protected int shutdownHookWaitMs = SHUTDOWN_HOOK_WAIT_MS_DEFAULT;

  /** Constructor for test case */
  @SuppressWarnings("unused")
  public ShutdownHookCleanUp() {
    this(true, SHUTDOWN_HOOK_WAIT_MS_DEFAULT);
  }

  public ShutdownHookCleanUp(boolean executeShutdownHooks, int shutdownHookWaitMs) {
    this.executeShutdownHooks = executeShutdownHooks;
    this.shutdownHookWaitMs = shutdownHookWaitMs;
  }

  public void setExecuteShutdownHooks(boolean executeShutdownHooks) {
    this.executeShutdownHooks = executeShutdownHooks;
  }

  public void setShutdownHookWaitMs(int shutdownHookWaitMs) {
    this.shutdownHookWaitMs = shutdownHookWaitMs;
  }

  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    
    // We will not remove known shutdown hooks, since loading the owning class of the hook,
    // may register the hook if previously unregistered 
    final Map<Thread, Thread> shutdownHooks = preventor.getStaticFieldValue("java.lang.ApplicationShutdownHooks", "hooks");
    if(shutdownHooks != null) { // Could be null during JVM shutdown, which we already avoid, but be extra precautious
      // Iterate copy to avoid ConcurrentModificationException
      for(Thread shutdownHook : new ArrayList<Thread>(shutdownHooks.keySet())) {
        if(preventor.isThreadInClassLoader(shutdownHook)) { // Planned to run in protected ClassLoader
          removeShutdownHook(preventor, shutdownHook);
        }
      }
    }
  }

  /** Deregister shutdown hook and execute it immediately */
  @SuppressWarnings({"deprecation", "WeakerAccess"})
  protected void removeShutdownHook(ClassLoaderLeakPreventor preventor, Thread shutdownHook) {
    final String displayString = "'" + shutdownHook + "' of type " + shutdownHook.getClass().getName();
    preventor.error("Removing shutdown hook: " + displayString);
    Runtime.getRuntime().removeShutdownHook(shutdownHook);

    if(executeShutdownHooks) { // Shutdown hooks should be executed
      
      preventor.info("Executing shutdown hook now: " + displayString);
      // Make sure it's from protected ClassLoader
      shutdownHook.start(); // Run cleanup immediately
      
      if(shutdownHookWaitMs > 0) { // Wait for shutdown hook to finish
        try {
          shutdownHook.join(shutdownHookWaitMs); // Wait for thread to run
        }
        catch (InterruptedException e) {
          // Do nothing
        }
        if(shutdownHook.isAlive()) {
          preventor.warn(shutdownHook + "still running after " + shutdownHookWaitMs + " ms - Stopping!");
          shutdownHook.stop();
        }
      }
    }
  }

}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessControlContext;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

import static se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor.THREAD_WAIT_MS_DEFAULT;

/**
 * Check if there are threads running within the protected {@link ClassLoader}, or otherwise referencing it,
 * and either warn or stop those threads depending on settings.
 * @author Mattias Jiderhamn
 */
@SuppressWarnings("WeakerAccess")
public class StopThreadsCleanUp implements ClassLoaderPreMortemCleanUp {

  protected static final String JURT_ASYNCHRONOUS_FINALIZER = "com.sun.star.lib.util.AsynchronousFinalizer";

  /** Thread {@link Runnable} for Sun/Oracle JRE i.e. java.lang.Thread.target */
  private Field oracleTarget;
  
  /** Thread {@link Runnable} for IBM JRE i.e. java.lang.Thread.runnable */
  private Field ibmRunnable;

  protected boolean stopThreads;

  /**
   * No of milliseconds to wait for threads to finish execution, before stopping them.
   */
  protected int threadWaitMs = THREAD_WAIT_MS_DEFAULT;
  
  /** Should Timer threads tied to the protected ClassLoader classloader be forced to stop at application shutdown? */
  protected boolean stopTimerThreads;

  /** Default constructor with {@link #stopThreads} = true and {@link #stopTimerThreads} = true */
  @SuppressWarnings("unused")
  public StopThreadsCleanUp() {
    this(true, true);
  }

  public StopThreadsCleanUp(boolean stopThreads, boolean stopTimerThreads) {
    this.stopThreads = stopThreads;
    this.stopTimerThreads = stopTimerThreads;
  }

  public void setStopThreads(boolean stopThreads) {
    this.stopThreads = stopThreads;
  }

  public void setStopTimerThreads(boolean stopTimerThreads) {
    this.stopTimerThreads = stopTimerThreads;
  }

  public void setThreadWaitMs(int threadWaitMs) {
    this.threadWaitMs = threadWaitMs;
  }

  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    // Force the execution of the cleanup code for JURT; see https://issues.apache.org/ooo/show_bug.cgi?id=122517
    forceStartOpenOfficeJurtCleanup(preventor); // (Do this before stopThreads())
    
    ////////////////////
    // Fix generic leaks
    
    stopThreads(preventor);
  }
  
  /**
   * The bug detailed at https://issues.apache.org/ooo/show_bug.cgi?id=122517 is quite tricky. This is a try to 
   * avoid the issues by force starting the threads and it's job queue.
   */
  protected void forceStartOpenOfficeJurtCleanup(ClassLoaderLeakPreventor preventor) {
    if(stopThreads) {
      if(preventor.isLoadedByClassLoader(preventor.findClass(JURT_ASYNCHRONOUS_FINALIZER))) {
        /* 
          The com.sun.star.lib.util.AsynchronousFinalizer class was found and loaded, which means that in case the
          static block that starts the daemon thread had not been started yet, it has been started now.
          
          Now let's force Garbage Collection, with the hopes of having the finalize()ers that put Jobs on the
          AsynchronousFinalizer queue be executed. Then just leave it, and handle the rest in {@link #stopThreads}.
          */
        preventor.info("OpenOffice JURT AsynchronousFinalizer thread started - forcing garbage collection to invoke finalizers");
        ClassLoaderLeakPreventor.gc();
      }
    }
    else {
      // Check for class existence without loading class and thus executing static block
      if(preventor.getClassLoader().getResource("com/sun/star/lib/util/AsynchronousFinalizer.class") != null) {
        preventor.warn("OpenOffice JURT AsynchronousFinalizer thread will not be stopped if started, as stopThreads is false");
        /* 
         By forcing Garbage Collection, we'll hopefully start the thread now, in case it would have been started by
         GC later, so that at least it will appear in the logs. 
         */
        ClassLoaderLeakPreventor.gc();
      }
    }
  }
  
  /**
   * Partially inspired by org.apache.catalina.loader.WebappClassLoader.clearReferencesThreads()
   */
  protected void stopThreads(ClassLoaderLeakPreventor preventor) {
    final Class<?> workerClass = preventor.findClass("java.util.concurrent.ThreadPoolExecutor$Worker");

    final boolean waitForThreads = threadWaitMs > 0;
    for(Thread thread : preventor.getAllThreads()) {
      final Runnable runnable = getRunnable(preventor, thread);

      final boolean threadLoadedByClassLoader = preventor.isLoadedInClassLoader(thread);
      final boolean threadGroupLoadedByClassLoader = preventor.isLoadedInClassLoader(thread.getThreadGroup());
      final boolean runnableLoadedByClassLoader = preventor.isLoadedInClassLoader(runnable);
      final boolean hasContextClassLoader = preventor.isClassLoaderOrChild(thread.getContextClassLoader());
      if(thread != Thread.currentThread() && // Ignore current thread
         (threadLoadedByClassLoader || threadGroupLoadedByClassLoader || hasContextClassLoader || // = preventor.isThreadInClassLoader(thread) 
          runnableLoadedByClassLoader)) {

        if (thread.getClass().getName().startsWith(StopThreadsCleanUp.JURT_ASYNCHRONOUS_FINALIZER)) {
          // Note, the thread group of this thread may be "system" if it is triggered by the Garbage Collector
          // however if triggered by us in forceStartOpenOfficeJurtCleanup() it may depend on the application server
          if(stopThreads) {
            preventor.info("Found JURT thread " + thread.getName() + "; starting " + JURTKiller.class.getSimpleName());
            new JURTKiller(preventor, thread).start();
          }
          else
            preventor.warn("JURT thread " + thread.getName() + " is still running in protected ClassLoader");
        }
        else if(thread.getThreadGroup() != null && 
           ("system".equals(thread.getThreadGroup().getName()) ||  // System thread
            "RMI Runtime".equals(thread.getThreadGroup().getName()))) { // RMI thread (honestly, just copied from Tomcat)
          
          if("Keep-Alive-Timer".equals(thread.getName())) {
            thread.setContextClassLoader(preventor.getLeakSafeClassLoader());
            preventor.debug("Changed contextClassLoader of HTTP keep alive thread");
          }
        }
        else if(thread.isAlive()) { // Non-system, running in protected ClassLoader

          if(thread.getClass().getName().startsWith("java.util.Timer")) { // Sun/Oracle = "java.util.TimerThread"; IBM = "java.util.Timer$TimerImpl"
            if(thread.getName() != null && thread.getName().startsWith("PostgreSQL-JDBC-SharedTimer-")) { // Postgresql JDBC timer thread
              // Replace contextClassLoader, if needed
              if(hasContextClassLoader) {
                final Class<?> postgresqlDriver = preventor.findClass("org.postgresql.Driver");
                final ClassLoader postgresqlCL = (postgresqlDriver != null && ! preventor.isLoadedByClassLoader(postgresqlDriver)) ?
                    postgresqlDriver.getClassLoader() : // Postgresql driver loaded by other classloader than we want to protect
                    preventor.getLeakSafeClassLoader();
                thread.setContextClassLoader(postgresqlCL);
                preventor.warn("Changing contextClassLoader of " + thread + " to " + postgresqlCL);
              }

              // Replace AccessControlContext
              setThreadSafeAccessControlContext(preventor, thread);
            }
            else if(stopTimerThreads) {
              preventor.warn("Stopping Timer thread '" + thread.getName() + "' running in protected ClassLoader. " +
                  preventor.getStackTrace(thread));
              stopTimerThread(preventor, thread);
            }
            else {
              preventor.info("Timer thread is running in protected ClassLoader, but will not be stopped. " + 
                  preventor.getStackTrace(thread));
            }
          }
          else {
            final String displayString = "Thread '" + thread + "'" + 
                (threadLoadedByClassLoader ? " of type " + thread.getClass().getName() + " loaded by protected ClassLoader" : "") +
                (runnableLoadedByClassLoader ? " with Runnable of type " + runnable.getClass().getName() + " loaded by protected ClassLoader" : "") +
                (threadGroupLoadedByClassLoader ? " with ThreadGroup of type " + thread.getThreadGroup().getClass().getName() + " loaded by protected ClassLoader" : "") +
                (hasContextClassLoader ? " with contextClassLoader = protected ClassLoader or child" : "");

            // If threads is running an java.util.concurrent.ThreadPoolExecutor.Worker try shutting down the executor
            if(workerClass != null && workerClass.isInstance(runnable)) {
              try {
                // java.util.concurrent.ThreadPoolExecutor, introduced in Java 1.5
                final Field workerExecutor = preventor.findField(workerClass, "this$0");
                final ThreadPoolExecutor executor = preventor.getFieldValue(workerExecutor, runnable);
                if(executor != null) {
                  if("org.apache.tomcat.util.threads.ThreadPoolExecutor".equals(executor.getClass().getName())) {
                    // Tomcat pooled thread
                    preventor.debug(displayString + " is worker of " + executor.getClass().getName());
                  }
                  else if(preventor.isLoadedInClassLoader(executor) || preventor.isLoadedInClassLoader(executor.getThreadFactory())) {
                    if(stopThreads) {
                      preventor.warn("Shutting down ThreadPoolExecutor of type " + executor.getClass().getName());
                      executor.shutdownNow();
                    }
                    else {
                      preventor.warn("ThreadPoolExecutor of type " + executor.getClass().getName() +
                          " should be shut down.");
                    }
                  }
                  else {
                    preventor.info(displayString + " is a ThreadPoolExecutor.Worker of " + executor.getClass().getName() +
                        " but found no reason to shut down ThreadPoolExecutor.");
                  }
                }
              }
              catch (Exception ex) {
                preventor.error(ex);
              }
            }

            if(! threadLoadedByClassLoader && ! runnableLoadedByClassLoader && ! threadGroupLoadedByClassLoader) { // Not loaded in protected ClassLoader - just running there
              // This would for example be the case with org.apache.tomcat.util.threads.TaskThread
              if(waitForThreads) {
                preventor.warn(displayString + "; waiting " + threadWaitMs + 
                    " ms. " + preventor.getStackTrace(thread));
                preventor.waitForThread(thread, threadWaitMs, false /* No interrupt */);
              }

              if(thread.isAlive() && preventor.isClassLoaderOrChild(thread.getContextClassLoader())) { // Still running in ClassLoader
                preventor.warn(displayString + (waitForThreads ? " still" : "") + 
                    " alive; changing context ClassLoader to leak safe (" + 
                    preventor.getLeakSafeClassLoader() + "). " + preventor.getStackTrace(thread));
                thread.setContextClassLoader(preventor.getLeakSafeClassLoader());

                // Replace AccessControlContext since we already replaced ClassLoader,
                // for test/use cease @see StopThreadsClenup_ExecutorTest
                setThreadSafeAccessControlContext(preventor, thread);
              }
            }
            else if(stopThreads) { // Thread/Runnable/ThreadGroup loaded by protected ClassLoader
              if(waitForThreads) {
                preventor.warn("Waiting for " + displayString + " for " + threadWaitMs + " ms. " +
                    preventor.getStackTrace(thread));

                preventor.waitForThread(thread, threadWaitMs, true /* Interrupt if needed */);
              }

              // Normally threads should not be stopped (method is deprecated), since it may cause an inconsistent state.
              // In this case however, the alternative is a classloader leak, which may or may not be considered worse.
              if(thread.isAlive()) {
                preventor.warn("Stopping " + displayString + ". " + preventor.getStackTrace(thread));
                //noinspection deprecation
                thread.stop();
              }
              else {
                preventor.info(displayString + " no longer alive - no action needed.");
              }
            }
            else {
              preventor.warn(displayString + " would cause leak. " + preventor.getStackTrace(thread));
            }
              
          }
        }
      }
    }
  }


  /**
   * Replace Thread AccessControlContext to allow for Protection Domain GC
   */
  private void setThreadSafeAccessControlContext(ClassLoaderLeakPreventor preventor, Thread thread) {
      // Replace AccessControlContext
      final Field inheritedAccessControlContext = preventor.findField(Thread.class, "inheritedAccessControlContext");
      if(inheritedAccessControlContext != null) {
        try {
          final AccessControlContext acc = preventor.createAccessControlContext();
          inheritedAccessControlContext.set(thread, acc);
          preventor.removeDomainCombiner("thread " + thread, acc);
        }
        catch (Exception e) {
          preventor.error(e);
        }
      }
  }

  /** Get {@link Runnable} of given thread, if any */
  private Runnable getRunnable(ClassLoaderLeakPreventor preventor, Thread thread) {
    if(oracleTarget == null && ibmRunnable == null) { // Not yet initialized
      oracleTarget = preventor.findField(Thread.class, "target"); // Sun/Oracle JRE
      ibmRunnable = preventor.findField(Thread.class, "runnable"); // IBM JRE       
    }

    return (oracleTarget != null) ? (Runnable) preventor.getFieldValue(oracleTarget, thread) : // Sun/Oracle JRE  
        (Runnable) preventor.getFieldValue(ibmRunnable, thread);   // IBM JRE
  }

  protected void stopTimerThread(ClassLoaderLeakPreventor preventor, Thread thread) {
    // Seems it is not possible to access Timer of TimerThread, so we need to mimic Timer.cancel()
    /** 
    try {
      Timer timer = (Timer) findField(thread.getClass(), "this$0").get(thread); // This does not work!
      warn("Cancelling Timer " + timer + " / TimeThread '" + thread + "'");
      timer.cancel();
    }
    catch (IllegalAccessException iaex) {
      error(iaex);
    }
    */

    try {
      final Field newTasksMayBeScheduled = preventor.findField(thread.getClass(), "newTasksMayBeScheduled");
      final Object queue = preventor.findField(thread.getClass(), "queue").get(thread); // java.lang.TaskQueue
      final Method clear = preventor.findMethod(queue.getClass(), "clear");
      
      // Do what java.util.Timer.cancel() does
      //noinspection SynchronizationOnLocalVariableOrMethodParameter
      synchronized (queue) {
        newTasksMayBeScheduled.set(thread, Boolean.FALSE);
        clear.invoke(queue);
        queue.notify(); // "In case queue was already empty."
      }
      
      // We shouldn't need to join() here, thread will finish soon enough
    }
    catch (Exception ex) {
      preventor.error(ex);
    }
  }
  
  /** 
   * Inner class with the sole task of killing JURT finalizer thread after it is done processing jobs. 
   * We need to postpone the stopping of this thread, since more Jobs may in theory be add()ed when the protected 
   * ClassLoader is closing down and being garbage collected.
   * See https://issues.apache.org/ooo/show_bug.cgi?id=122517
   */
  protected class JURTKiller extends Thread {

    private final ClassLoaderLeakPreventor preventor;

    private final Thread jurtThread;

    private final List<?> jurtQueue;

    public JURTKiller(ClassLoaderLeakPreventor preventor, Thread jurtThread) {
      super("JURTKiller");
      this.preventor = preventor;
      this.jurtThread = jurtThread;
      jurtQueue = preventor.getStaticFieldValue(StopThreadsCleanUp.JURT_ASYNCHRONOUS_FINALIZER, "queue");
      // Make sure all classes are loaded from the current app classloader before it executes,
      // as it may use them *after* the classloader has been "shutdown" by the container (if any).
      State state = State.RUNNABLE;
    }

    @Override
    public void run() {
        try {
            if(jurtQueue == null || jurtThread == null) {
                preventor.error(getName() + ": No queue or thread!?");
                return;
              }
              if(! jurtThread.isAlive()) {
                preventor.warn(getName() + ": " + jurtThread.getName() + " is already dead?");
              }

              boolean queueIsEmpty = false;
              while(! queueIsEmpty) {
                try {
                  preventor.debug(getName() + " goes to sleep for " + ClassLoaderLeakPreventor.THREAD_WAIT_MS_DEFAULT + " ms");
                  Thread.sleep(ClassLoaderLeakPreventor.THREAD_WAIT_MS_DEFAULT);
                }
                catch (InterruptedException e) {
                  // Do nothing
                }

                if(State.RUNNABLE != jurtThread.getState()) { // Unless thread is currently executing a Job
                  preventor.debug(getName() + " about to force Garbage Collection");
                  ClassLoaderLeakPreventor.gc(); // Force garbage collection, which may put new items on queue

                  synchronized (jurtQueue) {
                    queueIsEmpty = jurtQueue.isEmpty();
                    preventor.debug(getName() + ": JURT queue is empty? " + queueIsEmpty);
                  }
                }
                else
                  preventor.debug(getName() + ": JURT thread " + jurtThread.getName() + " is executing Job");
                }

              preventor.info(getName() + " about to kill " + jurtThread);
              if(jurtThread.isAlive()) {
                //noinspection deprecation
                jurtThread.stop();
              }
        }
        catch (Throwable t) {
            preventor.error(t);
        }
    }
  }
  
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Method;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;
import se.jiderhamn.classloader.leak.prevention.MustBeAfter;

/**
 * Destroy any {@link ThreadGroup}s that are loaded by the protected classloader
 * @author Mattias Jiderhamn
 */
public class ThreadGroupCleanUp implements ClassLoaderPreMortemCleanUp, MustBeAfter {

  @Override
  public Class[] mustBeBeforeMe() {
    return new Class[] {JavaServerFaces2746CleanUp.class};
  }

  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    boolean threadGroupDestroyed = false;
    try {
      ThreadGroup systemThreadGroup = Thread.currentThread().getThreadGroup();
      while(systemThreadGroup.getParent() != null) {
        systemThreadGroup = systemThreadGroup.getParent();
      }
      // systemThreadGroup should now be the topmost ThreadGroup, "system"

      int enumeratedGroups;
      ThreadGroup[] allThreadGroups;
      int noOfGroups = systemThreadGroup.activeGroupCount(); // Estimate no of groups
      do {
        noOfGroups += 10; // Make room for 10 extra
        allThreadGroups = new ThreadGroup[noOfGroups];
        enumeratedGroups = systemThreadGroup.enumerate(allThreadGroups);
      } while(enumeratedGroups >= noOfGroups); // If there was not room for all groups, try again
      
      for(ThreadGroup threadGroup : allThreadGroups) {
        if(preventor.isLoadedInClassLoader(threadGroup) && ! threadGroup.isDestroyed()) {
          preventor.warn("ThreadGroup '" + threadGroup + "' was loaded inside application, needs to be destroyed");
          
          int noOfThreads = threadGroup.activeCount();
          if(noOfThreads > 0) {
            preventor.warn("There seems to be " + noOfThreads + " running in ThreadGroup '" + threadGroup + "'; interrupting");
            try {
              threadGroup.interrupt();
            }
            catch (Exception e) {
              preventor.error(e);
            }
          }

          try {
            threadGroup.destroy();
            threadGroupDestroyed = true;
            preventor.info("ThreadGroup '" + threadGroup + "' successfully destroyed");
          }
          catch (Exception e) {
            preventor.error(e);
          }
        }
      }
    }
    catch (Exception ex) {
      preventor.error(ex);
    }

    try {
      final Object contexts = preventor.getStaticFieldValue("java.beans.ThreadGroupContext", "contexts");
      if(contexts != null) { // Since Java 1.7
        if(threadGroupDestroyed) // At least one ThreadGroup destroyed by this clean up 
          ClassLoaderLeakPreventor.gc(); // Force GC so WeakIdentityMap turns destroyed ThreadGroups into stale entries

        final Method removeStaleEntries = preventor.findMethod("java.beans.WeakIdentityMap", "removeStaleEntries");
        if(removeStaleEntries != null)
          removeStaleEntries.invoke(contexts);
      }
    }
    catch (Throwable t) { // IllegalAccessException, InvocationTargetException 
      preventor.warn(t);
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupContextCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * Clean all {@link java.beans.ThreadGroupContext#beanInfoCache}s in {@link java.beans.ThreadGroupContext#contexts}
 * since they may contain beans/properties loaded in the protected classloader.
 * @author Mattias Jiderhamn
 */
public class ThreadGroupContextCleanUp implements ClassLoaderPreMortemCleanUp {
  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final Object /*WeakIdentityMap<ThreadGroupContext>*/ contexts = preventor.getStaticFieldValue("java.beans.ThreadGroupContext", "contexts");
    if(contexts != null) { // Since Java 1.7
      // final WeakReference/*java.beans.WeakIdentityMap.Entry*/[] table = preventor.getFieldValue(contexts, "table");
      final Field tableField = preventor.findField(preventor.findClass("java.beans.WeakIdentityMap"), "table");
      if(tableField != null) {
        final WeakReference/*java.beans.WeakIdentityMap.Entry*/[] table = preventor.getFieldValue(tableField, contexts);
        if(table != null) {
          Method clearBeanInfoCache = null;
          for(WeakReference entry : table) {
            if(entry != null) {
              Object /*ThreadGroupContext*/ context = preventor.getFieldValue(entry, "value");
              if(context != null) {
                if(clearBeanInfoCache == null) { // FirstThreadGroupContext 
                  clearBeanInfoCache = preventor.findMethod(context.getClass(), "clearBeanInfoCache");
                }

                try {
                  clearBeanInfoCache.invoke(context);
                }
                catch (Exception e) {
                  preventor.error(e);
                }
              }
            }
          }
        }
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.ref.Reference;
import java.lang.reflect.Field;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;
import se.jiderhamn.classloader.leak.prevention.MustBeAfter;

/**
 * Clear {@link ThreadLocal}s for which {@link ThreadLocal#remove()} has not been called, in case either the 
 * {@link ThreadLocal} is a custom one (subclassed in the protected ClassLoader), or the value is loaded by (or is)
 * the protected ClassLoader.
 * This must be done after threads have been stopped, or new ThreadLocals may be added by those threads.
 * @author Mattias Jiderhamn
 */
@SuppressWarnings("WeakerAccess")
public class ThreadLocalCleanUp implements ClassLoaderPreMortemCleanUp, MustBeAfter<ClassLoaderPreMortemCleanUp> {

  /** Class name for per thread transaction in Caucho Resin transaction manager */
  private static final String CAUCHO_TRANSACTION_IMPL = "com.caucho.transaction.TransactionImpl";
  
  protected Field java_lang_Thread_threadLocals;

  protected Field java_lang_Thread_inheritableThreadLocals;

  protected Field java_lang_ThreadLocal$ThreadLocalMap_table;

  protected Field java_lang_ThreadLocal$ThreadLocalMap$Entry_value;

  /** Needs to be done after {@link StopThreadsCleanUp}, since new {@link ThreadLocal}s may be added when threads are 
   * shutting down. */
  @Override
  public Class<? extends ClassLoaderPreMortemCleanUp>[] mustBeBeforeMe() {
    return new Class[] {StopThreadsCleanUp.class};
  }

  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    initFields(preventor); // Initialize some reflection variables
    
    if(java_lang_Thread_threadLocals == null)
      preventor.error("java.lang.Thread.threadLocals not found; something is seriously wrong!");
    
    if(java_lang_Thread_inheritableThreadLocals == null)
      preventor.error("java.lang.Thread.inheritableThreadLocals not found; something is seriously wrong!");

    if(java_lang_ThreadLocal$ThreadLocalMap_table == null)
      preventor.error("java.lang.ThreadLocal$ThreadLocalMap.table not found; something is seriously wrong!");


    for(Thread thread : preventor.getAllThreads()) {
      forEachThreadLocalInThread(preventor, thread);
    }
  }

  /** Make sure fields are initialized */
  private void initFields(ClassLoaderLeakPreventor preventor) {
    if(java_lang_Thread_threadLocals == null) { // First invokation of this preventor
      java_lang_Thread_threadLocals = preventor.findField(Thread.class, "threadLocals");
      java_lang_Thread_inheritableThreadLocals = preventor.findField(Thread.class, "inheritableThreadLocals");
      java_lang_ThreadLocal$ThreadLocalMap_table = preventor.findFieldOfClass("java.lang.ThreadLocal$ThreadLocalMap", "table");
    }
  }

  protected void forEachThreadLocalInThread(ClassLoaderLeakPreventor preventor, Thread thread) {
    try {
      if(java_lang_Thread_threadLocals != null) {
        processThreadLocalMap(preventor, thread, java_lang_Thread_threadLocals.get(thread));
      }

      if(java_lang_Thread_inheritableThreadLocals != null) {
        processThreadLocalMap(preventor, thread, java_lang_Thread_inheritableThreadLocals.get(thread));
      }
    }
    catch (/*IllegalAccess*/Exception ex) {
      preventor.error(ex);
    }
  }

  protected void processThreadLocalMap(ClassLoaderLeakPreventor preventor,
                                       Thread thread, Object threadLocalMap) throws IllegalAccessException {
    if(threadLocalMap != null && java_lang_ThreadLocal$ThreadLocalMap_table != null) {
      Field resin_suspendState = null;
      Field resin_isSuspended = null;
      final Object[] threadLocalMapTable = (Object[]) java_lang_ThreadLocal$ThreadLocalMap_table.get(threadLocalMap); // java.lang.ThreadLocal.ThreadLocalMap.Entry[]
      for(Object entry : threadLocalMapTable) {
        if(entry != null) {
          // Key is kept in WeakReference
          Reference<?> reference = (Reference<?>) entry;
          final ThreadLocal<?> threadLocal = (ThreadLocal<?>) reference.get();

          if(java_lang_ThreadLocal$ThreadLocalMap$Entry_value == null) {
            java_lang_ThreadLocal$ThreadLocalMap$Entry_value = preventor.findField(entry.getClass(), "value");
          }

          // Dereference the value if this is a Reference<T>: all Reference<T> implementations are all loaded using the bootstrap classloader,
          // so checking the Reference<T> classloader won't indicate if the held value was itself loaded using the app classloader 
          // We could have called Reference.clear() directly, which would have fixed the leak even when not allowed to modify the ThreadLocalMap.Entry
          final Object value = dereferenceIfApplicable(java_lang_ThreadLocal$ThreadLocalMap$Entry_value.get(entry));

          // Workaround for http://bugs.caucho.com/view.php?id=5647
          if(value != null && CAUCHO_TRANSACTION_IMPL.equals(value.getClass().getName())) { // Resin transaction
            if(resin_suspendState == null && resin_isSuspended == null) { // First thread with Resin transaction, look up fields
              resin_suspendState = preventor.findField(value.getClass(), "_suspendState");
              resin_isSuspended = preventor.findField(value.getClass(), "_isSuspended");
            }

            if(resin_suspendState != null && resin_isSuspended != null) { // Both fields exist (as per version 4.0.37)
              if(preventor.getFieldValue(resin_suspendState, value) != null) { // There is a suspended state that may cause leaks
                // In theory a new transaction can be started and suspended between where we read and write the state,
                // and flag, therefore we suspend the thread meanwhile.
                try {
                  //noinspection deprecation
                  thread.suspend(); // Suspend the thread
                  if(preventor.getFieldValue(resin_suspendState, value) != null) { // Re-read suspend state when thread is suspended
                    final Object isSuspended = preventor.getFieldValue(resin_isSuspended, value);
                    if(!(isSuspended instanceof Boolean)) {
                      preventor.error(thread.toString() + " has " + CAUCHO_TRANSACTION_IMPL + " but _isSuspended is not boolean: " + isSuspended);
                    }
                    else if((Boolean) isSuspended) { // Is currently suspended - suspend state is correct
                      preventor.debug(thread.toString() + " has " + CAUCHO_TRANSACTION_IMPL + " that is suspended");
                    }
                    else { // Is not suspended, and thus should not have suspend state
                      resin_suspendState.set(value, null);
                      preventor.error(thread.toString() + " had " + CAUCHO_TRANSACTION_IMPL + " with unused _suspendState that was removed");
                    }
                  }
                }
                catch (Throwable t) { // Such as SecurityException
                  preventor.error(t);
                }
                finally {
                  //noinspection deprecation
                  thread.resume();
                }
              }
            }
          }
          
          final boolean customThreadLocal = preventor.isLoadedInClassLoader(threadLocal); // This is not an actual problem
          final boolean valueLoadedInWebApp = preventor.isLoadedInClassLoader(value);
          if(customThreadLocal || valueLoadedInWebApp ||
              (value instanceof ClassLoader && preventor.isClassLoaderOrChild((ClassLoader) value))) { // The value is classloader (child) itself
            // This ThreadLocal is either itself loaded by the web app classloader, or it's value is
            // Let's do something about it

            StringBuilder message = new StringBuilder();
            if(threadLocal != null) {
              if(customThreadLocal) {
                message.append("Custom ");
              }
              message.append("ThreadLocal of type ").append(threadLocal.getClass().getName()).append(": ").append(threadLocal);
            }
            else {
              message.append("Unknown ThreadLocal");
            }
            message.append(" with value ").append(value);
            if(value != null) {
              message.append(" of type ").append(value.getClass().getName());
              if(valueLoadedInWebApp)
                message.append(" that is loaded by web app");
            }


            // Process the detected potential leak
            processLeak(preventor, thread, reference, threadLocal, value, message.toString());
          }
        }
      }
    }
  }
  
  protected Object dereferenceIfApplicable(Object value) {
      return value instanceof Reference ? dereferenceIfApplicable(((Reference<?>) value).get()) : value; 
  }

  /**
   * After having detected potential ThreadLocal leak, this method is called.
   * Default implementation tries to clear the entry to avoid a leak.
   */
  protected void processLeak(ClassLoaderLeakPreventor preventor, Thread thread, Reference<?> entry,
                             ThreadLocal<?> threadLocal, Object value, String message) {
    if(threadLocal != null && thread == Thread.currentThread()) { // If running for current thread and we have the ThreadLocal ...
      // ... remove properly
      preventor.info(message + " will be remove()d from " + thread);
      threadLocal.remove();
    }
    else { // We cannot remove entry properly, so just make it stale
      preventor.info(message + " will be made stale for later expunging from " + thread);
    }

    // It seems like remove() doesn't really do the job, so play it safe and remove references from entry either way
    // (Example problem org.infinispan.context.SingleKeyNonTxInvocationContext) 
    entry.clear(); // Clear the key

    if(java_lang_ThreadLocal$ThreadLocalMap$Entry_value == null) {
      java_lang_ThreadLocal$ThreadLocalMap$Entry_value = preventor.findField(entry.getClass(), "value");
    }

    try {
      java_lang_ThreadLocal$ThreadLocalMap$Entry_value.set(entry, null); // Clear value to avoid circular references
    }
    catch (IllegalAccessException iaex) {
      preventor.error(iaex);
    }
  }
}


================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/WarningThreadLocalCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.ref.Reference;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * {@link ClassLoaderPreMortemCleanUp} that does not clear {@link ThreadLocal}s to remove the leak, but only logs a 
 * warning
 * @author Mattias Jiderhamn
 */
@SuppressWarnings("unused")
public class WarningThreadLocalCleanUp extends ThreadLocalCleanUp {

  /**
   * Log not {@link ThreadLocal#remove()}ed leak as a warning. 
   */
  protected void processLeak(ClassLoaderLeakPreventor preventor, Thread thread, Reference<?> entry, 
                             ThreadLocal<?> threadLocal, Object value, String message) {
    preventor.warn(message);
  } 
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/X509TrustManagerImplUnparseableExtensionCleanUp.java
================================================
package se.jiderhamn.classloader.leak.prevention.cleanup;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.cert.X509Certificate;
import java.util.Map;
import javax.net.ssl.SSLContextSpi;
import javax.net.ssl.X509TrustManager;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;

/**
 * {@link sun.security.ssl.X509TrustManagerImpl} keeps a list set of trusted certs, which may include 
 * {@link sun.security.x509.UnparseableExtension} that in turn may include an {@link Exception} with a backtrace
 * with references to the classloader that we want to protect 
 * @author Mattias Jiderhamn
 */
public class X509TrustManagerImplUnparseableExtensionCleanUp implements ClassLoaderPreMortemCleanUp {

  private static final String SUN_SECURITY_X509_X509_CERT_IMPL = "sun.security.x509.X509CertImpl";

  @Override
  public void cleanUp(ClassLoaderLeakPreventor preventor) {
    final SSLContextSpi sslContext = preventor.getStaticFieldValue("sun.security.ssl.SSLContextImpl$DefaultSSLContext", "defaultImpl");
    if(sslContext != null) {
      final Field trustManagerField = preventor.findFieldOfClass("sun.security.ssl.SSLContextImpl", "trustManager");
      final Method get = preventor.findMethod(SUN_SECURITY_X509_X509_CERT_IMPL, "get", String.class);
      final Method getUnparseableExtensions = preventor.findMethod("sun.security.x509.CertificateExtensions", "getUnparseableExtensions");
      final Field why = preventor.findFieldOfClass("sun.security.x509.UnparseableExtension", "why");

      if(trustManagerField != null && get != null && getUnparseableExtensions != null && why != null) {
        final X509TrustManager/*Impl*/ trustManager = preventor.getFieldValue(trustManagerField, sslContext);
        for(X509Certificate x509Certificate : trustManager.getAcceptedIssuers()) {
          if(SUN_SECURITY_X509_X509_CERT_IMPL.equals(x509Certificate.getClass().getName())) {
            try {
              final /* sun.security.x509.CertificateExtensions*/ Object extensions = get.invoke(x509Certificate, "x509.info.extensions");
              if(extensions != null) {
                Map/*<String, sun.security.x509.Extension>*/ unparseableExtensions = (Map) getUnparseableExtensions.invoke(extensions);
                for(Object unparseableExtension : unparseableExtensions.values()) {
                  if(why.get(unparseableExtension) != null) {
                    preventor.warn(trustManager + " cached X509Certificate that had unparseable extension; removing 'why': " +
                        x509Certificate);
                    why.set(unparseableExtension, null);
                  }
                }
              }
            }
            catch (Exception e) {
              preventor.error(e);
            }
          }
        }
      }
    }
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/AwtToolkitInitiator.java
================================================
package se.jiderhamn.classloader.leak.prevention.preinit;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;

/**
 * The first call to java.awt.Toolkit.getDefaultToolkit() will spawn a new thread with the
 * same contextClassLoader as the caller.
 * 
 * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/
 * @author Mattias Jiderhamn
 */
public class AwtToolkitInitiator implements PreClassLoaderInitiator {
  @Override
  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {
    try {
      java.awt.Toolkit.getDefaultToolkit(); // Will start a Thread
    }
    catch (Throwable t) {
      preventor.error(t);
      preventor.warn("Consider adding -Djava.awt.headless=true to your JVM parameters");
    }
    
  }
}

================================================
FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/DatatypeConverterImplInitiator.java
================================================
package se.jiderhamn.classloader.leak.prevention.preinit;

import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;
import se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;

/**
 * {@link javax.xml.bind.DatatypeConverterImpl} in the JAXB Reference Implementation shipped with JDK 1.6+ will
 * keep a static reference ({@link javax.xml.bind.DatatypeConverterImpl#datatypeFactory}) to a concrete subclass of 
 * {@link javax.xml.datatype.DatatypeFactory}, that is resolved when the class is loaded (which I believe happens if you
 * have custom bindings that reference the static methods in {@link javax.xml.bind.DatatypeConverter}). It seems that if 
 * for example you have a version of Xerces inside your application, the factory method may resolve {@code 
 * org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl} as the implementation to use (rather than
 * {@code com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl} shipped with the JDK), which
 * means there will a reference from {@link javax.xml.bind.DatatypeConverterImpl} to your classloader.
 * 
 * See http://java.jiderhamn.se/2012/02/26/classloader
Download .txt
gitextract_ovazmkyr/

├── .gitignore
├── .mvn/
│   └── wrapper/
│       ├── MavenWrapperDownloader.java
│       └── maven-wrapper.properties
├── .travis.yml
├── LICENSE.txt
├── README.md
├── classloader-leak-prevention/
│   ├── classloader-leak-prevention-core/
│   │   ├── README.md
│   │   ├── pom.xml
│   │   └── src/
│   │       ├── main/
│   │       │   └── java/
│   │       │       └── se/
│   │       │           └── jiderhamn/
│   │       │               └── classloader/
│   │       │                   └── leak/
│   │       │                       └── prevention/
│   │       │                           ├── ClassLoaderLeakPreventor.java
│   │       │                           ├── ClassLoaderLeakPreventorFactory.java
│   │       │                           ├── ClassLoaderPreMortemCleanUp.java
│   │       │                           ├── JULLogger.java
│   │       │                           ├── Logger.java
│   │       │                           ├── MustBeAfter.java
│   │       │                           ├── PreClassLoaderInitiator.java
│   │       │                           ├── ReplaceDOMNormalizerSerializerAbortException.java
│   │       │                           ├── StdLogger.java
│   │       │                           ├── cleanup/
│   │       │                           │   ├── ApacheCommonsLoggingCleanUp.java
│   │       │                           │   ├── BeanELResolverCleanUp.java
│   │       │                           │   ├── BeanIntrospectorCleanUp.java
│   │       │                           │   ├── BeanValidationCleanUp.java
│   │       │                           │   ├── DefaultAuthenticatorCleanUp.java
│   │       │                           │   ├── DriverManagerCleanUp.java
│   │       │                           │   ├── GeoToolsCleanUp.java
│   │       │                           │   ├── IIOServiceProviderCleanUp.java
│   │       │                           │   ├── IntrospectionUtilsCleanUp.java
│   │       │                           │   ├── JDK8151486CleanUp.java
│   │       │                           │   ├── JacksonCleanUp.java
│   │       │                           │   ├── JavaServerFaces2746CleanUp.java
│   │       │                           │   ├── JavaUtilLoggingLevelCleanUp.java
│   │       │                           │   ├── JavaxSecurityAuthLoginConfigurationCleanUp.java
│   │       │                           │   ├── JceSecurityCleanUp.java
│   │       │                           │   ├── KeepAliveTimerCacheCleanUp.java
│   │       │                           │   ├── MBeanCleanUp.java
│   │       │                           │   ├── MXBeanNotificationListenersCleanUp.java
│   │       │                           │   ├── MoxyCleanUp.java
│   │       │                           │   ├── MultiThreadedHttpConnectionManagerCleanUp.java
│   │       │                           │   ├── ObjectStreamClassCleanup.java
│   │       │                           │   ├── PropertyEditorCleanUp.java
│   │       │                           │   ├── ProxySelectorCleanUp.java
│   │       │                           │   ├── ReactorNettyHttpResourcesCleanUp.java
│   │       │                           │   ├── ResourceBundleCleanUp.java
│   │       │                           │   ├── RmiTargetsCleanUp.java
│   │       │                           │   ├── SAAJEnvelopeFactoryParserPoolCleanUp.java
│   │       │                           │   ├── SecurityProviderCleanUp.java
│   │       │                           │   ├── ShutdownHookCleanUp.java
│   │       │                           │   ├── StopThreadsCleanUp.java
│   │       │                           │   ├── ThreadGroupCleanUp.java
│   │       │                           │   ├── ThreadGroupContextCleanUp.java
│   │       │                           │   ├── ThreadLocalCleanUp.java
│   │       │                           │   ├── WarningThreadLocalCleanUp.java
│   │       │                           │   └── X509TrustManagerImplUnparseableExtensionCleanUp.java
│   │       │                           └── preinit/
│   │       │                               ├── AwtToolkitInitiator.java
│   │       │                               ├── DatatypeConverterImplInitiator.java
│   │       │                               ├── DocumentBuilderFactoryInitiator.java
│   │       │                               ├── JarUrlConnectionInitiator.java
│   │       │                               ├── Java2dDisposerInitiator.java
│   │       │                               ├── Java2dRenderQueueInitiator.java
│   │       │                               ├── JavaxSecurityLoginConfigurationInitiator.java
│   │       │                               ├── JdbcDriversInitiator.java
│   │       │                               ├── LdapPoolManagerInitiator.java
│   │       │                               ├── OracleJdbcThreadInitiator.java
│   │       │                               ├── SecurityPolicyInitiator.java
│   │       │                               ├── SecurityProvidersInitiator.java
│   │       │                               ├── SunAwtAppContextInitiator.java
│   │       │                               └── SunGCInitiator.java
│   │       └── test/
│   │           ├── java/
│   │           │   └── se/
│   │           │       └── jiderhamn/
│   │           │           └── classloader/
│   │           │               └── leak/
│   │           │                   └── prevention/
│   │           │                       ├── ClassLoaderLeakPreventorFactoryTest.java
│   │           │                       ├── PreventionsTestBase.java
│   │           │                       ├── StopThreadsCleanUp_TimerTest.java
│   │           │                       ├── cleanup/
│   │           │                       │   ├── BeanELResolverCleanUpTest.java
│   │           │                       │   ├── BeanIntrospectorCleanUpTest.java
│   │           │                       │   ├── BeanValidationCleanUpTest.java
│   │           │                       │   ├── ClassLoaderPreMortemCleanUpTestBase.java
│   │           │                       │   ├── DefaultAuthenticatorCleanUpTest.java
│   │           │                       │   ├── DriverManagerCleanUpTest.java
│   │           │                       │   ├── GeoToolsCleanUpTest.java
│   │           │                       │   ├── IIOServiceProviderCleanUpTest.java
│   │           │                       │   ├── ImageIOMockImageInputStreamSPI.java
│   │           │                       │   ├── JDK8151486CleanUpTest.java
│   │           │                       │   ├── JacksonCleanUpTest.java
│   │           │                       │   ├── JavaServerFaces2746CleanUpTest.java
│   │           │                       │   ├── JavaUtilLoggingLevelCleanUpTest.java
│   │           │                       │   ├── JavaxSecurityAuthLoginConfigurationCleanUpTest.java
│   │           │                       │   ├── JceSecurityCleanUpTest.java
│   │           │                       │   ├── MBeanCleanUpTest.java
│   │           │                       │   ├── MXBeanNotificationListenersCleanUpTest.java
│   │           │                       │   ├── MXBeanNotificationListenersCleanUp_ListenerWrapperTest.java
│   │           │                       │   ├── MoxyCleanUpTest.java
│   │           │                       │   ├── MultiThreadedHttpConnectionManagerCleanUpTest.java
│   │           │                       │   ├── ObjectStreamClassCleanupTest.java
│   │           │                       │   ├── PropertyEditorCleanUpTest.java
│   │           │                       │   ├── ProxySelectorCleanUpTest.java
│   │           │                       │   ├── ReplaceDOMNormalizerSerializerAbortExceptionCleanUpTest.java
│   │           │                       │   ├── SAAJEnvelopeFactoryParserPoolCleanUpTest.java
│   │           │                       │   ├── SecurityProviderCleanUpTest.java
│   │           │                       │   ├── ShutdownHookCleanUpTest.java
│   │           │                       │   ├── StopThreadsCleanUp_MultiThreadedHttpConnectionManagerTest.java
│   │           │                       │   ├── StopThreadsCleanUp_PostgresqlJdbcTest.java
│   │           │                       │   ├── StopThreadsCleanUp_Runnable.java
│   │           │                       │   ├── StopThreadsClenup_ExecutorTest.java
│   │           │                       │   ├── ThreadGroupCleanUpTest.java
│   │           │                       │   ├── ThreadLocalCleanUpTest.java
│   │           │                       │   ├── ThreadLocalWithNestedRefValueCleanUpTest.java
│   │           │                       │   ├── ThreadLocalWithRefValueCleanUpTest.java
│   │           │                       │   ├── X509TrustManagerImplUnparseableExtensionCleanUpTest.java
│   │           │                       │   └── package-info.java
│   │           │                       ├── package-info.java
│   │           │                       └── preinit/
│   │           │                           ├── AwtToolkitInitiatorTest.java
│   │           │                           ├── DatatypeConverterImplInitiatorTest.java
│   │           │                           ├── DocumentBuilderFactoryInitiatorTest.java
│   │           │                           ├── Java2dDisposerInitiatorTest.java
│   │           │                           ├── Java2dRenderQueueInitiatorTest.java
│   │           │                           ├── JavaxSecurityLoginConfigurationInitiatorTest.java
│   │           │                           ├── JdbcDriversInitiatorTest.java
│   │           │                           ├── LdapPoolManagerInitiatorTest.java
│   │           │                           ├── OracleJdbcThreadInitiatorTest.java
│   │           │                           ├── PreClassLoaderInitiatorTestBase.java
│   │           │                           ├── ReplaceDOMNormalizerSerializerAbortExceptionInitiatorTest.java
│   │           │                           ├── SecurityPolicyInitiatorTest.java
│   │           │                           ├── SecurityProvidersInitiatorTest.java
│   │           │                           ├── SunAwtAppContextInitiatorTest.java
│   │           │                           └── SunGCInitiatorTest.java
│   │           └── resources/
│   │               ├── META-INF/
│   │               │   └── services/
│   │               │       └── javax.imageio.spi.ImageInputStreamSpi
│   │               ├── spi-cacert-2008.crt
│   │               └── spi-cacert-2008.keystore
│   ├── classloader-leak-prevention-servlet/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           └── java/
│   │               └── se/
│   │                   └── jiderhamn/
│   │                       └── classloader/
│   │                           └── leak/
│   │                               └── prevention/
│   │                                   └── ClassLoaderLeakPreventorListener.java
│   ├── classloader-leak-prevention-servlet3/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── se/
│   │           │       └── jiderhamn/
│   │           │           └── classloader/
│   │           │               └── leak/
│   │           │                   └── prevention/
│   │           │                       └── ClassLoaderLeakPreventionContainerInitializer.java
│   │           └── resources/
│   │               └── META-INF/
│   │                   ├── services/
│   │                   │   └── javax.servlet.ServletContainerInitializer
│   │                   └── web-fragment.xml
│   └── pom.xml
├── classloader-leak-test-framework/
│   ├── README.md
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── se/
│       │           └── jiderhamn/
│       │               ├── HeapDumper.java
│       │               └── classloader/
│       │                   ├── PackagesLoadedOutsideClassLoader.java
│       │                   ├── RedefiningClassLoader.java
│       │                   ├── ZombieMarker.java
│       │                   └── leak/
│       │                       ├── JUnitClassloaderRunner.java
│       │                       ├── LeakPreventor.java
│       │                       └── Leaks.java
│       └── test/
│           └── java/
│               ├── com/
│               │   └── classloader/
│               │       └── test/
│               │           └── CustomClass.java
│               └── se/
│                   └── jiderhamn/
│                       └── classloader/
│                           ├── RedefiningClassLoaderTest.java
│                           └── leak/
│                               ├── JUnitClassloaderRunnerTest.java
│                               ├── NonLeakingTest.java
│                               ├── accused/
│                               │   ├── CustomThreadLocalTest.java
│                               │   └── package-info.java
│                               └── known/
│                                   ├── CustomThreadLocalCustomValueTest.java
│                                   ├── JEditorPaneTest.java
│                                   └── package-info.java
├── mvnw
├── mvnw.cmd
└── pom.xml
Download .txt
SYMBOL INDEX (488 symbols across 126 files)

FILE: .mvn/wrapper/MavenWrapperDownloader.java
  class MavenWrapperDownloader (line 33) | public final class MavenWrapperDownloader
    method main (line 62) | public static void main( String[] args )
    method downloadFileFromURL (line 102) | private static void downloadFileFromURL( String urlString, Path destin...
    method createDirectories (line 125) | private static void createDirectories(Path outputPath) throws IOException
    method readWrapperUrl (line 133) | private static String readWrapperUrl( Path mavenWrapperPropertyFile )
    method log (line 154) | private static void log( String msg )

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventor.java
  class ClassLoaderLeakPreventor (line 19) | @SuppressWarnings("WeakerAccess")
    method ClassLoaderLeakPreventor (line 60) | public ClassLoaderLeakPreventor(ClassLoader leakSafeClassLoader, Class...
    method runPreClassLoaderInitiators (line 90) | public void runPreClassLoaderInitiators() {
    method doInLeakSafeClassLoader (line 111) | protected void doInLeakSafeClassLoader(final Runnable runnable) {
    method createAccessControlContext (line 139) | public AccessControlContext createAccessControlContext() {
    method createDomainCombiner (line 158) | private DomainCombiner createDomainCombiner() {
    method removeDomainCombiner (line 197) | @Deprecated
    method removeDomainCombiner (line 206) | public void removeDomainCombiner(String owner, AccessControlContext ac...
    method runCleanUps (line 230) | public void runCleanUps() {
    method getClassLoader (line 254) | public ClassLoader getClassLoader() {
    method getLeakSafeClassLoader (line 263) | public ClassLoader getLeakSafeClassLoader() {
    method isLoadedInClassLoader (line 268) | public boolean isLoadedInClassLoader(Object o) {
    method isLoadedByClassLoader (line 274) | public boolean isLoadedByClassLoader(Class<?> clazz) {
    method isClassLoaderOrChild (line 279) | public boolean isClassLoaderOrChild(ClassLoader cl) {
    method isThreadInClassLoader (line 325) | public boolean isThreadInClassLoader(Thread thread) {
    method waitForThread (line 338) | public void waitForThread(Thread thread, long waitMs, boolean interrup...
    method getStackTrace (line 359) | public String getStackTrace(Thread thread) {
    method getStaticFieldValue (line 380) | public <E> E getStaticFieldValue(Class<?> clazz, String fieldName) {
    method getStaticFieldValue (line 385) | public <E> E getStaticFieldValue(String className, String fieldName) {
    method getStaticFieldValue (line 389) | public <E> E getStaticFieldValue(String className, String fieldName, b...
    method findFieldOfClass (line 394) | public Field findFieldOfClass(String className, String fieldName) {
    method findFieldOfClass (line 398) | public Field findFieldOfClass(String className, String fieldName, bool...
    method findClass (line 407) | public Class<?> findClass(String className) {
    method findClass (line 411) | public Class<?> findClass(String className, boolean trySystemCL) {
    method findField (line 437) | public Field findField(Class<?> clazz, String fieldName) {
    method getStaticFieldValue (line 456) | public <T> T getStaticFieldValue(Field field) {
    method getFieldValue (line 472) | public <T> T getFieldValue(Object obj, String fieldName) {
    method getFieldValue (line 477) | public <T> T getFieldValue(Field field, Object obj) {
    method setFinalStaticField (line 488) | public void setFinalStaticField(Field field, Object newValue) {
    method findMethod (line 514) | public Method findMethod(String className, String methodName, Class......
    method findMethod (line 523) | public Method findMethod(Class<?> clazz, String methodName, Class... p...
    method getAllThreads (line 541) | public Collection<Thread> getAllThreads() {
    method isJBoss (line 574) | public boolean isJBoss() {
    method isOracleJRE (line 591) | public boolean isOracleJRE() {
    method gc (line 601) | public static void gc() {
    method isDisableExplicitGCEnabled (line 622) | private static boolean isDisableExplicitGCEnabled() {
    method isJvmShuttingDown (line 630) | public boolean isJvmShuttingDown() {
    class NestedProtectionDomainCombinerException (line 648) | private static class NestedProtectionDomainCombinerException extends R...
    method debug (line 656) | public void debug(String msg) {
    method warn (line 660) | public void warn(Throwable t) {
    method error (line 664) | public void error(Throwable t) {
    method warn (line 668) | public void warn(String msg) {
    method error (line 672) | public void error(String msg) {
    method info (line 676) | public void info(String msg) {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorFactory.java
  class ClassLoaderLeakPreventorFactory (line 18) | public class ClassLoaderLeakPreventorFactory {
    method ClassLoaderLeakPreventorFactory (line 54) | public ClassLoaderLeakPreventorFactory() {
    method ClassLoaderLeakPreventorFactory (line 62) | public ClassLoaderLeakPreventorFactory(ClassLoader leakSafeClassLoader) {
    method configureDefaults (line 68) | public void configureDefaults() {
    method newLeakPreventor (line 145) | public ClassLoaderLeakPreventor newLeakPreventor() {
    method newLeakPreventor (line 150) | public ClassLoaderLeakPreventor newLeakPreventor(ClassLoader classLoad...
    method setLogger (line 160) | public void setLogger(Logger logger) {
    method addPreInitiator (line 165) | public void addPreInitiator(PreClassLoaderInitiator preClassLoaderInit...
    method addCleanUp (line 170) | public void addCleanUp(ClassLoaderPreMortemCleanUp classLoaderPreMorte...
    method addConsideringOrder (line 175) | private <I> void addConsideringOrder(Map<String, I> map, I newEntry) {
    method addCleanUp (line 193) | public void addCleanUp(String name, ClassLoaderPreMortemCleanUp classL...
    method clearPreInitiators (line 198) | public void clearPreInitiators() {
    method clearCleanUps (line 203) | public void clearCleanUps() {
    method getPreInitiator (line 213) | public <C extends PreClassLoaderInitiator> C getPreInitiator(Class<C> ...
    method getCleanUp (line 223) | public <C extends ClassLoaderPreMortemCleanUp> C getCleanUp(Class<C> c...
    method removePreInitiator (line 228) | public <C extends PreClassLoaderInitiator> void removePreInitiator(Cla...
    method removeCleanUp (line 233) | public <C extends ClassLoaderPreMortemCleanUp> void removeCleanUp(Clas...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderPreMortemCleanUp.java
  type ClassLoaderPreMortemCleanUp (line 8) | public interface ClassLoaderPreMortemCleanUp {
    method cleanUp (line 14) | void cleanUp(ClassLoaderLeakPreventor preventor);

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/JULLogger.java
  class JULLogger (line 10) | public class JULLogger implements Logger {
    method debug (line 15) | @Override
    method info (line 20) | @Override
    method warn (line 25) | @Override
    method warn (line 30) | @Override
    method error (line 35) | @Override
    method error (line 40) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/Logger.java
  type Logger (line 13) | public interface Logger {
    method debug (line 16) | void debug(String msg);
    method info (line 19) | void info(String msg);
    method warn (line 22) | void warn(String msg);
    method warn (line 25) | void warn(Throwable t);
    method error (line 28) | void error(String msg);
    method error (line 31) | void error(Throwable t);

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/MustBeAfter.java
  type MustBeAfter (line 13) | public interface MustBeAfter<I> {
    method mustBeBeforeMe (line 19) | Class<? extends I>[] mustBeBeforeMe();

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/PreClassLoaderInitiator.java
  type PreClassLoaderInitiator (line 8) | public interface PreClassLoaderInitiator {
    method doOutsideClassLoader (line 16) | void doOutsideClassLoader(ClassLoaderLeakPreventor preventor);

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ReplaceDOMNormalizerSerializerAbortException.java
  class ReplaceDOMNormalizerSerializerAbortException (line 24) | public class ReplaceDOMNormalizerSerializerAbortException implements Pre...
    method doOutsideClassLoader (line 26) | @Override
    method cleanUp (line 31) | @Override
    method replaceDOMNormalizerSerializerAbortException (line 36) | @SuppressWarnings("WeakerAccess")
    method constructRuntimeExceptionWithoutStackTrace (line 51) | @SuppressWarnings("WeakerAccess")

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/StdLogger.java
  class StdLogger (line 10) | public class StdLogger implements Logger {
    method getLogPrefix (line 13) | protected String getLogPrefix() {
    method debug (line 17) | @Override
    method info (line 22) | @Override
    method warn (line 27) | @Override
    method warn (line 32) | @Override
    method error (line 37) | @Override
    method error (line 42) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ApacheCommonsLoggingCleanUp.java
  class ApacheCommonsLoggingCleanUp (line 16) | public class ApacheCommonsLoggingCleanUp implements ClassLoaderPreMortem...
    method cleanUp (line 17) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanELResolverCleanUp.java
  class BeanELResolverCleanUp (line 14) | public class BeanELResolverCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 15) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanIntrospectorCleanUp.java
  class BeanIntrospectorCleanUp (line 13) | public class BeanIntrospectorCleanUp implements ClassLoaderPreMortemClea...
    method cleanUp (line 14) | @Override
    method clearClassInfoCache (line 28) | private void clearClassInfoCache(ClassLoaderLeakPreventor preventor) {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanValidationCleanUp.java
  class BeanValidationCleanUp (line 13) | public class BeanValidationCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 14) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/DefaultAuthenticatorCleanUp.java
  class DefaultAuthenticatorCleanUp (line 17) | public class DefaultAuthenticatorCleanUp implements ClassLoaderPreMortem...
    method cleanUp (line 18) | @Override
    method getDefaultAuthenticator (line 70) | @SuppressWarnings("WeakerAccess")
    method removeWrappedAuthenticators (line 90) | @SuppressWarnings("WeakerAccess")

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/DriverManagerCleanUp.java
  class DriverManagerCleanUp (line 17) | public class DriverManagerCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 18) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/GeoToolsCleanUp.java
  class GeoToolsCleanUp (line 12) | public class GeoToolsCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 13) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/IIOServiceProviderCleanUp.java
  class IIOServiceProviderCleanUp (line 18) | public class IIOServiceProviderCleanUp implements ClassLoaderPreMortemCl...
    method cleanUp (line 19) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/IntrospectionUtilsCleanUp.java
  class IntrospectionUtilsCleanUp (line 10) | public class IntrospectionUtilsCleanUp implements ClassLoaderPreMortemCl...
    method cleanUp (line 11) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JDK8151486CleanUp.java
  class JDK8151486CleanUp (line 14) | public class JDK8151486CleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 15) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JacksonCleanUp.java
  class JacksonCleanUp (line 13) | public class JacksonCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 14) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaServerFaces2746CleanUp.java
  class JavaServerFaces2746CleanUp (line 15) | public class JavaServerFaces2746CleanUp implements ClassLoaderPreMortemC...
    method cleanUp (line 16) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaUtilLoggingLevelCleanUp.java
  class JavaUtilLoggingLevelCleanUp (line 14) | public class JavaUtilLoggingLevelCleanUp implements ClassLoaderPreMortem...
    method cleanUp (line 15) | @Override
    method process (line 44) | private Set/*<KnownLevel>*/ process(ClassLoaderLeakPreventor preventor...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaxSecurityAuthLoginConfigurationCleanUp.java
  class JavaxSecurityAuthLoginConfigurationCleanUp (line 12) | public class JavaxSecurityAuthLoginConfigurationCleanUp implements Class...
    method cleanUp (line 14) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JceSecurityCleanUp.java
  class JceSecurityCleanUp (line 14) | public class JceSecurityCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 16) | @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/KeepAliveTimerCacheCleanUp.java
  class KeepAliveTimerCacheCleanUp (line 12) | public class KeepAliveTimerCacheCleanUp implements ClassLoaderPreMortemC...
    method mustBeBeforeMe (line 15) | @Override
    method cleanUp (line 20) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MBeanCleanUp.java
  class MBeanCleanUp (line 20) | public class MBeanCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 21) | @Override
    method isJettyWithJMX (line 71) | @SuppressWarnings("WeakerAccess")
    class JettyJMXRemover (line 98) | private class JettyJMXRemover {
      method JettyJMXRemover (line 114) | @SuppressWarnings("WeakerAccess")
      method unregisterJettyJMXBean (line 187) | boolean unregisterJettyJMXBean(ObjectName objectName) {
      method findJettyClass (line 213) | Class findJettyClass(String className) throws ClassNotFoundException {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUp.java
  class MXBeanNotificationListenersCleanUp (line 21) | public class MXBeanNotificationListenersCleanUp implements ClassLoaderPr...
    method cleanUp (line 22) | @Override
    method unregisterNotificationListeners (line 83) | protected void unregisterNotificationListeners(ClassLoaderLeakPrevento...
    method unwrap (line 120) | private NotificationListener unwrap(ClassLoaderLeakPreventor preventor...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MoxyCleanUp.java
  class MoxyCleanUp (line 16) | public class MoxyCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 17) | @Override
    method findClass (line 36) | public Class<?> findClass(ClassLoaderLeakPreventor preventor, String c...
    method unsetField (line 50) | private void unsetField(ClassLoaderLeakPreventor preventor,

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MultiThreadedHttpConnectionManagerCleanUp.java
  class MultiThreadedHttpConnectionManagerCleanUp (line 11) | public class MultiThreadedHttpConnectionManagerCleanUp implements ClassL...
    method cleanUp (line 13) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ObjectStreamClassCleanup.java
  class ObjectStreamClassCleanup (line 11) | public class ObjectStreamClassCleanup implements ClassLoaderPreMortemCle...
    method cleanUp (line 13) | @Override
    method clearIfConcurrentHashMap (line 30) | protected void clearIfConcurrentHashMap(Object object, ClassLoaderLeak...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/PropertyEditorCleanUp.java
  class PropertyEditorCleanUp (line 17) | public class PropertyEditorCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 18) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ProxySelectorCleanUp.java
  class ProxySelectorCleanUp (line 14) | public class ProxySelectorCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 15) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ReactorNettyHttpResourcesCleanUp.java
  class ReactorNettyHttpResourcesCleanUp (line 13) | public class ReactorNettyHttpResourcesCleanUp implements ClassLoaderPreM...
    method cleanUp (line 14) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ResourceBundleCleanUp.java
  class ResourceBundleCleanUp (line 17) | public class ResourceBundleCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 18) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/RmiTargetsCleanUp.java
  class RmiTargetsCleanUp (line 14) | public class RmiTargetsCleanUp implements ClassLoaderPreMortemCleanUp {
    method cleanUp (line 15) | @Override
    method clearRmiTargetsMap (line 30) | @SuppressWarnings("WeakerAccess")

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/SAAJEnvelopeFactoryParserPoolCleanUp.java
  class SAAJEnvelopeFactoryParserPoolCleanUp (line 15) | public class SAAJEnvelopeFactoryParserPoolCleanUp implements ClassLoader...
    method cleanUp (line 16) | @Override
    method cleanupWithFactoryClass (line 24) | private void cleanupWithFactoryClass(final ClassLoaderLeakPreventor pr...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/SecurityProviderCleanUp.java
  class SecurityProviderCleanUp (line 13) | public class SecurityProviderCleanUp implements ClassLoaderPreMortemClea...
    method cleanUp (line 14) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ShutdownHookCleanUp.java
  class ShutdownHookCleanUp (line 13) | public class ShutdownHookCleanUp implements ClassLoaderPreMortemCleanUp {
    method ShutdownHookCleanUp (line 30) | @SuppressWarnings("unused")
    method ShutdownHookCleanUp (line 35) | public ShutdownHookCleanUp(boolean executeShutdownHooks, int shutdownH...
    method setExecuteShutdownHooks (line 40) | public void setExecuteShutdownHooks(boolean executeShutdownHooks) {
    method setShutdownHookWaitMs (line 44) | public void setShutdownHookWaitMs(int shutdownHookWaitMs) {
    method cleanUp (line 48) | @Override
    method removeShutdownHook (line 65) | @SuppressWarnings({"deprecation", "WeakerAccess"})

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp.java
  class StopThreadsCleanUp (line 19) | @SuppressWarnings("WeakerAccess")
    method StopThreadsCleanUp (line 41) | @SuppressWarnings("unused")
    method StopThreadsCleanUp (line 46) | public StopThreadsCleanUp(boolean stopThreads, boolean stopTimerThread...
    method setStopThreads (line 51) | public void setStopThreads(boolean stopThreads) {
    method setStopTimerThreads (line 55) | public void setStopTimerThreads(boolean stopTimerThreads) {
    method setThreadWaitMs (line 59) | public void setThreadWaitMs(int threadWaitMs) {
    method cleanUp (line 63) | @Override
    method forceStartOpenOfficeJurtCleanup (line 78) | protected void forceStartOpenOfficeJurtCleanup(ClassLoaderLeakPrevento...
    method stopThreads (line 108) | protected void stopThreads(ClassLoaderLeakPreventor preventor) {
    method setThreadSafeAccessControlContext (line 260) | private void setThreadSafeAccessControlContext(ClassLoaderLeakPrevento...
    method getRunnable (line 276) | private Runnable getRunnable(ClassLoaderLeakPreventor preventor, Threa...
    method stopTimerThread (line 286) | protected void stopTimerThread(ClassLoaderLeakPreventor preventor, Thr...
    class JURTKiller (line 325) | protected class JURTKiller extends Thread {
      method JURTKiller (line 333) | public JURTKiller(ClassLoaderLeakPreventor preventor, Thread jurtThr...
      method run (line 343) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupCleanUp.java
  class ThreadGroupCleanUp (line 13) | public class ThreadGroupCleanUp implements ClassLoaderPreMortemCleanUp, ...
    method mustBeBeforeMe (line 15) | @Override
    method cleanUp (line 20) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupContextCleanUp.java
  class ThreadGroupContextCleanUp (line 15) | public class ThreadGroupContextCleanUp implements ClassLoaderPreMortemCl...
    method cleanUp (line 16) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalCleanUp.java
  class ThreadLocalCleanUp (line 17) | @SuppressWarnings("WeakerAccess")
    method mustBeBeforeMe (line 33) | @Override
    method cleanUp (line 38) | @Override
    method initFields (line 58) | private void initFields(ClassLoaderLeakPreventor preventor) {
    method forEachThreadLocalInThread (line 66) | protected void forEachThreadLocalInThread(ClassLoaderLeakPreventor pre...
    method processThreadLocalMap (line 81) | protected void processThreadLocalMap(ClassLoaderLeakPreventor preventor,
    method dereferenceIfApplicable (line 174) | protected Object dereferenceIfApplicable(Object value) {
    method processLeak (line 182) | protected void processLeak(ClassLoaderLeakPreventor preventor, Thread ...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/WarningThreadLocalCleanUp.java
  class WarningThreadLocalCleanUp (line 13) | @SuppressWarnings("unused")
    method processLeak (line 19) | protected void processLeak(ClassLoaderLeakPreventor preventor, Thread ...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/X509TrustManagerImplUnparseableExtensionCleanUp.java
  class X509TrustManagerImplUnparseableExtensionCleanUp (line 19) | public class X509TrustManagerImplUnparseableExtensionCleanUp implements ...
    method cleanUp (line 23) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/AwtToolkitInitiator.java
  class AwtToolkitInitiator (line 13) | public class AwtToolkitInitiator implements PreClassLoaderInitiator {
    method doOutsideClassLoader (line 14) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/DatatypeConverterImplInitiator.java
  class DatatypeConverterImplInitiator (line 20) | public class DatatypeConverterImplInitiator implements PreClassLoaderIni...
    method doOutsideClassLoader (line 21) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/DocumentBuilderFactoryInitiator.java
  class DocumentBuilderFactoryInitiator (line 13) | public class DocumentBuilderFactoryInitiator implements PreClassLoaderIn...
    method doOutsideClassLoader (line 14) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/JarUrlConnectionInitiator.java
  class JarUrlConnectionInitiator (line 17) | public class JarUrlConnectionInitiator implements PreClassLoaderInitiator {
    method doOutsideClassLoader (line 18) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dDisposerInitiator.java
  class Java2dDisposerInitiator (line 14) | public class Java2dDisposerInitiator implements PreClassLoaderInitiator {
    method doOutsideClassLoader (line 15) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dRenderQueueInitiator.java
  class Java2dRenderQueueInitiator (line 11) | public class Java2dRenderQueueInitiator implements PreClassLoaderInitiat...
    method doOutsideClassLoader (line 12) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/JavaxSecurityLoginConfigurationInitiator.java
  class JavaxSecurityLoginConfigurationInitiator (line 14) | public class JavaxSecurityLoginConfigurationInitiator implements PreClas...
    method doOutsideClassLoader (line 15) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/JdbcDriversInitiator.java
  class JdbcDriversInitiator (line 20) | public class JdbcDriversInitiator implements PreClassLoaderInitiator {
    method doOutsideClassLoader (line 21) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/LdapPoolManagerInitiator.java
  class LdapPoolManagerInitiator (line 15) | public class LdapPoolManagerInitiator implements PreClassLoaderInitiator {
    method doOutsideClassLoader (line 16) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/OracleJdbcThreadInitiator.java
  class OracleJdbcThreadInitiator (line 20) | public class OracleJdbcThreadInitiator implements PreClassLoaderInitiator {
    method doOutsideClassLoader (line 21) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityPolicyInitiator.java
  class SecurityPolicyInitiator (line 16) | public class SecurityPolicyInitiator implements PreClassLoaderInitiator {
    method doOutsideClassLoader (line 17) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityProvidersInitiator.java
  class SecurityProvidersInitiator (line 14) | public class SecurityProvidersInitiator implements PreClassLoaderInitiat...
    method doOutsideClassLoader (line 15) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SunAwtAppContextInitiator.java
  class SunAwtAppContextInitiator (line 16) | public class SunAwtAppContextInitiator implements PreClassLoaderInitiator {
    method doOutsideClassLoader (line 17) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SunGCInitiator.java
  class SunGCInitiator (line 21) | public class SunGCInitiator implements PreClassLoaderInitiator {
    method doOutsideClassLoader (line 22) | @Override
    method getGCClass (line 45) | private Class<?> getGCClass() throws ClassNotFoundException {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorFactoryTest.java
  class ClassLoaderLeakPreventorFactoryTest (line 15) | public class ClassLoaderLeakPreventorFactoryTest {
    method cleanUpMustBeAfter (line 18) | @Test(expected = IllegalStateException.class) // TODO #51
    method circularMustBeAfter (line 80) | @Test(expected = IllegalStateException.class)
    class RecordingCleanUp (line 90) | private abstract static class RecordingCleanUp implements ClassLoaderP...
      method RecordingCleanUp (line 94) | RecordingCleanUp(List<ClassLoaderPreMortemCleanUp> cleanUps) {
      method cleanUp (line 98) | @Override
      method toString (line 103) | @Override
    class Foo (line 109) | private static class Foo extends RecordingCleanUp {
      method Foo (line 110) | Foo(List<ClassLoaderPreMortemCleanUp> cleanUps) {
    class Bar (line 115) | private static class Bar extends RecordingCleanUp {
      method Bar (line 116) | Bar(List<ClassLoaderPreMortemCleanUp> cleanUps) {
    class AfterFoo (line 121) | private static class AfterFoo extends RecordingCleanUp implements Must...
      method AfterFoo (line 122) | AfterFoo(List<ClassLoaderPreMortemCleanUp> cleanUps) {
      method mustBeBeforeMe (line 126) | @Override
    class AfterBar (line 132) | private static class AfterBar extends RecordingCleanUp implements Must...
      method AfterBar (line 133) | AfterBar(List<ClassLoaderPreMortemCleanUp> cleanUps) {
      method mustBeBeforeMe (line 137) | @Override
    class AfterFooAndBar (line 143) | private static class AfterFooAndBar extends RecordingCleanUp implement...
      method AfterFooAndBar (line 144) | AfterFooAndBar(List<ClassLoaderPreMortemCleanUp> cleanUps) {
      method mustBeBeforeMe (line 148) | @Override
    class Circle1 (line 156) | private static class Circle1 extends RecordingCleanUp implements MustB...
      method Circle1 (line 157) | Circle1() {
      method mustBeBeforeMe (line 161) | @Override
    class Circle2 (line 167) | private static class Circle2 extends RecordingCleanUp implements MustB...
      method Circle2 (line 168) | Circle2() {
      method mustBeBeforeMe (line 172) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/PreventionsTestBase.java
  class PreventionsTestBase (line 10) | public abstract class PreventionsTestBase<C> {
    method getTestedImplementation (line 15) | protected C getTestedImplementation() throws IllegalAccessException, I...
    method getClassLoaderLeakPreventor (line 31) | protected ClassLoaderLeakPreventor getClassLoaderLeakPreventor() {
    method getLeakSafeClassLoader (line 43) | protected ClassLoader getLeakSafeClassLoader() {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/StopThreadsCleanUp_TimerTest.java
  class StopThreadsCleanUp_TimerTest (line 15) | @RunWith(JUnitClassloaderRunner.class)
    method createTimer (line 22) | @Test
    class Preventor (line 28) | public static class Preventor implements Runnable {
      method run (line 29) | public void run() {
    class TimerThreadsCleanUp (line 51) | private static class TimerThreadsCleanUp extends StopThreadsCleanUp {
      method TimerThreadsCleanUp (line 52) | public TimerThreadsCleanUp() {
      method stopTimerThread (line 57) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanELResolverCleanUpTest.java
  class BeanELResolverCleanUpTest (line 11) | public class BeanELResolverCleanUpTest extends ClassLoaderPreMortemClean...
    method setUp (line 13) | @Before
    method triggerLeak (line 19) | @Override
    class Bean (line 29) | @SuppressWarnings("unused")
      method getFoo (line 33) | public String getFoo() {
      method setFoo (line 37) | public void setFoo(String foo) {
    class MyELContext (line 43) | private static class MyELContext extends ELContext {
      method getELResolver (line 44) | @Override
      method getFunctionMapper (line 49) | @Override
      method getVariableMapper (line 54) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanIntrospectorCleanUpTest.java
  class BeanIntrospectorCleanUpTest (line 8) | public class BeanIntrospectorCleanUpTest extends ClassLoaderPreMortemCle...
    method triggerLeak (line 10) | @Override
    class Bean (line 15) | protected class Bean {
      method getDummyField (line 18) | public int getDummyField() {
      method setDummyField (line 22) | public void setDummyField(int dummyField) {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanValidationCleanUpTest.java
  class BeanValidationCleanUpTest (line 10) | public class BeanValidationCleanUpTest extends ClassLoaderPreMortemClean...
    method triggerLeak (line 12) | @Override
    class ThreadLocalCleanUp_ApacheAxis14Test (line 21) | @Ignore // Fixed in newer versions of Java???
      method triggerLeak (line 24) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ClassLoaderPreMortemCleanUpTestBase.java
  class ClassLoaderPreMortemCleanUpTestBase (line 15) | @RunWith(JUnitClassloaderRunner.class)
    method triggerLeakWithoutCleanup (line 22) | @SuppressWarnings("DefaultAnnotationParam")
    method cleanUpAfterTriggeringLeak (line 29) | @Test
    method triggerLeak (line 37) | protected abstract void triggerLeak() throws Exception;
    method getClassLoaderPreMortemCleanUp (line 45) | @SuppressWarnings("WeakerAccess")

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/DefaultAuthenticatorCleanUpTest.java
  class DefaultAuthenticatorCleanUpTest (line 10) | public class DefaultAuthenticatorCleanUpTest extends ClassLoaderPreMorte...
    method triggerLeak (line 11) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/DriverManagerCleanUpTest.java
  class DriverManagerCleanUpTest (line 9) | @PackagesLoadedOutsideClassLoader(packages = "org.postgresql", addToDefa...
    method triggerLeak (line 12) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/GeoToolsCleanUpTest.java
  class GeoToolsCleanUpTest (line 9) | public class GeoToolsCleanUpTest extends ClassLoaderPreMortemCleanUpTest...
    method triggerLeak (line 10) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/IIOServiceProviderCleanUpTest.java
  class IIOServiceProviderCleanUpTest (line 13) | public class IIOServiceProviderCleanUpTest extends ClassLoaderPreMortemC...
    method systemClassLoader (line 16) | @Before
    method triggerLeak (line 21) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ImageIOMockImageInputStreamSPI.java
  class ImageIOMockImageInputStreamSPI (line 10) | public class ImageIOMockImageInputStreamSPI extends ImageInputStreamSpi {
    method createInputStreamInstance (line 12) | @Override
    method getDescription (line 17) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JDK8151486CleanUpTest.java
  class JDK8151486CleanUpTest (line 10) | @Ignore
    method triggerLeak (line 12) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JacksonCleanUpTest.java
  class JacksonCleanUpTest (line 10) | @PackagesLoadedOutsideClassLoader(packages = {"com.fasterxml.jackson.dat...
    method triggerLeak (line 12) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaServerFaces2746CleanUpTest.java
  class JavaServerFaces2746CleanUpTest (line 13) | public class JavaServerFaces2746CleanUpTest extends ClassLoaderPreMortem...
    method doTriggerLeak (line 22) | private static void doTriggerLeak() {
    class MyComponent (line 30) | @SuppressWarnings("unused")
      method getFamily (line 32) | @Override
      method getAttribute (line 38) | public MyAttribute getAttribute() {
      method setAttribute (line 43) | public void setAttribute(MyAttribute myAttribute) {
    class MyAttribute (line 49) | private static class MyAttribute {
    method triggerLeak (line 59) | @SuppressWarnings("UnusedAssignment")

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaUtilLoggingLevelCleanUpTest.java
  class JavaUtilLoggingLevelCleanUpTest (line 7) | public class JavaUtilLoggingLevelCleanUpTest extends ClassLoaderPreMorte...
    method triggerLeak (line 8) | @Override
    class CustomLevel (line 17) | public static class CustomLevel extends java.util.logging.Level {
      method CustomLevel (line 18) | public CustomLevel() {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaxSecurityAuthLoginConfigurationCleanUpTest.java
  class JavaxSecurityAuthLoginConfigurationCleanUpTest (line 10) | public class JavaxSecurityAuthLoginConfigurationCleanUpTest
    method triggerLeak (line 13) | @Override
    class MockConfiguration (line 18) | private class MockConfiguration extends Configuration {
      method getAppConfigurationEntry (line 19) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JceSecurityCleanUpTest.java
  class JceSecurityCleanUpTest (line 11) | public class JceSecurityCleanUpTest extends ClassLoaderPreMortemCleanUpT...
    method triggerLeak (line 12) | @Override
    class MyProvider (line 28) | public static class MyProvider extends Provider {
      method MyProvider (line 29) | public MyProvider(String name, double version, String info) {
      method getService (line 33) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MBeanCleanUpTest.java
  class MBeanCleanUpTest (line 11) | public class MBeanCleanUpTest extends ClassLoaderPreMortemCleanUpTestBas...
    method triggerLeak (line 13) | @Override
    type CustomMBean (line 19) | public interface CustomMBean {
    class Custom (line 22) | public static class Custom implements CustomMBean {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUpTest.java
  class MXBeanNotificationListenersCleanUpTest (line 12) | public class MXBeanNotificationListenersCleanUpTest extends ClassLoaderP...
    method triggerLeak (line 13) | @Override
    class CustomNotificationListener (line 19) | static class CustomNotificationListener implements NotificationListener {
      method handleNotification (line 20) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUp_ListenerWrapperTest.java
  class MXBeanNotificationListenersCleanUp_ListenerWrapperTest (line 15) | public class MXBeanNotificationListenersCleanUp_ListenerWrapperTest exte...
    method triggerLeak (line 16) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MoxyCleanUpTest.java
  class MoxyCleanUpTest (line 11) | @PackagesLoadedOutsideClassLoader(packages = {"org.eclipse.persistence.j...
    method triggerLeak (line 13) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MultiThreadedHttpConnectionManagerCleanUpTest.java
  class MultiThreadedHttpConnectionManagerCleanUpTest (line 15) | public class MultiThreadedHttpConnectionManagerCleanUpTest extends Class...
    method triggerLeak (line 17) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ObjectStreamClassCleanupTest.java
  class ObjectStreamClassCleanupTest (line 9) | public class ObjectStreamClassCleanupTest extends ClassLoaderPreMortemCl...
    method triggerLeak (line 11) | @Override
    class SerializableEntity (line 16) | protected final class SerializableEntity implements Serializable {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/PropertyEditorCleanUpTest.java
  class PropertyEditorCleanUpTest (line 11) | @Ignore // No longer leaks in Java 7+
    method triggerLeak (line 13) | @Override
    class Foo (line 19) | public static class Foo {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ProxySelectorCleanUpTest.java
  class ProxySelectorCleanUpTest (line 14) | public class ProxySelectorCleanUpTest extends ClassLoaderPreMortemCleanU...
    method triggerLeak (line 15) | @Override
    class MyProxySelector (line 21) | private static class MyProxySelector extends ProxySelector {
      method select (line 22) | @Override
      method connectFailed (line 27) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ReplaceDOMNormalizerSerializerAbortExceptionCleanUpTest.java
  class ReplaceDOMNormalizerSerializerAbortExceptionCleanUpTest (line 11) | public class ReplaceDOMNormalizerSerializerAbortExceptionCleanUpTest ext...
    method triggerLeak (line 12) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/SAAJEnvelopeFactoryParserPoolCleanUpTest.java
  class SAAJEnvelopeFactoryParserPoolCleanUpTest (line 14) | public class SAAJEnvelopeFactoryParserPoolCleanUpTest extends ClassLoade...
    method triggerLeak (line 16) | @Override
    method getCustomErrorHandlerInstance (line 52) | public Object getCustomErrorHandlerInstance(final ClassLoaderLeakPreve...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/SecurityProviderCleanUpTest.java
  class SecurityProviderCleanUpTest (line 9) | public class SecurityProviderCleanUpTest extends ClassLoaderPreMortemCle...
    method triggerLeak (line 14) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ShutdownHookCleanUpTest.java
  class ShutdownHookCleanUpTest (line 7) | public class ShutdownHookCleanUpTest extends ClassLoaderPreMortemCleanUp...
    method triggerLeak (line 8) | @Override
    class ShutdownHookThread (line 14) | private class ShutdownHookThread extends Thread {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp_MultiThreadedHttpConnectionManagerTest.java
  class StopThreadsCleanUp_MultiThreadedHttpConnectionManagerTest (line 17) | public class StopThreadsCleanUp_MultiThreadedHttpConnectionManagerTest e...
    method triggerLeak (line 19) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp_PostgresqlJdbcTest.java
  class StopThreadsCleanUp_PostgresqlJdbcTest (line 10) | @PackagesLoadedOutsideClassLoader(packages = {"org.postgresql", "com.mys...
    method triggerLeak (line 13) | @Override
    method tearDown (line 18) | @After

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp_Runnable.java
  class StopThreadsCleanUp_Runnable (line 8) | public class StopThreadsCleanUp_Runnable extends ClassLoaderPreMortemCle...
    method triggerLeak (line 10) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsClenup_ExecutorTest.java
  class StopThreadsClenup_ExecutorTest (line 13) | public class StopThreadsClenup_ExecutorTest extends ClassLoaderPreMortem...
    method createSharedExecutor (line 17) | private static ExecutorService createSharedExecutor() {
    method triggerLeak (line 33) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupCleanUpTest.java
  class ThreadGroupCleanUpTest (line 7) | public class ThreadGroupCleanUpTest extends ClassLoaderPreMortemCleanUpT...
    method triggerLeak (line 12) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalCleanUpTest.java
  class ThreadLocalCleanUpTest (line 16) | public class ThreadLocalCleanUpTest extends ClassLoaderPreMortemCleanUpT...
    method triggerLeak (line 25) | @Override
    class Value (line 31) | private static class Value {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalWithNestedRefValueCleanUpTest.java
  class ThreadLocalWithNestedRefValueCleanUpTest (line 10) | public class ThreadLocalWithNestedRefValueCleanUpTest extends ClassLoade...
    method triggerLeak (line 14) | @Override
    class Value (line 20) | private static class Value {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalWithRefValueCleanUpTest.java
  class ThreadLocalWithRefValueCleanUpTest (line 14) | public class ThreadLocalWithRefValueCleanUpTest extends ClassLoaderPreMo...
    method triggerLeak (line 18) | @Override
    class Value (line 24) | private static class Value {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/X509TrustManagerImplUnparseableExtensionCleanUpTest.java
  class X509TrustManagerImplUnparseableExtensionCleanUpTest (line 10) | public class X509TrustManagerImplUnparseableExtensionCleanUpTest extends...
    method triggerLeak (line 11) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/AwtToolkitInitiatorTest.java
  class AwtToolkitInitiatorTest (line 9) | @Ignore // Fixed in newer versions of Java?

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/DatatypeConverterImplInitiatorTest.java
  class DatatypeConverterImplInitiatorTest (line 17) | @Ignore // Doesn't leak in Java 1.7.0 (_55, _56), but does in 1.8.0 (_74)
    method setSystemProperty (line 19) | @Before
    class MyDatatypeFactory (line 25) | public static class MyDatatypeFactory extends DatatypeFactory {
      method newDuration (line 26) | @Override
      method newDuration (line 31) | @Override
      method newDuration (line 36) | @Override
      method newXMLGregorianCalendar (line 41) | @Override
      method newXMLGregorianCalendar (line 46) | @Override
      method newXMLGregorianCalendar (line 51) | @Override
      method newXMLGregorianCalendar (line 56) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/DocumentBuilderFactoryInitiatorTest.java
  class DocumentBuilderFactoryInitiatorTest (line 9) | @Ignore // Fixed in newer versions of Java?

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dDisposerInitiatorTest.java
  class Java2dDisposerInitiatorTest (line 9) | @Ignore // Fixed in newer versions of Java

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dRenderQueueInitiatorTest.java
  class Java2dRenderQueueInitiatorTest (line 6) | public class Java2dRenderQueueInitiatorTest extends PreClassLoaderInitia...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/JavaxSecurityLoginConfigurationInitiatorTest.java
  class JavaxSecurityLoginConfigurationInitiatorTest (line 9) | @Ignore // Fixed in newer versions of Java

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/JdbcDriversInitiatorTest.java
  class JdbcDriversInitiatorTest (line 9) | @Ignore // Cannot be tested this way

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/LdapPoolManagerInitiatorTest.java
  class LdapPoolManagerInitiatorTest (line 9) | public class LdapPoolManagerInitiatorTest extends PreClassLoaderInitiato...
    method setSystemProperty (line 10) | @Before

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/OracleJdbcThreadInitiatorTest.java
  class OracleJdbcThreadInitiatorTest (line 10) | @Ignore // Oracle JDBC driver needs to be available for this test

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/PreClassLoaderInitiatorTestBase.java
  class PreClassLoaderInitiatorTestBase (line 16) | @RunWith(JUnitClassloaderRunner.class)
    method firstShouldLeak (line 21) | @SuppressWarnings("DefaultAnnotationParam")
    method secondShouldNotLeak (line 29) | @Leaks(false)
    method invokeInitiator (line 35) | private void invokeInitiator() throws IllegalAccessException, Instanti...
    method getLeakSafeClassLoader (line 40) | @Override

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/ReplaceDOMNormalizerSerializerAbortExceptionInitiatorTest.java
  class ReplaceDOMNormalizerSerializerAbortExceptionInitiatorTest (line 20) | @RunWith(JUnitClassloaderRunner.class)
    method noLeakAfterInitiatorRun (line 23) | @Leaks(false)
    method triggerLeak (line 31) | public static void triggerLeak() throws ParserConfigurationException {

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityPolicyInitiatorTest.java
  class SecurityPolicyInitiatorTest (line 9) | @Ignore // Fixed in newer versions of Java?

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityProvidersInitiatorTest.java
  class SecurityProvidersInitiatorTest (line 9) | @Ignore // Cannot be tested this way?

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SunAwtAppContextInitiatorTest.java
  class SunAwtAppContextInitiatorTest (line 7) | public class SunAwtAppContextInitiatorTest extends PreClassLoaderInitiat...

FILE: classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SunGCInitiatorTest.java
  class SunGCInitiatorTest (line 7) | public class SunGCInitiatorTest extends PreClassLoaderInitiatorTestBase<...

FILE: classloader-leak-prevention/classloader-leak-prevention-servlet/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorListener.java
  class ClassLoaderLeakPreventorListener (line 121) | @SuppressWarnings("WeakerAccess")
    method getDefaultOtherListeners (line 133) | static List<ServletContextListener> getDefaultOtherListeners() {
    method contextInitialized (line 152) | @Override
    method contextInitialized (line 168) | void contextInitialized(final ServletContext servletContext) {
    method contextDestroyed (line 227) | @Override
    method createClassLoaderLeakPreventorFactory (line 250) | protected ClassLoaderLeakPreventorFactory createClassLoaderLeakPrevent...
    method getIntInitParameter (line 255) | protected static int getIntInitParameter(ServletContext servletContext...
    method getLogPrefix (line 277) | protected String getLogPrefix() {
    method info (line 284) | protected void info(String s) {

FILE: classloader-leak-prevention/classloader-leak-prevention-servlet3/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventionContainerInitializer.java
  class ClassLoaderLeakPreventionContainerInitializer (line 13) | public class ClassLoaderLeakPreventionContainerInitializer implements ja...
    method onStartup (line 16) | @Override

FILE: classloader-leak-test-framework/src/main/java/se/jiderhamn/HeapDumper.java
  class HeapDumper (line 14) | public class HeapDumper {
    method dumpHeap (line 30) | public static void dumpHeap(File file, boolean live) throws ClassNotFo...
    method getHotSpotDiagnosticMBean (line 46) | private static HotSpotDiagnosticMXBean getHotSpotDiagnosticMBean() {

FILE: classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/RedefiningClassLoader.java
  class RedefiningClassLoader (line 7) | public class RedefiningClassLoader extends org.apache.bcel.util.ClassLoa...
    method RedefiningClassLoader (line 25) | public RedefiningClassLoader(ClassLoader parent) {
    method RedefiningClassLoader (line 29) | public RedefiningClassLoader() {
    method RedefiningClassLoader (line 33) | public RedefiningClassLoader(ClassLoader parent, String name) {
    method RedefiningClassLoader (line 37) | RedefiningClassLoader(String name) {
    method RedefiningClassLoader (line 41) | public RedefiningClassLoader(ClassLoader parent, String name, String[]...
    method RedefiningClassLoader (line 47) | RedefiningClassLoader(String name, String[] ignoredPackages) {
    method isDebugLoggingEnabled (line 53) | public static boolean isDebugLoggingEnabled() {
    method modifyClass (line 57) | @Override
    method markAsZombie (line 66) | public void markAsZombie() {
    method toString (line 70) | @Override
    method loadClass (line 76) | @Override

FILE: classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/ZombieMarker.java
  class ZombieMarker (line 8) | public class ZombieMarker {

FILE: classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/leak/JUnitClassloaderRunner.java
  class JUnitClassloaderRunner (line 27) | public class JUnitClassloaderRunner extends BlockJUnit4ClassRunner {
    method JUnitClassloaderRunner (line 32) | public JUnitClassloaderRunner(Class<?> klass) throws InitializationErr...
    method methodInvoker (line 37) | @Override
    class SeparateClassLoaderInvokeMethod (line 46) | private class SeparateClassLoaderInvokeMethod extends InvokeMethod {
      method SeparateClassLoaderInvokeMethod (line 69) | private SeparateClassLoaderInvokeMethod(FrameworkMethod testMethod, ...
      method SeparateClassLoaderInvokeMethod (line 73) | private SeparateClassLoaderInvokeMethod(FrameworkMethod testMethod, ...
      method evaluate (line 91) | @SuppressWarnings("UnusedAssignment")
      method performErrorActions (line 203) | private void performErrorActions(String testName) throws Interrupted...
    method forceGc (line 215) | public static void forceGc(int n) {
    method forceGc (line 222) | public static void forceGc() {
    method waitForHeapDump (line 229) | private static void waitForHeapDump() throws InterruptedException {
    method dumpHeap (line 236) | private void dumpHeap(String testName) {
    method getSurefireReportsDirectory (line 252) | private File getSurefireReportsDirectory() {
    method getSurefireReportsDirectory (line 259) | private static File getSurefireReportsDirectory(final Class<?> clazz) {
    method appendArrays (line 291) | private <T> T[] appendArrays(T[] arr1, T[] arr2) {

FILE: classloader-leak-test-framework/src/test/java/com/classloader/test/CustomClass.java
  class CustomClass (line 3) | public class CustomClass {

FILE: classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/RedefiningClassLoaderTest.java
  class RedefiningClassLoaderTest (line 11) | @RunWith(JUnitClassloaderRunner.class)
    method getPackage (line 14) | @Test

FILE: classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/JUnitClassloaderRunnerTest.java
  class JUnitClassloaderRunnerTest (line 13) | @RunWith(JUnitClassloaderRunner.class)
    method throwException (line 16) | @Test(expected = RuntimeException.class) // FileNotFoundException repl...
    method throwAssertionError (line 22) | @Test(expected = RuntimeException.class) // CustomError replaced by Ru...
    class CustomError (line 28) | public static class CustomError extends Error {

FILE: classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/NonLeakingTest.java
  class NonLeakingTest (line 10) | @RunWith(JUnitClassloaderRunner.class)
    method nonLeakingMethod (line 13) | @Test

FILE: classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/accused/CustomThreadLocalTest.java
  class CustomThreadLocalTest (line 11) | @RunWith(JUnitClassloaderRunner.class)
    method initialValue (line 16) | @Override
    method setValueOfCustomThreadLocal (line 25) | @Test

FILE: classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/known/CustomThreadLocalCustomValueTest.java
  class CustomThreadLocalCustomValueTest (line 10) | @RunWith(JUnitClassloaderRunner.class)
    method initialValue (line 15) | @Override
    method setCustomThreadLocalValue (line 21) | @Test
    class Value (line 27) | private static class Value {

FILE: classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/known/JEditorPaneTest.java
  class JEditorPaneTest (line 13) | @RunWith(JUnitClassloaderRunner.class)
    method triggerJEditorPaneLeak (line 16) | @Test
Condensed preview — 153 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (373K chars).
[
  {
    "path": ".gitignore",
    "chars": 68,
    "preview": "target\n.classpath\n.project\n.settings\n.mvn/wrapper/maven-wrapper.jar\n"
  },
  {
    "path": ".mvn/wrapper/MavenWrapperDownloader.java",
    "chars": 6127,
    "preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOT"
  },
  {
    "path": ".mvn/wrapper/maven-wrapper.properties",
    "chars": 1019,
    "preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE f"
  },
  {
    "path": ".travis.yml",
    "chars": 409,
    "preview": "dist: trusty\n\nlanguage: java\n\njdk:\n  - oraclejdk8\n  - openjdk11\n\n# Uncomment to upload heapdumps to S3 bucket; https://d"
  },
  {
    "path": "LICENSE.txt",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 5238,
    "preview": "# Classloader Leak Prevention library\n[![Build Status](https://travis-ci.org/mjiderhamn/classloader-leak-prevention.svg?"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/README.md",
    "chars": 2941,
    "preview": "# Classloader Leak Prevention library integration\n\n_This document is about using the Classloader Leak Prevention library"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/pom.xml",
    "chars": 6265,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventor.java",
    "chars": 24244,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.manag"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorFactory.java",
    "chars": 11149,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport ja"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderPreMortemCleanUp.java",
    "chars": 494,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Interface for cleanup actions that should be performed as part"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/JULLogger.java",
    "chars": 886,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.logging.Level;\n\n/**\n * Implementation of {@link Logg"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/Logger.java",
    "chars": 903,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Interface for logging, with similarities to common logging fra"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/MustBeAfter.java",
    "chars": 1054,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Interface to be implemented by {@link PreClassLoaderInitiator}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/PreClassLoaderInitiator.java",
    "chars": 815,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Interface for preventative actions that should be executed in "
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ReplaceDOMNormalizerSerializerAbortException.java",
    "chars": 3807,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/StdLogger.java",
    "chars": 1149,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Implementation of {@link Logger} interface, that uses {@link S"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ApacheCommonsLoggingCleanUp.java",
    "chars": 1599,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.security.CodeSource;\n\nimport se.jiderhamn.classlo"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanELResolverCleanUp.java",
    "chars": 1771,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Meth"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanIntrospectorCleanUp.java",
    "chars": 1854,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Meth"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanValidationCleanUp.java",
    "chars": 1342,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.util.Map;\n\nimport"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/DefaultAuthenticatorCleanUp.java",
    "chars": 5958,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.Reference;\nimport java.lang.reflect.Fiel"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/DriverManagerCleanUp.java",
    "chars": 1314,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.sql.Driver;\nimport java.sql.DriverManager;\nimport"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/GeoToolsCleanUp.java",
    "chars": 943,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\n\nimport se.jiderhamn.classloa"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/IIOServiceProviderCleanUp.java",
    "chars": 3057,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.security.AccessCo"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/IntrospectionUtilsCleanUp.java",
    "chars": 1554,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JDK8151486CleanUp.java",
    "chars": 1029,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JacksonCleanUp.java",
    "chars": 1708,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Method;\nimport java.util.Map;\n\nimpor"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaServerFaces2746CleanUp.java",
    "chars": 2737,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.u"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaUtilLoggingLevelCleanUp.java",
    "chars": 2807,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.util.*;\nimport ja"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaxSecurityAuthLoginConfigurationCleanUp.java",
    "chars": 717,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.security.auth.login.Configuration;\n\nimport se.ji"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JceSecurityCleanUp.java",
    "chars": 1564,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.net.URL;\nimport java.security.Provider;\nimport ja"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/KeepAliveTimerCacheCleanUp.java",
    "chars": 1521,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MBeanCleanUp.java",
    "chars": 9587,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport java.la"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUp.java",
    "chars": 7270,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport java.la"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MoxyCleanUp.java",
    "chars": 4089,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Meth"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MultiThreadedHttpConnectionManagerCleanUp.java",
    "chars": 927,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ObjectStreamClassCleanup.java",
    "chars": 1490,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport se.jid"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/PropertyEditorCleanUp.java",
    "chars": 1912,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.beans.PropertyEditorManager;\nimport java.lang.ref"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ProxySelectorCleanUp.java",
    "chars": 1017,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.net.ProxySelector;\nimport java.security.AccessCon"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ReactorNettyHttpResourcesCleanUp.java",
    "chars": 1213,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Method;\n\nimport se.jiderhamn.classlo"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ResourceBundleCleanUp.java",
    "chars": 2138,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect."
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/RmiTargetsCleanUp.java",
    "chars": 1861,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.util.Iterator;\nim"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/SAAJEnvelopeFactoryParserPoolCleanUp.java",
    "chars": 1636,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.util.Map;\n\nimport"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/SecurityProviderCleanUp.java",
    "chars": 1044,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport se.ji"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ShutdownHookCleanUp.java",
    "chars": 3676,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.ArrayList;\nimport java.util.Map;\n\nimport se."
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp.java",
    "chars": 18473,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Meth"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupCleanUp.java",
    "chars": 3180,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Method;\n\nimport se.jiderhamn.classlo"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupContextCleanUp.java",
    "chars": 2008,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect."
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalCleanUp.java",
    "chars": 10355,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.Reference;\nimport java.lang.reflect.Fiel"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/WarningThreadLocalCleanUp.java",
    "chars": 807,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.Reference;\n\nimport se.jiderhamn.classloa"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/X509TrustManagerImplUnparseableExtensionCleanUp.java",
    "chars": 2918,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Meth"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/AwtToolkitInitiator.java",
    "chars": 876,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/DatatypeConverterImplInitiator.java",
    "chars": 1661,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/DocumentBuilderFactoryInitiator.java",
    "chars": 971,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/JarUrlConnectionInitiator.java",
    "chars": 1159,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.net.URL;\n\nimport se.jiderhamn.classloader.leak.pr"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dDisposerInitiator.java",
    "chars": 978,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dRenderQueueInitiator.java",
    "chars": 834,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/JavaxSecurityLoginConfigurationInitiator.java",
    "chars": 880,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/JdbcDriversInitiator.java",
    "chars": 1213,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/LdapPoolManagerInitiator.java",
    "chars": 987,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/OracleJdbcThreadInitiator.java",
    "chars": 4372,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.lang.management.ManagementFactory;\nimport java.la"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityPolicyInitiator.java",
    "chars": 1157,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.lang.reflect.InvocationTargetException;\n\nimport s"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityProvidersInitiator.java",
    "chars": 800,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SunAwtAppContextInitiator.java",
    "chars": 1266,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport javax.swing.*;\n\nimport se.jiderhamn.classloader.leak.p"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SunGCInitiator.java",
    "chars": 1948,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.lang.reflect.InvocationTargetException;\nimport ja"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorFactoryTest.java",
    "chars": 5588,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit."
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/PreventionsTestBase.java",
    "chars": 1852,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.util.Collecti"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/StopThreadsCleanUp_TimerTest.java",
    "chars": 2064,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.Collection;\nimport java.util.Timer;\n\nimport org.juni"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanELResolverCleanUpTest.java",
    "chars": 1529,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.el.*;\n\nimport org.junit.Before;\n\n/**\n * Test cas"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanIntrospectorCleanUpTest.java",
    "chars": 631,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.beans.Introspector;\n\n/**\n * Test case for {@link "
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanValidationCleanUpTest.java",
    "chars": 898,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.apache.axis.utils.XMLUtils;\nimport org.junit.Ignor"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ClassLoaderPreMortemCleanUpTestBase.java",
    "chars": 1959,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimpor"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/DefaultAuthenticatorCleanUpTest.java",
    "chars": 510,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.apache.cxf.transport.http.CXFAuthenticator;\n\n/**\n "
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/DriverManagerCleanUpTest.java",
    "chars": 564,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.PackagesLoadedOutsideClassLoa"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/GeoToolsCleanUpTest.java",
    "chars": 408,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.geotools.util.WeakCollectionCleaner;\n\n/**\n * Test "
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/IIOServiceProviderCleanUpTest.java",
    "chars": 795,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.imageio.ImageIO;\nimport javax.swing.*;\n\nimport o"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ImageIOMockImageInputStreamSPI.java",
    "chars": 625,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java."
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JDK8151486CleanUpTest.java",
    "chars": 700,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.junit.Ignore;\n\nimport java.security.Permission;\n\n/"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JacksonCleanUpTest.java",
    "chars": 612,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport com.fasterxml.jackson.databind.type.TypeFactory;\nimpor"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaServerFaces2746CleanUpTest.java",
    "chars": 2408,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.el.BeanELResolver;\nimport javax.el.ELContext;\nim"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaUtilLoggingLevelCleanUpTest.java",
    "chars": 660,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test cases for {@link JavaUtilLoggingLevelCleanUp}\n * "
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaxSecurityAuthLoginConfigurationCleanUpTest.java",
    "chars": 725,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.security.auth.login.AppConfigurationEntry;\nimpor"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JceSecurityCleanUpTest.java",
    "chars": 1336,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.security.NoSuchAlgorithmException;\nimport java.se"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MBeanCleanUpTest.java",
    "chars": 731,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport javax.m"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUpTest.java",
    "chars": 867,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport javax.m"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUp_ListenerWrapperTest.java",
    "chars": 1286,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport java.la"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MoxyCleanUpTest.java",
    "chars": 1563,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.eclipse.persistence.jaxb.compiler.CompilerHelper;\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MultiThreadedHttpConnectionManagerCleanUpTest.java",
    "chars": 1220,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport com.sun.jersey.api.client.Client;\nimport com.sun.jerse"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ObjectStreamClassCleanupTest.java",
    "chars": 594,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.io.ObjectStreamClass;\nimport java.io.Serializable"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/PropertyEditorCleanUpTest.java",
    "chars": 605,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.beans.PropertyEditorManager;\n\nimport org.junit.Ig"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ProxySelectorCleanUpTest.java",
    "chars": 906,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.io.IOException;\nimport java.net.Proxy;\nimport jav"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ReplaceDOMNormalizerSerializerAbortExceptionCleanUpTest.java",
    "chars": 805,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPr"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/SAAJEnvelopeFactoryParserPoolCleanUpTest.java",
    "chars": 2908,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Method;\nimport javax.xml.parsers.SAX"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/SecurityProviderCleanUpTest.java",
    "chars": 516,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.security.Provider;\n\n/**\n * Test case for {@link S"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ShutdownHookCleanUpTest.java",
    "chars": 471,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test case for {@link ShutdownHookCleanUp}\n * @author M"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp_MultiThreadedHttpConnectionManagerTest.java",
    "chars": 1432,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport com.sun.jersey.api.client.Client;\nimport com.sun.jerse"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp_PostgresqlJdbcTest.java",
    "chars": 729,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.junit.After;\nimport se.jiderhamn.classloader.Packa"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp_Runnable.java",
    "chars": 749,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test case for leaks caused by {@link Runnable} of thre"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsClenup_ExecutorTest.java",
    "chars": 1299,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupCleanUpTest.java",
    "chars": 631,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test cases for {@link ThreadGroupCleanUp}\n * @author M"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalCleanUpTest.java",
    "chars": 1478,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test cases for {@link ThreadLocalCleanUp}\n *\n * Thread"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalWithNestedRefValueCleanUpTest.java",
    "chars": 892,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.SoftReference;\n\n/**\n * Another variant t"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalWithRefValueCleanUpTest.java",
    "chars": 1029,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.Reference;\nimport java.lang.ref.SoftRefe"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/X509TrustManagerImplUnparseableExtensionCleanUpTest.java",
    "chars": 680,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.io.File;\nimport javax.net.ssl.SSLContext;\n\n/**\n *"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/package-info.java",
    "chars": 266,
    "preview": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test cases in this package are used to confirm a) that"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/package-info.java",
    "chars": 263,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Test cases in this package are used to confirm a) that a leak "
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/AwtToolkitInitiatorTest.java",
    "chars": 312,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test case for {@link AwtTool"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/DatatypeConverterImplInitiatorTest.java",
    "chars": 2105,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimp"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/DocumentBuilderFactoryInitiatorTest.java",
    "chars": 349,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link Docume"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dDisposerInitiatorTest.java",
    "chars": 325,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link Java2d"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dRenderQueueInitiatorTest.java",
    "chars": 235,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\n/**\n * Test cases for {@link Java2dRenderQueueInitiator}\n */\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/JavaxSecurityLoginConfigurationInitiatorTest.java",
    "chars": 376,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link JavaxS"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/JdbcDriversInitiatorTest.java",
    "chars": 309,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link JdbcDr"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/LdapPoolManagerInitiatorTest.java",
    "chars": 433,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Before;\n\n/**\n * Test cases for {@link LdapPo"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/OracleJdbcThreadInitiatorTest.java",
    "chars": 500,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\nimport se.jiderhamn.classloader.Pack"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/PreClassLoaderInitiatorTestBase.java",
    "chars": 1638,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimpor"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/ReplaceDOMNormalizerSerializerAbortExceptionInitiatorTest.java",
    "chars": 1681,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityPolicyInitiatorTest.java",
    "chars": 325,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link Securi"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityProvidersInitiatorTest.java",
    "chars": 328,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link Securi"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SunAwtAppContextInitiatorTest.java",
    "chars": 261,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\n/**\n * Test cases for {@link SunAwtAppContextInitiator}\n * @a"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SunGCInitiatorTest.java",
    "chars": 228,
    "preview": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\n/**\n * Test cases for {@link SunGCInitiator}\n * @author Matti"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/resources/META-INF/services/javax.imageio.spi.ImageInputStreamSpi",
    "chars": 79,
    "preview": "se.jiderhamn.classloader.leak.prevention.cleanup.ImageIOMockImageInputStreamSPI"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/resources/spi-cacert-2008.crt",
    "chars": 2854,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIIDjCCBfagAwIBAgIJAOiOtsn4KhQoMA0GCSqGSIb3DQEBBQUAMIG8MQswCQYD\nVQQGEwJVUzEQMA4GA1UECBMHSW5"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet/pom.xml",
    "chars": 1241,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorListener.java",
    "chars": 12775,
    "preview": "/*\n   Copyright 2012 Mattias Jiderhamn\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may no"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet3/pom.xml",
    "chars": 1462,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet3/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventionContainerInitializer.java",
    "chars": 1776,
    "preview": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.Set;\nimport javax.servlet.*;\n\n/**\n * Servlet 3.0 {@l"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet3/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer",
    "chars": 86,
    "preview": "se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventionContainerInitializer"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet3/src/main/resources/META-INF/web-fragment.xml",
    "chars": 794,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-fragment xmlns=\"http://java.sun.com/xml/ns/javaee\"\n              xmlns:xsi=\""
  },
  {
    "path": "classloader-leak-prevention/pom.xml",
    "chars": 6099,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
  },
  {
    "path": "classloader-leak-test-framework/README.md",
    "chars": 3973,
    "preview": "# Classloader Leak test framework\n\nStand-alone test framework for detecting and/or verifying the existence or non-existe"
  },
  {
    "path": "classloader-leak-test-framework/pom.xml",
    "chars": 5143,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/HeapDumper.java",
    "chars": 2051,
    "preview": "package se.jiderhamn;\n\nimport java.io.File;\nimport java.lang.management.ManagementFactory;\nimport javax.management.MBean"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/PackagesLoadedOutsideClassLoader.java",
    "chars": 1028,
    "preview": "package se.jiderhamn.classloader;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimpor"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/RedefiningClassLoader.java",
    "chars": 2928,
    "preview": "package se.jiderhamn.classloader;\n\nimport org.apache.bcel.classfile.ClassFormatException;\nimport org.apache.bcel.classfi"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/ZombieMarker.java",
    "chars": 199,
    "preview": "package se.jiderhamn.classloader;\n\n/**\n * Class used to help identify leaked class loaders in a heap dump.\n * Inspired b"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/leak/JUnitClassloaderRunner.java",
    "chars": 12718,
    "preview": "package se.jiderhamn.classloader.leak;\n\nimport java.io.File;\nimport java.lang.ref.WeakReference;\nimport java.lang.reflec"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/leak/LeakPreventor.java",
    "chars": 301,
    "preview": "package se.jiderhamn.classloader.leak;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPoli"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/leak/Leaks.java",
    "chars": 802,
    "preview": "package se.jiderhamn.classloader.leak;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPoli"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/com/classloader/test/CustomClass.java",
    "chars": 60,
    "preview": "package com.classloader.test;\n\npublic class CustomClass {\n}\n"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/RedefiningClassLoaderTest.java",
    "chars": 654,
    "preview": "package se.jiderhamn.classloader;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderhamn.classload"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/JUnitClassloaderRunnerTest.java",
    "chars": 847,
    "preview": "package se.jiderhamn.classloader.leak;\n\nimport java.io.FileNotFoundException;\n\nimport org.junit.Test;\nimport org.junit.r"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/NonLeakingTest.java",
    "chars": 400,
    "preview": "package se.jiderhamn.classloader.leak;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\n/**\n * Test that isn't "
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/accused/CustomThreadLocalTest.java",
    "chars": 838,
    "preview": "package se.jiderhamn.classloader.leak.accused;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderh"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/accused/package-info.java",
    "chars": 182,
    "preview": "package se.jiderhamn.classloader.leak.accused;\n\n/* Test cases in this package are used to confirm that code accused of c"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/known/CustomThreadLocalCustomValueTest.java",
    "chars": 784,
    "preview": "package se.jiderhamn.classloader.leak.known;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderham"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/known/JEditorPaneTest.java",
    "chars": 455,
    "preview": "package se.jiderhamn.classloader.leak.known;\n\nimport javax.swing.*;\n\nimport org.junit.Test;\nimport org.junit.runner.RunW"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/known/package-info.java",
    "chars": 128,
    "preview": "package se.jiderhamn.classloader.leak.known;\n\n/** Test cases in this package are used to confirm the existence of known "
  },
  {
    "path": "mvnw",
    "chars": 9781,
    "preview": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Softwa"
  },
  {
    "path": "mvnw.cmd",
    "chars": 6702,
    "preview": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software F"
  },
  {
    "path": "pom.xml",
    "chars": 773,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the mjiderhamn/classloader-leak-prevention GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 153 files (329.3 KB), approximately 87.3k tokens, and a symbol index with 488 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!