[
  {
    "path": ".gitignore",
    "content": "target\n.classpath\n.project\n.settings\n.mvn/wrapper/maven-wrapper.jar\n"
  },
  {
    "path": ".mvn/wrapper/MavenWrapperDownloader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.Authenticator;\nimport java.net.PasswordAuthentication;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.LinkOption;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardCopyOption;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Properties;\n\npublic final class MavenWrapperDownloader\n{\n    private static final String WRAPPER_VERSION = \"3.1.1\";\n\n    private static final boolean VERBOSE = Boolean.parseBoolean( System.getenv( \"MVNW_VERBOSE\" ) );\n\n    /**\n     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.\n     */\n    private static final String DEFAULT_DOWNLOAD_URL =\n        \"https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/\" + WRAPPER_VERSION\n            + \"/maven-wrapper-\" + WRAPPER_VERSION + \".jar\";\n\n    /**\n     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to use instead of the\n     * default one.\n     */\n    private static final String MAVEN_WRAPPER_PROPERTIES_PATH = \".mvn/wrapper/maven-wrapper.properties\";\n\n    /**\n     * Path where the maven-wrapper.jar will be saved to.\n     */\n    private static final String MAVEN_WRAPPER_JAR_PATH = \".mvn/wrapper/maven-wrapper.jar\";\n\n    /**\n     * Name of the property which should be used to override the default download url for the wrapper.\n     */\n    private static final String PROPERTY_NAME_WRAPPER_URL = \"wrapperUrl\";\n\n    public static void main( String[] args )\n    {\n        if ( args.length == 0 )\n        {\n            System.err.println( \" - ERROR projectBasedir parameter missing\" );\n            System.exit( 1 );\n        }\n\n        log( \" - Downloader started\" );\n        final String dir = args[0].replace( \"..\", \"\" ); // Sanitize path\n        final Path projectBasedir = Paths.get( dir ).toAbsolutePath().normalize();\n        if ( !Files.isDirectory( projectBasedir, LinkOption.NOFOLLOW_LINKS ) )\n        {\n            System.err.println( \" - ERROR projectBasedir not exists: \" + projectBasedir );\n            System.exit( 1 );\n        }\n\n        log( \" - Using base directory: \" + projectBasedir );\n\n        // If the maven-wrapper.properties exists, read it and check if it contains a custom\n        // wrapperUrl parameter.\n        Path mavenWrapperPropertyFile = projectBasedir.resolve( MAVEN_WRAPPER_PROPERTIES_PATH );\n        String url = readWrapperUrl( mavenWrapperPropertyFile );\n\n        try\n        {\n            Path outputFile = projectBasedir.resolve( MAVEN_WRAPPER_JAR_PATH );\n            createDirectories( outputFile.getParent() );\n            downloadFileFromURL( url, outputFile );\n            log( \"Done\" );\n            System.exit( 0 );\n        }\n        catch ( IOException e )\n        {\n            System.err.println( \"- Error downloading\" );\n            e.printStackTrace();\n            System.exit( 1 );\n        }\n    }\n\n    private static void downloadFileFromURL( String urlString, Path destination ) throws IOException\n    {\n        log( \" - Downloading to: \" + destination );\n        if ( System.getenv( \"MVNW_USERNAME\" ) != null && System.getenv( \"MVNW_PASSWORD\" ) != null )\n        {\n            final String username = System.getenv( \"MVNW_USERNAME\" );\n            final char[] password = System.getenv( \"MVNW_PASSWORD\" ).toCharArray();\n            Authenticator.setDefault( new Authenticator()\n            {\n                @Override\n                protected PasswordAuthentication getPasswordAuthentication()\n                {\n                    return new PasswordAuthentication( username, password );\n                }\n            } );\n        }\n        URL website = new URL( urlString );\n        try ( InputStream inStream = website.openStream() ) {\n            Files.copy( inStream, destination, StandardCopyOption.REPLACE_EXISTING );\n        }\n        log( \" - Downloader complete\" );\n    }\n\n    private static void createDirectories(Path outputPath) throws IOException\n    {\n        if ( !Files.isDirectory( outputPath, LinkOption.NOFOLLOW_LINKS ) ) {\n            Path createDirectories = Files.createDirectories( outputPath );\n            log( \" - Directories created: \" + createDirectories );\n        }\n    }\n\n    private static String readWrapperUrl( Path mavenWrapperPropertyFile )\n    {\n        String url = DEFAULT_DOWNLOAD_URL;\n        if ( Files.exists( mavenWrapperPropertyFile, LinkOption.NOFOLLOW_LINKS ) )\n        {\n            log( \" - Reading property file: \" + mavenWrapperPropertyFile );\n            try ( InputStream in = Files.newInputStream( mavenWrapperPropertyFile, StandardOpenOption.READ ) )\n            {\n                Properties mavenWrapperProperties = new Properties();\n                mavenWrapperProperties.load( in );\n                url = mavenWrapperProperties.getProperty( PROPERTY_NAME_WRAPPER_URL, DEFAULT_DOWNLOAD_URL );\n            }\n            catch ( IOException e )\n            {\n                System.err.println( \" - ERROR loading '\" + MAVEN_WRAPPER_PROPERTIES_PATH + \"'\" );\n            }\n        }\n        log( \" - Downloading from: \" + url );\n        return url;\n    }\n\n    private static void log( String msg )\n    {\n        if ( VERBOSE )\n        {\n            System.out.println( msg );\n        }\n    }\n\n}\n"
  },
  {
    "path": ".mvn/wrapper/maven-wrapper.properties",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\ndistributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip\nwrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar\n"
  },
  {
    "path": ".travis.yml",
    "content": "dist: trusty\n\nlanguage: java\n\njdk:\n  - oraclejdk8\n  - openjdk11\n\n# Uncomment to upload heapdumps to S3 bucket; https://docs.travis-ci.com/user/uploading-artifacts/\n#addons:\n#  artifacts:\n#    paths:\n#      - $(ls $HOME/build/mjiderhamn/classloader-leak-prevention/classloader-leak-prevention/classloader-leak-prevention-core/target/surefire-reports/*.hprof | tr \"\\n\" \":\")\n\ncache:\n  directories:\n  - $HOME/.m2\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# Classloader Leak Prevention library\n[![Build Status](https://travis-ci.org/mjiderhamn/classloader-leak-prevention.svg?branch=master)](http://travis-ci.org/mjiderhamn/classloader-leak-prevention)\n[![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/)\n[![License](https://img.shields.io/badge/license-Apache2-blue.svg?style=flat)](https://github.com/mjiderhamn/classloader-leak-prevention/blob/master/LICENSE.txt)\n\nIf you want to avoid the dreaded `java.lang.OutOfMemoryError: Metaspace` / `PermGen space`, \njust include this library into your Java EE application and it should take care of the rest!\n\nTo 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/\n\n## Servlet 3.0+\nIn a Servlet 3.0+ environment, all you need to do is include this Maven \ndependency in your `.war`:\n```xml\n<dependency>\n  <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n  <artifactId>classloader-leak-prevention-servlet3</artifactId>\n  <version>2.7.0</version>\n</dependency>\n```\n\nIf you run into problems with the Servlet 3.0 module, try the Servlet 2.5 alternative below.\nSince the [Servlet spec does not guarantee the order of `ServletContainerInitializer`s](https://java.net/jira/browse/SERVLET_SPEC-79),\nit means this library may not initialize first and clean up last in case you have other Servlet 3.0 dependencies, which\ncould lead to unexpected behaviour.\n\n## Servlet 2.5 (and earlier)\nFor Servlet 2.5 (and earlier) environments, you need to use a different\nMaven dependency (notice the difference in `artifactId`):\n```xml\n<dependency>\n  <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n  <artifactId>classloader-leak-prevention-servlet</artifactId>\n  <version>2.7.0</version>\n</dependency>\n```\n\nYou also have to add this to your `web.xml`:\n```xml\n<listener>\n  <listener-class>se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventorListener</listener-class>\n</listener>\n```\n_Note that the name of the listener class has changed since 1.x!_\n\nIt makes sense to keep this listener \"outermost\" (initializing first, \ndestroying last), so you should normally declare it before any other \nlisteners in `web.xml`.\n\n## Configuration\nThe context listener used in both cases has a number of settings that can be configured with context parameters in `web.xml`:\n \n```xml\n<context-param>\n  <param-name>ClassLoaderLeakPreventor.stopThreads</param-name>\n  <param-value>false</param-value>\n</context-param>\n```\n \n The available settings are\n <table border=\"1\">\n   <tr>\n     <th>Parameter name</th>\n     <th>Default value</th>\n     <th>Description</th>\n   </tr>\n   <tr>\n     <td><code>ClassLoaderLeakPreventor.stopThreads</code></td>\n     <td><code>true</code></td>\n     <td>Should threads tied to the web app classloader be forced to stop at application shutdown?</td>\n   </tr>\n   <tr>\n     <td><code>ClassLoaderLeakPreventor.stopTimerThreads</code></td>\n     <td><code>true</code></td>\n     <td>Should Timer threads tied to the web app classloader be forced to stop at application shutdown?</td>\n   </tr>\n   <tr>\n     <td><code>ClassLoaderLeakPreventor.executeShutdownHooks</td>\n     <td><code>true</code></td>\n     <td>Should shutdown hooks registered from the application be executed at application shutdown?</td>\n   </tr>\n   <tr>\n     <td><code>ClassLoaderLeakPreventor.startOracleTimeoutThread</td>\n     <td><code>true</code></td>\n     <td>\n       Should the <code>oracle.jdbc.driver.OracleTimeoutPollingThread</code> thread be forced to start with system ClassLoader,\n       in case Oracle JDBC driver is present? This is normally a good idea, but can be disabled in case the Oracle JDBC\n       driver is not used even though it is on the classpath.\n     </td>\n   </tr>\n   <tr>\n     <td><code>ClassLoaderLeakPreventor.threadWaitMs</td>\n     <td nowrap=\"nowrap\"><code>5000</code><br />(5 seconds)</td>\n     <td>No of milliseconds to wait for threads to finish execution, before stopping them.</td>\n   </tr>\n   <tr>\n     <td><code>ClassLoaderLeakPreventor.shutdownHookWaitMs</code></td>\n     <td nowrap=\"nowrap\"><code>10000</code><br />(10 seconds)</td>\n     <td>\n       No of milliseconds to wait for shutdown hooks to finish execution, before stopping them.\n       If set to -1 there will be no waiting at all, but Thread is allowed to run until finished.\n     </td>\n   </tr>\n </table>\n\n## Classloader leak detection / test framework\n\nThe test framework has its own Maven module and its own documentation, see [classloader-leak-test-framework](classloader-leak-test-framework).\n\n## Integration\n\nFor non-servlet environments, please see the documentation for the [core module](classloader-leak-prevention/classloader-leak-prevention-core).\n\n## License\n\nThis 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.\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/README.md",
    "content": "# Classloader Leak Prevention library integration\n\n_This document is about using the Classloader Leak Prevention library in\na non-servlet environment. For general information and use in servlet \nenvironments, please see the [root README.md](../../README.md)_\n\nVersion 2.x of the Classloader Leak Prevention library has been refactored\nto allow for use outside a servlet environment, or by all means in a\nservlet container (Java EE application server).\n\n# Setting up\nWhat you will want to do is first create a [ClassLoaderLeakPreventorFactory](src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorFactory.java)\ninstance, either by using the default constructor that will configure the system\n`ClassLoader` (`ClassLoader.getSystemClassLoader()`) to be used for pre-inits,\nor provide your own leak safe `ClassLoader` to the constructor.\n\nMake any configurations on the factory instance, i.e. add or remove any\n[cleanup](src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderPreMortemCleanUp.java)\nor [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)\nplugins, or change parameters of any of the default plugins.\n\n# Protect ClassLoader\nThen for every `ClassLoader` that needs leak protection, create a new\n[ClassLoaderLeakPreventor](src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventor.java)\nusing\n```java\nclassLoaderLeakPreventor = classLoaderLeakPreventorFactory.newLeakPreventor(classLoader);\n```\n \nBefore letting any code execute inside the `ClassLoader` (or at least as\nsoon as possible), invoke\n```java\nclassLoaderLeakPreventor.runPreClassLoaderInitiators();\n```\n \nYou can reuse the same `ClassLoaderLeakPreventorFactory` for multiple\n`ClassLoaders`, but please be aware that any configuration changes made\nto plugins of the factory will affect all `ClassLoaderLeakPreventor`s \ncreated by the factory - both future and existing. If however you add\nor remove plugins, that will only affect new `ClassLoaderLeakPreventor`s. \n\n# Shutting down\nWhen you believe the `ClassLoader` should no longer be used, but be ready\nfor Garbage Collection, invoke \n```java\nclassLoaderLeakPreventor.runCleanUps();\n```\non the `ClassLoaderLeakPreventor` that corresponds to the `ClassLoader`.\n\n# Example\nFor an example how to use the framework, feel free to study the\n[ClassLoaderLeakPreventorListener](../classloader-leak-prevention-servlet/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorListener.java)\nin the `classloader-leak-prevention-servlet` module.\n\n# Maven\nThe module is available in Maven as\n```xml\n<dependency>\n  <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n  <artifactId>classloader-leak-prevention-core</artifactId>\n  <version>2.7.0</version>\n</dependency>\n```"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/pom.xml",
    "content": "<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\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n    <artifactId>classloader-leak-prevention-parent</artifactId>\n    <version>2.7.1-SNAPSHOT</version>\n  </parent>\n\n  <artifactId>classloader-leak-prevention-core</artifactId>\n  <packaging>jar</packaging>\n  <name>ClassLoader Leak Prevention library</name>\n  <description>Library that prevents ClassLoader leaks / java.lang.OutOfMemoryError: PermGen space</description>\n  <url>https://github.com/mjiderhamn/classloader-leak-prevention</url>\n  \n  <dependencies>\n    <!-- Dependency on test framework -->\n    <dependency>\n      <groupId>se.jiderhamn</groupId>\n      <artifactId>classloader-leak-test-framework</artifactId>\n      <version>1.1.2</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Required by some of the tested APIs --> \n    <dependency>\n      <groupId>commons-logging</groupId>\n      <artifactId>commons-logging</artifactId>\n      <version>1.1.3</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Validation API needed for testing leak -->\n    <dependency>\n      <groupId>javax.validation</groupId>\n      <artifactId>validation-api</artifactId>\n      <version>1.0.0.GA</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.hibernate</groupId>\n      <artifactId>hibernate-validator</artifactId>\n      <version>4.2.0.Final</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Apache Axis 1.4 for leak test -->\n    <dependency>\n      <groupId>org.apache.axis</groupId>\n      <artifactId>axis</artifactId>\n      <version>1.4</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Required by Axis -->\n    <dependency>\n      <groupId>commons-discovery</groupId>\n      <artifactId>commons-discovery</artifactId>\n      <version>0.5</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- JDBC driver for DriverManager test -->\n    <dependency>\n      <groupId>mysql</groupId>\n      <artifactId>mysql-connector-java</artifactId>\n      <version>5.1.18</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Test leak in EL implementation cache -->\n    <dependency>\n      <groupId>javax.el</groupId>\n      <artifactId>el-api</artifactId>\n      <version>2.2.1-b04</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- MultiThreadedHttpConnectionManagerCleanUpTest --> \n    <dependency>\n      <groupId>com.sun.jersey.contribs</groupId>\n      <artifactId>jersey-apache-client</artifactId>\n      <version>1.19</version>\n      <scope>test</scope>\n    </dependency> \n    \n    <!-- Test leak in CXF custom authenticator -->\n    <dependency>\n      <groupId>org.apache.cxf</groupId>\n      <artifactId>cxf-rt-transports-http</artifactId>\n      <version>2.6.10</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Test that GeoTools leaks are prevented -->\n    <dependency>\n      <groupId>org.geotools</groupId>\n      <artifactId>gt-metadata</artifactId>\n      <version>2.6.2</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Test leak in JSF api -->\n    <dependency>\n      <groupId>com.sun.faces</groupId>\n      <artifactId>jsf-api</artifactId>\n      <version>2.1.19</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Could be removed if Mockito was used to mock ELContext -->\n    <dependency>\n      <groupId>com.sun.faces</groupId>\n      <artifactId>jsf-impl</artifactId>\n      <version>2.1.19</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.postgresql</groupId>\n      <artifactId>postgresql</artifactId>\n      <version>9.4-1201-jdbc41</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Test that MOXy leaks are prevented -->\n    <dependency>\n      <groupId>org.eclipse.persistence</groupId>\n      <artifactId>org.eclipse.persistence.moxy</artifactId>\n      <version>2.7.0</version>\n      <scope>test</scope>\n    </dependency>\n    <!-- Test that Jackson leaks are prevented -->\n    <dependency>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <artifactId>jackson-databind</artifactId>\n      <version>2.9.2</version>\n      <scope>test</scope>\n    </dependency>\n    \n    <!-- Example dependency for test Oracle JDBC -->\n    <!--\n    <dependency>\n      <groupId>com.oracle</groupId>\n      <artifactId>ojdbc</artifactId>\n      <version>12.2.0.1</version>\n      <scope>test</scope>\n    </dependency>\n    -->\n\n    <!-- Internal APIs that have been removed from the JDK in java 11. -->\n    <!-- Used for testing SAAJEnvelopeFactoryParserPoolCleanUp. -->\n    <dependency>\n      <groupId>com.sun.xml.messaging.saaj</groupId>\n      <artifactId>saaj-impl</artifactId>\n      <version>1.4.0</version>\n      <scope>provided</scope>\n    </dependency>\n    \n    <!-- Internal APIs that have been removed from the JDK in java 11. Used for MoxyCleanUpTest -->\n    <dependency>\n      <groupId>javax.xml.bind</groupId>\n      <artifactId>jaxb-api</artifactId>\n      <version>2.2.11</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.sun.xml.bind</groupId>\n      <artifactId>jaxb-core</artifactId>\n      <version>2.2.11</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.sun.xml.bind</groupId>\n      <artifactId>jaxb-impl</artifactId>\n      <version>2.2.11</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>javax.activation</groupId>\n      <artifactId>activation</artifactId>\n      <version>1.1.1</version>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <!-- Create artifact (jar) with test classes https://maven.apache.org/guides/mini/guide-attached-tests.html -->\n  <build>\n    <plugins>\n     <plugin>\n       <groupId>org.apache.maven.plugins</groupId>\n       <artifactId>maven-jar-plugin</artifactId>\n       <version>3.0.2</version>\n       <executions>\n         <execution>\n           <goals>\n             <goal>test-jar</goal>\n           </goals>\n         </execution>\n       </executions>\n     </plugin>\n    </plugins>\n  </build>\n</project>"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventor.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.RuntimeMXBean;\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.security.*;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * This class helps prevent classloader leaks.\n * @author Mattias Jiderhamn\n */\n@SuppressWarnings(\"WeakerAccess\")\npublic class ClassLoaderLeakPreventor {\n\n  /** Default no of milliseconds to wait for threads to finish execution */\n  public static final int THREAD_WAIT_MS_DEFAULT = 5 * 1000; // 5 seconds\n  \n  private static final ProtectionDomain[] NO_DOMAINS = new ProtectionDomain[0];\n\n  private static final AccessControlContext NO_DOMAINS_ACCESS_CONTROL_CONTEXT = new AccessControlContext(NO_DOMAINS);\n\n  /** {@link ClassLoader#isAncestor(ClassLoader)} */\n  private final Method java_lang_ClassLoader_isAncestor;\n  \n  /** {@link ClassLoader#isAncestorOf(ClassLoader)} of IBM JRE */\n  private final Method java_lang_ClassLoader_isAncestorOf;\n  \n  private final Field java_security_AccessControlContext$combiner;\n  \n  private final Field java_security_AccessControlContext$parent;\n  \n  private final Field java_security_AccessControlContext$privilegedContext;\n\n  /** \n   * {@link ClassLoader} to be used when invoking the {@link PreClassLoaderInitiator}s.\n   * This will normally be the {@link ClassLoader#getSystemClassLoader()}, but could be any other framework or \n   * app server classloader. Normally, but not necessarily, a parent of {@link #classLoader}.\n   */\n  private final ClassLoader leakSafeClassLoader;\n  \n  /** The {@link ClassLoader} we want to avoid leaking */\n  private final ClassLoader classLoader;\n  \n  private final Logger logger;\n  \n  private final Collection<PreClassLoaderInitiator> preClassLoaderInitiators;\n  \n  private final Collection<ClassLoaderPreMortemCleanUp> cleanUps;\n  \n  /** {@link DomainCombiner} that filters any {@link ProtectionDomain}s loaded by our classloader */\n  private final DomainCombiner domainCombiner;\n\n  public ClassLoaderLeakPreventor(ClassLoader leakSafeClassLoader, ClassLoader classLoader, Logger logger,\n                           Collection<PreClassLoaderInitiator> preClassLoaderInitiators,\n                           Collection<ClassLoaderPreMortemCleanUp> cleanUps) {\n    this.leakSafeClassLoader = leakSafeClassLoader;\n    this.classLoader = classLoader;\n    this.logger = logger;\n    this.preClassLoaderInitiators = preClassLoaderInitiators;\n    this.cleanUps = cleanUps;\n\n    final String javaVendor = System.getProperty(\"java.vendor\");\n    if(javaVendor != null && javaVendor.startsWith(\"IBM\")) { // IBM\n      java_lang_ClassLoader_isAncestor = null;\n      java_lang_ClassLoader_isAncestorOf = findMethod(ClassLoader.class, \"isAncestorOf\", ClassLoader.class);\n    }\n    else { // Oracle\n      java_lang_ClassLoader_isAncestor = findMethod(ClassLoader.class, \"isAncestor\", ClassLoader.class);\n      java_lang_ClassLoader_isAncestorOf = null;\n    }\n    NestedProtectionDomainCombinerException.class.getName(); // Should be loaded before switching to leak safe classloader\n    \n    this.domainCombiner = createDomainCombiner();\n\n    // Reflection inits\n    java_security_AccessControlContext$combiner = findField(AccessControlContext.class, \"combiner\");\n    java_security_AccessControlContext$parent = findField(AccessControlContext.class, \"parent\");\n    java_security_AccessControlContext$privilegedContext = findField(AccessControlContext.class, \"privilegedContext\");\n\n  }\n  \n  /** Invoke all the registered {@link PreClassLoaderInitiator}s in the {@link #leakSafeClassLoader} */\n  public void runPreClassLoaderInitiators() {\n    info(\"Initializing by loading some known offenders with leak safe classloader\"); \n    \n    doInLeakSafeClassLoader(new Runnable() {\n      @Override\n      public void run() {\n        for(PreClassLoaderInitiator preClassLoaderInitiator : preClassLoaderInitiators) {\n          preClassLoaderInitiator.doOutsideClassLoader(ClassLoaderLeakPreventor.this);\n        }\n      }\n    });\n  }\n  \n  /**\n   * Perform action in the provided ClassLoader (normally system ClassLoader, that may retain references to the \n   * {@link Thread#contextClassLoader}. \n   * The motive for the custom {@link AccessControlContext} is to avoid spawned threads from inheriting all the \n   * {@link java.security.ProtectionDomain}s of the running code, since that may include the classloader we want to \n   * avoid leaking. This however means the {@link AccessControlContext} will have a {@link DomainCombiner} referencing the \n   * classloader, which will be taken care of in {@link #runCleanUps()}.\n   */\n   protected void doInLeakSafeClassLoader(final Runnable runnable) {\n     final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();\n     \n     try {\n       Thread.currentThread().setContextClassLoader(leakSafeClassLoader);\n \n       // Use doPrivileged() not to perform secured actions, but to avoid threads spawned inheriting the \n       // AccessControlContext of the current thread, since among the ProtectionDomains there will be one\n       // (the top one) whose classloader is the web app classloader\n       AccessController.doPrivileged(new PrivilegedAction<Object>() {\n         @Override\n         public Object run() {\n           runnable.run();\n           return null; // Nothing to return\n         }\n       }, createAccessControlContext());\n     }\n     finally {\n       // Reset original classloader\n       Thread.currentThread().setContextClassLoader(contextClassLoader);\n     }\n   }\n   \n   /** \n    * Create {@link AccessControlContext} that is used in {@link #doInLeakSafeClassLoader(Runnable)}.\n    * The motive is to avoid spawned threads from inheriting all the {@link java.security.ProtectionDomain}s of the \n    * running code, since that will include the web app classloader.\n    */\n   public AccessControlContext createAccessControlContext() {\n     try { // Try the normal way\n       return new AccessControlContext(NO_DOMAINS_ACCESS_CONTROL_CONTEXT, domainCombiner);\n     }\n     catch (SecurityException e) { // createAccessControlContext not granted\n       try { // Try reflection\n         Constructor<AccessControlContext> constructor = \n             AccessControlContext.class.getDeclaredConstructor(ProtectionDomain[].class, DomainCombiner.class);\n         constructor.setAccessible(true);\n         return constructor.newInstance(NO_DOMAINS, domainCombiner);\n       }\n       catch (Exception e1) {\n         logger.error(\"createAccessControlContext not granted and AccessControlContext could not be created via reflection\");\n         return AccessController.getContext();\n       }\n     }\n   } \n   \n   /** {@link DomainCombiner} that filters any {@link ProtectionDomain}s loaded by our classloader */\n   private DomainCombiner createDomainCombiner() {\n     return new DomainCombiner() {\n       \n       /** Flag to detected recursive calls */\n       private final ThreadLocal<Boolean> isExecuting = new ThreadLocal<Boolean>();\n       \n       @Override\n       public ProtectionDomain[] combine(ProtectionDomain[] currentDomains, ProtectionDomain[] assignedDomains) {\n         if(assignedDomains != null && assignedDomains.length > 0) {\n           logger.error(\"Unexpected assignedDomains - please report to developer of this library!\");\n         }\n \n         if(isExecuting.get() == Boolean.TRUE)\n           throw new NestedProtectionDomainCombinerException();\n           \n         try {\n           isExecuting.set(Boolean.TRUE); // Throw NestedProtectionDomainCombinerException on nested calls\n\n           // Keep all ProtectionDomain not involving the web app classloader \n           final List<ProtectionDomain> output = new ArrayList<ProtectionDomain>();\n           for(ProtectionDomain protectionDomain : currentDomains) {\n             if(protectionDomain.getClassLoader() == null ||\n                 ! isClassLoaderOrChild(protectionDomain.getClassLoader())) {\n               output.add(protectionDomain);\n             }\n           }\n           return output.toArray(new ProtectionDomain[output.size()]);\n         }\n         finally {\n           isExecuting.remove();\n         }\n       }\n     };\n   }  \n  \n  /** \n   * Recursively unset our custom {@link DomainCombiner} (loaded in the web app) from the {@link AccessControlContext} \n   * and any parents or privilegedContext thereof.\n   */\n  @Deprecated\n  public void removeDomainCombiner(Thread thread, AccessControlContext accessControlContext) {\n    removeDomainCombiner(\"thread \" + thread, accessControlContext);\n  }\n  \n  /** \n   * Recursively unset our custom {@link DomainCombiner} (loaded in the web app) from the {@link AccessControlContext} \n   * and any parents or privilegedContext thereof.\n   */\n  public void removeDomainCombiner(String owner, AccessControlContext accessControlContext) {\n    if(accessControlContext != null && java_security_AccessControlContext$combiner != null) {\n      if(getFieldValue(java_security_AccessControlContext$combiner, accessControlContext) == this.domainCombiner) {\n        warn(AccessControlContext.class.getSimpleName() + \" of \" + owner + \" used custom combiner - unsetting\");\n        try {\n          java_security_AccessControlContext$combiner.set(accessControlContext, null);\n        }\n        catch (Exception e) {\n          error(e);\n        }\n      }\n      \n      // Recurse\n      if(java_security_AccessControlContext$parent != null) {\n        removeDomainCombiner(owner, (AccessControlContext) getFieldValue(java_security_AccessControlContext$parent, accessControlContext));\n      }\n      if(java_security_AccessControlContext$privilegedContext != null) {\n        removeDomainCombiner(owner, (AccessControlContext) getFieldValue(java_security_AccessControlContext$privilegedContext, accessControlContext));\n      }\n    }\n  }\n  \n  \n  /** Invoke all the registered {@link ClassLoaderPreMortemCleanUp}s */\n  public void runCleanUps() {\n    if(isJvmShuttingDown()) {\n      info(\"JVM is shutting down - skip cleanup\");\n      // Don't do anything more\n    }\n    else {\n      final Field inheritedAccessControlContext = this.findField(Thread.class, \"inheritedAccessControlContext\");\n      if(inheritedAccessControlContext != null) {\n        // Check if threads have been started in doInLeakSafeClassLoader() and need fixed ACC\n        for(Thread thread : getAllThreads()) { // (We actually only need to do this for threads not running in web app, as per StopThreadsCleanUp) \n          final AccessControlContext accessControlContext = getFieldValue(inheritedAccessControlContext, thread);\n          removeDomainCombiner(\"thread \" + thread , accessControlContext);\n        }\n      }\n      \n      for(ClassLoaderPreMortemCleanUp cleanUp : cleanUps) {\n        cleanUp.cleanUp(this);\n      }\n    }\n  }\n  \n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  // Utility methods\n\n  public ClassLoader getClassLoader() {\n    return classLoader;\n  }\n\n  /**\n   * Get {@link ClassLoader} to be used when invoking the {@link PreClassLoaderInitiator}s.\n   * This will normally be the {@link ClassLoader#getSystemClassLoader()}, but could be any other framework or \n   * app server classloader. Normally, but not necessarily, a parent of {@link #classLoader}.\n   */\n  public ClassLoader getLeakSafeClassLoader() {\n    return leakSafeClassLoader;\n  }\n\n  /** Test if provided object is loaded by {@link #classLoader} */\n  public boolean isLoadedInClassLoader(Object o) {\n    return (o instanceof Class) && isLoadedByClassLoader((Class<?>)o) || // Object is a java.lang.Class instance \n        o != null && isLoadedByClassLoader(o.getClass());\n  }\n\n  /** Test if provided class is loaded wby {@link #classLoader} */\n  public boolean isLoadedByClassLoader(Class<?> clazz) {\n    return clazz != null && isClassLoaderOrChild(clazz.getClassLoader());\n  }\n\n  /** Test if provided ClassLoader is the {@link #classLoader}, or a child thereof */\n  public boolean isClassLoaderOrChild(ClassLoader cl) {\n    if(cl == null) {\n      return false;\n    }\n    else if(cl == classLoader) {\n      return true;\n    }\n    else { // It could be a child of the webapp classloader\n      if(java_lang_ClassLoader_isAncestor != null) { // Primarily use ClassLoader.isAncestor()\n        try {\n          return (Boolean) java_lang_ClassLoader_isAncestor.invoke(cl, classLoader);\n        }\n        catch (Exception e) {\n          error(e);\n        }\n      }\n\n      if(java_lang_ClassLoader_isAncestorOf != null) { // Secondarily use IBM ClassLoader.isAncestorOf()\n        try {\n          return (Boolean) java_lang_ClassLoader_isAncestorOf.invoke(classLoader, cl);\n        }\n        catch (Exception e) {\n          error(e);\n        }\n      }\n\n      // We were unable to use ClassLoader.isAncestor() or isAncestorOf()\n      try {\n        while(cl != null) {\n          if(cl == classLoader)\n            return true;\n\n          cl = cl.getParent();\n        }\n      }\n      catch (NestedProtectionDomainCombinerException e) {\n        return false; // Since we needed permission to call getParent(), it is unlikely it is a descendant\n      }\n      return false;\n    }\n  }\n\n  /**\n   * Is the {@link Thread} ties do the protected classloader, either by being a custom {@link Thread} class, having a \n   * custom {@link ThreadGroup} or having the protected classloader as its {@link Thread#contextClassLoader}?\n   */\n  public boolean isThreadInClassLoader(Thread thread) {\n    return isLoadedInClassLoader(thread) || // Custom Thread class in classloader\n       isLoadedInClassLoader(thread.getThreadGroup()) || // Custom ThreadGroup class in classloader \n       isClassLoaderOrChild(thread.getContextClassLoader()); // Running in classloader\n  }\n  \n  /**\n   * Make the provided Thread stop sleep(), wait() or join() and then give it the provided no of milliseconds to finish\n   * executing. \n   * @param thread The thread to wake up and wait for\n   * @param waitMs The no of milliseconds to wait. If <= 0 this method does nothing.\n   * @param interrupt Should {@link Thread#interrupt()} be called first, to make thread stop sleep(), wait() or join()?               \n   */\n  public void waitForThread(Thread thread, long waitMs, boolean interrupt) {\n    if(waitMs > 0) {\n      if(interrupt) {\n        try {\n          thread.interrupt(); // Make Thread stop waiting in sleep(), wait() or join()\n        }\n        catch (SecurityException e) {\n          error(e);\n        }\n      }\n\n      try {\n        thread.join(waitMs); // Wait for thread to run\n      }\n      catch (InterruptedException e) {\n        // Do nothing\n      }\n    }\n  }\n  \n  /** Get current stack trace or provided thread as string. Returns {@code \"unavailable\"} if stack trace could not be acquired. */\n  public String getStackTrace(Thread thread) {\n    try {\n      final StackTraceElement[] stackTrace = thread.getStackTrace();\n      if(stackTrace.length == 0)\n        return \"Thread state: \" + thread.getState();\n\n      final StringBuilder output = new StringBuilder(\"Thread stack trace: \");\n      for(StackTraceElement stackTraceElement : stackTrace) {\n        // if(output.length() > 0) // Except first\n          output.append(\"\\n\\tat \");\n        output.append(stackTraceElement.toString());\n      }\n      return output.toString().trim(); // \n    }\n    catch (Throwable t) { // SecurityException\n      return \"Thread details unavailable\";\n    }\n  }\n  \n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  \n  public <E> E getStaticFieldValue(Class<?> clazz, String fieldName) {\n    Field staticField = findField(clazz, fieldName);\n    return (staticField != null) ? (E) getStaticFieldValue(staticField) : null;\n  }\n\n  public <E> E getStaticFieldValue(String className, String fieldName) {\n    return (E) getStaticFieldValue(className, fieldName, false);\n  }\n  \n  public <E> E getStaticFieldValue(String className, String fieldName, boolean trySystemCL) {\n    Field staticField = findFieldOfClass(className, fieldName, trySystemCL);\n    return (staticField != null) ? (E) getStaticFieldValue(staticField) : null;\n  }\n  \n  public Field findFieldOfClass(String className, String fieldName) {\n    return findFieldOfClass(className, fieldName, false);\n  }\n  \n  public Field findFieldOfClass(String className, String fieldName, boolean trySystemCL) {\n    Class<?> clazz = findClass(className, trySystemCL);\n    if(clazz != null) {\n      return findField(clazz, fieldName);\n    }\n    else\n      return null;\n  }\n  \n  public Class<?> findClass(String className) {\n    return findClass(className, false);\n  }\n  \n  public Class<?> findClass(String className, boolean trySystemCL) {\n    try {\n      return Class.forName(className);\n    }\n//    catch (NoClassDefFoundError e) {\n//      // Silently ignore\n//      return null;\n//    }\n    catch (ClassNotFoundException e) {\n      if (trySystemCL) {\n        try {\n          return Class.forName(className, true, ClassLoader.getSystemClassLoader());\n        } catch (ClassNotFoundException e1) {\n          // Silently ignore\n          return null;\n        }\n      }\n      // Silently ignore\n      return null;\n    }\n    catch (Exception ex) { // Example SecurityException\n      warn(ex);\n      return null;\n    }\n  }\n  \n  public Field findField(Class<?> clazz, String fieldName) {\n    if(clazz == null)\n      return null;\n\n    try {\n      final Field field = clazz.getDeclaredField(fieldName);\n      field.setAccessible(true); // (Field is probably private) \n      return field;\n    }\n    catch (NoSuchFieldException ex) {\n      // Silently ignore\n      return null;\n    }\n    catch (Exception ex) { // Example SecurityException\n      warn(ex);\n      return null;\n    }\n  }\n  \n  public <T> T getStaticFieldValue(Field field) {\n    try {\n      if(! Modifier.isStatic(field.getModifiers())) {\n        warn(field.toString() + \" is not static\");\n        return null;\n      }\n      \n      return (T) field.get(null);\n    }\n    catch (Exception ex) {\n      warn(ex);\n      // Silently ignore\n      return null;\n    }\n  }\n  \n  public <T> T getFieldValue(Object obj, String fieldName) {\n    final Field field = findField(obj.getClass(), fieldName);\n    return (T) getFieldValue(field, obj);\n  }\n  \n  public <T> T getFieldValue(Field field, Object obj) {\n    try {\n      return (T) field.get(obj);\n    }\n    catch (Exception ex) {\n      warn(ex);\n      // Silently ignore\n      return null;\n    }\n  }\n  \n  public void setFinalStaticField(Field field, Object newValue) {\n    // Allow modification of final field \n    try {\n      Field modifiersField = Field.class.getDeclaredField(\"modifiers\");\n      modifiersField.setAccessible(true);\n      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);\n    }\n    catch (NoSuchFieldException e) {\n      warn(\"Unable to get 'modifiers' field of java.lang.Field\");\n    }\n    catch (IllegalAccessException e) {\n      warn(\"Unable to set 'modifiers' field of java.lang.Field\");\n    }\n    catch (Throwable t) {\n      warn(t);\n    }\n\n    // Update the field\n    try {\n      field.set(null, newValue);\n    }\n    catch (Throwable e) {\n      error(\"Error setting value of \" + field + \" to \" + newValue);\n    }\n  }\n  \n  public Method findMethod(String className, String methodName, Class... parameterTypes) {\n    Class<?> clazz = findClass(className);\n    if(clazz != null) {\n      return findMethod(clazz, methodName, parameterTypes);\n    }\n    else \n      return null;\n  }\n  \n  public Method findMethod(Class<?> clazz, String methodName, Class... parameterTypes) {\n    if(clazz == null)\n      return null;\n\n    try {\n      final Method method = clazz.getDeclaredMethod(methodName, parameterTypes);\n      method.setAccessible(true);\n      return method;\n    }\n    catch (NoSuchMethodException ex) {\n      warn(ex);\n      // Silently ignore\n      return null;\n    }\n  }\n\n  /** Get a Collection with all Threads. \n   * This method is heavily inspired by org.apache.catalina.loader.WebappClassLoader.getThreads() */\n  public Collection<Thread> getAllThreads() {\n    // This is some orders of magnitude slower...\n    // return Thread.getAllStackTraces().keySet();\n    \n    // Find root ThreadGroup\n    ThreadGroup tg = Thread.currentThread().getThreadGroup();\n    while(tg.getParent() != null)\n      tg = tg.getParent();\n    \n    // Note that ThreadGroup.enumerate() silently ignores all threads that does not fit into array\n    int guessThreadCount = tg.activeCount() + 50;\n    Thread[] threads = new Thread[guessThreadCount];\n    int actualThreadCount = tg.enumerate(threads);\n    while(actualThreadCount == guessThreadCount) { // Map was filled, there may be more\n      guessThreadCount *= 2;\n      threads = new Thread[guessThreadCount];\n      actualThreadCount = tg.enumerate(threads);\n    }\n    \n    // Filter out nulls\n    final List<Thread> output = new ArrayList<Thread>();\n    for(Thread t : threads) {\n      if(t != null) {\n        output.add(t);\n      }\n    }\n    return output;\n  }\n  \n  /**\n   * Override this method if you want to customize how we determine if we're running in\n   * JBoss WildFly (a.k.a JBoss AS).\n   */\n  public boolean isJBoss() {\n    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();\n    \n    try {\n      // If package org.jboss is found, we may be running under JBoss\n      return (contextClassLoader.getResource(\"org/jboss\") != null);\n    }\n    catch(Exception ex) {\n      return false;\n    }\n  }\n  \n  /**\n   * Are we running in the Oracle/Sun Java Runtime Environment?\n   * Override this method if you want to customize how we determine if this is a Oracle/Sun\n   * Java Runtime Environment.\n   */\n  public boolean isOracleJRE() {\n    String javaVendor = System.getProperty(\"java.vendor\");\n    \n    return javaVendor.startsWith(\"Oracle\") || javaVendor.startsWith(\"Sun\");\n  }\n\n  /**\n   * Unlike <code>{@link System#gc()}</code> this method guarantees that garbage collection has been performed before\n   * returning.\n   */\n  public static void gc() {\n    if (isDisableExplicitGCEnabled()) {\n      System.err.println(ClassLoaderLeakPreventor.class.getSimpleName() + \": \"\n          + \"Skipping GC call since -XX:+DisableExplicitGC is supplied as VM option.\");\n      return;\n    }\n    \n    Object obj = new Object();\n    WeakReference<Object> ref = new WeakReference<Object>(obj);\n    //noinspection UnusedAssignment\n    obj = null;\n    while(ref.get() != null) {\n      System.gc();\n    }\n  }\n  \n  /**\n   * Check is \"-XX:+DisableExplicitGC\" enabled.\n   *\n   * @return true is \"-XX:+DisableExplicitGC\" is set als vm argument, false otherwise.\n   */\n  private static boolean isDisableExplicitGCEnabled() {\n    RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();\n    List<String> aList = bean.getInputArguments();\n\n    return aList.contains(\"-XX:+DisableExplicitGC\");\n  }  \n\n  /** Is the JVM currently shutting down? */\n  public boolean isJvmShuttingDown() {\n    try {\n      final Thread dummy = new Thread(); // Will never be started\n      Runtime.getRuntime().removeShutdownHook(dummy);\n      return false;\n    }\n    catch (IllegalStateException isex) {\n      return true; // Shutting down\n    }\n    catch (Throwable t) { // Any other Exception, assume we are not shutting down\n      return false;\n    }\n  }\n\n  /**\n   * Exception thrown when {@link DomainCombiner#combine(ProtectionDomain[], ProtectionDomain[])} is called recursively\n   * during the execution of that same method.\n   */\n  private static class NestedProtectionDomainCombinerException extends RuntimeException {\n\n  }\n\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  // Delegate methods for Logger\n\n\n  public void debug(String msg) {\n    logger.debug(msg);\n  }\n\n  public void warn(Throwable t) {\n    logger.warn(t);\n  }\n\n  public void error(Throwable t) {\n    logger.error(t);\n  }\n\n  public void warn(String msg) {\n    logger.warn(msg);\n  }\n\n  public void error(String msg) {\n    logger.error(msg);\n  }\n\n  public void info(String msg) {\n    logger.info(msg);\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorFactory.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport se.jiderhamn.classloader.leak.prevention.cleanup.*;\nimport se.jiderhamn.classloader.leak.prevention.preinit.*;\n\nimport static java.util.Collections.synchronizedMap;\n\n/**\n * Orchestrator class responsible for invoking the preventative and cleanup measures.\n * Contains the configuration and can be reused for multiple classloaders (assume it is not itself loaded by the\n * classloader which we want to avoid leaking). In that case, the {@link #logger} may need to be thread safe.\n * @author Mattias Jiderhamn\n */\npublic class ClassLoaderLeakPreventorFactory {\n  \n  /** \n   * {@link ClassLoader} to be used when invoking the {@link PreClassLoaderInitiator}s.\n   * Defaults to {@link ClassLoader#getSystemClassLoader()}, but could be any other framework or \n   * app server classloader.\n   */\n  protected final ClassLoader leakSafeClassLoader;\n  \n  /** \n   * The {@link Logger} that will be passed on to the different {@link PreClassLoaderInitiator}s and \n   * {@link ClassLoaderPreMortemCleanUp}s \n   */\n  protected Logger logger = new JULLogger();\n\n  /** \n   * Map from name to {@link PreClassLoaderInitiator}s with all the actions to invoke in the \n   * {@link #leakSafeClassLoader}. Maintains insertion order. Thread safe.\n   */\n  protected final Map<String, PreClassLoaderInitiator> preInitiators =\n      synchronizedMap(new LinkedHashMap<String, PreClassLoaderInitiator>());\n\n  /** \n   * Map from name to {@link ClassLoaderPreMortemCleanUp}s with all the actions to invoke to make a \n   * {@link ClassLoader} ready for Garbage Collection. Maintains insertion order. Thread safe.\n   */\n  protected final Map<String, ClassLoaderPreMortemCleanUp> cleanUps = \n      synchronizedMap(new LinkedHashMap<String, ClassLoaderPreMortemCleanUp>());\n\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  // Constructors\n  \n  /** \n   * Create new {@link ClassLoaderLeakPreventorFactory} with {@link ClassLoader#getSystemClassLoader()} as the \n   * {@link #leakSafeClassLoader} and default {@link PreClassLoaderInitiator}s and {@link ClassLoaderPreMortemCleanUp}s. \n   */\n  public ClassLoaderLeakPreventorFactory() {\n    this(ClassLoader.getSystemClassLoader());\n  }\n\n  /** \n   * Create new {@link ClassLoaderLeakPreventorFactory} with supplied {@link ClassLoader} as the \n   * {@link #leakSafeClassLoader} and default {@link PreClassLoaderInitiator}s and {@link ClassLoaderPreMortemCleanUp}s.  \n   */\n  public ClassLoaderLeakPreventorFactory(ClassLoader leakSafeClassLoader) {\n    this.leakSafeClassLoader = leakSafeClassLoader;\n    configureDefaults();\n  }\n  \n  /** Configure default {@link PreClassLoaderInitiator}s and {@link ClassLoaderPreMortemCleanUp}s */\n  public void configureDefaults() {\n    // The pre-initiators part is heavily inspired by Tomcats JreMemoryLeakPreventionListener  \n    // See http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java?view=markup\n    this.addPreInitiator(new AwtToolkitInitiator());\n    // initSecurityProviders()\n    this.addPreInitiator(new JdbcDriversInitiator());\n    this.addPreInitiator(new SunAwtAppContextInitiator());\n    this.addPreInitiator(new SecurityPolicyInitiator());\n    this.addPreInitiator(new SecurityProvidersInitiator());\n    this.addPreInitiator(new DocumentBuilderFactoryInitiator());\n    this.addPreInitiator(new ReplaceDOMNormalizerSerializerAbortException());\n    this.addPreInitiator(new DatatypeConverterImplInitiator());\n    this.addPreInitiator(new JavaxSecurityLoginConfigurationInitiator());\n    this.addPreInitiator(new JarUrlConnectionInitiator());\n    // Load Sun specific classes that may cause leaks\n    this.addPreInitiator(new LdapPoolManagerInitiator());\n    this.addPreInitiator(new Java2dDisposerInitiator());\n    this.addPreInitiator(new Java2dRenderQueueInitiator());\n    this.addPreInitiator(new SunGCInitiator());\n    this.addPreInitiator(new OracleJdbcThreadInitiator());\n\n    this.addCleanUp(new BeanIntrospectorCleanUp());\n    this.addCleanUp(new ObjectStreamClassCleanup());\n    \n    // Apache Commons Pool can leave unfinished threads. Anything specific we can do?\n    this.addCleanUp(new BeanELResolverCleanUp());\n    this.addCleanUp(new BeanValidationCleanUp());\n    this.addCleanUp(new JacksonCleanUp());\n    this.addCleanUp(new JavaServerFaces2746CleanUp());\n    this.addCleanUp(new GeoToolsCleanUp());\n    // Can we do anything about Google Guice ?\n    // Can we do anything about Groovy http://jira.codehaus.org/browse/GROOVY-4154 ?\n    this.addCleanUp(new IntrospectionUtilsCleanUp());\n    // Can we do anything about Logback http://jira.qos.ch/browse/LBCORE-205 ?\n    this.addCleanUp(new IIOServiceProviderCleanUp()); // clear ImageIO registry\n    this.addCleanUp(new MoxyCleanUp());\n    this.addCleanUp(new ReactorNettyHttpResourcesCleanUp());\n    this.addCleanUp(new ThreadGroupContextCleanUp());\n    this.addCleanUp(new X509TrustManagerImplUnparseableExtensionCleanUp());\n    this.addCleanUp(new SAAJEnvelopeFactoryParserPoolCleanUp());\n    \n    ////////////////////\n    // Fix generic leaks\n    this.addCleanUp(new DriverManagerCleanUp());\n    \n    this.addCleanUp(new DefaultAuthenticatorCleanUp());\n\n    this.addCleanUp(new MBeanCleanUp());\n    this.addCleanUp(new MXBeanNotificationListenersCleanUp());\n    \n    this.addCleanUp(new ShutdownHookCleanUp());\n    this.addCleanUp(new PropertyEditorCleanUp());\n    this.addCleanUp(new SecurityProviderCleanUp());\n    this.addCleanUp(new JceSecurityCleanUp()); // (Probably best to do after deregistering the providers)\n    this.addCleanUp(new ProxySelectorCleanUp());\n    this.addCleanUp(new RmiTargetsCleanUp());\n    this.addCleanUp(new StopThreadsCleanUp());\n    this.addCleanUp(new ThreadGroupCleanUp());\n    this.addCleanUp(new ThreadLocalCleanUp()); // This must be done after threads have been stopped, or new ThreadLocals may be added by those threads\n    this.addCleanUp(new KeepAliveTimerCacheCleanUp());\n    this.addCleanUp(new ResourceBundleCleanUp());\n    this.addCleanUp(new JDK8151486CleanUp());\n    this.addCleanUp(new JavaUtilLoggingLevelCleanUp()); // Do this last, in case other shutdown procedures want to log something.\n    this.addCleanUp(new ApacheCommonsLoggingCleanUp()); // Do this last, in case other shutdown procedures want to log something.\n    \n  }\n\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  // Factory methods\n  \n  /** \n   * Create new {@link ClassLoaderLeakPreventor} used to prevent the provided {@link Thread#contextClassLoader} of the\n   * {@link Thread#currentThread()} from leaking.\n   * \n   * Please be aware that {@link ClassLoaderLeakPreventor}s created by the same factory share the same \n   * {@link PreClassLoaderInitiator} and {@link ClassLoaderPreMortemCleanUp} instances, in case their config is changed. \n   */\n  public ClassLoaderLeakPreventor newLeakPreventor() {\n    return newLeakPreventor(Thread.currentThread().getContextClassLoader());\n  }\n  \n  /** Create new {@link ClassLoaderLeakPreventor} used to prevent the provided {@link ClassLoader} from leaking */\n  public ClassLoaderLeakPreventor newLeakPreventor(ClassLoader classLoader) {\n    return new ClassLoaderLeakPreventor(leakSafeClassLoader, classLoader, logger,\n        new ArrayList<PreClassLoaderInitiator>(preInitiators.values()), // Snapshot\n        new ArrayList<ClassLoaderPreMortemCleanUp>(cleanUps.values())); // Snapshot\n  }\n\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  // Methods for configuring the factory \n  \n  /** Set logger */\n  public void setLogger(Logger logger) {\n    this.logger = logger;\n  }\n  \n  /** Add a new {@link PreClassLoaderInitiator}, using the class name as name */\n  public void addPreInitiator(PreClassLoaderInitiator preClassLoaderInitiator) {\n    addConsideringOrder(this.preInitiators, preClassLoaderInitiator);\n  }\n\n  /** Add a new {@link ClassLoaderPreMortemCleanUp}, using the class name as name */\n  public void addCleanUp(ClassLoaderPreMortemCleanUp classLoaderPreMortemCleanUp) {\n    addConsideringOrder(this.cleanUps, classLoaderPreMortemCleanUp);\n  }\n  \n  /** Add new {@link I} entry to {@code map}, taking {@link MustBeAfter} into account */\n  private <I> void addConsideringOrder(Map<String, I> map, I newEntry) {\n    for(Map.Entry<String, I> entry : map.entrySet()) {\n      if(entry.getValue() instanceof MustBeAfter<?>) {\n        final Class<? extends ClassLoaderPreMortemCleanUp>[] existingMustBeAfter = \n            ((MustBeAfter<ClassLoaderPreMortemCleanUp>)entry.getValue()).mustBeBeforeMe();\n        for(Class<? extends ClassLoaderPreMortemCleanUp> clazz : existingMustBeAfter) {\n          if(clazz.isAssignableFrom(newEntry.getClass())) { // Entry needs to be after new entry\n            // TODO Resolve order automatically #51\n            throw new IllegalStateException(clazz.getName() + \" must be added after \" + newEntry.getClass());\n          }\n        }\n      }\n    }\n    \n    map.put(newEntry.getClass().getName(), newEntry);\n  }\n\n  /** Add a new named {@link ClassLoaderPreMortemCleanUp} */\n  public void addCleanUp(String name, ClassLoaderPreMortemCleanUp classLoaderPreMortemCleanUp) {\n    this.cleanUps.put(name, classLoaderPreMortemCleanUp);\n  }\n  \n  /** Remove all the currently configured {@link PreClassLoaderInitiator}s */\n  public void clearPreInitiators() {\n    this.preInitiators.clear();\n  }\n\n  /** Remove all the currently configured {@link ClassLoaderPreMortemCleanUp}s */\n  public void clearCleanUps() {\n    this.cleanUps.clear();\n  }\n  \n  /** \n   * Get instance of {@link PreClassLoaderInitiator} for further configuring.\n   * \n   * Please be aware that {@link ClassLoaderLeakPreventor}s created by the same factory share the same \n   * {@link PreClassLoaderInitiator} and {@link ClassLoaderPreMortemCleanUp} instances, in case their config is changed. \n   */\n  public <C extends PreClassLoaderInitiator> C getPreInitiator(Class<C> clazz) {\n    return (C) this.preInitiators.get(clazz.getName());\n  }\n\n  /** \n   * Get instance of {@link ClassLoaderPreMortemCleanUp} for further configuring.\n   * \n   * Please be aware that {@link ClassLoaderLeakPreventor}s created by the same factory share the same \n   * {@link PreClassLoaderInitiator} and {@link ClassLoaderPreMortemCleanUp} instances, in case their config is changed. \n   */\n  public <C extends ClassLoaderPreMortemCleanUp> C getCleanUp(Class<C> clazz) {\n    return (C) this.cleanUps.get(clazz.getName());\n  }\n\n  /** Get instance of {@link PreClassLoaderInitiator} for further configuring */\n  public <C extends PreClassLoaderInitiator> void removePreInitiator(Class<C> clazz) {\n    this.preInitiators.remove(clazz.getName());\n  }\n\n  /** Get instance of {@link ClassLoaderPreMortemCleanUp} for further configuring */\n  public <C extends ClassLoaderPreMortemCleanUp> void removeCleanUp(Class<C> clazz) {\n    this.cleanUps.remove(clazz.getName());\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderPreMortemCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Interface for cleanup actions that should be performed as part of the preparations to make a {@link ClassLoader} available\n * for garbage collection.\n * @author Mattias Jiderhamn\n */\npublic interface ClassLoaderPreMortemCleanUp {\n  \n  /** \n   * Perform cleanup actions needed to make provided {@link ClassLoaderLeakPreventor#classLoader} \n   * ready for garbage collection.\n   */\n  void cleanUp(ClassLoaderLeakPreventor preventor);\n  \n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/JULLogger.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.logging.Level;\n\n/**\n * Implementation of {@link Logger} interface, that uses {@link java.util.logging}.\n * \n * @author Mattias Jiderhamn\n */\npublic class JULLogger implements Logger {\n  \n  private static final java.util.logging.Logger LOG = \n      java.util.logging.Logger.getLogger(ClassLoaderLeakPreventor.class.getName());\n  \n  @Override\n  public void debug(String msg) {\n    LOG.config(msg);\n  } \n\n  @Override\n  public void info(String msg) {\n    LOG.info(msg);\n  } \n\n  @Override\n  public void warn(String msg) {\n    LOG.warning(msg);\n  } \n\n  @Override\n  public void warn(Throwable t) {\n    LOG.log(Level.WARNING, t.getMessage(), t);\n  } \n\n  @Override\n  public void error(String msg) {\n    LOG.severe(msg);\n  } \n\n  @Override\n  public void error(Throwable t) {\n    LOG.log(Level.SEVERE, t.getMessage(), t);\n  }\n  \n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/Logger.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Interface for logging, with similarities to common logging frameworks. If you want to plug in the leak preventor\n * into an existing architecture (such as an application server), you may want to use a custom implementation of this \n * interface.\n * \n * If the {@link ClassLoaderLeakPreventorFactory} is beeing reused, the {@link Logger} implementation may need to be \n * thread safe.\n * \n * @author Mattias Jiderhamn\n */\npublic interface Logger {\n\n  /** Log debug level message */\n  void debug(String msg);\n\n  /** Log info level message */\n  void info(String msg);\n\n  /** Log a warning message */\n  void warn(String msg);\n\n  /** Log a {@link Throwable} as a warning message */\n  void warn(Throwable t);\n\n  /** Log an error message */\n  void error(String msg);\n  \n  /** Log a {@link Throwable} as an error message */\n  void error(Throwable t);\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/MustBeAfter.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Interface to be implemented by {@link PreClassLoaderInitiator}s and {@link ClassLoaderPreMortemCleanUp}s when order\n * is important. The class implementing this interface will define what other implementations it needs to be invoked\n * *after* for correct behaviour. It is the responsibility of {@link ClassLoaderLeakPreventorFactory} to make sure\n * the implementations are ordered correctly. Currently an {@link IllegalStateException} will be thrown (TODO #51)\n * @param <I> The interface that both this class and the dependent classes implements, \n * i.e. either {@link PreClassLoaderInitiator} or {@link ClassLoaderPreMortemCleanUp}. \n * \n * @author Mattias Jiderhamn\n */\npublic interface MustBeAfter<I> {\n  \n  /** \n   * Returns an array of classes that, if part of they or any subclass of them are part of the list of \n   * {@link PreClassLoaderInitiator}s/{@link ClassLoaderPreMortemCleanUp}s, needs to be prior to this element in the list.\n   */\n  Class<? extends I>[] mustBeBeforeMe();\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/PreClassLoaderInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Interface for preventative actions that should be executed in the system (or other parent) classloader before they \n * may be triggered within the classloader that is about to be launched, and thereby may trigger leaks.\n * @author Mattias Jiderhamn\n */\npublic interface PreClassLoaderInitiator {\n  \n  /** \n   * Perform action that needs to be done outside the leak susceptible classloader, i.e. in the system or other parent\n   * classloader. Assume that the system or parent classloader is the {@link Thread#contextClassLoader} of the current \n   * thread when method is invoked.\n   * Must NOT have modified {@link Thread#contextClassLoader} of the current thread when returning.\n   */\n  void doOutsideClassLoader(ClassLoaderLeakPreventor preventor);\n  \n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/ReplaceDOMNormalizerSerializerAbortException.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\n\n/**\n * As reported at https://github.com/mjiderhamn/classloader-leak-prevention/issues/36, invoking\n * {@code DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().normalizeDocument();} or \n * <code>\n *   Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();\n *   DOMImplementationLS implementation = (DOMImplementationLS)document.getImplementation();\n *   implementation.createLSSerializer().writeToString(document);\n * </code> may trigger leaks caused by the static fields {@link com.sun.org.apache.xerces.internal.dom.DOMNormalizer#abort} and\n * {@link com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl#abort} respectively keeping stacktraces/backtraces\n * that may include references to classes loaded by our web application.\n * \n * Since the {@link java.lang.Throwable#backtrace} itself cannot be accessed via reflection (see \n * http://bugs.java.com/view_bug.do?bug_id=4496456) we need to replace the with new one without any stack trace.\n * \n * This can be done either as a {@link PreClassLoaderInitiator} (recommended) or {@link ClassLoaderPreMortemCleanUp}.\n * \n * @author Mattias Jiderhamn\n */\npublic class ReplaceDOMNormalizerSerializerAbortException implements PreClassLoaderInitiator, ClassLoaderPreMortemCleanUp {\n\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    replaceDOMNormalizerSerializerAbortException(preventor);\n  }\n\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    replaceDOMNormalizerSerializerAbortException(preventor);\n  }\n\n  @SuppressWarnings(\"WeakerAccess\")\n  protected void replaceDOMNormalizerSerializerAbortException(ClassLoaderLeakPreventor preventor) {\n    final RuntimeException abort = constructRuntimeExceptionWithoutStackTrace(preventor, \"abort\", null);\n    if(abort != null) {\n      final Field normalizerAbort = preventor.findFieldOfClass(\"com.sun.org.apache.xerces.internal.dom.DOMNormalizer\", \"abort\");\n      if(normalizerAbort != null)\n        preventor.setFinalStaticField(normalizerAbort, abort);\n\n      final Field serializerAbort = preventor.findFieldOfClass(\"com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl\", \"abort\");\n      if(serializerAbort != null)\n        preventor.setFinalStaticField(serializerAbort, abort);\n    }\n  }\n\n  /** Construct a new {@link RuntimeException} without any stack trace, in order to avoid any references back to this class */\n  @SuppressWarnings(\"WeakerAccess\")\n  public static RuntimeException constructRuntimeExceptionWithoutStackTrace(ClassLoaderLeakPreventor preventor,\n                                                                        String message, Throwable cause) {\n    try {\n      final Constructor<RuntimeException> constructor = \n          RuntimeException.class.getDeclaredConstructor(String.class, Throwable.class, Boolean.TYPE, Boolean.TYPE);\n      constructor.setAccessible(true);\n      return constructor.newInstance(message, cause, true, false /* disable stack trace */);\n    }\n    catch (Throwable e) { // InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException\n      preventor.warn(\"Unable to construct RuntimeException without stack trace. The likely reason is that you are using Java <= 1.6. \" +\n          \"No worries, except there might be some leaks you're not protected from (https://github.com/mjiderhamn/classloader-leak-prevention/issues/36 , \" +\n          \"https://github.com/mjiderhamn/classloader-leak-prevention/issues/69). \" + \n          \"If you are already on Java 1.7+, please report issue to developer of this library!\");\n      preventor.warn(e);\n      return null;\n    }\n  }\n  \n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/StdLogger.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Implementation of {@link Logger} interface, that uses {@link System#out} and {@link System#err}.\n * Because log frameworks may themselves cause leaks, we may want to avoid them altogether.\n * \n * To \"turn off\" a log level, override the corresponding method(s) with an empty implementation.\n * @author Mattias Jiderhamn\n */\npublic class StdLogger implements Logger {\n  \n  /** Get prefix to use when logging to {@link System#out}/{@link System#err} */\n  protected String getLogPrefix() {\n    return \"ClassLoader Leak Preventor: \";\n  }\n  \n  @Override\n  public void debug(String msg) {\n    System.out.println(getLogPrefix() + msg);\n  } \n\n  @Override\n  public void info(String s) {\n    System.out.println(getLogPrefix() + s);\n  } \n\n  @Override\n  public void warn(String s) {\n    System.err.println(getLogPrefix() + s);\n  } \n\n  @Override\n  public void warn(Throwable t) {\n    t.printStackTrace(System.err);\n  } \n\n  @Override\n  public void error(String s) {\n    System.err.println(getLogPrefix() + s);\n  } \n\n  @Override\n  public void error(Throwable t) {\n    t.printStackTrace(System.err);\n  }\n  \n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ApacheCommonsLoggingCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.security.CodeSource;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Release this classloader from Apache Commons Logging (ACL) by calling \n * {@code LogFactory.release(getCurrentClassLoader());}\n * Use reflection in case ACL is not present.\n * Tip: Do this last, in case other shutdown procedures want to log something.\n * \n * @author Mattias Jiderhamn\n */\npublic class ApacheCommonsLoggingCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Class<?> logFactory = preventor.findClass(\"org.apache.commons.logging.LogFactory\");\n    if(logFactory != null) { // Apache Commons Logging present\n      try {\n        final CodeSource codeSource = logFactory.getProtectionDomain().getCodeSource();\n        final String codeSourceStr = codeSource != null ? codeSource.toString() : \"\";\n        if (codeSourceStr.contains(\"spring-jcl\")) {\n          preventor.info(\"ignore ApacheCommonsLoggingCleanUp for spring-jcl at \" + codeSource);\n          return;\n        }\n      } catch (SecurityException ex) {\n        preventor.error(ex);\n      }\n      preventor.info(\"Releasing web app classloader from Apache Commons Logging\");\n      try {\n        logFactory.getMethod(\"release\", java.lang.ClassLoader.class)\n            .invoke(null, preventor.getClassLoader());\n      }\n      catch (Exception ex) {\n        preventor.error(ex);\n      }\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanELResolverCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Map;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clean for the cache of {@link javax.el.BeanELResolver}, which leaks prior to version 2.2.4.\n * @author Mattias Jiderhamn\n */\npublic class BeanELResolverCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    java.beans.Introspector.flushCaches(); // This must also be done          \n\n    final Class<?> beanElResolverClass = preventor.findClass(\"javax.el.BeanELResolver\");\n    if(beanElResolverClass != null) {\n      boolean cleared = false;\n      try {\n        final Method purgeBeanClasses = beanElResolverClass.getDeclaredMethod(\"purgeBeanClasses\", ClassLoader.class);\n        purgeBeanClasses.setAccessible(true);\n        purgeBeanClasses.invoke(beanElResolverClass.newInstance(), preventor.getClassLoader());\n        cleared = true;\n      }\n      catch (NoSuchMethodException e) {\n        // Version of javax.el probably > 2.2; no real need to clear\n      }\n      catch (Exception e) {\n        preventor.error(e);\n      }\n      \n      if(! cleared) {\n        // Fallback, if purgeBeanClasses() could not be called\n        final Field propertiesField = preventor.findField(beanElResolverClass, \"properties\");\n        if(propertiesField != null) {\n          try {\n            final Map<?, ?> properties = (Map<?, ?>) propertiesField.get(null);\n            properties.clear();\n          }\n          catch (Exception e) {\n            preventor.error(e);\n          }\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanIntrospectorCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clear {@link java.beans.Introspector} cache\n * @author Mattias Jiderhamn\n */\npublic class BeanIntrospectorCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    java.beans.Introspector.flushCaches(); // Clear cache of strong references\n    clearClassInfoCache(preventor);\n  }\n\n  /**\n   * Clears the BeanInfo SoftReference-based cache introduced in JDK 9\n   *\n   * References:\n   * * Clear explanation of the root cause: https://bugs.openjdk.java.net/browse/JDK-8207331\n   * * Issue which triggered the JDK fix: https://bugs.openjdk.java.net/browse/JDK-8231454\n   * * Fix commit (JDK16+ only as of now): https://github.com/openjdk/jdk/commit/2ee2b4ae\n   */\n  private void clearClassInfoCache(ClassLoaderLeakPreventor preventor) {\n      try {\n          final Class<?> classInfoClass = preventor.findClass(\"com.sun.beans.introspect.ClassInfo\");\n          if (classInfoClass == null) {\n            return;\n          }\n\n          Field cacheField = preventor.findField(classInfoClass, \"CACHE\");\n          if (cacheField == null) {\n            return;  // Either pre-JDK9 or exception occurred (should have been logged as warn at this point)\n          }\n\n          Object cacheInstance = cacheField.get(null);\n          if (cacheInstance == null) {\n            return;\n          }\n          Method clearMethod = cacheInstance.getClass().getSuperclass().getDeclaredMethod(\"clear\");\n          clearMethod.invoke(cacheInstance);\n      }\n      catch (Exception e) {\n          preventor.warn(e);\n      }\n  }\n\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanValidationCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.util.Map;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clean up leak caused by cache in {@link javax.validation.Validation}\n * @author Mattias Jiderhamn\n */\npublic class BeanValidationCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Class<?> offendingClass = \n        preventor.findClass(\"javax.validation.Validation$DefaultValidationProviderResolver\");\n    if(offendingClass != null) { // Class is present on class path\n      Field offendingField = preventor.findField(offendingClass, \"providersPerClassloader\");\n      if(offendingField != null) {\n        final Object providersPerClassloader = preventor.getStaticFieldValue(offendingField);\n        if(providersPerClassloader instanceof Map) { // Map<ClassLoader, List<ValidationProvider<?>>> in offending code\n          //noinspection SynchronizationOnLocalVariableOrMethodParameter\n          synchronized (providersPerClassloader) {\n            // Fix the leak!\n            ((Map<?, ?>)providersPerClassloader).remove(preventor.getClassLoader());\n          }\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/DefaultAuthenticatorCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.Reference;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.net.Authenticator;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clear the default {@link java.net.Authenticator} (in case current one is loaded by protected ClassLoader). \n * Includes special workaround for CXF issue https://issues.apache.org/jira/browse/CXF-5442\n * @author Mattias Jiderhamn\n */\npublic class DefaultAuthenticatorCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Authenticator defaultAuthenticator = getDefaultAuthenticator(preventor);\n    if(defaultAuthenticator == null || // Can both mean not set, or error retrieving, so unset anyway to be safe \n        preventor.isLoadedInClassLoader(defaultAuthenticator)) {\n      if(defaultAuthenticator != null) // Log warning only if a default was actually found\n        preventor.warn(\"Unsetting default \" + Authenticator.class.getName() + \": \" + defaultAuthenticator);\n      Authenticator.setDefault(null);\n    }\n    else {\n      if(\"org.apache.cxf.transport.http.ReferencingAuthenticator\".equals(defaultAuthenticator.getClass().getName())) {\n        /*\n         Needed since org.apache.cxf.transport.http.ReferencingAuthenticator is loaded by dummy classloader that\n         references protected classloader via AccessControlContext + ProtectionDomain.\n         See https://issues.apache.org/jira/browse/CXF-5442\n        */\n\n        final Class<?> cxfAuthenticator = preventor.findClass(\"org.apache.cxf.transport.http.CXFAuthenticator\");\n        if(cxfAuthenticator != null && preventor.isLoadedByClassLoader(cxfAuthenticator)) { // CXF loaded in this application\n          final Object cxfAuthenticator$instance = preventor.getStaticFieldValue(cxfAuthenticator, \"instance\");\n          if(cxfAuthenticator$instance != null) { // CXF authenticator has been initialized in protected ClassLoader\n            final Object authReference = preventor.getFieldValue(defaultAuthenticator, \"auth\");\n            if(authReference instanceof Reference) { // WeakReference \n              final Reference<?> reference = (Reference<?>) authReference;\n              final Object referencedAuth = reference.get();\n              if(referencedAuth == cxfAuthenticator$instance) { // References CXFAuthenticator of this classloader \n                preventor.warn(\"Default \" + Authenticator.class.getName() + \" was \" + defaultAuthenticator + \" that referenced \" +\n                    cxfAuthenticator$instance + \" loaded by protected ClassLoader\");\n\n                // Let CXF unwrap in it's own way (in case there are multiple CXF webapps in the container)\n                reference.clear(); // Remove the weak reference before calling check()\n                try {\n                  final Method check = defaultAuthenticator.getClass().getMethod(\"check\");\n                  check.setAccessible(true);\n                  check.invoke(defaultAuthenticator);\n                }\n                catch (Exception e) {\n                  preventor.error(e);\n                }\n              }\n            }\n          }\n        }\n      }\n      \n      removeWrappedAuthenticators(preventor, defaultAuthenticator);\n      \n      preventor.info(\"Default \" + Authenticator.class.getName() + \" not loaded by protected ClassLoader: \" + defaultAuthenticator);\n    }\n  }\n  \n  /** Find default {@link Authenticator} */\n  @SuppressWarnings(\"WeakerAccess\")\n  protected Authenticator getDefaultAuthenticator(ClassLoaderLeakPreventor preventor) {\n    // Normally Corresponds to getStaticFieldValue(Authenticator.class, \"theAuthenticator\");\n    for(final Field f : Authenticator.class.getDeclaredFields()) {\n      if (f.getType().equals(Authenticator.class)) { // Supposedly \"theAuthenticator\"\n        try {\n          f.setAccessible(true);\n          return (Authenticator)f.get(null);\n        } catch (Exception e) {\n          preventor.error(e);\n        }\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Recursively removed wrapped {@link Authenticator} loaded in protected ClassLoader.\n   * May be needed in case there are multiple CXF applications within the same container.\n   */\n  @SuppressWarnings(\"WeakerAccess\")\n  protected void removeWrappedAuthenticators(final ClassLoaderLeakPreventor preventor,\n                                             final Authenticator authenticator) {\n    if(authenticator == null)\n      return;\n\n    try {\n      Class<?> authenticatorClass = authenticator.getClass();\n      do {\n        for(final Field f : authenticator.getClass().getDeclaredFields()) {\n          if(Authenticator.class.isAssignableFrom(f.getType())) {\n            try {\n              final boolean isStatic = Modifier.isStatic(f.getModifiers()); // In CXF case this should be false\n              final Authenticator owner = isStatic ? null : authenticator;\n              f.setAccessible(true);\n              final Authenticator wrapped = (Authenticator)f.get(owner);\n              if(preventor.isLoadedInClassLoader(wrapped)) {\n                preventor.warn(Authenticator.class.getName() + \": \" + wrapped + \", wrapped by \" + authenticator + \n                    \", is loaded by protected ClassLoader\");\n                f.set(owner, null); // For added safety\n              }\n              else {\n                removeWrappedAuthenticators(preventor, wrapped); // Recurse\n              }\n            } catch (Exception e) {\n              preventor.error(e);\n            }\n          }\n        }\n        authenticatorClass = authenticatorClass.getSuperclass();\n      } while (authenticatorClass != null && authenticatorClass != Object.class);\n    }\n    catch (Exception e) { // Should never happen\n      preventor.error(e);\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/DriverManagerCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.sql.Driver;\nimport java.sql.DriverManager;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Deregister JDBC drivers loaded by classloader\n * @author Mattias Jiderhamn\n */\npublic class DriverManagerCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final List<Driver> driversToDeregister = new ArrayList<Driver>();\n    final Enumeration<Driver> allDrivers = DriverManager.getDrivers();\n    while(allDrivers.hasMoreElements()) {\n      final Driver driver = allDrivers.nextElement();\n      if(preventor.isLoadedInClassLoader(driver)) // Should be true for all returned by DriverManager.getDrivers()\n        driversToDeregister.add(driver);\n    }\n    \n    for(Driver driver : driversToDeregister) {\n      try {\n        preventor.warn(\"JDBC driver loaded by protected ClassLoader deregistered: \" + driver.getClass());\n        DriverManager.deregisterDriver(driver);\n      }\n      catch (SQLException e) {\n        preventor.error(e);\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/GeoToolsCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Shutdown GeoTools cleaner thread as of https://osgeo-org.atlassian.net/browse/GEOT-2742\n * @author Mattias Jiderhamn\n */\npublic class GeoToolsCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Class<?> weakCollectionCleanerClass = preventor.findClass(\"org.geotools.util.WeakCollectionCleaner\");\n    if(weakCollectionCleanerClass != null) {\n      try {\n        final Field DEFAULT = preventor.findField(weakCollectionCleanerClass, \"DEFAULT\");\n        weakCollectionCleanerClass.getMethod(\"exit\").invoke(DEFAULT.get(null));\n      }\n      catch (Exception ex) {\n        preventor.error(ex);\n      }\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/IIOServiceProviderCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.security.AccessControlContext;\nimport java.util.*;\nimport javax.imageio.spi.IIORegistry;\nimport javax.imageio.spi.IIOServiceProvider;\nimport javax.imageio.spi.ServiceRegistry;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Unregister ImageIO Service Provider loaded by the protected ClassLoader\n * @author Thomas Scheffler (1.x version)\n * @author Mattias Jiderhamn\n */\npublic class IIOServiceProviderCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(final ClassLoaderLeakPreventor preventor) {\n    final IIORegistry registry = IIORegistry.getDefaultInstance();\n    Iterator<Class<?>> categories = registry.getCategories();\n    ServiceRegistry.Filter classLoaderFilter = new ServiceRegistry.Filter() {\n      @Override\n      public boolean filter(Object provider) {\n        //remove all service provider loaded by the current ClassLoader\n        return preventor.isLoadedInClassLoader(provider);\n      }\n    };\n    while (categories.hasNext()) {\n      @SuppressWarnings(\"unchecked\")\n      Class<IIOServiceProvider> category = (Class<IIOServiceProvider>) categories.next();\n      Iterator<IIOServiceProvider> serviceProviders = registry.getServiceProviders(\n          category,\n          classLoaderFilter, true);\n      if (serviceProviders.hasNext()) {\n        //copy to list\n        List<IIOServiceProvider> serviceProviderList = new ArrayList<IIOServiceProvider>();\n        while (serviceProviders.hasNext()) {\n          serviceProviderList.add(serviceProviders.next());\n        }\n        for (IIOServiceProvider serviceProvider : serviceProviderList) {\n          preventor.warn(\"ImageIO \" + category.getSimpleName() + \" service provider deregistered: \"\n            + serviceProvider.getDescription(Locale.ROOT));\n          registry.deregisterServiceProvider(serviceProvider);\n        }\n      }\n    }\n\n    // Leak as of Java 1.8u141, see https://github.com/mjiderhamn/classloader-leak-prevention/issues/71\n    // The providers are probably registered by SunAwtAppContextInitiator\n    final Field accMapField = preventor.findFieldOfClass(\"javax.imageio.spi.SubRegistry\", \"accMap\");\n    if(accMapField != null) {\n      final Field categoryMapField = preventor.findField(ServiceRegistry.class, \"categoryMap\");\n      if(categoryMapField != null) {\n        final Map categoryMap = preventor.getFieldValue(categoryMapField, registry);\n        if(categoryMap != null) {\n          for(/*SubRegistry*/ Object subRegistry : categoryMap.values()) {\n            final Map<Class<?>, AccessControlContext> accMap = preventor.getFieldValue(accMapField, subRegistry);\n            if(accMap != null) {\n              for(AccessControlContext acc : accMap.values()) {\n                preventor.removeDomainCombiner(IIORegistry.class.getName(), acc);\n              }\n            }\n          }\n        }\n      }\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/IntrospectionUtilsCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clear IntrospectionUtils caches of Tomcat and Apache Commons Modeler\n * @author Mattias Jiderhamn\n */\npublic class IntrospectionUtilsCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    // Tomcat\n    final Class<?> tomcatIntrospectionUtils = preventor.findClass(\"org.apache.tomcat.util.IntrospectionUtils\");\n    if(tomcatIntrospectionUtils != null) {\n      try {\n        tomcatIntrospectionUtils.getMethod(\"clear\").invoke(null);\n      }\n      catch (Exception ex) {\n        if(! preventor.isJBoss()) // JBoss includes this class, but no cache and no clear() method\n          preventor.error(ex);\n      }\n    }\n\n    // Apache Commons Modeler\n    final Class<?> modelIntrospectionUtils = preventor.findClass(\"org.apache.commons.modeler.util.IntrospectionUtils\");\n    if(modelIntrospectionUtils != null && ! preventor.isClassLoaderOrChild(modelIntrospectionUtils.getClassLoader())) { // Loaded outside protected ClassLoader\n      try {\n        modelIntrospectionUtils.getMethod(\"clear\").invoke(null);\n      }\n      catch (Exception ex) {\n        preventor.warn(\"org.apache.commons.modeler.util.IntrospectionUtils needs to be cleared but there was an error, \" +\n            \"consider upgrading Apache Commons Modeler\");\n        preventor.error(ex);\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JDK8151486CleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\nimport java.lang.reflect.Field;\nimport java.util.Set;\n\n/**\n * Clear the \"domains\" field of the parent ClassLoader.\n *\n * See <a href=\"https://bugs.openjdk.java.net/browse/JDK-8151486\">JDK-8151486</a>\n */\npublic class JDK8151486CleanUp implements ClassLoaderPreMortemCleanUp {\n    @Override\n    public void cleanUp(ClassLoaderLeakPreventor preventor) {\n        Field field = preventor.findField(ClassLoader.class, \"domains\");\n        if (field == null) {\n            // field only exists in JDK versions [8u25, 9u140)\n            return;\n        }\n\n        for (ClassLoader cl = preventor.getClassLoader().getParent(); cl != null; cl = cl.getParent()) {\n            Set<?> domains = preventor.getFieldValue(field, cl);\n            if (domains != null) {\n                domains.clear();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JacksonCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Method;\nimport java.util.Map;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clear Jackson TypeFactory cache as per https://github.com/FasterXML/jackson-databind/issues/1363\n * @author Mattias Jiderhamn\n */\npublic class JacksonCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Class<?> typeFactoryClass = preventor.findClass(\"com.fasterxml.jackson.databind.type.TypeFactory\");\n    if(typeFactoryClass != null && ! preventor.isLoadedInClassLoader(typeFactoryClass)) {\n      try {\n        final Method defaultInstance = preventor.findMethod(typeFactoryClass, \"defaultInstance\");\n        if(defaultInstance != null) {\n          final Object defaultTypeFactory = defaultInstance.invoke(null);\n          if(defaultTypeFactory != null) {\n            final Method clearCache = preventor.findMethod(typeFactoryClass, \"clearCache\");\n            if(clearCache != null) { \n              clearCache.invoke(defaultTypeFactory);\n            }\n            else { // Version < 2.4.1\n              final Object typeCache = preventor.getFieldValue(defaultTypeFactory, \"_typeCache\");\n              if(typeCache instanceof Map) {\n                //noinspection SynchronizationOnLocalVariableOrMethodParameter\n                synchronized (typeCache) {\n                  ((Map) typeCache).clear();\n                }\n              }\n            }\n          }\n        }\n      }\n      catch (Exception e) {\n        preventor.error(e);\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaServerFaces2746CleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.WeakHashMap;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Workaround for leak caused by Mojarra JSF implementation if included in the container.\n * See <a href=\"http://java.net/jira/browse/JAVASERVERFACES-2746\">JAVASERVERFACES-2746</a>\n * @author Mattias Jiderhamn\n */\npublic class JavaServerFaces2746CleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    /*\n     Note that since a WeakHashMap is used, it is not the map key that is the problem. However the value is a\n     Map with java.beans.PropertyDescriptor as value, and java.beans.PropertyDescriptor has a Hashtable in which\n     a class is put with \"type\" as key. This class may have been loaded by the protected ClassLoader.\n\n     One example case is the class org.primefaces.component.menubutton.MenuButton that points to a Map with a key \n     \"model\" whose PropertyDescriptor.table has key \"type\" with the class org.primefaces.model.MenuModel as its value.\n\n     For performance reasons however, we'll only look at the top level key and remove any that has been loaded by \n     protected ClassLoader.     \n     */\n    \n    Object o = preventor.getStaticFieldValue(\"javax.faces.component.UIComponentBase\", \"descriptors\"); // Non-static as of JSF 2.2.5\n    if(o instanceof WeakHashMap) {\n      WeakHashMap<?, ?> descriptors = (WeakHashMap<?, ?>) o;\n      final Set<Class<?>> toRemove = new HashSet<Class<?>>();\n      for(Object key : descriptors.keySet()) {\n        if(key instanceof Class && preventor.isLoadedByClassLoader((Class<?>)key)) {\n          // For performance reasons, remove all classes loaded by protected ClassLoader\n          toRemove.add((Class<?>) key);\n          \n          // This would be more correct, but presumably slower\n          /*\n          Map<String, PropertyDescriptor> m = (Map<String, PropertyDescriptor>) descriptors.get(key);\n          for(Map.Entry<String,PropertyDescriptor> entry : m.entrySet()) {\n            Object type = entry.getValue().getValue(\"type\"); // Key constant javax.el.ELResolver.TYPE\n            if(type instanceof Class && isLoadedByWebApplication((Class)type)) {\n              toRemove.add((Class) key); \n            }\n          }\n          */\n        }\n      }\n      \n      if(! toRemove.isEmpty()) {\n        preventor.info(\"Removing \" + toRemove.size() + \" classes from Mojarra descriptors cache\");\n        for(Class<?> clazz : toRemove) {\n          descriptors.remove(clazz);\n        }\n      }\n    }    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaUtilLoggingLevelCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.util.*;\nimport java.util.logging.Level;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Cleanup for removing custom {@link java.util.logging.Level}s loaded within the protected class loader.\n * @author Mattias Jiderhamn\n */\npublic class JavaUtilLoggingLevelCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Class<?> knownLevelClass = preventor.findClass(\"java.util.logging.Level$KnownLevel\");\n    if(knownLevelClass != null) {\n      final Field levelObjectField = preventor.findField(knownLevelClass, \"levelObject\");\n      if(levelObjectField != null) {\n\n        //noinspection SynchronizationOnLocalVariableOrMethodParameter\n        synchronized (knownLevelClass) {\n          final Map<?, List/*<KnownLevel>*/> nameToLevels = preventor.getStaticFieldValue(knownLevelClass, \"nameToLevels\");\n          final Map<?, List/*<KnownLevel>*/> intToLevels = preventor.getStaticFieldValue(knownLevelClass, \"intToLevels\");\n          if(nameToLevels != null) {\n            final Set/*<KnownLevel>*/ removed = process(preventor, knownLevelClass, levelObjectField, nameToLevels);\n            if(intToLevels != null) {\n              for(List/*<KnownLevel>*/ knownLevels : intToLevels.values()) {\n                knownLevels.removeAll(removed);\n              }\n            }\n          }\n          else if(intToLevels != null) { // Use intToLevels as fallback; both should contain same values\n            process(preventor, knownLevelClass, levelObjectField, intToLevels);\n          }\n        }\n      }\n      else \n        preventor.warn(\"Found \" + knownLevelClass + \" but not levelObject field\");\n    }\n  }\n\n  private Set/*<KnownLevel>*/ process(ClassLoaderLeakPreventor preventor, Class<?> knownLevelClass, \n                                      Field levelObjectField, Map<?, List/*<KnownLevel>*/> levelsMaps) {\n    final Set/*<KnownLevel>*/ output = new HashSet<Object>();\n    for(List/*<KnownLevel>*/ knownLevels : levelsMaps.values()) {\n      for(Iterator/*<KnownLevel>*/ iter = knownLevels.listIterator(); iter.hasNext(); ) {\n        final Object /* KnownLevel */ knownLevel = iter.next();\n        final Level levelObject = preventor.getFieldValue(levelObjectField, knownLevel);\n        if(preventor.isLoadedInClassLoader(levelObject)) {\n          preventor.warn(Level.class.getName() + \" subclass loaded by protected ClassLoader: \" +\n              levelObject.getClass() + \"; removing from \" + knownLevelClass);\n          iter.remove();\n          output.add(knownLevel);\n        }\n      }\n    }\n    return output;\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaxSecurityAuthLoginConfigurationCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.security.auth.login.Configuration;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Cleanup for removing custom {@link javax.security.auth.login.Configuration}s loaded within the protected class loader.\n * @author Nikos Epping\n */\npublic class JavaxSecurityAuthLoginConfigurationCleanUp implements ClassLoaderPreMortemCleanUp {\n\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    if (preventor.isLoadedInClassLoader(Configuration.getConfiguration())) {\n      Configuration.setConfiguration(null);\n    }\n  }\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/JceSecurityCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.net.URL;\nimport java.security.Provider;\nimport java.util.Map;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clean up for the static caches of {@link javax.crypto.JceSecurity}\n * @author Mattias Jiderhamn\n */\npublic class JceSecurityCleanUp implements ClassLoaderPreMortemCleanUp {\n  \n  @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Class<?> javax_crypto_JceSecurity = preventor.findClass(\"javax.crypto.JceSecurity\");\n    if(javax_crypto_JceSecurity != null) {\n      synchronized (javax_crypto_JceSecurity) { // synchronized methods are used for querying and updating the caches\n        final Map<Provider, Object> verificationResults = preventor.getStaticFieldValue(javax_crypto_JceSecurity, \"verificationResults\");\n        final Map<Provider, Object> verifyingProviders = preventor.getStaticFieldValue(javax_crypto_JceSecurity, \"verifyingProviders\");\n        final Map<Class<?>, URL> codeBaseCacheRef = preventor.getStaticFieldValue(javax_crypto_JceSecurity, \"codeBaseCacheRef\");\n        \n        if(verificationResults != null) {\n          verificationResults.clear();\n        }\n        if(verifyingProviders != null) {\n          verifyingProviders.clear();\n        }\n        if(codeBaseCacheRef != null) {\n          codeBaseCacheRef.clear();\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/KeepAliveTimerCacheCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\nimport se.jiderhamn.classloader.leak.prevention.MustBeAfter;\n\n/**\n * Since Keep-Alive-Timer thread may have terminated, but still be referenced, we need to make sure it does not\n * reference this classloader.\n * @author Mattias Jiderhamn\n */\npublic class KeepAliveTimerCacheCleanUp implements ClassLoaderPreMortemCleanUp, MustBeAfter<ClassLoaderPreMortemCleanUp> {\n\n  /** Needs to be done after {@link StopThreadsCleanUp}, since in there the Keep-Alive-Timer may be stopped. */\n  @Override\n  public Class<? extends ClassLoaderPreMortemCleanUp>[] mustBeBeforeMe() {\n    return new Class[] {StopThreadsCleanUp.class};\n  }\n\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    Object keepAliveCache = preventor.getStaticFieldValue(\"sun.net.www.http.HttpClient\", \"kac\", true);\n    if(keepAliveCache != null) {\n      final Thread keepAliveTimer = preventor.getFieldValue(keepAliveCache, \"keepAliveTimer\");\n      if(keepAliveTimer != null) {\n        if(preventor.isClassLoaderOrChild(keepAliveTimer.getContextClassLoader())) {\n          keepAliveTimer.setContextClassLoader(preventor.getLeakSafeClassLoader());\n          preventor.error(\"ContextClassLoader of sun.net.www.http.HttpClient cached Keep-Alive-Timer set to \" + preventor.getLeakSafeClassLoader());\n        }\n      }\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MBeanCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Set;\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Unregister MBeans loaded by the protected class loader\n * @author Mattias Jiderhamn\n * @author rapla\n */\npublic class MBeanCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    try {\n      final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();\n      final Set<ObjectName> allMBeanNames = mBeanServer.queryNames(new ObjectName(\"*:*\"), null);\n\n      // Special treatment for Jetty, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=423255\n      JettyJMXRemover jettyJMXRemover = null;\n      if(isJettyWithJMX(preventor)) {\n        try {\n          jettyJMXRemover = new JettyJMXRemover(preventor);\n        }\n        catch (Exception ex) {\n          preventor.error(ex);\n        }\n      }\n      \n      // Look for custom MBeans\n      for(ObjectName objectName : allMBeanNames) {\n        try {\n          if (jettyJMXRemover != null && jettyJMXRemover.unregisterJettyJMXBean(objectName)) {\n        \t  continue;\n          }\n          \n          final ClassLoader mBeanClassLoader = mBeanServer.getClassLoaderFor(objectName);\n          if(preventor.isClassLoaderOrChild(mBeanClassLoader)) { // MBean loaded by protected ClassLoader\n            preventor.warn(\"MBean '\" + objectName + \"' was loaded by protected ClassLoader; unregistering\");\n            mBeanServer.unregisterMBean(objectName);\n          }\n          /* \n          else if(... instanceof NotificationBroadcasterSupport) {\n            unregisterNotificationListeners((NotificationBroadcasterSupport) ...);\n          }\n          */\n        }\n        catch(Exception e) { // MBeanRegistrationException / InstanceNotFoundException\n          preventor.error(e);\n        }\n      }\n    }\n    catch (Exception e) { // MalformedObjectNameException\n      preventor.error(e);\n    }\n    \n  }\n\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  // Methods and classes for Jetty, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=423255 \n  \n  /** Are we running in Jetty with JMX enabled? */\n  @SuppressWarnings(\"WeakerAccess\")\n  protected boolean isJettyWithJMX(ClassLoaderLeakPreventor preventor) {\n    final ClassLoader classLoader = preventor.getClassLoader();\n    try {\n      // If package org.eclipse.jetty is found, we may be running under jetty\n      if (classLoader.getResource(\"org/eclipse/jetty\") == null) {\n        return false;\n      }\n\n      Class.forName(\"org.eclipse.jetty.jmx.MBeanContainer\", false, classLoader.getParent()); // JMX enabled?\n      Class.forName(\"org.eclipse.jetty.webapp.WebAppContext\", false, classLoader.getParent());\n    }\n    catch(Exception ex) { // For example ClassNotFoundException\n      return false;\n    }\n    \n    // Seems we are running in Jetty with JMX enabled\n    return true;\n  }\n  \n  /** \n   * Inner utility class that helps dealing with Jetty MBeans class.\n   * If you enable JMX support in Jetty 8 or 9 some MBeans (e.g. for the ServletHolder or SessionManager) are\n   * instantiated in the web application thread and a reference to the WebappClassloader is stored in a private\n   * ObjectMBean._loader which is unfortunately not the classloader that loaded the class. Therefore we need to access \n   * the MBeanContainer class of the Jetty container and unregister the MBeans.\n   */\n  private class JettyJMXRemover {\n    \n    private final ClassLoaderLeakPreventor preventor;\n\n    /** List of objects that may be wrapped in MBean by Jetty. Should be allowed to contain null. */\n    private List<Object> objectsWrappedWithMBean;\n\n    /** The org.eclipse.jetty.jmx.MBeanContainer instance */\n    private Object beanContainer;\n\n    /** org.eclipse.jetty.jmx.MBeanContainer.findBean() */\n    private Method findBeanMethod;\n\n    /** org.eclipse.jetty.jmx.MBeanContainer.removeBean() */\n    private Method removeBeanMethod;\n\n    @SuppressWarnings(\"WeakerAccess\")\n    public JettyJMXRemover(ClassLoaderLeakPreventor preventor) throws Exception {\n      this.preventor = preventor;\n      \n      // First we need access to the MBeanContainer to access the beans\n      // WebAppContext webappContext = (WebAppContext)servletContext;\n      final Object webappContext = findJettyClass(\"org.eclipse.jetty.webapp.WebAppClassLoader\")\n              .getMethod(\"getContext\").invoke(preventor.getClassLoader());\n      if(webappContext == null)\n        return;\n      \n      // Server server = (Server)webappContext.getServer();\n      final Class<?> webAppContextClass = findJettyClass(\"org.eclipse.jetty.webapp.WebAppContext\");\n      final Object server = webAppContextClass.getMethod(\"getServer\").invoke(webappContext);\n      if(server == null)\n        return;\n\n      // MBeanContainer beanContainer = (MBeanContainer)server.getBean(MBeanContainer.class);\n\t  \n      final Class<?> mBeanContainerClass = findJettyClass(\"org.eclipse.jetty.jmx.MBeanContainer\");\n      beanContainer = findJettyClass(\"org.eclipse.jetty.server.Server\")\n              .getMethod(\"getBean\", Class.class).invoke(server, mBeanContainerClass);\n      // Now we store all objects that belong to the web application and that will be wrapped by MBeans in a list\n      if (beanContainer != null) {\n        findBeanMethod = mBeanContainerClass.getMethod(\"findBean\", ObjectName.class);\n        try {\n          removeBeanMethod = mBeanContainerClass.getMethod(\"removeBean\", Object.class);\n        } catch (NoSuchMethodException e) {\n          preventor.warn(\"MBeanContainer.removeBean() method can not be found. giving up\");\n          return;\n        }\n\n        objectsWrappedWithMBean = new ArrayList<Object>();\n        // SessionHandler sessionHandler = webappContext.getSessionHandler();\n        final Object sessionHandler = webAppContextClass.getMethod(\"getSessionHandler\").invoke(webappContext);\n        if(sessionHandler != null) {\n          objectsWrappedWithMBean.add(sessionHandler);\n  \n          // SessionManager sessionManager = sessionHandler.getSessionManager();\n          final Object sessionManager = findJettyClass(\"org.eclipse.jetty.server.session.SessionHandler\")\n                  .getMethod(\"getSessionManager\").invoke(sessionHandler);\n          if(sessionManager != null) {\n            objectsWrappedWithMBean.add(sessionManager);\n\n            // SessionIdManager sessionIdManager = sessionManager.getSessionIdManager();\n            final Object sessionIdManager = findJettyClass(\"org.eclipse.jetty.server.SessionManager\")\n                    .getMethod(\"getSessionIdManager\").invoke(sessionManager);\n            objectsWrappedWithMBean.add(sessionIdManager);\n          }\n        }\n\n        // SecurityHandler securityHandler = webappContext.getSecurityHandler();\n        objectsWrappedWithMBean.add(webAppContextClass.getMethod(\"getSecurityHandler\").invoke(webappContext));\n\n        // ServletHandler servletHandler = webappContext.getServletHandler();\n        final Object servletHandler = webAppContextClass.getMethod(\"getServletHandler\").invoke(webappContext);\n        if(servletHandler != null) {\n          objectsWrappedWithMBean.add(servletHandler);\n\n          final Class<?> servletHandlerClass = findJettyClass(\"org.eclipse.jetty.servlet.ServletHandler\");\n          // Object[] servletMappings = servletHandler.getServletMappings();\n          objectsWrappedWithMBean.add(Arrays.asList((Object[]) servletHandlerClass.getMethod(\"getServletMappings\").invoke(servletHandler)));\n\n          // Object[] servlets = servletHandler.getServlets();\n          objectsWrappedWithMBean.add(Arrays.asList((Object[]) servletHandlerClass.getMethod(\"getServlets\").invoke(servletHandler)));\n        }\n      }\n    }\n\n    /**\n     * Test if objectName denotes a wrapping Jetty MBean and if so unregister it.\n     * @return {@code true} if Jetty MBean was unregistered, otherwise {@code false}\n     */\n    boolean unregisterJettyJMXBean(ObjectName objectName) {\n      if (objectsWrappedWithMBean == null || ! objectName.getDomain().contains(\"org.eclipse.jetty\")) {\n        return false;\n      }\n      else { // Possibly a Jetty MBean that needs to be unregistered\n        try {\n\t\t      final Object bean = findBeanMethod.invoke(beanContainer, objectName);\n          if(bean == null)\n            return false;\n          \n\t\t      // Search suspect list\n\t\t      for (Object wrapped : objectsWrappedWithMBean) {\n\t\t        if (wrapped == bean) {\n              preventor.warn(\"Jetty MBean '\" + objectName + \"' is a suspect in causing memory leaks; unregistering\");\n\t\t\t        removeBeanMethod.invoke(beanContainer, bean); // Remove it via the MBeanContainer\n\t\t\t        return true;\n            }\n\t\t      }\n  \t\t  }\n        catch (Exception ex)  {\n          preventor.error(ex);\n\t\t    }\n\t\t    return false;\n\t    }\n    }\n\n    Class findJettyClass(String className) throws ClassNotFoundException {\n      try {\n        return Class.forName(className, false, preventor.getClassLoader());\n      } catch (ClassNotFoundException e1) {\n        try {\n          return Class.forName(className);\n        } catch (ClassNotFoundException e2) {\n          e2.addSuppressed(e1);\n          throw e2;\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.PlatformManagedObject;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.Set;\n\nimport javax.management.*;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Unregister MBeans, MXBean {@link NotificationListener}s/{@link NotificationFilter}s/handbacks loaded by the \n * protected class loader\n * @author Mattias Jiderhamn\n */\npublic class MXBeanNotificationListenersCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Class<?> notificationEmitterSupportClass = preventor.findClass(\"sun.management.NotificationEmitterSupport\");\n    final Field listenerListField = preventor.findField(notificationEmitterSupportClass, \"listenerList\");\n    final Class<?> listenerInfoClass = preventor.findClass(\"sun.management.NotificationEmitterSupport$ListenerInfo\");\n    final Field listenerField = preventor.findField(listenerInfoClass, \"listener\");\n    final Field filterField = preventor.findField(listenerInfoClass, \"filter\");\n    final Field handbackField = preventor.findField(listenerInfoClass, \"handback\");\n\n    final Class<?> listenerWrapperClass = preventor.findClass(\"com.sun.jmx.interceptor.DefaultMBeanServerInterceptor$ListenerWrapper\");\n\n    final boolean canProcessNotificationEmitterSupport = listenerListField != null && listenerInfoClass != null && listenerField != null && filterField != null && handbackField != null;\n\n    if (!canProcessNotificationEmitterSupport) {\n      preventor.warn(\"Unable to unregister NotificationEmitterSupport listeners, because details could not be found using reflection\");\n    }\n\n    final Set<Class<? extends PlatformManagedObject>> platformInterfaces = ManagementFactory.getPlatformManagementInterfaces();\n\n    if (platformInterfaces != null) {\n      for (Class<? extends PlatformManagedObject> platformInterface : platformInterfaces) {\n        for (Object mxBean : ManagementFactory.getPlatformMXBeans(platformInterface)) {\n          if (mxBean instanceof NotificationEmitter) { // The MXBean may have NotificationListeners\n            if (canProcessNotificationEmitterSupport && notificationEmitterSupportClass.isAssignableFrom(mxBean.getClass())) {\n              final List<? /* NotificationEmitterSupport.ListenerInfo */> listenerList = preventor.getFieldValue(listenerListField, mxBean);\n              if (listenerList != null) {\n                for (Object listenerInfo : listenerList) { // Loop all listeners\n                  final NotificationListener listener = preventor.getFieldValue(listenerField, listenerInfo);\n                  final NotificationListener rawListener = unwrap(preventor, listenerWrapperClass, listener);\n                  final NotificationFilter filter = preventor.getFieldValue(filterField, listenerInfo);\n                  final Object handback = preventor.getFieldValue(handbackField, listenerInfo);\n\n                  if (preventor.isLoadedInClassLoader(rawListener) || preventor.isLoadedInClassLoader(filter) || preventor.isLoadedInClassLoader(handback)) {\n                    preventor.warn(((listener == rawListener) ? \"Listener '\" : \"Wrapped listener '\") + listener + \n                    \"' (or its filter or handback) of MXBean \" + mxBean + \n                    \" of PlatformManagedObject \" + platformInterface + \" was loaded in protected ClassLoader; removing\");\n                    // This is safe, as the implementation (as of this writing) works with a copy,\n                    // not altering the original\n                    try {\n                      ((NotificationEmitter) mxBean).removeNotificationListener(listener, filter, handback);\n                    }\n                    catch (ListenerNotFoundException e) { // Should never happen\n                      preventor.error(e);\n                    }\n                  }\n                }\n              }\n            }\n            else if(mxBean instanceof NotificationBroadcasterSupport) { // Unlikely case\n              unregisterNotificationListeners(preventor, (NotificationBroadcasterSupport) mxBean, listenerWrapperClass);\n            }\n          }\n        }\n      }\n    }  \n  }\n\n  /** \n   * Unregister {@link NotificationListener}s from subclass of {@link NotificationBroadcasterSupport}, if listener,\n   * filter or handback is loaded by the protected ClassLoader.\n   */\n  protected void unregisterNotificationListeners(ClassLoaderLeakPreventor preventor, NotificationBroadcasterSupport mBean,\n                                                 final Class<?> listenerWrapperClass) {\n    final Field listenerListField = preventor.findField(NotificationBroadcasterSupport.class, \"listenerList\");\n    if(listenerListField != null) {\n      final Class<?> listenerInfoClass = preventor.findClass(\"javax.management.NotificationBroadcasterSupport$ListenerInfo\");\n\n      final List<? /*javax.management.NotificationBroadcasterSupport.ListenerInfo*/> listenerList =\n          preventor.getFieldValue(listenerListField, mBean);\n\n      if(listenerList != null) {\n        final Field listenerField = preventor.findField(listenerInfoClass, \"listener\");\n        final Field filterField = preventor.findField(listenerInfoClass, \"filter\");\n        final Field handbackField = preventor.findField(listenerInfoClass, \"handback\");\n        for(Object listenerInfo : listenerList) {\n          final NotificationListener listener = preventor.getFieldValue(listenerField, listenerInfo);\n          final NotificationListener rawListener = unwrap(preventor, listenerWrapperClass, listener);\n          final NotificationFilter filter = preventor.getFieldValue(filterField, listenerInfo);\n          final Object handback = preventor.getFieldValue(handbackField, listenerInfo);\n          \n          if(preventor.isLoadedInClassLoader(rawListener) || preventor.isLoadedInClassLoader(filter) || preventor.isLoadedInClassLoader(handback)) {\n            preventor.warn(((listener == rawListener) ? \"Listener '\" : \"Wrapped listener '\") + listener + \n                \"' (or its filter or handback) of MBean \" + mBean + \n                \" was loaded in protected ClassLoader; removing\");\n            // This is safe, as the implementation works with a copy, not altering the original\n            try {\n              mBean.removeNotificationListener(listener, filter, handback);\n            }\n            catch (ListenerNotFoundException e) { // Should never happen\n              preventor.error(e);\n            }\n          }\n        }\n      }\n    }\n  }\n\n  /** Unwrap {@link NotificationListener} wrapped by {@link com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.ListenerWrapper} */\n  private NotificationListener unwrap(ClassLoaderLeakPreventor preventor, Class<?> listenerWrapperClass, NotificationListener listener) {\n    if(listenerWrapperClass != null && listenerWrapperClass.isInstance(listener)) {\n      return preventor.getFieldValue(listener, \"listener\"); // Unwrap\n    }\n    else \n      return listener;\n  }\n\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MoxyCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.ConcurrentModificationException;\nimport java.util.Map;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Cleanup for leak caused by EclipseLink MOXy\n * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=529270\n * @author Mattias Jiderhamn\n */\npublic class MoxyCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Class<?> helperClass = findClass(preventor, \"org.eclipse.persistence.jaxb.javamodel.Helper\");\n    if(helperClass != null) {\n      unsetField(preventor, helperClass, \"COLLECTION_CLASS\");\n      unsetField(preventor, helperClass, \"LIST_CLASS\");\n      unsetField(preventor, helperClass, \"SET_CLASS\");\n      unsetField(preventor, helperClass, \"MAP_CLASS\");\n      unsetField(preventor, helperClass, \"JAXBELEMENT_CLASS\");\n      unsetField(preventor, helperClass, \"OBJECT_CLASS\");\n    }\n\n    final Class<?> propertyClass = findClass(preventor, \"org.eclipse.persistence.jaxb.compiler.Property\");\n    if(propertyClass != null) {\n      unsetField(preventor, propertyClass, \"OBJECT_CLASS\");\n      unsetField(preventor, propertyClass, \"XML_ADAPTER_CLASS\");\n    }\n  }\n  \n  public Class<?> findClass(ClassLoaderLeakPreventor preventor, String className) {\n    try {\n      return Class.forName(className, true, preventor.getLeakSafeClassLoader());\n    }\n    catch (ClassNotFoundException e) {\n      // Silently ignore\n      return null;\n    }\n    catch (Exception ex) { // Example SecurityException\n      preventor.warn(ex);\n      return null;\n    }\n  }\n\n  private void unsetField(ClassLoaderLeakPreventor preventor,\n                          Class<?> clazz, String fieldName) {\n    final Field field = preventor.findField(clazz, fieldName);\n    if(field != null) {\n      try {\n        final Object /* org.eclipse.persistence.jaxb.javamodel.reflection.JavaClassImpl */ javaClass = field.get(null);\n        if(javaClass != null) {\n          final Object /* org.eclipse.persistence.jaxb.javamodel.reflection.JavaModelImpl */ javaModelImpl = \n              preventor.getFieldValue(javaClass, \"javaModelImpl\");\n          if(javaModelImpl != null) {\n            final Method getClassLoader = preventor.findMethod(javaModelImpl.getClass(), \"getClassLoader\");\n            if(getClassLoader != null) {\n              final ClassLoader classLoader = (ClassLoader) getClassLoader.invoke(javaModelImpl);\n              if(preventor.isClassLoaderOrChild(classLoader)) {\n                preventor.info(\"Changing ClassLoader of \" + field);\n                preventor.findMethod(javaModelImpl.getClass(), \"setClassLoader\", ClassLoader.class)\n                    .invoke(javaModelImpl, preventor.getLeakSafeClassLoader());\n                final Field isJaxbClassLoader = preventor.findField(javaModelImpl.getClass(), \"isJaxbClassLoader\");\n                if(isJaxbClassLoader != null) {\n                  isJaxbClassLoader.set(javaModelImpl, false);\n                }\n              }\n            }\n            else\n              preventor.error(\"Cannot get ClassLoader of \" + javaModelImpl);\n            \n            // Clear cachedJavaClasses\n            final Map cachedJavaClasses = preventor.getFieldValue(javaModelImpl, \"cachedJavaClasses\");\n            if(cachedJavaClasses != null) {\n              try {\n                cachedJavaClasses.clear();\n              }\n              catch (ConcurrentModificationException e) {\n                preventor.error(\"Unable to clear \" + javaModelImpl + \".cachedJavaClasses\");\n              }\n            }\n          }\n          else {\n            preventor.error(\"Cannot get javaModelImpl of \" + javaClass);\n            field.set(null, null);\n          }\n        }\n      }\n      catch (Exception e) {\n        preventor.warn(e);\n      }\n    }\n    else \n      preventor.warn(\"Unable to find field \" + fieldName + \" of class \" + clazz);\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/MultiThreadedHttpConnectionManagerCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Invokes static method org.apache.commons.httpclient.MultiThreadedHttpConnectionManager.shutdownAll() to close connections left out by com.sun.jersey.client.apache.ApacheHttpClient.  \n *\n * @author Marian Petrik\n */\npublic class MultiThreadedHttpConnectionManagerCleanUp implements ClassLoaderPreMortemCleanUp {\n\n\t@Override\n\tpublic void cleanUp(ClassLoaderLeakPreventor preventor) {\n\t\tfinal Class<?> connManager = preventor.findClass(\"org.apache.commons.httpclient.MultiThreadedHttpConnectionManager\");\n\t\tif(connManager != null && preventor.isLoadedByClassLoader(connManager)) {\n\t\t\ttry {\n\t\t\t\tconnManager.getMethod(\"shutdownAll\").invoke(null);\n\t\t\t}\n\t\t\tcatch (Throwable t) {\n\t\t\t\tpreventor.warn(t);\n\t\t\t}\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ObjectStreamClassCleanup.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clean up for the static caches of {@link java.io.ObjectStreamClass}\n */\npublic class ObjectStreamClassCleanup implements ClassLoaderPreMortemCleanUp {\n\n    @Override\n    public void cleanUp(ClassLoaderLeakPreventor preventor) {\n        try {\n            final Class<?> cacheClass = preventor.findClass(\"java.io.ObjectStreamClass$Caches\");\n            if (cacheClass == null) { return; }\n\n            Object localDescsCache = preventor.getStaticFieldValue(cacheClass, \"localDescs\");\n            clearIfConcurrentHashMap(localDescsCache, preventor);\n\n            Object reflectorsCache = preventor.getStaticFieldValue(cacheClass, \"reflectors\");\n            clearIfConcurrentHashMap(reflectorsCache, preventor);\n        }\n        catch (Exception e) {\n            preventor.error(e);\n        }\n    }\n\n    protected void clearIfConcurrentHashMap(Object object, ClassLoaderLeakPreventor preventor) {\n        if (!(object instanceof ConcurrentHashMap)) { return; }\n        ConcurrentHashMap<?,?> map = (ConcurrentHashMap<?,?>) object;\n        int nbOfEntries=map.size();\n        map.clear();\n        preventor.info(\"Detected and fixed leak situation for java.io.ObjectStreamClass (\"+nbOfEntries+\" entries were flushed).\");\n    }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/PropertyEditorCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.beans.PropertyEditorManager;\nimport java.lang.reflect.Field;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Deregister custom property editors.\n * This has been fixed in Java 7.\n * @author Mattias Jiderhamn\n */\npublic class PropertyEditorCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Field registryField = preventor.findField(PropertyEditorManager.class, \"registry\");\n    if(registryField == null) { // We're probably on a newer JDK\n      preventor.info(\"Internal registry of \" + PropertyEditorManager.class.getName() + \" not found\");\n    }\n    else {\n      try {\n        synchronized (PropertyEditorManager.class) {\n          final Map<Class<?>, Class<?>> registry = (Map<Class<?>, Class<?>>) registryField.get(null);\n          if(registry != null) { // Initialized\n            final Set<Class<?>> toRemove = new HashSet<Class<?>>();\n            \n            for(Map.Entry<Class<?>, Class<?>> entry : registry.entrySet()) {\n              if(preventor.isLoadedByClassLoader(entry.getKey()) ||\n                 preventor.isLoadedByClassLoader(entry.getValue())) { // More likely\n                toRemove.add(entry.getKey());\n              }\n            }\n            \n            for(Class<?> clazz : toRemove) {\n              preventor.warn(\"Property editor for type \" + clazz +  \" = \" + registry.get(clazz) + \" needs to be deregistered\");\n              PropertyEditorManager.registerEditor(clazz, null); // Deregister\n            }\n          }\n        }\n      }\n      catch (Exception e) { // Such as IllegalAccessException\n        preventor.error(e);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ProxySelectorCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.net.ProxySelector;\nimport java.security.AccessController;\nimport java.security.PrivilegedAction;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * If default {@link java.net.ProxySelector} is loaded by protected ClassLoader it needs to be unset\n * @author Mattias Jiderhamn\n */\npublic class ProxySelectorCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(final ClassLoaderLeakPreventor preventor) {\n    AccessController.doPrivileged(new PrivilegedAction<Void>() {\n      @Override\n      public Void run() {\n        ProxySelector selector = ProxySelector.getDefault();\n        if(preventor.isLoadedInClassLoader(selector)) {\n          ProxySelector.setDefault(null);\n          preventor.warn(\"Removing default java.net.ProxySelector: \" + selector);\n        }\n        return null;\n      }\n    });\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ReactorNettyHttpResourcesCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Method;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n\n/**\n * Clean up Reactor Netty resources\n * @author Mattias Jiderhamn\n */\npublic class ReactorNettyHttpResourcesCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    Class<?> clazz = preventor.findClass(\"reactor.ipc.netty.http.HttpResources\");\n    if(preventor.isLoadedByClassLoader(clazz)) {\n      final Method shutdown = preventor.findMethod(clazz, \"shutdown\");\n      if(shutdown != null) {\n        try {\n          shutdown.invoke(null);\n        }\n        catch (Throwable e) {\n          preventor.warn(e);\n        }\n      }\n    }\n    clazz = preventor.findClass(\"reactor.netty.http.HttpResources\");\n    if(preventor.isLoadedByClassLoader(clazz)) {\n      final Method shutdown = preventor.findMethod(clazz, \"shutdown\");\n      if(shutdown != null) {\n        try {\n          shutdown.invoke(null);\n        }\n        catch (Throwable e) {\n          preventor.warn(e);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ResourceBundleCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.ResourceBundle;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clean up caches in {@link ResourceBundle}\n * @author Mattias Jiderhamn\n */\npublic class ResourceBundleCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    try {\n      try { // First try Java 1.6 method\n        final Method clearCache16 = ResourceBundle.class.getMethod(\"clearCache\", ClassLoader.class);\n        preventor.debug(\"Since Java 1.6+ is used, we can call \" + clearCache16);\n        clearCache16.invoke(null, preventor.getClassLoader());\n      }\n      catch (NoSuchMethodException e) {\n        // Not Java 1.6+, we have to clear manually\n        final Map<?,?> cacheList = preventor.getStaticFieldValue(ResourceBundle.class, \"cacheList\"); // Java 5: SoftCache extends AbstractMap\n        final Iterator<?> iter = cacheList.keySet().iterator();\n        Field loaderRefField = null;\n        while(iter.hasNext()) {\n          Object key = iter.next(); // CacheKey\n          \n          if(loaderRefField == null) { // First time\n            loaderRefField = key.getClass().getDeclaredField(\"loaderRef\");\n            loaderRefField.setAccessible(true);\n          }\n          WeakReference<ClassLoader> loaderRef = (WeakReference<ClassLoader>) loaderRefField.get(key); // LoaderReference extends WeakReference\n          ClassLoader classLoader = loaderRef.get();\n          \n          if(preventor.isClassLoaderOrChild(classLoader)) {\n            preventor.info(\"Removing ResourceBundle from cache: \" + key);\n            iter.remove();\n          }\n          \n        }\n      }\n    }\n    catch(Exception ex) {\n      preventor.error(ex);\n    }\n    \n    // (CacheKey of java.util.ResourceBundle.NONEXISTENT_BUNDLE will point to first referring classloader...)\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/RmiTargetsCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.util.Iterator;\nimport java.util.Map;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Heavily inspired by org.apache.catalina.loader.WebappClassLoader.clearReferencesRmiTargets()\n * @author Mattias Jiderhamn\n */\npublic class RmiTargetsCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    try {\n      final Class<?> objectTableClass = preventor.findClass(\"sun.rmi.transport.ObjectTable\");\n      if(objectTableClass != null) {\n        clearRmiTargetsMap(preventor, (Map<?, ?>) preventor.getStaticFieldValue(objectTableClass, \"objTable\"));\n        clearRmiTargetsMap(preventor, (Map<?, ?>) preventor.getStaticFieldValue(objectTableClass, \"implTable\"));\n      }\n    }\n    catch (Exception ex) {\n      preventor.error(ex);\n    }\n  }\n\n  /** Iterate RMI Targets Map and remove entries loaded by protected ClassLoader */\n  @SuppressWarnings(\"WeakerAccess\")\n  protected void clearRmiTargetsMap(ClassLoaderLeakPreventor preventor, Map<?, ?> rmiTargetsMap) {\n    try {\n      final Field cclField = preventor.findFieldOfClass(\"sun.rmi.transport.Target\", \"ccl\");\n      preventor.debug(\"Looping \" + rmiTargetsMap.size() + \" RMI Targets to find leaks\");\n      for(Iterator<?> iter = rmiTargetsMap.values().iterator(); iter.hasNext(); ) {\n        Object target = iter.next(); // sun.rmi.transport.Target\n        ClassLoader ccl = (ClassLoader) cclField.get(target);\n        if(preventor.isClassLoaderOrChild(ccl)) {\n          preventor.warn(\"Removing RMI Target: \" + target);\n          iter.remove();\n        }\n      }\n    }\n    catch (Exception ex) {\n      preventor.error(ex);\n    }\n  }\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/SAAJEnvelopeFactoryParserPoolCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.util.Map;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clean up leak caused by {@link javax.xml.parsers.SAXParser} attribute/property being loaded by protected class loader\n * and cached in {@link com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory#parserPool}.\n * See <a href=\"https://issues.apache.org/jira/browse/XALANJ-2600\">here</a>.\n * @author Mattias Jiderhamn\n */\npublic class SAAJEnvelopeFactoryParserPoolCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    // Internal class from the JDK (Removed in JDK11)\n    cleanupWithFactoryClass(preventor, preventor.findClass(\"com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory\"));\n    // Maven dependency\n    cleanupWithFactoryClass(preventor, preventor.findClass(\"com.sun.xml.messaging.saaj.soap.EnvelopeFactory\"));\n  }\n\n  private void cleanupWithFactoryClass(final ClassLoaderLeakPreventor preventor, Class<?> factoryClass) {\n    final Object parserPool = preventor.getStaticFieldValue(factoryClass, \"parserPool\");\n    \n    if(parserPool != null) {\n      final Field CACHE = preventor.findField(parserPool.getClass().getSuperclass(), \"CACHE\");\n      if(CACHE != null) {\n        final Object cache = preventor.getFieldValue(CACHE, parserPool);\n        if(cache instanceof Map) { // WeakHashMap\n          ((Map) cache).remove(preventor.getClassLoader());\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/SecurityProviderCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Deregister custom security providers\n * @author Mattias Jiderhamn\n */\npublic class SecurityProviderCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Set<String> providersToRemove = new HashSet<String>();\n    for(java.security.Provider provider : java.security.Security.getProviders()) {\n      if(preventor.isLoadedInClassLoader(provider)) {\n        providersToRemove.add(provider.getName());\n      }\n    }\n    \n    if(! providersToRemove.isEmpty()) {\n      preventor.warn(\"Removing security providers loaded by protected ClassLoader: \" + providersToRemove);\n      for(String providerName : providersToRemove) {\n        java.security.Security.removeProvider(providerName);\n      }\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ShutdownHookCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.ArrayList;\nimport java.util.Map;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Find and deregister shutdown hooks. Will by default execute the hooks immediately after removing them.\n * @author Mattias Jiderhamn\n */\npublic class ShutdownHookCleanUp implements ClassLoaderPreMortemCleanUp {\n\n  /** Default no of milliseconds to wait for shutdown hook to finish execution */\n  public static final int SHUTDOWN_HOOK_WAIT_MS_DEFAULT = 10 * 1000; // 10 seconds\n\n  /** Should shutdown hooks registered from the application be executed at application shutdown? */\n  @SuppressWarnings(\"WeakerAccess\")\n  protected boolean executeShutdownHooks = true;\n\n  /** \n   * No of milliseconds to wait for shutdown hooks to finish execution, before stopping them.\n   * If set to -1 there will be no waiting at all, but Thread is allowed to run until finished.\n   */\n  @SuppressWarnings(\"WeakerAccess\")\n  protected int shutdownHookWaitMs = SHUTDOWN_HOOK_WAIT_MS_DEFAULT;\n\n  /** Constructor for test case */\n  @SuppressWarnings(\"unused\")\n  public ShutdownHookCleanUp() {\n    this(true, SHUTDOWN_HOOK_WAIT_MS_DEFAULT);\n  }\n\n  public ShutdownHookCleanUp(boolean executeShutdownHooks, int shutdownHookWaitMs) {\n    this.executeShutdownHooks = executeShutdownHooks;\n    this.shutdownHookWaitMs = shutdownHookWaitMs;\n  }\n\n  public void setExecuteShutdownHooks(boolean executeShutdownHooks) {\n    this.executeShutdownHooks = executeShutdownHooks;\n  }\n\n  public void setShutdownHookWaitMs(int shutdownHookWaitMs) {\n    this.shutdownHookWaitMs = shutdownHookWaitMs;\n  }\n\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    \n    // We will not remove known shutdown hooks, since loading the owning class of the hook,\n    // may register the hook if previously unregistered \n    final Map<Thread, Thread> shutdownHooks = preventor.getStaticFieldValue(\"java.lang.ApplicationShutdownHooks\", \"hooks\");\n    if(shutdownHooks != null) { // Could be null during JVM shutdown, which we already avoid, but be extra precautious\n      // Iterate copy to avoid ConcurrentModificationException\n      for(Thread shutdownHook : new ArrayList<Thread>(shutdownHooks.keySet())) {\n        if(preventor.isThreadInClassLoader(shutdownHook)) { // Planned to run in protected ClassLoader\n          removeShutdownHook(preventor, shutdownHook);\n        }\n      }\n    }\n  }\n\n  /** Deregister shutdown hook and execute it immediately */\n  @SuppressWarnings({\"deprecation\", \"WeakerAccess\"})\n  protected void removeShutdownHook(ClassLoaderLeakPreventor preventor, Thread shutdownHook) {\n    final String displayString = \"'\" + shutdownHook + \"' of type \" + shutdownHook.getClass().getName();\n    preventor.error(\"Removing shutdown hook: \" + displayString);\n    Runtime.getRuntime().removeShutdownHook(shutdownHook);\n\n    if(executeShutdownHooks) { // Shutdown hooks should be executed\n      \n      preventor.info(\"Executing shutdown hook now: \" + displayString);\n      // Make sure it's from protected ClassLoader\n      shutdownHook.start(); // Run cleanup immediately\n      \n      if(shutdownHookWaitMs > 0) { // Wait for shutdown hook to finish\n        try {\n          shutdownHook.join(shutdownHookWaitMs); // Wait for thread to run\n        }\n        catch (InterruptedException e) {\n          // Do nothing\n        }\n        if(shutdownHook.isAlive()) {\n          preventor.warn(shutdownHook + \"still running after \" + shutdownHookWaitMs + \" ms - Stopping!\");\n          shutdownHook.stop();\n        }\n      }\n    }\n  }\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.security.AccessControlContext;\nimport java.util.List;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\nimport static se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor.THREAD_WAIT_MS_DEFAULT;\n\n/**\n * Check if there are threads running within the protected {@link ClassLoader}, or otherwise referencing it,\n * and either warn or stop those threads depending on settings.\n * @author Mattias Jiderhamn\n */\n@SuppressWarnings(\"WeakerAccess\")\npublic class StopThreadsCleanUp implements ClassLoaderPreMortemCleanUp {\n\n  protected static final String JURT_ASYNCHRONOUS_FINALIZER = \"com.sun.star.lib.util.AsynchronousFinalizer\";\n\n  /** Thread {@link Runnable} for Sun/Oracle JRE i.e. java.lang.Thread.target */\n  private Field oracleTarget;\n  \n  /** Thread {@link Runnable} for IBM JRE i.e. java.lang.Thread.runnable */\n  private Field ibmRunnable;\n\n  protected boolean stopThreads;\n\n  /**\n   * No of milliseconds to wait for threads to finish execution, before stopping them.\n   */\n  protected int threadWaitMs = THREAD_WAIT_MS_DEFAULT;\n  \n  /** Should Timer threads tied to the protected ClassLoader classloader be forced to stop at application shutdown? */\n  protected boolean stopTimerThreads;\n\n  /** Default constructor with {@link #stopThreads} = true and {@link #stopTimerThreads} = true */\n  @SuppressWarnings(\"unused\")\n  public StopThreadsCleanUp() {\n    this(true, true);\n  }\n\n  public StopThreadsCleanUp(boolean stopThreads, boolean stopTimerThreads) {\n    this.stopThreads = stopThreads;\n    this.stopTimerThreads = stopTimerThreads;\n  }\n\n  public void setStopThreads(boolean stopThreads) {\n    this.stopThreads = stopThreads;\n  }\n\n  public void setStopTimerThreads(boolean stopTimerThreads) {\n    this.stopTimerThreads = stopTimerThreads;\n  }\n\n  public void setThreadWaitMs(int threadWaitMs) {\n    this.threadWaitMs = threadWaitMs;\n  }\n\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    // Force the execution of the cleanup code for JURT; see https://issues.apache.org/ooo/show_bug.cgi?id=122517\n    forceStartOpenOfficeJurtCleanup(preventor); // (Do this before stopThreads())\n    \n    ////////////////////\n    // Fix generic leaks\n    \n    stopThreads(preventor);\n  }\n  \n  /**\n   * The bug detailed at https://issues.apache.org/ooo/show_bug.cgi?id=122517 is quite tricky. This is a try to \n   * avoid the issues by force starting the threads and it's job queue.\n   */\n  protected void forceStartOpenOfficeJurtCleanup(ClassLoaderLeakPreventor preventor) {\n    if(stopThreads) {\n      if(preventor.isLoadedByClassLoader(preventor.findClass(JURT_ASYNCHRONOUS_FINALIZER))) {\n        /* \n          The com.sun.star.lib.util.AsynchronousFinalizer class was found and loaded, which means that in case the\n          static block that starts the daemon thread had not been started yet, it has been started now.\n          \n          Now let's force Garbage Collection, with the hopes of having the finalize()ers that put Jobs on the\n          AsynchronousFinalizer queue be executed. Then just leave it, and handle the rest in {@link #stopThreads}.\n          */\n        preventor.info(\"OpenOffice JURT AsynchronousFinalizer thread started - forcing garbage collection to invoke finalizers\");\n        ClassLoaderLeakPreventor.gc();\n      }\n    }\n    else {\n      // Check for class existence without loading class and thus executing static block\n      if(preventor.getClassLoader().getResource(\"com/sun/star/lib/util/AsynchronousFinalizer.class\") != null) {\n        preventor.warn(\"OpenOffice JURT AsynchronousFinalizer thread will not be stopped if started, as stopThreads is false\");\n        /* \n         By forcing Garbage Collection, we'll hopefully start the thread now, in case it would have been started by\n         GC later, so that at least it will appear in the logs. \n         */\n        ClassLoaderLeakPreventor.gc();\n      }\n    }\n  }\n  \n  /**\n   * Partially inspired by org.apache.catalina.loader.WebappClassLoader.clearReferencesThreads()\n   */\n  protected void stopThreads(ClassLoaderLeakPreventor preventor) {\n    final Class<?> workerClass = preventor.findClass(\"java.util.concurrent.ThreadPoolExecutor$Worker\");\n\n    final boolean waitForThreads = threadWaitMs > 0;\n    for(Thread thread : preventor.getAllThreads()) {\n      final Runnable runnable = getRunnable(preventor, thread);\n\n      final boolean threadLoadedByClassLoader = preventor.isLoadedInClassLoader(thread);\n      final boolean threadGroupLoadedByClassLoader = preventor.isLoadedInClassLoader(thread.getThreadGroup());\n      final boolean runnableLoadedByClassLoader = preventor.isLoadedInClassLoader(runnable);\n      final boolean hasContextClassLoader = preventor.isClassLoaderOrChild(thread.getContextClassLoader());\n      if(thread != Thread.currentThread() && // Ignore current thread\n         (threadLoadedByClassLoader || threadGroupLoadedByClassLoader || hasContextClassLoader || // = preventor.isThreadInClassLoader(thread) \n          runnableLoadedByClassLoader)) {\n\n        if (thread.getClass().getName().startsWith(StopThreadsCleanUp.JURT_ASYNCHRONOUS_FINALIZER)) {\n          // Note, the thread group of this thread may be \"system\" if it is triggered by the Garbage Collector\n          // however if triggered by us in forceStartOpenOfficeJurtCleanup() it may depend on the application server\n          if(stopThreads) {\n            preventor.info(\"Found JURT thread \" + thread.getName() + \"; starting \" + JURTKiller.class.getSimpleName());\n            new JURTKiller(preventor, thread).start();\n          }\n          else\n            preventor.warn(\"JURT thread \" + thread.getName() + \" is still running in protected ClassLoader\");\n        }\n        else if(thread.getThreadGroup() != null && \n           (\"system\".equals(thread.getThreadGroup().getName()) ||  // System thread\n            \"RMI Runtime\".equals(thread.getThreadGroup().getName()))) { // RMI thread (honestly, just copied from Tomcat)\n          \n          if(\"Keep-Alive-Timer\".equals(thread.getName())) {\n            thread.setContextClassLoader(preventor.getLeakSafeClassLoader());\n            preventor.debug(\"Changed contextClassLoader of HTTP keep alive thread\");\n          }\n        }\n        else if(thread.isAlive()) { // Non-system, running in protected ClassLoader\n\n          if(thread.getClass().getName().startsWith(\"java.util.Timer\")) { // Sun/Oracle = \"java.util.TimerThread\"; IBM = \"java.util.Timer$TimerImpl\"\n            if(thread.getName() != null && thread.getName().startsWith(\"PostgreSQL-JDBC-SharedTimer-\")) { // Postgresql JDBC timer thread\n              // Replace contextClassLoader, if needed\n              if(hasContextClassLoader) {\n                final Class<?> postgresqlDriver = preventor.findClass(\"org.postgresql.Driver\");\n                final ClassLoader postgresqlCL = (postgresqlDriver != null && ! preventor.isLoadedByClassLoader(postgresqlDriver)) ?\n                    postgresqlDriver.getClassLoader() : // Postgresql driver loaded by other classloader than we want to protect\n                    preventor.getLeakSafeClassLoader();\n                thread.setContextClassLoader(postgresqlCL);\n                preventor.warn(\"Changing contextClassLoader of \" + thread + \" to \" + postgresqlCL);\n              }\n\n              // Replace AccessControlContext\n              setThreadSafeAccessControlContext(preventor, thread);\n            }\n            else if(stopTimerThreads) {\n              preventor.warn(\"Stopping Timer thread '\" + thread.getName() + \"' running in protected ClassLoader. \" +\n                  preventor.getStackTrace(thread));\n              stopTimerThread(preventor, thread);\n            }\n            else {\n              preventor.info(\"Timer thread is running in protected ClassLoader, but will not be stopped. \" + \n                  preventor.getStackTrace(thread));\n            }\n          }\n          else {\n            final String displayString = \"Thread '\" + thread + \"'\" + \n                (threadLoadedByClassLoader ? \" of type \" + thread.getClass().getName() + \" loaded by protected ClassLoader\" : \"\") +\n                (runnableLoadedByClassLoader ? \" with Runnable of type \" + runnable.getClass().getName() + \" loaded by protected ClassLoader\" : \"\") +\n                (threadGroupLoadedByClassLoader ? \" with ThreadGroup of type \" + thread.getThreadGroup().getClass().getName() + \" loaded by protected ClassLoader\" : \"\") +\n                (hasContextClassLoader ? \" with contextClassLoader = protected ClassLoader or child\" : \"\");\n\n            // If threads is running an java.util.concurrent.ThreadPoolExecutor.Worker try shutting down the executor\n            if(workerClass != null && workerClass.isInstance(runnable)) {\n              try {\n                // java.util.concurrent.ThreadPoolExecutor, introduced in Java 1.5\n                final Field workerExecutor = preventor.findField(workerClass, \"this$0\");\n                final ThreadPoolExecutor executor = preventor.getFieldValue(workerExecutor, runnable);\n                if(executor != null) {\n                  if(\"org.apache.tomcat.util.threads.ThreadPoolExecutor\".equals(executor.getClass().getName())) {\n                    // Tomcat pooled thread\n                    preventor.debug(displayString + \" is worker of \" + executor.getClass().getName());\n                  }\n                  else if(preventor.isLoadedInClassLoader(executor) || preventor.isLoadedInClassLoader(executor.getThreadFactory())) {\n                    if(stopThreads) {\n                      preventor.warn(\"Shutting down ThreadPoolExecutor of type \" + executor.getClass().getName());\n                      executor.shutdownNow();\n                    }\n                    else {\n                      preventor.warn(\"ThreadPoolExecutor of type \" + executor.getClass().getName() +\n                          \" should be shut down.\");\n                    }\n                  }\n                  else {\n                    preventor.info(displayString + \" is a ThreadPoolExecutor.Worker of \" + executor.getClass().getName() +\n                        \" but found no reason to shut down ThreadPoolExecutor.\");\n                  }\n                }\n              }\n              catch (Exception ex) {\n                preventor.error(ex);\n              }\n            }\n\n            if(! threadLoadedByClassLoader && ! runnableLoadedByClassLoader && ! threadGroupLoadedByClassLoader) { // Not loaded in protected ClassLoader - just running there\n              // This would for example be the case with org.apache.tomcat.util.threads.TaskThread\n              if(waitForThreads) {\n                preventor.warn(displayString + \"; waiting \" + threadWaitMs + \n                    \" ms. \" + preventor.getStackTrace(thread));\n                preventor.waitForThread(thread, threadWaitMs, false /* No interrupt */);\n              }\n\n              if(thread.isAlive() && preventor.isClassLoaderOrChild(thread.getContextClassLoader())) { // Still running in ClassLoader\n                preventor.warn(displayString + (waitForThreads ? \" still\" : \"\") + \n                    \" alive; changing context ClassLoader to leak safe (\" + \n                    preventor.getLeakSafeClassLoader() + \"). \" + preventor.getStackTrace(thread));\n                thread.setContextClassLoader(preventor.getLeakSafeClassLoader());\n\n                // Replace AccessControlContext since we already replaced ClassLoader,\n                // for test/use cease @see StopThreadsClenup_ExecutorTest\n                setThreadSafeAccessControlContext(preventor, thread);\n              }\n            }\n            else if(stopThreads) { // Thread/Runnable/ThreadGroup loaded by protected ClassLoader\n              if(waitForThreads) {\n                preventor.warn(\"Waiting for \" + displayString + \" for \" + threadWaitMs + \" ms. \" +\n                    preventor.getStackTrace(thread));\n\n                preventor.waitForThread(thread, threadWaitMs, true /* Interrupt if needed */);\n              }\n\n              // Normally threads should not be stopped (method is deprecated), since it may cause an inconsistent state.\n              // In this case however, the alternative is a classloader leak, which may or may not be considered worse.\n              if(thread.isAlive()) {\n                preventor.warn(\"Stopping \" + displayString + \". \" + preventor.getStackTrace(thread));\n                //noinspection deprecation\n                thread.stop();\n              }\n              else {\n                preventor.info(displayString + \" no longer alive - no action needed.\");\n              }\n            }\n            else {\n              preventor.warn(displayString + \" would cause leak. \" + preventor.getStackTrace(thread));\n            }\n              \n          }\n        }\n      }\n    }\n  }\n\n\n  /**\n   * Replace Thread AccessControlContext to allow for Protection Domain GC\n   */\n  private void setThreadSafeAccessControlContext(ClassLoaderLeakPreventor preventor, Thread thread) {\n      // Replace AccessControlContext\n      final Field inheritedAccessControlContext = preventor.findField(Thread.class, \"inheritedAccessControlContext\");\n      if(inheritedAccessControlContext != null) {\n        try {\n          final AccessControlContext acc = preventor.createAccessControlContext();\n          inheritedAccessControlContext.set(thread, acc);\n          preventor.removeDomainCombiner(\"thread \" + thread, acc);\n        }\n        catch (Exception e) {\n          preventor.error(e);\n        }\n      }\n  }\n\n  /** Get {@link Runnable} of given thread, if any */\n  private Runnable getRunnable(ClassLoaderLeakPreventor preventor, Thread thread) {\n    if(oracleTarget == null && ibmRunnable == null) { // Not yet initialized\n      oracleTarget = preventor.findField(Thread.class, \"target\"); // Sun/Oracle JRE\n      ibmRunnable = preventor.findField(Thread.class, \"runnable\"); // IBM JRE       \n    }\n\n    return (oracleTarget != null) ? (Runnable) preventor.getFieldValue(oracleTarget, thread) : // Sun/Oracle JRE  \n        (Runnable) preventor.getFieldValue(ibmRunnable, thread);   // IBM JRE\n  }\n\n  protected void stopTimerThread(ClassLoaderLeakPreventor preventor, Thread thread) {\n    // Seems it is not possible to access Timer of TimerThread, so we need to mimic Timer.cancel()\n    /** \n    try {\n      Timer timer = (Timer) findField(thread.getClass(), \"this$0\").get(thread); // This does not work!\n      warn(\"Cancelling Timer \" + timer + \" / TimeThread '\" + thread + \"'\");\n      timer.cancel();\n    }\n    catch (IllegalAccessException iaex) {\n      error(iaex);\n    }\n    */\n\n    try {\n      final Field newTasksMayBeScheduled = preventor.findField(thread.getClass(), \"newTasksMayBeScheduled\");\n      final Object queue = preventor.findField(thread.getClass(), \"queue\").get(thread); // java.lang.TaskQueue\n      final Method clear = preventor.findMethod(queue.getClass(), \"clear\");\n      \n      // Do what java.util.Timer.cancel() does\n      //noinspection SynchronizationOnLocalVariableOrMethodParameter\n      synchronized (queue) {\n        newTasksMayBeScheduled.set(thread, Boolean.FALSE);\n        clear.invoke(queue);\n        queue.notify(); // \"In case queue was already empty.\"\n      }\n      \n      // We shouldn't need to join() here, thread will finish soon enough\n    }\n    catch (Exception ex) {\n      preventor.error(ex);\n    }\n  }\n  \n  /** \n   * Inner class with the sole task of killing JURT finalizer thread after it is done processing jobs. \n   * We need to postpone the stopping of this thread, since more Jobs may in theory be add()ed when the protected \n   * ClassLoader is closing down and being garbage collected.\n   * See https://issues.apache.org/ooo/show_bug.cgi?id=122517\n   */\n  protected class JURTKiller extends Thread {\n\n    private final ClassLoaderLeakPreventor preventor;\n\n    private final Thread jurtThread;\n\n    private final List<?> jurtQueue;\n\n    public JURTKiller(ClassLoaderLeakPreventor preventor, Thread jurtThread) {\n      super(\"JURTKiller\");\n      this.preventor = preventor;\n      this.jurtThread = jurtThread;\n      jurtQueue = preventor.getStaticFieldValue(StopThreadsCleanUp.JURT_ASYNCHRONOUS_FINALIZER, \"queue\");\n      // Make sure all classes are loaded from the current app classloader before it executes,\n      // as it may use them *after* the classloader has been \"shutdown\" by the container (if any).\n      State state = State.RUNNABLE;\n    }\n\n    @Override\n    public void run() {\n        try {\n            if(jurtQueue == null || jurtThread == null) {\n                preventor.error(getName() + \": No queue or thread!?\");\n                return;\n              }\n              if(! jurtThread.isAlive()) {\n                preventor.warn(getName() + \": \" + jurtThread.getName() + \" is already dead?\");\n              }\n\n              boolean queueIsEmpty = false;\n              while(! queueIsEmpty) {\n                try {\n                  preventor.debug(getName() + \" goes to sleep for \" + ClassLoaderLeakPreventor.THREAD_WAIT_MS_DEFAULT + \" ms\");\n                  Thread.sleep(ClassLoaderLeakPreventor.THREAD_WAIT_MS_DEFAULT);\n                }\n                catch (InterruptedException e) {\n                  // Do nothing\n                }\n\n                if(State.RUNNABLE != jurtThread.getState()) { // Unless thread is currently executing a Job\n                  preventor.debug(getName() + \" about to force Garbage Collection\");\n                  ClassLoaderLeakPreventor.gc(); // Force garbage collection, which may put new items on queue\n\n                  synchronized (jurtQueue) {\n                    queueIsEmpty = jurtQueue.isEmpty();\n                    preventor.debug(getName() + \": JURT queue is empty? \" + queueIsEmpty);\n                  }\n                }\n                else\n                  preventor.debug(getName() + \": JURT thread \" + jurtThread.getName() + \" is executing Job\");\n                }\n\n              preventor.info(getName() + \" about to kill \" + jurtThread);\n              if(jurtThread.isAlive()) {\n                //noinspection deprecation\n                jurtThread.stop();\n              }\n        }\n        catch (Throwable t) {\n            preventor.error(t);\n        }\n    }\n  }\n  \n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Method;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\nimport se.jiderhamn.classloader.leak.prevention.MustBeAfter;\n\n/**\n * Destroy any {@link ThreadGroup}s that are loaded by the protected classloader\n * @author Mattias Jiderhamn\n */\npublic class ThreadGroupCleanUp implements ClassLoaderPreMortemCleanUp, MustBeAfter {\n\n  @Override\n  public Class[] mustBeBeforeMe() {\n    return new Class[] {JavaServerFaces2746CleanUp.class};\n  }\n\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    boolean threadGroupDestroyed = false;\n    try {\n      ThreadGroup systemThreadGroup = Thread.currentThread().getThreadGroup();\n      while(systemThreadGroup.getParent() != null) {\n        systemThreadGroup = systemThreadGroup.getParent();\n      }\n      // systemThreadGroup should now be the topmost ThreadGroup, \"system\"\n\n      int enumeratedGroups;\n      ThreadGroup[] allThreadGroups;\n      int noOfGroups = systemThreadGroup.activeGroupCount(); // Estimate no of groups\n      do {\n        noOfGroups += 10; // Make room for 10 extra\n        allThreadGroups = new ThreadGroup[noOfGroups];\n        enumeratedGroups = systemThreadGroup.enumerate(allThreadGroups);\n      } while(enumeratedGroups >= noOfGroups); // If there was not room for all groups, try again\n      \n      for(ThreadGroup threadGroup : allThreadGroups) {\n        if(preventor.isLoadedInClassLoader(threadGroup) && ! threadGroup.isDestroyed()) {\n          preventor.warn(\"ThreadGroup '\" + threadGroup + \"' was loaded inside application, needs to be destroyed\");\n          \n          int noOfThreads = threadGroup.activeCount();\n          if(noOfThreads > 0) {\n            preventor.warn(\"There seems to be \" + noOfThreads + \" running in ThreadGroup '\" + threadGroup + \"'; interrupting\");\n            try {\n              threadGroup.interrupt();\n            }\n            catch (Exception e) {\n              preventor.error(e);\n            }\n          }\n\n          try {\n            threadGroup.destroy();\n            threadGroupDestroyed = true;\n            preventor.info(\"ThreadGroup '\" + threadGroup + \"' successfully destroyed\");\n          }\n          catch (Exception e) {\n            preventor.error(e);\n          }\n        }\n      }\n    }\n    catch (Exception ex) {\n      preventor.error(ex);\n    }\n\n    try {\n      final Object contexts = preventor.getStaticFieldValue(\"java.beans.ThreadGroupContext\", \"contexts\");\n      if(contexts != null) { // Since Java 1.7\n        if(threadGroupDestroyed) // At least one ThreadGroup destroyed by this clean up \n          ClassLoaderLeakPreventor.gc(); // Force GC so WeakIdentityMap turns destroyed ThreadGroups into stale entries\n\n        final Method removeStaleEntries = preventor.findMethod(\"java.beans.WeakIdentityMap\", \"removeStaleEntries\");\n        if(removeStaleEntries != null)\n          removeStaleEntries.invoke(contexts);\n      }\n    }\n    catch (Throwable t) { // IllegalAccessException, InvocationTargetException \n      preventor.warn(t);\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupContextCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * Clean all {@link java.beans.ThreadGroupContext#beanInfoCache}s in {@link java.beans.ThreadGroupContext#contexts}\n * since they may contain beans/properties loaded in the protected classloader.\n * @author Mattias Jiderhamn\n */\npublic class ThreadGroupContextCleanUp implements ClassLoaderPreMortemCleanUp {\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final Object /*WeakIdentityMap<ThreadGroupContext>*/ contexts = preventor.getStaticFieldValue(\"java.beans.ThreadGroupContext\", \"contexts\");\n    if(contexts != null) { // Since Java 1.7\n      // final WeakReference/*java.beans.WeakIdentityMap.Entry*/[] table = preventor.getFieldValue(contexts, \"table\");\n      final Field tableField = preventor.findField(preventor.findClass(\"java.beans.WeakIdentityMap\"), \"table\");\n      if(tableField != null) {\n        final WeakReference/*java.beans.WeakIdentityMap.Entry*/[] table = preventor.getFieldValue(tableField, contexts);\n        if(table != null) {\n          Method clearBeanInfoCache = null;\n          for(WeakReference entry : table) {\n            if(entry != null) {\n              Object /*ThreadGroupContext*/ context = preventor.getFieldValue(entry, \"value\");\n              if(context != null) {\n                if(clearBeanInfoCache == null) { // FirstThreadGroupContext \n                  clearBeanInfoCache = preventor.findMethod(context.getClass(), \"clearBeanInfoCache\");\n                }\n\n                try {\n                  clearBeanInfoCache.invoke(context);\n                }\n                catch (Exception e) {\n                  preventor.error(e);\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.Reference;\nimport java.lang.reflect.Field;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\nimport se.jiderhamn.classloader.leak.prevention.MustBeAfter;\n\n/**\n * Clear {@link ThreadLocal}s for which {@link ThreadLocal#remove()} has not been called, in case either the \n * {@link ThreadLocal} is a custom one (subclassed in the protected ClassLoader), or the value is loaded by (or is)\n * the protected ClassLoader.\n * This must be done after threads have been stopped, or new ThreadLocals may be added by those threads.\n * @author Mattias Jiderhamn\n */\n@SuppressWarnings(\"WeakerAccess\")\npublic class ThreadLocalCleanUp implements ClassLoaderPreMortemCleanUp, MustBeAfter<ClassLoaderPreMortemCleanUp> {\n\n  /** Class name for per thread transaction in Caucho Resin transaction manager */\n  private static final String CAUCHO_TRANSACTION_IMPL = \"com.caucho.transaction.TransactionImpl\";\n  \n  protected Field java_lang_Thread_threadLocals;\n\n  protected Field java_lang_Thread_inheritableThreadLocals;\n\n  protected Field java_lang_ThreadLocal$ThreadLocalMap_table;\n\n  protected Field java_lang_ThreadLocal$ThreadLocalMap$Entry_value;\n\n  /** Needs to be done after {@link StopThreadsCleanUp}, since new {@link ThreadLocal}s may be added when threads are \n   * shutting down. */\n  @Override\n  public Class<? extends ClassLoaderPreMortemCleanUp>[] mustBeBeforeMe() {\n    return new Class[] {StopThreadsCleanUp.class};\n  }\n\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    initFields(preventor); // Initialize some reflection variables\n    \n    if(java_lang_Thread_threadLocals == null)\n      preventor.error(\"java.lang.Thread.threadLocals not found; something is seriously wrong!\");\n    \n    if(java_lang_Thread_inheritableThreadLocals == null)\n      preventor.error(\"java.lang.Thread.inheritableThreadLocals not found; something is seriously wrong!\");\n\n    if(java_lang_ThreadLocal$ThreadLocalMap_table == null)\n      preventor.error(\"java.lang.ThreadLocal$ThreadLocalMap.table not found; something is seriously wrong!\");\n\n\n    for(Thread thread : preventor.getAllThreads()) {\n      forEachThreadLocalInThread(preventor, thread);\n    }\n  }\n\n  /** Make sure fields are initialized */\n  private void initFields(ClassLoaderLeakPreventor preventor) {\n    if(java_lang_Thread_threadLocals == null) { // First invokation of this preventor\n      java_lang_Thread_threadLocals = preventor.findField(Thread.class, \"threadLocals\");\n      java_lang_Thread_inheritableThreadLocals = preventor.findField(Thread.class, \"inheritableThreadLocals\");\n      java_lang_ThreadLocal$ThreadLocalMap_table = preventor.findFieldOfClass(\"java.lang.ThreadLocal$ThreadLocalMap\", \"table\");\n    }\n  }\n\n  protected void forEachThreadLocalInThread(ClassLoaderLeakPreventor preventor, Thread thread) {\n    try {\n      if(java_lang_Thread_threadLocals != null) {\n        processThreadLocalMap(preventor, thread, java_lang_Thread_threadLocals.get(thread));\n      }\n\n      if(java_lang_Thread_inheritableThreadLocals != null) {\n        processThreadLocalMap(preventor, thread, java_lang_Thread_inheritableThreadLocals.get(thread));\n      }\n    }\n    catch (/*IllegalAccess*/Exception ex) {\n      preventor.error(ex);\n    }\n  }\n\n  protected void processThreadLocalMap(ClassLoaderLeakPreventor preventor,\n                                       Thread thread, Object threadLocalMap) throws IllegalAccessException {\n    if(threadLocalMap != null && java_lang_ThreadLocal$ThreadLocalMap_table != null) {\n      Field resin_suspendState = null;\n      Field resin_isSuspended = null;\n      final Object[] threadLocalMapTable = (Object[]) java_lang_ThreadLocal$ThreadLocalMap_table.get(threadLocalMap); // java.lang.ThreadLocal.ThreadLocalMap.Entry[]\n      for(Object entry : threadLocalMapTable) {\n        if(entry != null) {\n          // Key is kept in WeakReference\n          Reference<?> reference = (Reference<?>) entry;\n          final ThreadLocal<?> threadLocal = (ThreadLocal<?>) reference.get();\n\n          if(java_lang_ThreadLocal$ThreadLocalMap$Entry_value == null) {\n            java_lang_ThreadLocal$ThreadLocalMap$Entry_value = preventor.findField(entry.getClass(), \"value\");\n          }\n\n          // Dereference the value if this is a Reference<T>: all Reference<T> implementations are all loaded using the bootstrap classloader,\n          // so checking the Reference<T> classloader won't indicate if the held value was itself loaded using the app classloader \n          // We could have called Reference.clear() directly, which would have fixed the leak even when not allowed to modify the ThreadLocalMap.Entry\n          final Object value = dereferenceIfApplicable(java_lang_ThreadLocal$ThreadLocalMap$Entry_value.get(entry));\n\n          // Workaround for http://bugs.caucho.com/view.php?id=5647\n          if(value != null && CAUCHO_TRANSACTION_IMPL.equals(value.getClass().getName())) { // Resin transaction\n            if(resin_suspendState == null && resin_isSuspended == null) { // First thread with Resin transaction, look up fields\n              resin_suspendState = preventor.findField(value.getClass(), \"_suspendState\");\n              resin_isSuspended = preventor.findField(value.getClass(), \"_isSuspended\");\n            }\n\n            if(resin_suspendState != null && resin_isSuspended != null) { // Both fields exist (as per version 4.0.37)\n              if(preventor.getFieldValue(resin_suspendState, value) != null) { // There is a suspended state that may cause leaks\n                // In theory a new transaction can be started and suspended between where we read and write the state,\n                // and flag, therefore we suspend the thread meanwhile.\n                try {\n                  //noinspection deprecation\n                  thread.suspend(); // Suspend the thread\n                  if(preventor.getFieldValue(resin_suspendState, value) != null) { // Re-read suspend state when thread is suspended\n                    final Object isSuspended = preventor.getFieldValue(resin_isSuspended, value);\n                    if(!(isSuspended instanceof Boolean)) {\n                      preventor.error(thread.toString() + \" has \" + CAUCHO_TRANSACTION_IMPL + \" but _isSuspended is not boolean: \" + isSuspended);\n                    }\n                    else if((Boolean) isSuspended) { // Is currently suspended - suspend state is correct\n                      preventor.debug(thread.toString() + \" has \" + CAUCHO_TRANSACTION_IMPL + \" that is suspended\");\n                    }\n                    else { // Is not suspended, and thus should not have suspend state\n                      resin_suspendState.set(value, null);\n                      preventor.error(thread.toString() + \" had \" + CAUCHO_TRANSACTION_IMPL + \" with unused _suspendState that was removed\");\n                    }\n                  }\n                }\n                catch (Throwable t) { // Such as SecurityException\n                  preventor.error(t);\n                }\n                finally {\n                  //noinspection deprecation\n                  thread.resume();\n                }\n              }\n            }\n          }\n          \n          final boolean customThreadLocal = preventor.isLoadedInClassLoader(threadLocal); // This is not an actual problem\n          final boolean valueLoadedInWebApp = preventor.isLoadedInClassLoader(value);\n          if(customThreadLocal || valueLoadedInWebApp ||\n              (value instanceof ClassLoader && preventor.isClassLoaderOrChild((ClassLoader) value))) { // The value is classloader (child) itself\n            // This ThreadLocal is either itself loaded by the web app classloader, or it's value is\n            // Let's do something about it\n\n            StringBuilder message = new StringBuilder();\n            if(threadLocal != null) {\n              if(customThreadLocal) {\n                message.append(\"Custom \");\n              }\n              message.append(\"ThreadLocal of type \").append(threadLocal.getClass().getName()).append(\": \").append(threadLocal);\n            }\n            else {\n              message.append(\"Unknown ThreadLocal\");\n            }\n            message.append(\" with value \").append(value);\n            if(value != null) {\n              message.append(\" of type \").append(value.getClass().getName());\n              if(valueLoadedInWebApp)\n                message.append(\" that is loaded by web app\");\n            }\n\n\n            // Process the detected potential leak\n            processLeak(preventor, thread, reference, threadLocal, value, message.toString());\n          }\n        }\n      }\n    }\n  }\n  \n  protected Object dereferenceIfApplicable(Object value) {\n      return value instanceof Reference ? dereferenceIfApplicable(((Reference<?>) value).get()) : value; \n  }\n\n  /**\n   * After having detected potential ThreadLocal leak, this method is called.\n   * Default implementation tries to clear the entry to avoid a leak.\n   */\n  protected void processLeak(ClassLoaderLeakPreventor preventor, Thread thread, Reference<?> entry,\n                             ThreadLocal<?> threadLocal, Object value, String message) {\n    if(threadLocal != null && thread == Thread.currentThread()) { // If running for current thread and we have the ThreadLocal ...\n      // ... remove properly\n      preventor.info(message + \" will be remove()d from \" + thread);\n      threadLocal.remove();\n    }\n    else { // We cannot remove entry properly, so just make it stale\n      preventor.info(message + \" will be made stale for later expunging from \" + thread);\n    }\n\n    // It seems like remove() doesn't really do the job, so play it safe and remove references from entry either way\n    // (Example problem org.infinispan.context.SingleKeyNonTxInvocationContext) \n    entry.clear(); // Clear the key\n\n    if(java_lang_ThreadLocal$ThreadLocalMap$Entry_value == null) {\n      java_lang_ThreadLocal$ThreadLocalMap$Entry_value = preventor.findField(entry.getClass(), \"value\");\n    }\n\n    try {\n      java_lang_ThreadLocal$ThreadLocalMap$Entry_value.set(entry, null); // Clear value to avoid circular references\n    }\n    catch (IllegalAccessException iaex) {\n      preventor.error(iaex);\n    }\n  }\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/WarningThreadLocalCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.Reference;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * {@link ClassLoaderPreMortemCleanUp} that does not clear {@link ThreadLocal}s to remove the leak, but only logs a \n * warning\n * @author Mattias Jiderhamn\n */\n@SuppressWarnings(\"unused\")\npublic class WarningThreadLocalCleanUp extends ThreadLocalCleanUp {\n\n  /**\n   * Log not {@link ThreadLocal#remove()}ed leak as a warning. \n   */\n  protected void processLeak(ClassLoaderLeakPreventor preventor, Thread thread, Reference<?> entry, \n                             ThreadLocal<?> threadLocal, Object value, String message) {\n    preventor.warn(message);\n  } \n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/cleanup/X509TrustManagerImplUnparseableExtensionCleanUp.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.security.cert.X509Certificate;\nimport java.util.Map;\nimport javax.net.ssl.SSLContextSpi;\nimport javax.net.ssl.X509TrustManager;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\n\n/**\n * {@link sun.security.ssl.X509TrustManagerImpl} keeps a list set of trusted certs, which may include \n * {@link sun.security.x509.UnparseableExtension} that in turn may include an {@link Exception} with a backtrace\n * with references to the classloader that we want to protect \n * @author Mattias Jiderhamn\n */\npublic class X509TrustManagerImplUnparseableExtensionCleanUp implements ClassLoaderPreMortemCleanUp {\n\n  private static final String SUN_SECURITY_X509_X509_CERT_IMPL = \"sun.security.x509.X509CertImpl\";\n\n  @Override\n  public void cleanUp(ClassLoaderLeakPreventor preventor) {\n    final SSLContextSpi sslContext = preventor.getStaticFieldValue(\"sun.security.ssl.SSLContextImpl$DefaultSSLContext\", \"defaultImpl\");\n    if(sslContext != null) {\n      final Field trustManagerField = preventor.findFieldOfClass(\"sun.security.ssl.SSLContextImpl\", \"trustManager\");\n      final Method get = preventor.findMethod(SUN_SECURITY_X509_X509_CERT_IMPL, \"get\", String.class);\n      final Method getUnparseableExtensions = preventor.findMethod(\"sun.security.x509.CertificateExtensions\", \"getUnparseableExtensions\");\n      final Field why = preventor.findFieldOfClass(\"sun.security.x509.UnparseableExtension\", \"why\");\n\n      if(trustManagerField != null && get != null && getUnparseableExtensions != null && why != null) {\n        final X509TrustManager/*Impl*/ trustManager = preventor.getFieldValue(trustManagerField, sslContext);\n        for(X509Certificate x509Certificate : trustManager.getAcceptedIssuers()) {\n          if(SUN_SECURITY_X509_X509_CERT_IMPL.equals(x509Certificate.getClass().getName())) {\n            try {\n              final /* sun.security.x509.CertificateExtensions*/ Object extensions = get.invoke(x509Certificate, \"x509.info.extensions\");\n              if(extensions != null) {\n                Map/*<String, sun.security.x509.Extension>*/ unparseableExtensions = (Map) getUnparseableExtensions.invoke(extensions);\n                for(Object unparseableExtension : unparseableExtensions.values()) {\n                  if(why.get(unparseableExtension) != null) {\n                    preventor.warn(trustManager + \" cached X509Certificate that had unparseable extension; removing 'why': \" +\n                        x509Certificate);\n                    why.set(unparseableExtension, null);\n                  }\n                }\n              }\n            }\n            catch (Exception e) {\n              preventor.error(e);\n            }\n          }\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/AwtToolkitInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * The first call to java.awt.Toolkit.getDefaultToolkit() will spawn a new thread with the\n * same contextClassLoader as the caller.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * @author Mattias Jiderhamn\n */\npublic class AwtToolkitInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    try {\n      java.awt.Toolkit.getDefaultToolkit(); // Will start a Thread\n    }\n    catch (Throwable t) {\n      preventor.error(t);\n      preventor.warn(\"Consider adding -Djava.awt.headless=true to your JVM parameters\");\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/DatatypeConverterImplInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * {@link javax.xml.bind.DatatypeConverterImpl} in the JAXB Reference Implementation shipped with JDK 1.6+ will\n * keep a static reference ({@link javax.xml.bind.DatatypeConverterImpl#datatypeFactory}) to a concrete subclass of \n * {@link javax.xml.datatype.DatatypeFactory}, that is resolved when the class is loaded (which I believe happens if you\n * have custom bindings that reference the static methods in {@link javax.xml.bind.DatatypeConverter}). It seems that if \n * for example you have a version of Xerces inside your application, the factory method may resolve {@code \n * org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl} as the implementation to use (rather than\n * {@code com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl} shipped with the JDK), which\n * means there will a reference from {@link javax.xml.bind.DatatypeConverterImpl} to your classloader.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * \n * @author Mattias Jiderhamn\n */\npublic class DatatypeConverterImplInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    try {\n      Class.forName(\"javax.xml.bind.DatatypeConverterImpl\"); // Since JDK 1.6. May throw java.lang.Error\n    }\n    catch (ClassNotFoundException e) {\n      // Do nothing\n    }\n    catch (Throwable t) {\n      preventor.warn(t);\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/DocumentBuilderFactoryInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * The classloader of the first thread to call DocumentBuilderFactory.newInstance().newDocumentBuilder()\n * seems to be unable to garbage collection. Is it believed this is caused by some JVM internal bug.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * @author Mattias Jiderhamn\n */\npublic class DocumentBuilderFactoryInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    try {\n      javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder();\n    }\n    catch (Exception ex) { // Example: ParserConfigurationException\n      preventor.error(ex);\n    }\n                                            \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/JarUrlConnectionInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.net.URL;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * The caching mechanism of JarURLConnection can prevent JAR files to be reloaded. See\n * <a href=\"http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=b8cdbff5fd7a2482996ac1c7f708?bug_id=4405789\">this bug report</a>.\n * It is not entirely clear whether this will actually leak classloaders.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * \n * @author Mattias Jiderhamn\n */\npublic class JarUrlConnectionInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    // This probably does not affect classloaders, but prevents some problems with .jar files\n    try {\n      // URL needs to be well-formed, but does not need to exist\n      new URL(\"jar:file://dummy.jar!/\").openConnection().setDefaultUseCaches(false);\n    }\n    catch (Exception ex) {\n      preventor.error(ex);\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dDisposerInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * Loading the class sun.java2d.Disposer will spawn a new thread with the same contextClassLoader.\n * <a href=\"https://issues.apache.org/bugzilla/show_bug.cgi?id=51687\">More info</a>.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * \n * @author Mattias Jiderhamn\n */\npublic class Java2dDisposerInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    try {\n      Class.forName(\"sun.java2d.Disposer\"); // Will start a Thread\n    }\n    catch (ClassNotFoundException cnfex) {\n      if(preventor.isOracleJRE() && ! preventor.isJBoss()) // JBoss blocks this package/class, so don't warn\n        preventor.error(cnfex);\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dRenderQueueInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\nimport java.lang.reflect.Method;\n\n/**\n * Using the class sun.java2d.opengl.OGLRenderQueue will spawn a new QueueFlusher thread with the same contextClassLoader.\n */\npublic class Java2dRenderQueueInitiator implements PreClassLoaderInitiator {\n    @Override\n    public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n        try {\n            Method getInstance = preventor.findMethod(\"sun.java2d.opengl.OGLRenderQueue\", \"getInstance\");\n            if (getInstance != null) {\n                getInstance.invoke(null);\n            }\n        } catch (Throwable e) {\n            preventor.warn(e);\n        }\n    }\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/JavaxSecurityLoginConfigurationInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * The class javax.security.auth.login.Configuration will keep a strong static reference to the\n * contextClassLoader of Thread from which the class is loaded.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * \n * @author Mattias Jiderhamn\n */\npublic class JavaxSecurityLoginConfigurationInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    try {\n      Class.forName(\"javax.security.auth.login.Configuration\", true, preventor.getLeakSafeClassLoader());\n    }\n    catch (ClassNotFoundException e) {\n      // Do nothing\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/JdbcDriversInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\nimport se.jiderhamn.classloader.leak.prevention.cleanup.DriverManagerCleanUp;\n\n/**\n * Your JDBC driver will be registered in java.sql.DriverManager, which means that if\n * you include your JDBC driver inside your web application, there will be a reference\n * to your webapps classloader from system classes (see\n * <a href=\"http://java.jiderhamn.se/2012/01/01/classloader-leaks-ii-find-and-work-around-unwanted-references/\">part II</a>).\n * The simple solution is to put JDBC driver on server level instead, but you can also\n * deregister the driver at application shutdown.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * \n * TODO {@link DriverManagerCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class JdbcDriversInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    java.sql.DriverManager.getDrivers(); // Load initial drivers using leak safe classloader\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/LdapPoolManagerInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * The contextClassLoader of the thread loading the com.sun.jndi.ldap.LdapPoolManager class may be kept\n * from being garbage collected, since it will start a new thread if the system property\n * {@code com.sun.jndi.ldap.connect.pool.timeout} is set to a value greater than 0.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * \n * @author Mattias Jiderhamn\n */\npublic class LdapPoolManagerInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    try {\n      Class.forName(\"com.sun.jndi.ldap.LdapPoolManager\");\n    }\n    catch(ClassNotFoundException cnfex) {\n      if(preventor.isOracleJRE())\n        preventor.error(cnfex);\n    }\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/OracleJdbcThreadInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.reflect.Field;\nimport java.util.Set;\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\nimport se.jiderhamn.classloader.leak.prevention.ReplaceDOMNormalizerSerializerAbortException;\n\n/**\n * See https://github.com/mjiderhamn/classloader-leak-prevention/issues/8\n * and https://github.com/mjiderhamn/classloader-leak-prevention/issues/23\n * and https://github.com/mjiderhamn/classloader-leak-prevention/issues/69\n * and http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * @author Mattias Jiderhamn\n */\npublic class OracleJdbcThreadInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    // Cause oracle.jdbc.driver.OracleTimeoutPollingThread to be started with contextClassLoader = system classloader  \n    try {\n      Class.forName(\"oracle.jdbc.driver.OracleTimeoutThreadPerVM\");\n    }\n    catch (ClassNotFoundException e) {\n      // Ignore silently - class not present\n    }\n\n    // Cause oracle.jdbc.driver.BlockSource.ThreadedCachingBlockSource.BlockReleaser to be started with contextClassLoader = system classloader  \n    try {\n      Class.forName(\"oracle.jdbc.driver.BlockSource$ThreadedCachingBlockSource$BlockReleaser\");\n    }\n    catch (ClassNotFoundException e) {\n      // Ignore silently - class not present\n    }\n\n    // Cause TimerThread to be started with contextClassLoader = safe classloader   \n    try {\n      Class.forName(\"oracle.net.nt.TimeoutInterruptHandler\");\n    }\n    catch (ClassNotFoundException e) {\n      // Ignore silently - class not present\n    }\n\n    // Cause instance to be created and in turn Timer and TimeThread to be created with contextClassLoader = safe classloader   \n    try {\n      Class.forName(\"oracle.jdbc.driver.NoSupportHAManager\");\n    }\n    catch (ClassNotFoundException e) {\n      // Ignore silently - class not present\n    }\n\n    // Avoid stack trace with trace elements being referenced from MBean   \n    try {\n      Class.forName(\"oracle.jdbc.driver.OracleDriver\"); // Cause oracle.jdbc.driver.OracleDiagnosabilityMBean to be registered\n      final Class<?> oracleDiagnosabilityMBeanClass = Class.forName(\"oracle.jdbc.driver.OracleDiagnosabilityMBean\");\n      \n      final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();\n      final Set<ObjectName> mBeanNames = mBeanServer.queryNames(new ObjectName(\"com.oracle.jdbc:type=diagnosability,*\"), null);\n      for(ObjectName mBeanName : mBeanNames) {\n        final  /* oracle.jdbc.driver.OracleDiagnosabilityMBean */ Object oracleDiagnosabilityMBean = oracleDiagnosabilityMBeanClass.newInstance();\n        final /* oracle.jdbc.logging.runtime.TraceControllerImpl */ Object traceController =\n            preventor.getFieldValue(oracleDiagnosabilityMBean, \"tc\");\n        if(traceController != null) {\n          final Field reSuspendedField = preventor.findField(traceController.getClass(), \"reSuspended\");\n          if(reSuspendedField != null) {\n            final Object oldValue = reSuspendedField.get(traceController);\n            reSuspendedField.set(traceController, \n                ReplaceDOMNormalizerSerializerAbortException.constructRuntimeExceptionWithoutStackTrace(preventor,\n                    (oldValue instanceof Exception) ? ((Exception)oldValue).getMessage() : \"trace controller is currently suspended\",\n                    null));\n            preventor.info(\"Replacing MBean \" + mBeanName + \" with \" + reSuspendedField.getName() + \" field of \" +\n                traceController + \" replaced to avoid backtrace references.\");\n\n            // Replace MBean\n            mBeanServer.unregisterMBean(mBeanName);\n            mBeanServer.registerMBean(oracleDiagnosabilityMBean, mBeanName);\n          }\n          else\n            preventor.warn(\"Unable to find 'reSuspended' field of \" + traceController);\n        }\n        else\n          preventor.warn(\"Found \" + oracleDiagnosabilityMBeanClass + \" but it has no 'tm' TraceController attribute\");\n      }\n    }\n    catch (Exception e) {\n      // Ignore silently\n    }\n\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityPolicyInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.lang.reflect.InvocationTargetException;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * javax.security.auth.Policy.getPolicy() will keep a strong static reference to\n * the contextClassLoader of the first calling thread.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * \n * @author Mattias Jiderhamn\n */\npublic class SecurityPolicyInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    try {\n      Class.forName(\"javax.security.auth.Policy\")\n          .getMethod(\"getPolicy\")\n          .invoke(null);\n    }\n    catch (IllegalAccessException iaex) {\n      preventor.error(iaex);\n    }\n    catch (InvocationTargetException itex) {\n      preventor.error(itex);\n    }\n    catch (NoSuchMethodException nsmex) {\n      preventor.error(nsmex);\n    }\n    catch (ClassNotFoundException e) {\n      // Ignore silently - class is deprecated\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityProvidersInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * Custom java.security.Provider loaded in your web application and registered with\n * java.security.Security.addProvider() must be unregistered with java.security.Security.removeProvider()\n * at application shutdown, or it will cause leaks.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * @author Mattias Jiderhamn\n */\npublic class SecurityProvidersInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    java.security.Security.getProviders();\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SunAwtAppContextInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport javax.swing.*;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * There will be a strong reference from {@link sun.awt.AppContext#contextClassLoader} to the classloader of the calls\n * to {@link sun.awt.AppContext#getAppContext()}. Avoid leak by forcing initialization using system classloader. \n * Note that Google Web Toolkit (GWT) will trigger this leak via its use of javax.imageio.\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * @author Mattias Jiderhamn\n */\npublic class SunAwtAppContextInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    try {\n      javax.imageio.ImageIO.getCacheDirectory(); // Will call sun.awt.AppContext.getAppContext()\n      new JEditorPane(\"text/plain\", \"dummy\"); // According to GitHub user dany52, the above is not enough\n    }\n    catch (Throwable t) {\n      preventor.error(t);\n      preventor.warn(\"Consider adding -Djava.awt.headless=true to your JVM parameters\");\n    }\n                                      \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/main/java/se/jiderhamn/classloader/leak/prevention/preinit/SunGCInitiator.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\n\n/**\n * sun.misc.GC.requestLatency(long), which is known to be called from\n * javax.management.remote.rmi.RMIConnectorServer.start(), will cause the current\n * contextClassLoader to be unavailable for garbage collection.\n * \n * See http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java?view=markup#l106 and \n * http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java?view=markup#l296\n * \n * See http://java.jiderhamn.se/2012/02/26/classloader-leaks-v-common-mistakes-and-known-offenders/\n * \n * @author Mattias Jiderhamn\n */\npublic class SunGCInitiator implements PreClassLoaderInitiator {\n  @Override\n  public void doOutsideClassLoader(ClassLoaderLeakPreventor preventor) {\n    try {\n      Class<?> gcClass = this.getGCClass();\n      final Method requestLatency = gcClass.getDeclaredMethod(\"requestLatency\", long.class);\n      requestLatency.setAccessible(true);\n      requestLatency.invoke(null, Long.valueOf(Long.MAX_VALUE - 1));\n    }\n    catch (ClassNotFoundException cnfex) {\n      if(preventor.isOracleJRE())\n        preventor.error(cnfex);\n    }\n    catch (NoSuchMethodException nsmex) {\n      preventor.error(nsmex);\n    }\n    catch (IllegalAccessException iaex) {\n      preventor.error(iaex);\n    }\n    catch (InvocationTargetException itex) {\n      preventor.error(itex);\n    }\n  }\n\n  private Class<?> getGCClass() throws ClassNotFoundException {\n    try {\n      return Class.forName(\"sun.misc.GC\");\n    } catch (ClassNotFoundException cnfex) {\n      // Try Jre 9 classpath\n      return Class.forName(\"sun.rmi.transport.GC\");\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorFactoryTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.Test;\n\nimport static org.hamcrest.Matchers.contains;\nimport static org.junit.Assert.assertThat;\n\n/**\n * Test cases for {@link ClassLoaderLeakPreventorFactory}\n * @author Mattias Jiderhamn\n */\npublic class ClassLoaderLeakPreventorFactoryTest {\n  \n  /** Test that {@link MustBeAfter} has expected effect on {@link ClassLoaderPreMortemCleanUp}s */\n  @Test(expected = IllegalStateException.class) // TODO #51\n  public void cleanUpMustBeAfter() {\n    final List<ClassLoaderPreMortemCleanUp> executionOrder = new ArrayList<ClassLoaderPreMortemCleanUp>();\n    \n    final RecordingCleanUp unordered1 = new RecordingCleanUp(executionOrder) { };\n    final RecordingCleanUp unordered2 = new RecordingCleanUp(executionOrder) { };\n    final Foo foo = new Foo(executionOrder);\n    final Bar bar = new Bar(executionOrder);\n    final AfterFoo afterFoo1 = new AfterFoo(executionOrder) { };\n    final AfterFoo afterFoo2 = new AfterFoo(executionOrder) { };\n    final AfterBar afterBar = new AfterBar(executionOrder);\n    final AfterFooAndBar afterFooAndBar = new AfterFooAndBar(executionOrder);\n    \n    ClassLoaderLeakPreventorFactory factory = new ClassLoaderLeakPreventorFactory();\n    factory.addCleanUp(unordered2);\n    factory.addCleanUp(bar);\n    factory.addCleanUp(afterFooAndBar);\n    factory.addCleanUp(afterBar);\n    factory.addCleanUp(unordered1);\n    factory.addCleanUp(afterFoo2);\n    factory.addCleanUp(afterFoo1);\n    factory.addCleanUp(foo);\n    \n    // TODO #51\n    \n    factory.newLeakPreventor().runCleanUps();\n    \n    // Make sure imposed order is achieved, while retaining order among moved elements\n    assertThat(executionOrder, contains((ClassLoaderPreMortemCleanUp) \n        unordered2, \n        bar, \n        afterBar, \n        unordered1, \n        foo, \n        afterFooAndBar, // Moved \n        afterFoo2,      // Moved  \n        afterFoo1));    // Moved\n    \n    ///////////\n    // Subclass\n    \n    executionOrder.clear();\n    \n    final Foo fooSubClass = new Foo(executionOrder) { };\n    \n    factory.addCleanUp(fooSubClass);\n\n    factory.newLeakPreventor().runCleanUps();\n\n    // Make sure imposed order is achieved, while retaining order among moved elements\n    assertThat(executionOrder, contains((ClassLoaderPreMortemCleanUp) \n        unordered2, \n        bar, \n        afterBar, \n        unordered1, \n        foo,\n        fooSubClass,    // Inserted\n        afterFooAndBar,\n        afterFoo2,  \n        afterFoo1));\n  }\n  \n  @Test(expected = IllegalStateException.class)\n  public void circularMustBeAfter() {\n    ClassLoaderLeakPreventorFactory factory = new ClassLoaderLeakPreventorFactory();\n    factory.addCleanUp(new Circle1());\n    factory.addCleanUp(new Circle2());\n  }\n  \n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  \n  /** Base class for {@link ClassLoaderPreMortemCleanUp}s that will record their execution */\n  private abstract static class RecordingCleanUp implements ClassLoaderPreMortemCleanUp {\n    \n    private final List<ClassLoaderPreMortemCleanUp> cleanUps;\n\n    RecordingCleanUp(List<ClassLoaderPreMortemCleanUp> cleanUps) {\n      this.cleanUps = cleanUps;\n    }\n\n    @Override\n    public void cleanUp(ClassLoaderLeakPreventor preventor) {\n      cleanUps.add(this);\n    }\n\n    @Override\n    public String toString() {\n      return this.getClass().getName() + \"@\" + System.identityHashCode(this);\n    }\n  }\n  \n  private static class Foo extends RecordingCleanUp {\n    Foo(List<ClassLoaderPreMortemCleanUp> cleanUps) {\n      super(cleanUps);\n    }\n  }\n\n  private static class Bar extends RecordingCleanUp {\n    Bar(List<ClassLoaderPreMortemCleanUp> cleanUps) {\n      super(cleanUps);\n    }\n  }\n\n  private static class AfterFoo extends RecordingCleanUp implements MustBeAfter<ClassLoaderPreMortemCleanUp> {\n    AfterFoo(List<ClassLoaderPreMortemCleanUp> cleanUps) {\n      super(cleanUps);\n    }\n\n    @Override\n    public Class<? extends ClassLoaderPreMortemCleanUp>[] mustBeBeforeMe() {\n      return new Class[] {Foo.class};\n    }\n  }\n\n  private static class AfterBar extends RecordingCleanUp implements MustBeAfter<ClassLoaderPreMortemCleanUp> {\n    AfterBar(List<ClassLoaderPreMortemCleanUp> cleanUps) {\n      super(cleanUps);\n    }\n\n    @Override\n    public Class<? extends ClassLoaderPreMortemCleanUp>[] mustBeBeforeMe() {\n      return new Class[] {Bar.class};\n    }\n  }\n\n  private static class AfterFooAndBar extends RecordingCleanUp implements MustBeAfter<ClassLoaderPreMortemCleanUp> {\n    AfterFooAndBar(List<ClassLoaderPreMortemCleanUp> cleanUps) {\n      super(cleanUps);\n    }\n\n    @Override\n    public Class<? extends ClassLoaderPreMortemCleanUp>[] mustBeBeforeMe() {\n      return new Class[] {Foo.class, Bar.class};\n    }\n  }\n  \n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  \n  private static class Circle1 extends RecordingCleanUp implements MustBeAfter<ClassLoaderPreMortemCleanUp> {\n    Circle1() {\n      super(null);\n    }\n\n    @Override\n    public Class<? extends ClassLoaderPreMortemCleanUp>[] mustBeBeforeMe() {\n      return new Class[] {Circle2.class};\n    }\n  }\n  \n  private static class Circle2 extends RecordingCleanUp implements MustBeAfter<ClassLoaderPreMortemCleanUp> {\n    Circle2() {\n      super(null);\n    }\n\n    @Override\n    public Class<? extends ClassLoaderPreMortemCleanUp>[] mustBeBeforeMe() {\n      return new Class[] {Circle2.class};\n    }\n  }\n  \n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/PreventionsTestBase.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.util.Collections;\n\n/**\n * Base class for test cases testing {@link PreClassLoaderInitiator} and {@link ClassLoaderPreMortemCleanUp} implementations.\n * @author Mattias Jiderhamn\n */\npublic abstract class PreventionsTestBase<C> {\n\n  /** \n   * Get an instance of the implementation under test. Will use the generics parameter type information.\n   */\n  protected C getTestedImplementation() throws IllegalAccessException, InstantiationException {\n    ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();\n    Object actualType = genericSuperclass.getActualTypeArguments()[genericSuperclass.getActualTypeArguments().length - 1];\n    \n    Class<C> cleanUpImplClass = (actualType instanceof ParameterizedType) ? \n        (Class<C>) ((ParameterizedType)actualType).getRawType() :\n        (Class<C>) actualType;\n      \n    return cleanUpImplClass.newInstance();\n  }\n\n  /**\n   * Concrete tests may override this method, in case they to provide a specific {@link ClassLoaderLeakPreventor}\n   * to the {@link ClassLoaderPreMortemCleanUp}.\n   * @return\n   */\n  protected ClassLoaderLeakPreventor getClassLoaderLeakPreventor() {\n    return new ClassLoaderLeakPreventor(getLeakSafeClassLoader(),\n        getClass().getClassLoader(),\n        new StdLogger(), \n        Collections.<PreClassLoaderInitiator>emptyList(),\n        Collections.<ClassLoaderPreMortemCleanUp>emptyList());\n  }\n\n  /** \n   * Get {@link ClassLoader} to be used as the {@link ClassLoaderLeakPreventor#leakSafeClassLoader} of the \n   * {@link ClassLoaderLeakPreventor}. This is normally the parent of the classloader of the test class.\n   */\n  protected ClassLoader getLeakSafeClassLoader() {\n    return getClass().getClassLoader().getParent();\n  }\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/StopThreadsCleanUp_TimerTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.Collection;\nimport java.util.Timer;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderhamn.classloader.leak.JUnitClassloaderRunner;\nimport se.jiderhamn.classloader.leak.LeakPreventor;\nimport se.jiderhamn.classloader.leak.prevention.cleanup.StopThreadsCleanUp;\n\n/**\n * @author Mattias Jiderhamn\n */\n@RunWith(JUnitClassloaderRunner.class)\n@LeakPreventor(StopThreadsCleanUp_TimerTest.Preventor.class)\npublic class StopThreadsCleanUp_TimerTest {\n  \n  /** \n   * Having a custom ThreadLocal with at non-custom value does not leak, since the key in the ThreadLocalMap is weak\n   */\n  @Test\n  public void createTimer() throws IllegalAccessException, NoSuchFieldException {\n    new Timer(\"MyTimer\"); // Create new Timer to spawn new TimerThread\n    Thread.yield(); // Allow the Timer thread to start\n  }\n  \n  public static class Preventor implements Runnable {\n    public void run() {\n      ClassLoaderLeakPreventorFactory factory = new ClassLoaderLeakPreventorFactory();\n      final ClassLoaderLeakPreventor preventor = factory.newLeakPreventor();\n\n      final TimerThreadsCleanUp timerThreadsCleanUp = new TimerThreadsCleanUp();\n\n      final Collection<Thread> threads = preventor.getAllThreads();\n      for(Thread thread : threads) {\n        if(\"java.util.TimerThread\".equals(thread.getClass().getName())) {\n          System.out.println(thread + \" is a TimerThread\");\n          timerThreadsCleanUp.stopTimerThread(preventor, thread);\n          try {\n            thread.join(10000); // Give thread up to 10 seconds to finish\n          }\n          catch (InterruptedException e) {\n            // Silently ignore\n          }\n        }\n      }\n    }\n  }\n  \n  private static class TimerThreadsCleanUp extends StopThreadsCleanUp {\n    public TimerThreadsCleanUp() {\n      super(true, true);\n    }\n\n    /** Change visibility */\n    @Override\n    public void stopTimerThread(ClassLoaderLeakPreventor preventor, Thread thread) {\n      super.stopTimerThread(preventor, thread);\n    }\n  }\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanELResolverCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.el.*;\n\nimport org.junit.Before;\n\n/**\n * Test case for {@link BeanELResolverCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class BeanELResolverCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<BeanELResolverCleanUp> {\n\n  @Before\n  public void setUp() {\n    // Must be done outside test classloader \n    javax.imageio.ImageIO.getCacheDirectory(); // Will call sun.awt.AppContext.getAppContext()\n  }\n\n  @Override\n  protected void triggerLeak() throws Exception {\n    BeanELResolver beanELResolver = new BeanELResolver();\n    beanELResolver.getValue(new MyELContext(), new Bean(), \"foo\"); // Will put class in strong reference cache\n    \n  }\n\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  \n  /** Bean for testing */\n  @SuppressWarnings(\"unused\")\n  public static class Bean {\n    private String foo;\n\n    public String getFoo() {\n      return foo;\n    }\n\n    public void setFoo(String foo) {\n      this.foo = foo;\n    }\n  }\n  \n  /** Dummy ELContext */\n  private static class MyELContext extends ELContext {\n    @Override\n    public ELResolver getELResolver() {\n      throw new UnsupportedOperationException(\"dummy\");\n    }\n\n    @Override\n    public FunctionMapper getFunctionMapper() {\n      throw new UnsupportedOperationException(\"dummy\");\n    }\n\n    @Override\n    public VariableMapper getVariableMapper() {\n      throw new UnsupportedOperationException(\"dummy\");\n    }\n  }\n  \n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanIntrospectorCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.beans.Introspector;\n\n/**\n * Test case for {@link BeanIntrospectorCleanUp}\n */\npublic class BeanIntrospectorCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<BeanIntrospectorCleanUp> {\n\n    @Override\n    protected void triggerLeak() throws Exception {\n        Introspector.getBeanInfo(Bean.class);\n    }\n\n    protected class Bean {\n        private int dummyField;\n\n        public int getDummyField() {\n            return dummyField;\n        }\n\n        public void setDummyField(int dummyField) {\n            this.dummyField = dummyField;\n        }\n    }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/BeanValidationCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.apache.axis.utils.XMLUtils;\nimport org.junit.Ignore;\n\n/**\n * Test case for {@link BeanValidationCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class BeanValidationCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<BeanValidationCleanUp> {\n\n  @Override\n  protected void triggerLeak() throws Exception {\n    javax.validation.Validation.buildDefaultValidatorFactory();    \n  }\n\n  /**\n   * Test case that {@link ThreadLocalCleanUp} fixes leak caused by Axis 1.4\n   * @author Mattias Jiderhamn\n   */\n  @Ignore // Fixed in newer versions of Java???\n  public static class ThreadLocalCleanUp_ApacheAxis14Test extends ClassLoaderPreMortemCleanUpTestBase<ThreadLocalCleanUp> {\n  \n    @Override\n    protected void triggerLeak() throws Exception {\n      // Trigger leak of Axis 1.4\n      XMLUtils.getDocumentBuilder();\n    }\n  \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ClassLoaderPreMortemCleanUpTestBase.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderhamn.classloader.leak.JUnitClassloaderRunner;\nimport se.jiderhamn.classloader.leak.Leaks;\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\nimport se.jiderhamn.classloader.leak.prevention.PreventionsTestBase;\n\n/**\n * Abstract base class for testing {@link ClassLoaderPreMortemCleanUp} implementations.\n * TODO Move this to test framework(?)\n * @author Mattias Jiderhamn\n */\n@RunWith(JUnitClassloaderRunner.class)\npublic abstract class ClassLoaderPreMortemCleanUpTestBase<C extends ClassLoaderPreMortemCleanUp> extends PreventionsTestBase<C> {\n  \n  /** \n   * Test case that verifies that {@link #triggerLeak()} indeed does cause a leak, in case the\n   * {@link ClassLoaderPreMortemCleanUp} is not executed.\n   */\n  @SuppressWarnings(\"DefaultAnnotationParam\")\n  @Test\n  @Leaks(true) // Without the cleanup we should expect a leak\n  public void triggerLeakWithoutCleanup() throws Exception {\n    triggerLeak();\n  }\n  \n  @Test\n  @Leaks(false) // After having run the cleanup, there should be no leak\n  public void cleanUpAfterTriggeringLeak() throws Exception {\n    triggerLeak();\n    getClassLoaderPreMortemCleanUp().cleanUp(getClassLoaderLeakPreventor());\n  }\n  \n  /** Concrete tests should implement this method to trigger the leak */\n  protected abstract void triggerLeak() throws Exception;\n  \n  /** \n   * Concrete tests may override this method to return a {@link ClassLoaderPreMortemCleanUp} \n   * that will clean up after the leak triggered by {@link #triggerLeak()}, so that {@link ClassLoader} can be\n   * garbage collected.\n   * The default implementation will use the generics parameter type information.\n   */\n  @SuppressWarnings(\"WeakerAccess\")\n  protected C getClassLoaderPreMortemCleanUp() throws IllegalAccessException, InstantiationException {\n    return getTestedImplementation();\n  }\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/DefaultAuthenticatorCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.apache.cxf.transport.http.CXFAuthenticator;\n\n/**\n * Test that the leak caused by CXF custom {@link java.net.Authenticator} is cleared.\n * Thanks to Arild Froeland for the report.\n * @author Mattias Jiderhamn\n */\npublic class DefaultAuthenticatorCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<DefaultAuthenticatorCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    CXFAuthenticator.addAuthenticator();\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/DriverManagerCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.PackagesLoadedOutsideClassLoader;\n\n/**\n * Test case for {@link DriverManagerCleanUp}\n * @author Mattias Jiderhamn\n */\n@PackagesLoadedOutsideClassLoader(packages = \"org.postgresql\", addToDefaults = true) // Postgresql driver not part of test\npublic class DriverManagerCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<DriverManagerCleanUp> {\n\n  @Override\n  protected void triggerLeak() throws ClassNotFoundException {\n    Class.forName(\"com.mysql.jdbc.Driver\");\n  }\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/GeoToolsCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.geotools.util.WeakCollectionCleaner;\n\n/**\n * Test case for {@link GeoToolsCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class GeoToolsCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<GeoToolsCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {    \n    WeakCollectionCleaner.DEFAULT.getReferenceQueue();\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/IIOServiceProviderCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.imageio.ImageIO;\nimport javax.swing.*;\n\nimport org.junit.Before;\n\n/**\n * Test case for {@link IIOServiceProviderCleanUp}\n * @author Thomas Scheffler (1.x version)\n * @author Mattias Jiderhamn\n */\npublic class IIOServiceProviderCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<IIOServiceProviderCleanUp> {\n  // ImageIO.scanForPlugins() triggers two different leaks, but the preventor only removes one, so we need to avoid\n  // the other one by running some code in parent classloader\n  @Before\n  public void systemClassLoader() {\n    new JEditorPane(\"text/plain\", \"dummy\"); // java.awt.Toolkit.getDefaultToolkit()\n  }\n\n  @Override\n  protected void triggerLeak() throws Exception {\n    ImageIO.scanForPlugins();\n\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ImageIOMockImageInputStreamSPI.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Locale;\n\nimport javax.imageio.spi.ImageInputStreamSpi;\nimport javax.imageio.stream.ImageInputStream;\n\npublic class ImageIOMockImageInputStreamSPI extends ImageInputStreamSpi {\n\n    @Override\n    public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) throws IOException {\n        throw new IllegalArgumentException(\"mock class\");\n    }\n\n    @Override\n    public String getDescription(Locale locale) {\n        return \"mock ImageInputStream provider\";\n    }\n\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JDK8151486CleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.junit.Ignore;\n\nimport java.security.Permission;\n\n/**\n * Test case for {@link JDK8151486CleanUp}\n */\n@Ignore\npublic class JDK8151486CleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<JDK8151486CleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    System.setSecurityManager(new SecurityManager() {\n      @Override\n      public void checkPermission(final Permission perm) {\n      }\n    });\n\n    Class.forName(\"java.lang.String\", false, ClassLoader.getSystemClassLoader());\n\n    // leaving the security manager will cause a leak, but not the one we're testing for\n    System.setSecurityManager(null);\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JacksonCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport com.fasterxml.jackson.databind.type.TypeFactory;\nimport se.jiderhamn.classloader.PackagesLoadedOutsideClassLoader;\n\n/**\n * Test cases for {@link JacksonCleanUp}\n * @author Mattias Jiderhamn\n */\n@PackagesLoadedOutsideClassLoader(packages = {\"com.fasterxml.jackson.databind\"}, addToDefaults = true)\npublic class JacksonCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<JacksonCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    TypeFactory.defaultInstance().constructSimpleType(JacksonCleanUpTest.class, null);\n  }\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaServerFaces2746CleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.el.BeanELResolver;\nimport javax.el.ELContext;\nimport javax.faces.component.UIComponentBase;\n\nimport com.sun.faces.el.ELContextImpl;\n\n/**\n * Test case for {@link JavaServerFaces2746CleanUp}\n * @author Mattias Jiderhamn\n */\npublic class JavaServerFaces2746CleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<JavaServerFaces2746CleanUp> {\n\n  /** \n   * Trigger leak by explicit call to {@link BeanELResolver#getFeatureDescriptors(javax.el.ELContext, Object)}.\n   * With Caucho Resin EL implementation, a call to {@link BeanELResolver#getValue(javax.el.ELContext, Object, Object)},\n   * {@link BeanELResolver#setValue(javax.el.ELContext, Object, Object, Object)},\n   * {@link BeanELResolver#getType(javax.el.ELContext, Object, Object)} or \n   * {@link BeanELResolver#isReadOnly(javax.el.ELContext, Object, Object)} would render the same result.\n   */\n  private static void doTriggerLeak() {\n    final MyComponent myComponent = new MyComponent();\n    final BeanELResolver beanELResolver = new BeanELResolver();\n    ELContext elContext = new ELContextImpl(new BeanELResolver()); // Irrelevant, could have been mock\n    beanELResolver.getFeatureDescriptors(elContext, myComponent);\n  }\n\n  /** Dummy custom component */\n  @SuppressWarnings(\"unused\")\n  private static class MyComponent extends UIComponentBase {\n    @Override\n    public String getFamily() {\n      throw new UnsupportedOperationException();\n    }\n    \n    /** Getter and setter must use custom attribute */\n    public MyAttribute getAttribute() {\n      return null;\n    }\n    \n    /** Getter and setter must use custom attribute */\n    public void setAttribute(MyAttribute myAttribute) {\n      \n    }\n  }\n  \n  /** Dummy custom component attribute type */\n  private static class MyAttribute {\n    \n  }\n  \n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n  /** \n   * Since {@link #doTriggerLeak()} also triggers another leak, by {@link java.beans.Introspector#getBeanInfo(java.lang.Class<?>)}\n   * invoking {@link java.beans.ThreadGroupContext}, we need to fix that leak as part of the triggering.\n   */\n  @SuppressWarnings(\"UnusedAssignment\")\n  @Override\n  protected void triggerLeak() throws Exception {\n    doTriggerLeak();\n\n    new ThreadGroupContextCleanUp().cleanUp(getClassLoaderLeakPreventor());\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaUtilLoggingLevelCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test cases for {@link JavaUtilLoggingLevelCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class JavaUtilLoggingLevelCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<JavaUtilLoggingLevelCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    // TODO Log\n    // Logger logger = Logger.getLogger(JavaUtilLoggingLevelCleanUpTest.class.getName());\n    // logger.setLevel(\n        new CustomLevel();\n  }\n\n  /** PropertyEditor for testing */\n  public static class CustomLevel extends java.util.logging.Level {\n    public CustomLevel() {\n      super(\"Foo\", 10);\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JavaxSecurityAuthLoginConfigurationCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\n\n/**\n * Test case for {@link JavaxSecurityAuthLoginConfigurationCleanUp}\n * @author Nikos Epping\n */\npublic class JavaxSecurityAuthLoginConfigurationCleanUpTest\n    extends ClassLoaderPreMortemCleanUpTestBase<JavaxSecurityAuthLoginConfigurationCleanUp> {\n\n  @Override\n  protected void triggerLeak() throws Exception {\n    Configuration.setConfiguration(new MockConfiguration());\n  }\n\n  private class MockConfiguration extends Configuration {\n    @Override\n    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {\n      return null;\n    }\n  }\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/JceSecurityCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.security.NoSuchAlgorithmException;\nimport java.security.Provider;\n\n/**\n * Test that the leak caused by {@link javax.crypto.JceSecurity} is cleared.\n * Thanks to Paul Kiman for the report.\n * @author Mattias Jiderhamn\n */\npublic class JceSecurityCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<JceSecurityCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    try {\n      // Alternative classes: KeyAgreement, KeyGenerator, ExemptionMechanism\n      MyProvider myProvider = new MyProvider(\"foo\", 1.0, \"bar\");\n      javax.crypto.Mac.getInstance(\"baz\", myProvider);\n    }\n    catch (SecurityException e) { // CS:IGNORE\n      // Leak is triggered despite an exception being thrown\n    }\n    catch (NoSuchAlgorithmException e) { // CS:IGNORE\n      // Leak is triggered despite an exception being thrown\n    }\n  }\n  \n  /** Custom {@link Provider}, to be put in {@link javax.crypto.JceSecurity} caches */\n  public static class MyProvider extends Provider {\n    public MyProvider(String name, double version, String info) {\n      super(name, version, info);\n    }\n\n    @Override\n    public synchronized Service getService(String type, String algorithm) {\n      return new Service(this, \"type\", \"algorithm\", \"className\", null, null);\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MBeanCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\n/**\n * Test case for {@link MBeanCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class MBeanCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<MBeanCleanUp> {\n  \n  @Override\n  protected void triggerLeak() throws Exception {\n    MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();\n    mBeanServer.registerMBean(new Custom(), new ObjectName(\"se.jiderhamn:foo=bar\" + System.currentTimeMillis() /* Unique name per test */));\n  }\n  \n  public interface CustomMBean {\n  }\n  \n  public static class Custom implements CustomMBean {\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport javax.management.Notification;\nimport javax.management.NotificationEmitter;\nimport javax.management.NotificationListener;\n\n/**\n * Test case for {@link MXBeanNotificationListenersCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class MXBeanNotificationListenersCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<MXBeanNotificationListenersCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).addNotificationListener(\n        new CustomNotificationListener(), null, null);\n  }\n\n  static class CustomNotificationListener implements NotificationListener {\n    @Override\n    public void handleNotification(Notification notification, Object handback) {\n      \n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MXBeanNotificationListenersCleanUp_ListenerWrapperTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.reflect.Constructor;\nimport javax.management.NotificationEmitter;\nimport javax.management.NotificationListener;\n\nimport com.sun.jmx.interceptor.DefaultMBeanServerInterceptor;\n\n/**\n * Test case for {@link MXBeanNotificationListenersCleanUp} when {@link DefaultMBeanServerInterceptor.ListenerWrapper}\n * is used.\n * @author Mattias Jiderhamn\n */\npublic class MXBeanNotificationListenersCleanUp_ListenerWrapperTest extends ClassLoaderPreMortemCleanUpTestBase<MXBeanNotificationListenersCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    final Class<?> listenerWrapperClass = getClassLoaderLeakPreventor().findClass(\"com.sun.jmx.interceptor.DefaultMBeanServerInterceptor$ListenerWrapper\");\n    final Constructor<?> constructor = listenerWrapperClass.getDeclaredConstructors()[0];\n    constructor.setAccessible(true);\n    final NotificationListener wrappedListener = (NotificationListener) constructor.newInstance(\n        new MXBeanNotificationListenersCleanUpTest.CustomNotificationListener(), null, null);\n\n    ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).addNotificationListener(\n        wrappedListener, null, null);\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MoxyCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.eclipse.persistence.jaxb.compiler.CompilerHelper;\nimport se.jiderhamn.classloader.PackagesLoadedOutsideClassLoader;\n\n/**\n * To trigger leak {@link org.eclipse.persistence.jaxb.compiler.CompilerHelper} must be loaded by leaking classloader\n * {@link org.eclipse.persistence.jaxb.javamodel.Helper} and/or {@link org.eclipse.persistence.jaxb.compiler.Property} must not\n * @author Mattias Jiderhamn\n */\n@PackagesLoadedOutsideClassLoader(packages = {\"org.eclipse.persistence.jaxb.javamodel\"}, addToDefaults = true)\npublic class MoxyCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<MoxyCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n     final ClassLoader leakSafeCL = Thread.currentThread().getContextClassLoader().getParent();\n    // Class.forName(\"org.eclipse.persistence.jaxb.javamodel.Helper\", true, leakSafeCL);\n    // Class.forName(\"org.eclipse.persistence.jaxb.compiler.Property\", true, leakSafeCL);\n    Class.forName(\"org.eclipse.persistence.jaxb.compiler.CompilerHelper\", true, leakSafeCL);\n    \n    try {\n      CompilerHelper.getXmlBindingsModelContext();\n    }\n    catch(IllegalAccessError e) {\n      // CompilerHelper.getXmlBindingsModelContext() tries to load some internal classes that \n      // cannot be loaded anymore with java versions > 8 (Jigsaw)\n      // Leak is triggered despite exception being thrown\n    }\n    \n    // This prevention needs to be run in addition\n    new ResourceBundleCleanUp().cleanUp(getClassLoaderLeakPreventor());\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/MultiThreadedHttpConnectionManagerCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport com.sun.jersey.api.client.Client;\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.api.client.WebResource;\nimport com.sun.jersey.api.client.config.DefaultClientConfig;\nimport com.sun.jersey.client.apache.ApacheHttpClient;\n\n/**\n * Test case for leaks caused by {@link ApacheHttpClient} failing to \n * close {@link org.apache.commons.httpclient.MultiThreadedHttpConnectionManager}\n *\n * @author Marian Petrik\n */\npublic class MultiThreadedHttpConnectionManagerCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<MultiThreadedHttpConnectionManagerCleanUp> {\n\n  @Override\n  protected void triggerLeak() {\n    Client client = ApacheHttpClient.create(new DefaultClientConfig());\n    try {\n      // it doesn't matter where we make our call, we only want to initiate connections to create the leak\n      WebResource webResource = client.resource(\"http://localhost:1234\");\n      webResource.accept(\"application/json\").get(ClientResponse.class);\n    } catch (Throwable ex) {\n      //exception thrown for a non existing url, we do not need to call a real url, only to start the relevant leaking classes \n    }\n    client.destroy();\n  }\n\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ObjectStreamClassCleanupTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.io.ObjectStreamClass;\nimport java.io.Serializable;\n\n/**\n * Test cases for {@link ObjectStreamClassCleanup}\n */\npublic class ObjectStreamClassCleanupTest extends ClassLoaderPreMortemCleanUpTestBase<ObjectStreamClassCleanup> {\n\n    @Override\n    protected void triggerLeak() throws Exception {\n        ObjectStreamClass.lookup(SerializableEntity.class);\n    }\n\n    protected final class SerializableEntity implements Serializable {\n\n        private static final long serialVersionUID = 1L;\n\n        public int value;\n    }\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/PropertyEditorCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.beans.PropertyEditorManager;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link PropertyEditorCleanUp}\n * @author Mattias Jiderhamn\n */\n@Ignore // No longer leaks in Java 7+\npublic class PropertyEditorCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<PropertyEditorCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    PropertyEditorManager.registerEditor(String[].class, Foo.class); // Before Java 7, this caused a leak\n  }\n\n  /** PropertyEditor for testing */\n  public static class Foo {\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ProxySelectorCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.io.IOException;\nimport java.net.Proxy;\nimport java.net.ProxySelector;\nimport java.net.SocketAddress;\nimport java.net.URI;\nimport java.util.List;\n\n/**\n * Test case for {@link ProxySelectorCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class ProxySelectorCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<ProxySelectorCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    ProxySelector.setDefault(new MyProxySelector());\n  }\n  \n  /** Custom {@link ProxySelector} to trigger leak */\n  private static class MyProxySelector extends ProxySelector {\n    @Override\n    public List<Proxy> select(URI uri) {\n      throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {\n      throw new UnsupportedOperationException();\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ReplaceDOMNormalizerSerializerAbortExceptionCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp;\nimport se.jiderhamn.classloader.leak.prevention.ReplaceDOMNormalizerSerializerAbortException;\nimport se.jiderhamn.classloader.leak.prevention.preinit.ReplaceDOMNormalizerSerializerAbortExceptionInitiatorTest;\n\n/**\n * Test cases for {@link ReplaceDOMNormalizerSerializerAbortException} when used as {@link ClassLoaderPreMortemCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class ReplaceDOMNormalizerSerializerAbortExceptionCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<ReplaceDOMNormalizerSerializerAbortException> {\n  @Override\n  public void triggerLeak() throws Exception {\n    ReplaceDOMNormalizerSerializerAbortExceptionInitiatorTest.triggerLeak();\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/SAAJEnvelopeFactoryParserPoolCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.reflect.Method;\nimport javax.xml.parsers.SAXParser;\n\nimport se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor;\n\nimport static org.junit.Assert.assertNotNull;\n\n/**\n * Test case for {@link SAAJEnvelopeFactoryParserPoolCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class SAAJEnvelopeFactoryParserPoolCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<SAAJEnvelopeFactoryParserPoolCleanUp> {\n\n  @Override\n  protected void triggerLeak() throws Exception {\n    final ClassLoaderLeakPreventor preventor = getClassLoaderLeakPreventor();\n\n    /*\n    try {\n      EnvelopeFactory.createEnvelope(new StreamSource(), new SOAPPart1_1Impl());\n    }\n    catch (SOAPException e) { // CS:IGNORE\n    }\n    */\n\n    Class<?> envelopeFactoryClass = preventor.findClass(\"com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory\");\n    if (envelopeFactoryClass == null) {\n      // Try the package for the maven dependency if the internal one is not available\n      envelopeFactoryClass = preventor.findClass(\"com.sun.xml.messaging.saaj.soap.EnvelopeFactory\");\n    }\n    \n    final Object /* com.sun.xml.internal.messaging.saaj.soap.ContextClassloaderLocal */\n            parserPool = preventor.getStaticFieldValue(envelopeFactoryClass, \"parserPool\");\n    final Object currentParserPool = preventor.findMethod(parserPool.getClass().getSuperclass(), \"get\").invoke(parserPool);\n    assertNotNull(currentParserPool);\n\n    final Method getMethod = preventor.findMethod(currentParserPool.getClass(), \"get\");\n    final SAXParser saxParser = (SAXParser) getMethod.invoke(currentParserPool);\n    \n    saxParser.setProperty(\"http://apache.org/xml/properties/internal/error-handler\", getCustomErrorHandlerInstance(preventor));\n    \n    final Method putMethod = preventor.findMethod(currentParserPool.getClass(), \"put\", SAXParser.class);\n    putMethod.invoke(currentParserPool, saxParser);\n  }\n\n  /*\n   * Create a dummy XMLErrorHandler to be loaded by the classloader that sould be garbage collected\n   * Create using reflection, since the type is not compile time accessible in newer Java Versions\n   */\n  public Object getCustomErrorHandlerInstance(final ClassLoaderLeakPreventor preventor) {\n    final Class<?> errorHandlerClass = preventor.findClass(\"com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler\");\n   \n    Object instance = java.lang.reflect.Proxy.newProxyInstance(\n        this.getClass().getClassLoader(),\n        new java.lang.Class[] { errorHandlerClass },\n        new java.lang.reflect.InvocationHandler() {\n\n        @Override\n        public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws java.lang.Throwable {\n          // Can be empty since we don't really want to use the handler  \n          return null;\n        }\n    });\n    \n    return errorHandlerClass.cast(instance);\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/SecurityProviderCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.security.Provider;\n\n/**\n * Test case for {@link SecurityProviderCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class SecurityProviderCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<SecurityProviderCleanUp> {\n  private static final Provider customProvider = new Provider(\"Foo\", 1.0, \"Bar\") {\n    // Nothing\n  };\n\n  @Override\n  protected void triggerLeak() throws Exception {\n    java.security.Security.addProvider(customProvider);\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ShutdownHookCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test case for {@link ShutdownHookCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class ShutdownHookCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<ShutdownHookCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    Runtime.getRuntime().addShutdownHook(new ShutdownHookThread());\n  }\n\n  /** Dummy shutdown hook */\n  private class ShutdownHookThread extends Thread {\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp_MultiThreadedHttpConnectionManagerTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport com.sun.jersey.api.client.Client;\nimport com.sun.jersey.api.client.ClientResponse;\nimport com.sun.jersey.api.client.WebResource;\nimport com.sun.jersey.api.client.config.DefaultClientConfig;\nimport com.sun.jersey.client.apache.ApacheHttpClient;\n\n/**\n * Test case for leaks caused by {@link com.sun.jersey.client.apache.ApacheHttpClient} failing to \n * close {@link org.apache.commons.httpclient.MultiThreadedHttpConnectionManager}. \n * Demonstrates {@link StopThreadsCleanUp} is sufficient, although {@link MultiThreadedHttpConnectionManagerCleanUp} may\n * be used in case you want to avoid {@link StopThreadsCleanUp}.  \n *\n * @author Mattias Jiderhamn\n */\npublic class StopThreadsCleanUp_MultiThreadedHttpConnectionManagerTest extends ClassLoaderPreMortemCleanUpTestBase<StopThreadsCleanUp> {\n\n  @Override\n  protected void triggerLeak() {\n    Client client = ApacheHttpClient.create(new DefaultClientConfig());\n    try {\n      // it doesn't matter where we make our call, we only want to initiate connections to create the leak\n      WebResource webResource = client.resource(\"http://localhost:1234\");\n      webResource.accept(\"application/json\").get(ClientResponse.class);\n    } catch (Throwable ex) {\n      //exception thrown for a non existing url, we do not need to call a real url, only to start the relevant leaking classes \n    }\n    client.destroy();\n  }\n\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp_PostgresqlJdbcTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport org.junit.After;\nimport se.jiderhamn.classloader.PackagesLoadedOutsideClassLoader;\n\n/**\n * Test case for leaks caused by Postgresql JDBC driver timer threads are avoided by {@link StopThreadsCleanUp}.  \n * @author Mattias Jiderhamn\n */\n@PackagesLoadedOutsideClassLoader(packages = {\"org.postgresql\", \"com.mysql\"}, addToDefaults = true)\npublic class StopThreadsCleanUp_PostgresqlJdbcTest extends ClassLoaderPreMortemCleanUpTestBase<StopThreadsCleanUp> {\n\n  @Override\n  protected void triggerLeak() {\n    org.postgresql.Driver.getSharedTimer().getTimer();\n  }\n  \n  @After\n  public void tearDown() {\n    org.postgresql.Driver.getSharedTimer().releaseTimer();\n  }\n\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsCleanUp_Runnable.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test case for leaks caused by {@link Runnable} of thread being loaded by classloader. \n *\n * @author Mattias Jiderhamn\n */\npublic class StopThreadsCleanUp_Runnable extends ClassLoaderPreMortemCleanUpTestBase<StopThreadsCleanUp> {\n\n  @Override\n  protected void triggerLeak() {\n    Thread t = new Thread(new Runnable() {\n      @Override\n      public void run() {\n        try {\n          Thread.sleep(5000L);\n        }\n        catch (InterruptedException e) {\n          System.out.println(\"Thread with custom Runnable was interrupted from sleeping. Going back to sleep.\");\n        }\n      }\n    });\n    t.setContextClassLoader(ClassLoader.getSystemClassLoader());\n    t.start();\n  }\n\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/StopThreadsClenup_ExecutorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * Test case for leaks caused by shared ThreadPool creating new Threads\n * \n * Treads are started by ExecutorService would have Protection Domain of inheritedAccessControlContext loaded by classLoader\n * \n * @author Vlad Skarzhevsky\n */\npublic class StopThreadsClenup_ExecutorTest extends ClassLoaderPreMortemCleanUpTestBase<StopThreadsCleanUp> {\n\n    private static final ExecutorService executor = createSharedExecutor();\n\n    private static ExecutorService createSharedExecutor() {\n        ExecutorService executor = Executors.newFixedThreadPool(3);\n\n        // initialize executor with one thread\n        if (true) {\n            executor.submit(new Runnable() {\n\n                @Override\n                public void run() {\n                }\n            });\n        }\n\n        return executor;\n    }\n\n    @Override\n    protected void triggerLeak() throws Exception {\n        // Start multiple threads to be sure that ThreadPool created new threads\n        for (int i = 0; i < 1; i++) {\n            executor.submit(new Runnable() {\n                @Override\n                public void run() {\n                }\n            });\n        }\n    }\n\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadGroupCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test cases for {@link ThreadGroupCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class ThreadGroupCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<ThreadGroupCleanUp> {\n\n  /** \n   * Having a custom ThreadGroup that is not destroyed will cause a leak\n   */\n  @Override\n  protected void triggerLeak() throws Exception {\n    new ThreadGroup(\"customThreadGroup\") {\n      @Override\n      public void uncaughtException(Thread t, Throwable e) {\n        System.out.println(\"Pretend to do something\");\n        super.uncaughtException(t, e);\n      }\n    };\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test cases for {@link ThreadLocalCleanUp}\n *\n * ThreadLocals work the same way as WeakHashMaps; from http://docs.oracle.com/javase/6/docs/api/java/util/WeakHashMap.html\n * \"Implementation note: The value objects in a WeakHashMap are held by ordinary strong references. Thus care should be \n * taken to ensure that value objects do not strongly refer to their own keys, either directly or indirectly, \n * since that will prevent the keys from being discarded.\"\n * \n * This means that the reference chain is like this: Thread -> custom value -> custom class ->\n * custom classloader -> class containing ThreadLocal -> static ThreadLocal \n *\n * @author Mattias Jiderhamn\n */\npublic class ThreadLocalCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<ThreadLocalCleanUp> {\n\n  private static final ThreadLocal<Value> threadLocalWithCustomValue = new ThreadLocal<Value>();\n\n  /**\n   * This may - and will - also leak, since the values aren't removed even when the weak referenced key is \n   * garbage collected. See java.lang.ThreadLocal.ThreadLocalMap JavaDoc: \"However, since reference queues are not\n   * used, stale entries are guaranteed to be removed only when the table starts running out of space.\"\n   */\n  @Override\n  protected void triggerLeak() throws Exception {\n    threadLocalWithCustomValue.set(new Value());\n  }\n\n  /** Custom value class to create leak */\n  private static class Value {\n    \n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalWithNestedRefValueCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.SoftReference;\n\n/**\n * Another variant test case for {@link ThreadLocalCleanUp} using chained {@link SoftReference}s to the value,\n * checking that the value is recursively dereferenced.\n * Also check {@link ThreadLocalWithRefValueCleanUpTest}\n */\npublic class ThreadLocalWithNestedRefValueCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<ThreadLocalCleanUp> {\n\n    private static final ThreadLocal<SoftReference<SoftReference<Value>>> threadLocalWithCustomValue = new ThreadLocal<SoftReference<SoftReference<Value>>>();\n\n    @Override\n    protected void triggerLeak() throws Exception {\n      threadLocalWithCustomValue.set(new SoftReference<SoftReference<Value>>(new SoftReference<Value>(new Value())));\n    }\n\n    /** Custom value class to create leak */\n    private static class Value {\n      \n    }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/ThreadLocalWithRefValueCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.lang.ref.Reference;\nimport java.lang.ref.SoftReference;\n\n/**\n * Variant test case for {@link ThreadLocalCleanUp} using a {@link Reference} instead of a direct, strong reference to the value.\n * \n * All {@link Reference} implementations are using the bootstrap classloader, so it's required to dereference the value\n * to check which classloader was used for the value held by the Reference instance.\n * \n * Also check {@link ThreadLocalWithNestedRefValueCleanUpTest}\n */\npublic class ThreadLocalWithRefValueCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<ThreadLocalCleanUp> {\n\n    private static final ThreadLocal<SoftReference<Value>> threadLocalWithCustomValue = new ThreadLocal<SoftReference<Value>>();\n\n    @Override\n    protected void triggerLeak() throws Exception {\n      threadLocalWithCustomValue.set(new SoftReference<Value>(new Value()));\n    }\n\n    /** Custom value class to create leak */\n    private static class Value {\n      \n    }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/X509TrustManagerImplUnparseableExtensionCleanUpTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\nimport java.io.File;\nimport javax.net.ssl.SSLContext;\n\n/**\n * Test case for {@link X509TrustManagerImplUnparseableExtensionCleanUp}\n * @author Mattias Jiderhamn\n */\npublic class X509TrustManagerImplUnparseableExtensionCleanUpTest extends ClassLoaderPreMortemCleanUpTestBase<X509TrustManagerImplUnparseableExtensionCleanUp> {\n  @Override\n  protected void triggerLeak() throws Exception {\n    final File keystore = new File(this.getClass().getClassLoader().getResource(\"./spi-cacert-2008.keystore\").toURI());\n    System.setProperty(\"javax.net.ssl.trustStore\", keystore.getAbsolutePath());\n    SSLContext.getDefault();\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/cleanup/package-info.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.cleanup;\n\n/**\n * Test cases in this package are used to confirm a) that a leak exists and b) that the \n * {@link se.jiderhamn.classloader.leak.prevention.ClassLoaderPreMortemCleanUp} is able to circumvent the leak. */"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/package-info.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\n/**\n * Test cases in this package are used to confirm a) that a leak exists and b) that the \n * {@link se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventorListener} is able to circumvent the leak. */"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/AwtToolkitInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test case for {@link AwtToolkitInitiator}\n * @author Mattias Jiderhamn\n */\n@Ignore // Fixed in newer versions of Java?\npublic class AwtToolkitInitiatorTest extends PreClassLoaderInitiatorTestBase<AwtToolkitInitiator> {\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/DatatypeConverterImplInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.GregorianCalendar;\nimport javax.xml.datatype.DatatypeFactory;\nimport javax.xml.datatype.Duration;\nimport javax.xml.datatype.XMLGregorianCalendar;\n\nimport org.junit.Before;\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link DatatypeConverterImplInitiator}\n * @author Mattias Jiderhamn\n */\n@Ignore // Doesn't leak in Java 1.7.0 (_55, _56), but does in 1.8.0 (_74) \npublic class DatatypeConverterImplInitiatorTest extends PreClassLoaderInitiatorTestBase<DatatypeConverterImplInitiator> {\n  @Before\n  public void setSystemProperty() {\n    System.setProperty(\"javax.xml.datatype.DatatypeFactory\", MyDatatypeFactory.class.getName());\n  }\n\n  /** Custom {@link DatatypeFactory} loaded by \"our\" classloader */\n  public static class MyDatatypeFactory extends DatatypeFactory {\n    @Override\n    public Duration newDuration(String lexicalRepresentation) {\n      throw new UnsupportedOperationException();\n    }\n  \n    @Override\n    public Duration newDuration(long durationInMilliSeconds) {\n      throw new UnsupportedOperationException();\n    }\n  \n    @Override\n    public Duration newDuration(boolean isPositive, BigInteger years, BigInteger months, BigInteger days, BigInteger hours, BigInteger minutes, BigDecimal seconds) {\n      throw new UnsupportedOperationException();\n    }\n  \n    @Override\n    public XMLGregorianCalendar newXMLGregorianCalendar() {\n      throw new UnsupportedOperationException();\n    }\n  \n    @Override\n    public XMLGregorianCalendar newXMLGregorianCalendar(String lexicalRepresentation) {\n      throw new UnsupportedOperationException();\n    }\n  \n    @Override\n    public XMLGregorianCalendar newXMLGregorianCalendar(GregorianCalendar cal) {\n      throw new UnsupportedOperationException();\n    }\n  \n    @Override\n    public XMLGregorianCalendar newXMLGregorianCalendar(BigInteger year, int month, int day, int hour, int minute, int second, BigDecimal fractionalSecond, int timezone) {\n      throw new UnsupportedOperationException();\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/DocumentBuilderFactoryInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link DocumentBuilderFactoryInitiator}\n * @author Mattias Jiderhamn\n */\n@Ignore // Fixed in newer versions of Java?\npublic class DocumentBuilderFactoryInitiatorTest extends PreClassLoaderInitiatorTestBase<DocumentBuilderFactoryInitiator> {\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dDisposerInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link Java2dDisposerInitiator}\n * @author Mattias Jiderhamn\n */\n@Ignore // Fixed in newer versions of Java\npublic class Java2dDisposerInitiatorTest extends PreClassLoaderInitiatorTestBase<Java2dDisposerInitiator> {\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/Java2dRenderQueueInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\n/**\n * Test cases for {@link Java2dRenderQueueInitiator}\n */\npublic class Java2dRenderQueueInitiatorTest extends PreClassLoaderInitiatorTestBase<Java2dRenderQueueInitiator> {\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/JavaxSecurityLoginConfigurationInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link JavaxSecurityLoginConfigurationInitiator}\n * @author Mattias Jiderhamn\n */\n@Ignore // Fixed in newer versions of Java\npublic class JavaxSecurityLoginConfigurationInitiatorTest extends PreClassLoaderInitiatorTestBase<JavaxSecurityLoginConfigurationInitiator> {\n\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/JdbcDriversInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link JdbcDriversInitiator}\n * @author Mattias Jiderhamn\n */\n@Ignore // Cannot be tested this way\npublic class JdbcDriversInitiatorTest extends PreClassLoaderInitiatorTestBase<JdbcDriversInitiator> {\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/LdapPoolManagerInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Before;\n\n/**\n * Test cases for {@link LdapPoolManagerInitiator}\n * @author Mattias Jiderhamn\n */\npublic class LdapPoolManagerInitiatorTest extends PreClassLoaderInitiatorTestBase<LdapPoolManagerInitiator> {\n  @Before\n  public void setSystemProperty() {\n    System.setProperty(\"com.sun.jndi.ldap.connect.pool.timeout\", \"1\"); // Required to trigger leak\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/OracleJdbcThreadInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\nimport se.jiderhamn.classloader.PackagesLoadedOutsideClassLoader;\n\n/**\n * Test cases for {@link OracleJdbcThreadInitiator}\n * @author Mattias Jiderhamn\n */\n@Ignore // Oracle JDBC driver needs to be available for this test\n@PackagesLoadedOutsideClassLoader(packages = \"oracle.\", addToDefaults = true)\npublic class OracleJdbcThreadInitiatorTest extends PreClassLoaderInitiatorTestBase<OracleJdbcThreadInitiator> {\n  \n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/PreClassLoaderInitiatorTestBase.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.MethodSorters;\nimport se.jiderhamn.classloader.leak.JUnitClassloaderRunner;\nimport se.jiderhamn.classloader.leak.Leaks;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\nimport se.jiderhamn.classloader.leak.prevention.PreventionsTestBase;\n\n/**\n * Base class for testing {@link PreClassLoaderInitiator} implementations\n * @author Mattias Jiderhamn\n */\n@RunWith(JUnitClassloaderRunner.class)\n@FixMethodOrder(MethodSorters.NAME_ASCENDING) // Execute tests in name order\npublic class PreClassLoaderInitiatorTestBase<C extends PreClassLoaderInitiator> extends PreventionsTestBase<C> {\n  \n  /** First time {@link PreClassLoaderInitiator} is invoked we expect a leak */\n  @SuppressWarnings(\"DefaultAnnotationParam\")\n  @Leaks(true)\n  @Test\n  public void firstShouldLeak() throws Exception {\n    invokeInitiator();\n  }\n\n  /** Second time {@link PreClassLoaderInitiator} is invoked there should be no leak, since only first call is affected */\n  @Leaks(false)\n  @Test\n  public void secondShouldNotLeak() throws Exception {\n    invokeInitiator();\n  }\n\n  private void invokeInitiator() throws IllegalAccessException, InstantiationException, InterruptedException {\n    getTestedImplementation().doOutsideClassLoader(getClassLoaderLeakPreventor());\n  }\n\n  /** Use the {@link ClassLoader} of the test as the leak safe classloader, to test leaks. */\n  @Override\n  protected ClassLoader getLeakSafeClassLoader() {\n    return getClass().getClassLoader();\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/ReplaceDOMNormalizerSerializerAbortExceptionInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.ls.DOMImplementationLS;\nimport se.jiderhamn.classloader.leak.JUnitClassloaderRunner;\nimport se.jiderhamn.classloader.leak.Leaks;\nimport se.jiderhamn.classloader.leak.prevention.PreClassLoaderInitiator;\nimport se.jiderhamn.classloader.leak.prevention.PreventionsTestBase;\nimport se.jiderhamn.classloader.leak.prevention.ReplaceDOMNormalizerSerializerAbortException;\n\n/**\n * Test cases for {@link ReplaceDOMNormalizerSerializerAbortException} when used as {@link PreClassLoaderInitiator}\n * @author Mattias Jiderhamn\n */\n@RunWith(JUnitClassloaderRunner.class)\npublic class ReplaceDOMNormalizerSerializerAbortExceptionInitiatorTest extends PreventionsTestBase<ReplaceDOMNormalizerSerializerAbortException> {\n  \n  @Leaks(false)\n  @Test\n  public void noLeakAfterInitiatorRun() throws Exception {\n    getTestedImplementation().doOutsideClassLoader(getClassLoaderLeakPreventor());\n    triggerLeak();\n  }\n\n  /** Invoke code that may trigger leak */\n  public static void triggerLeak() throws ParserConfigurationException {\n    // Alternative 1\n    DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().normalizeDocument();\n\n    // Alternative 2\n    Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();\n    DOMImplementationLS implementation = (DOMImplementationLS)document.getImplementation();\n    implementation.createLSSerializer().writeToString(document);\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityPolicyInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link SecurityPolicyInitiator}\n * @author Mattias Jiderhamn\n */\n@Ignore // Fixed in newer versions of Java?\npublic class SecurityPolicyInitiatorTest extends PreClassLoaderInitiatorTestBase<SecurityPolicyInitiator> {\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SecurityProvidersInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\nimport org.junit.Ignore;\n\n/**\n * Test cases for {@link SecurityProvidersInitiator}\n * @author Mattias Jiderhamn\n */\n@Ignore // Cannot be tested this way?\npublic class SecurityProvidersInitiatorTest extends PreClassLoaderInitiatorTestBase<SecurityProvidersInitiator> {\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SunAwtAppContextInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\n/**\n * Test cases for {@link SunAwtAppContextInitiator}\n * @author Mattias Jiderhamn\n */\npublic class SunAwtAppContextInitiatorTest extends PreClassLoaderInitiatorTestBase<SunAwtAppContextInitiator> {\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/java/se/jiderhamn/classloader/leak/prevention/preinit/SunGCInitiatorTest.java",
    "content": "package se.jiderhamn.classloader.leak.prevention.preinit;\n\n/**\n * Test cases for {@link SunGCInitiator}\n * @author Mattias Jiderhamn\n */\npublic class SunGCInitiatorTest extends PreClassLoaderInitiatorTestBase<SunGCInitiator> {\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/resources/META-INF/services/javax.imageio.spi.ImageInputStreamSpi",
    "content": "se.jiderhamn.classloader.leak.prevention.cleanup.ImageIOMockImageInputStreamSPI"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-core/src/test/resources/spi-cacert-2008.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIIDjCCBfagAwIBAgIJAOiOtsn4KhQoMA0GCSqGSIb3DQEBBQUAMIG8MQswCQYD\nVQQGEwJVUzEQMA4GA1UECBMHSW5kaWFuYTEVMBMGA1UEBxMMSW5kaWFuYXBvbGlz\nMSgwJgYDVQQKEx9Tb2Z0d2FyZSBpbiB0aGUgUHVibGljIEludGVyZXN0MRMwEQYD\nVQQLEwpob3N0bWFzdGVyMR4wHAYDVQQDExVDZXJ0aWZpY2F0ZSBBdXRob3JpdHkx\nJTAjBgkqhkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDgwNTEz\nMDgwNzU2WhcNMTgwNTExMDgwNzU2WjCBvDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\nB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdh\ncmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEe\nMBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZo\nb3N0bWFzdGVyQHNwaS1pbmMub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC\nCgKCAgEA3DbmR0LCxFF1KYdAw9iOIQbSGE7r7yC9kDyFEBOMKVuUY/b0LfEGQpG5\nGcRCaQi/izZF6igFM0lIoCdDkzWKQdh4s/Dvs24t3dHLfer0dSbTPpA67tfnLAS1\nfOH1fMVO73e9XKKTM5LOfYFIz2u1IiwIg/3T1c87Lf21SZBb9q1NE8re06adU1Fx\nY0b4ShZcmO4tbZoWoXaQ4mBDmdaJ1mwuepiyCwMs43pPx93jzONKao15Uvr0wa8u\njyoIyxspgpJyQ7zOiKmqp4pRQ1WFmjcDeJPI8L20QcgHQprLNZd6ioFl3h1UCAHx\nZFy3FxpRvB7DWYd2GBaY7r/2Z4GLBjXFS21ZGcfSxki+bhQog0oQnBv1b7ypjvVp\n/rLBVcznFMn5WxRTUQfqzj3kTygfPGEJ1zPSbqdu1McTCW9rXRTunYkbpWry9vjQ\nco7qch8vNGopCsUK7BxAhRL3pqXTT63AhYxMfHMgzFMY8bJYTAH1v+pk1Vw5xc5s\nzFNaVrpBDyXfa1C2x4qgvQLCxTtVpbJkIoRRKFauMe5e+wsWTUYFkYBE7axt8Feo\n+uthSKDLG7Mfjs3FIXcDhB78rKNDCGOM7fkn77SwXWfWT+3Qiz5dW8mRvZYChD3F\nTbxCP3T9PF2sXEg2XocxLxhsxGjuoYvJWdAY4wCAs1QnLpnwFVMCAwEAAaOCAg8w\nggILMB0GA1UdDgQWBBQ0cdE41xU2g0dr1zdkQjuOjVKdqzCB8QYDVR0jBIHpMIHm\ngBQ0cdE41xU2g0dr1zdkQjuOjVKdq6GBwqSBvzCBvDELMAkGA1UEBhMCVVMxEDAO\nBgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMf\nU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1h\nc3RlcjEeMBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcN\nAQkBFhZob3N0bWFzdGVyQHNwaS1pbmMub3JnggkA6I62yfgqFCgwDwYDVR0TAQH/\nBAUwAwEB/zARBglghkgBhvhCAQEEBAMCAAcwCQYDVR0SBAIwADAuBglghkgBhvhC\nAQ0EIRYfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDAwBglghkgBhvhC\nAQQEIxYhaHR0cHM6Ly9jYS5zcGktaW5jLm9yZy9jYS1jcmwucGVtMDIGCWCGSAGG\n+EIBAwQlFiNodHRwczovL2NhLnNwaS1pbmMub3JnL2NlcnQtY3JsLnBlbTAhBgNV\nHREEGjAYgRZob3N0bWFzdGVyQHNwaS1pbmMub3JnMA4GA1UdDwEB/wQEAwIBBjAN\nBgkqhkiG9w0BAQUFAAOCAgEAtM294LnqsgMrfjLp3nI/yUuCXp3ir1UJogxU6M8Y\nPCggHam7AwIvUjki+RfPrWeQswN/2BXja367m1YBrzXU2rnHZxeb1NUON7MgQS4M\nAcRb+WU+wmHo0vBqlXDDxm/VNaSsWXLhid+hoJ0kvSl56WEq2dMeyUakCHhBknIP\nqxR17QnwovBc78MKYiC3wihmrkwvLo9FYyaW8O4x5otVm6o6+YI5HYg84gd1GuEP\nsTC8cTLSOv76oYnzQyzWcsR5pxVIBcDYLXIC48s9Fmq6ybgREOJJhcyWR2AFJS7v\ndVkz9UcZFu/abF8HyKZQth3LZjQl/GaD68W2MEH4RkRiqMEMVObqTFoo5q7Gt/5/\nO5aoLu7HaD7dAD0prypjq1/uSSotxdz70cbT0ZdWUoa2lOvUYFG3/B6bzAKb1B+P\n+UqPti4oOxfMxaYF49LTtcYDyeFIQpvLP+QX4P4NAZUJurgNceQJcHdC2E3hQqlg\ng9cXiUPS1N2nGLar1CQlh7XU4vwuImm9rWgs/3K1mKoGnOcqarihk3bOsPN/nOHg\nT7jYhkalMwIsJWE3KpLIrIF0aGOHM3a9BX9e1dUCbb2v/ypaqknsmHlHU5H2DjRa\nyaXG67Ljxay2oHA1u8hRadDytaIybrw/oDc5fHE2pgXfDBLkFqfF1stjo5VwP+YE\no2A=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet/pom.xml",
    "content": "<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\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n    <artifactId>classloader-leak-prevention-parent</artifactId>\n    <version>2.7.1-SNAPSHOT</version>\n  </parent>\n  <artifactId>classloader-leak-prevention-servlet</artifactId>\n  <packaging>jar</packaging>\n  <name>ClassLoader Leak Prevention library for servlet environments</name>\n  <description>ServletContextListener that prevents ClassLoader leaks / java.lang.OutOfMemoryError: PermGen space</description>\n  <url>https://github.com/mjiderhamn/classloader-leak-prevention</url>\n  \n  <dependencies>\n    <dependency>\n      <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n      <artifactId>classloader-leak-prevention-core</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>javax.servlet</groupId>\n      <artifactId>servlet-api</artifactId>\n      <version>2.5</version>\n      <scope>provided</scope>\n    </dependency>\n  </dependencies>\n\n</project>"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventorListener.java",
    "content": "/*\n   Copyright 2012 Mattias Jiderhamn\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\npackage se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport javax.servlet.ServletContext;\nimport javax.servlet.ServletContextEvent;\nimport javax.servlet.ServletContextListener;\n\nimport se.jiderhamn.classloader.leak.prevention.cleanup.ShutdownHookCleanUp;\nimport se.jiderhamn.classloader.leak.prevention.cleanup.StopThreadsCleanUp;\nimport se.jiderhamn.classloader.leak.prevention.preinit.OracleJdbcThreadInitiator;\n\nimport static java.util.Collections.emptyList;\nimport static java.util.Collections.singletonList;\nimport static se.jiderhamn.classloader.leak.prevention.cleanup.ShutdownHookCleanUp.SHUTDOWN_HOOK_WAIT_MS_DEFAULT;\n\n/**\n * This class helps prevent classloader leaks.\n * <h1>Basic setup</h1>\n * <p>Activate protection by adding this class as a context listener\n * in your <code>web.xml</code>, like this:</p>\n * <pre>\n *  &lt;listener&gt;\n *     &lt;listener-class&gt;se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor&lt;/listener-class&gt;\n *  &lt;/listener&gt; \n * </pre>\n * \n * You should usually declare this <code>listener</code> before any other listeners, to make it \"outermost\".\n *\n * <h1>Configuration</h1>\n * The context listener has a number of settings that can be configured with context parameters in <code>web.xml</code>,\n * i.e.:\n * \n * <pre>\n *   &lt;context-param&gt;\n *     &lt;param-name&gt;ClassLoaderLeakPreventor.stopThreads&lt;/param-name&gt;\n *     &lt;param-value&gt;false&lt;/param-value&gt;\n *   &lt;/context-param&gt;\n * </pre>\n * \n * The available settings are\n * <table border=\"1\">\n *   <tr>\n *     <th>Parameter name</th>\n *     <th>Default value</th>\n *     <th>Description</th>\n *   </tr>\n *   <tr>\n *     <td><code>ClassLoaderLeakPreventor.stopThreads</code></td>\n *     <td><code>true</code></td>\n *     <td>Should threads tied to the web app classloader be forced to stop at application shutdown?</td>\n *   </tr>\n *   <tr>\n *     <td><code>ClassLoaderLeakPreventor.stopTimerThreads</code></td>\n *     <td><code>true</code></td>\n *     <td>Should Timer threads tied to the web app classloader be forced to stop at application shutdown?</td>\n *   </tr>\n *   <tr>\n *     <td><code>ClassLoaderLeakPreventor.executeShutdownHooks</td>\n *     <td><code>true</code></td>\n *     <td>Should shutdown hooks registered from the application be executed at application shutdown?</td>\n *   </tr>\n *   <tr>\n *     <td><code>ClassLoaderLeakPreventor.threadWaitMs</td>\n *     <td><code>5000</code> (5 seconds)</td>\n *     <td>No of milliseconds to wait for threads to finish execution, before stopping them.</td>\n *   </tr>\n *   <tr>\n *     <td><code>ClassLoaderLeakPreventor.shutdownHookWaitMs</code></td>\n *     <td><code>10000</code> (10 seconds)</td>\n *     <td>\n *       No of milliseconds to wait for shutdown hooks to finish execution, before stopping them.\n *       If set to -1 there will be no waiting at all, but Thread is allowed to run until finished.\n *     </td>\n *   </tr>\n * </table>\n * \n * \n * <h1>License</h1>\n * <p>This code is licensed under the <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">Apache 2</a> license,\n * which allows you to include modified versions of the code in your distributed software, without having to release\n * your source code.</p>\n *\n * <h1>More info</h1> \n * <p>For more info, see \n * <a href=\"http://java.jiderhamn.se/2012/03/04/classloader-leaks-vi-this-means-war-leak-prevention-library/\">here</a>.\n * </p>\n * \n * <h1>Design goals</h1>\n * <p>If you want to help improve this component, you should be aware of the design goals</p>\n * <p>\n *   Primary design goal: Zero dependencies. The component should build and run using nothing but the JDK and the \n *   Servlet API. Specifically we should <b>not</b> depend on any logging framework, since they are part of the problem.\n *   We also don't want to use any utility libraries, in order not to impose any further dependencies into any project\n *   that just wants to get rid of classloader leaks.\n *   Access to anything outside of the standard JDK (in order to prevent a known leak) should be managed\n *   with reflection.\n * </p>\n * <p>\n *   Secondary design goal: Keep the runtime component in a single <code>.java</code> file. It should be possible to\n *   just add this one <code>.java</code> file into your own source tree.\n * </p>\n * \n * @author Mattias Jiderhamn, 2012-2016\n */\n@SuppressWarnings(\"WeakerAccess\")\npublic class ClassLoaderLeakPreventorListener implements ServletContextListener {\n\n  protected ClassLoaderLeakPreventor classLoaderLeakPreventor;\n\n  /** Other {@link javax.servlet.ServletContextListener}s to use also */\n  protected final List<ServletContextListener> otherListeners = new LinkedList<ServletContextListener>();\n\n  /** \n   * Get the default set of other {@link ServletContextListener} to be automatically invoked.\n   * NOTE! Anything added here should be idempotent, i.e. there should be no problem executing the listener twice.\n   */\n  static List<ServletContextListener> getDefaultOtherListeners() {\n    try{\n      Class<ServletContextListener> introspectorCleanupListenerClass = \n          (Class<ServletContextListener>) Class.forName(\"org.springframework.web.util.IntrospectorCleanupListener\");\n      return singletonList(introspectorCleanupListenerClass.newInstance());\n    }\n    catch (ClassNotFoundException e) {\n      // Ignore silently - Spring not present on classpath\n    }\n    catch(Exception e){\n      e.printStackTrace(System.err);\n    }\n    return emptyList();\n  } \n\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  // Implement javax.servlet.ServletContextListener \n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n  @Override\n  public void contextInitialized(ServletContextEvent servletContextEvent) {\n    otherListeners.addAll(getDefaultOtherListeners());\n\n    contextInitialized(servletContextEvent.getServletContext());\n\n    for(ServletContextListener listener : otherListeners) {\n      try {\n        listener.contextInitialized(servletContextEvent);\n      }\n      catch(Exception e){\n        classLoaderLeakPreventor.error(e);\n      }\n    }\n  }\n  \n  void contextInitialized(final ServletContext servletContext) {\n    \n    // Should threads tied to the web app classloader be forced to stop at application shutdown?\n    boolean stopThreads = ! \"false\".equals(servletContext.getInitParameter(\"ClassLoaderLeakPreventor.stopThreads\"));\n    \n    // Should Timer threads tied to the web app classloader be forced to stop at application shutdown?\n    boolean stopTimerThreads = ! \"false\".equals(servletContext.getInitParameter(\"ClassLoaderLeakPreventor.stopTimerThreads\"));\n    \n    // Should shutdown hooks registered from the application be executed at application shutdown?\n    boolean executeShutdownHooks = ! \"false\".equals(servletContext.getInitParameter(\"ClassLoaderLeakPreventor.executeShutdownHooks\"));\n\n    /* \n     * Should the {@code oracle.jdbc.driver.OracleTimeoutPollingThread} thread be forced to start with system classloader,\n     * in case Oracle JDBC driver is present? This is normally a good idea, but can be disabled in case the Oracle JDBC\n     * driver is not used even though it is on the classpath.\n     */\n    boolean startOracleTimeoutThread = ! \"false\".equals(servletContext.getInitParameter(\"ClassLoaderLeakPreventor.startOracleTimeoutThread\"));\n    \n    // No of milliseconds to wait for threads to finish execution, before stopping them.\n    int threadWaitMs = getIntInitParameter(servletContext, \"ClassLoaderLeakPreventor.threadWaitMs\", ClassLoaderLeakPreventor.THREAD_WAIT_MS_DEFAULT);\n\n    /* \n     * No of milliseconds to wait for shutdown hooks to finish execution, before stopping them.\n     * If set to -1 there will be no waiting at all, but Thread is allowed to run until finished.\n     */\n    int shutdownHookWaitMs = getIntInitParameter(servletContext, \"ClassLoaderLeakPreventor.shutdownHookWaitMs\", SHUTDOWN_HOOK_WAIT_MS_DEFAULT);\n\n    final ClassLoader webAppClassLoader = Thread.currentThread().getContextClassLoader();\n    info(\"Settings for \" + this.getClass().getName() + \" (CL: 0x\" +\n         Integer.toHexString(System.identityHashCode(webAppClassLoader)) + \"):\");\n    info(\"  stopThreads = \" + stopThreads);\n    info(\"  stopTimerThreads = \" + stopTimerThreads);\n    info(\"  executeShutdownHooks = \" + executeShutdownHooks);\n    info(\"  threadWaitMs = \" + threadWaitMs + \" ms\");\n    info(\"  shutdownHookWaitMs = \" + shutdownHookWaitMs + \" ms\");\n    \n    // Create factory with default PreClassLoaderInitiators and ClassLoaderPreMortemCleanUps\n    final ClassLoaderLeakPreventorFactory classLoaderLeakPreventorFactory = createClassLoaderLeakPreventorFactory();\n    \n    // Configure default PreClassLoaderInitiators \n    if(! startOracleTimeoutThread)\n      classLoaderLeakPreventorFactory.removePreInitiator(OracleJdbcThreadInitiator.class);\n\n    // Configure default ClassLoaderPreMortemCleanUps \n    final ShutdownHookCleanUp shutdownHookCleanUp = classLoaderLeakPreventorFactory.getCleanUp(ShutdownHookCleanUp.class);\n    shutdownHookCleanUp.setExecuteShutdownHooks(executeShutdownHooks);\n    shutdownHookCleanUp.setShutdownHookWaitMs(shutdownHookWaitMs);\n    \n    final StopThreadsCleanUp stopThreadsCleanUp = classLoaderLeakPreventorFactory.getCleanUp(StopThreadsCleanUp.class);\n    stopThreadsCleanUp.setStopThreads(stopThreads);\n    stopThreadsCleanUp.setStopTimerThreads(stopTimerThreads);\n    stopThreadsCleanUp.setThreadWaitMs(threadWaitMs);\n\n\n    classLoaderLeakPreventor = classLoaderLeakPreventorFactory.newLeakPreventor(webAppClassLoader);\n\n    classLoaderLeakPreventor.runPreClassLoaderInitiators();\n  }\n\n  @Override\n  public void contextDestroyed(ServletContextEvent servletContextEvent) {\n\n    info(getClass().getName() + \" shutting down context by removing known leaks (CL: 0x\" +\n         Integer.toHexString(System.identityHashCode(classLoaderLeakPreventor.getClassLoader())) + \")\");\n\n    for(ServletContextListener listener : otherListeners) {\n      try {\n        listener.contextDestroyed(servletContextEvent);\n      }\n      catch(Exception e) {\n        classLoaderLeakPreventor.error(e);\n      }\n    }\n\n    classLoaderLeakPreventor.runCleanUps();\n  }\n\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  // Utility methods\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n  /** Create {@link ClassLoaderLeakPreventorFactory} to use. Subclasses may opt to override this method. */\n  protected ClassLoaderLeakPreventorFactory createClassLoaderLeakPreventorFactory() {\n    return new ClassLoaderLeakPreventorFactory();\n  }\n\n  /** Parse init parameter for integer value, returning default if not found or invalid */\n  protected static int getIntInitParameter(ServletContext servletContext, String parameterName, int defaultValue) {\n    final String parameterString = servletContext.getInitParameter(parameterName);\n    if(parameterString != null && parameterString.trim().length() > 0) {\n      try {\n        return Integer.parseInt(parameterString);\n      }\n      catch (NumberFormatException e) {\n        // Do nothing, return default value\n      }\n    }\n    return defaultValue;\n  }\n\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  // Log methods\n  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  \n  /*\n   * Since logging frameworks are part of the problem, we don't want to depend on any of them here.\n   * Feel free however to subclass or fork and use a log framework, in case you think you know what you're doing.\n   */\n  \n  protected String getLogPrefix() {\n    return ClassLoaderLeakPreventorListener.class.getSimpleName() + \": \";\n  }\n\n  /**\n   * To \"turn off\" info logging override this method in a subclass and make that subclass method empty.\n   */\n  protected void info(String s) {\n    System.out.println(getLogPrefix() + s);\n  }\n\n}\n"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet3/pom.xml",
    "content": "<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\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n    <artifactId>classloader-leak-prevention-parent</artifactId>\n    <version>2.7.1-SNAPSHOT</version>\n  </parent>\n  <artifactId>classloader-leak-prevention-servlet3</artifactId>\n  <packaging>jar</packaging>\n  <name>ClassLoader Leak Prevention library for servlet environments</name>\n  <description>ServletContextListener that prevents ClassLoader leaks / java.lang.OutOfMemoryError: PermGen space</description>\n  <url>https://github.com/mjiderhamn/classloader-leak-prevention</url>\n  \n  <dependencies>\n    <dependency>\n      <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n      <artifactId>classloader-leak-prevention-servlet</artifactId>\n      <version>${project.parent.version}</version>\n      <!-- Exclude Servlet 2.5 API -->\n      <exclusions>\n        <exclusion>\n          <groupId>javax.servlet</groupId>\n          <artifactId>servlet-api</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>javax.servlet</groupId>\n      <artifactId>javax.servlet-api</artifactId>\n      <version>3.0.1</version>\n      <scope>provided</scope>\n    </dependency>\n  </dependencies>\n\n</project>"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet3/src/main/java/se/jiderhamn/classloader/leak/prevention/ClassLoaderLeakPreventionContainerInitializer.java",
    "content": "package se.jiderhamn.classloader.leak.prevention;\n\nimport java.util.Set;\nimport javax.servlet.*;\n\n/**\n * Servlet 3.0 {@link ServletContainerInitializer} that will run the {@link PreClassLoaderInitiator}s (delegated to \n * {@link ClassLoaderLeakPreventorListener} and register a {@link ServletContextListener} that will run \n * {@link ClassLoaderPreMortemCleanUp}s on {@link ServletContextListener#contextDestroyed(ServletContextEvent)} (delegated\n * to the same {@link ClassLoaderLeakPreventorListener}).\n * @author Mattias Jiderhamn\n */\npublic class ClassLoaderLeakPreventionContainerInitializer implements javax.servlet.ServletContainerInitializer {\n  // TODO Order cannot be guaranteed https://java.net/jira/browse/SERVLET_SPEC-79\n  \n  @Override\n  public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {\n    final ClassLoaderLeakPreventorListener classLoaderLeakPreventorListener = new ClassLoaderLeakPreventorListener();\n    try {\n      classLoaderLeakPreventorListener.contextInitialized(servletContext); // Initialize immediately\n\n      servletContext.addListener(new ServletContextListener() {\n        @Override\n        public void contextInitialized(ServletContextEvent servletContextEvent) {\n          // Do nothing, already done above\n        }\n\n        @Override\n        public void contextDestroyed(ServletContextEvent servletContextEvent) {\n          classLoaderLeakPreventorListener.contextDestroyed(servletContextEvent);\n        }\n      });\n    }\n    catch (Throwable t) { // (Shouldn't really be needed)\n      t.printStackTrace(System.err);\n    }\n\n    for(ServletContextListener otherListener : ClassLoaderLeakPreventorListener.getDefaultOtherListeners()) {\n      servletContext.addListener(otherListener);\n    }\n  }\n}"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet3/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer",
    "content": "se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventionContainerInitializer"
  },
  {
    "path": "classloader-leak-prevention/classloader-leak-prevention-servlet3/src/main/resources/META-INF/web-fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-fragment xmlns=\"http://java.sun.com/xml/ns/javaee\"\n              xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n              xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd\"\n              version=\"3.0\">\n\n  <name>classloader_leak_prevention</name>\n  <distributable/>\n\n  <!--\n    Configure this fragment to be ordered before others, so that the listener is \"outermost\"\n    https://blogs.oracle.com/swchan/entry/servlet_3_0_web_fragment\n    \n    This may have no effect on javax.servlet.ServletContainerInitializer in Servlet 3.0/3.1 containers https://java.net/jira/browse/SERVLET_SPEC-79\n  -->\n  <ordering>\n    <before>\n      <others />\n    </before>\n  </ordering>\n\n</web-fragment> "
  },
  {
    "path": "classloader-leak-prevention/pom.xml",
    "content": "<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\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n  <artifactId>classloader-leak-prevention-parent</artifactId>\n  <version>2.7.1-SNAPSHOT</version>\n  <packaging>pom</packaging>\n  <name>ClassLoader Leak Prevention library parent</name>\n  <description>Library that prevents ClassLoader leaks / java.lang.OutOfMemoryError: PermGen space</description>\n  <url>https://github.com/mjiderhamn/classloader-leak-prevention</url>\n  \n  <scm>\n    <connection>scm:git:https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/mjiderhamn/classloader-leak-prevention.git</connection>\n    <developerConnection>scm:git:https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/mjiderhamn/classloader-leak-prevention.git</developerConnection>\n    <url>https://github.com/mjiderhamn/classloader-leak-prevention.git</url>\n    <tag>HEAD</tag>\n  </scm>\n\n  <!-- Configure Release: http://central.sonatype.org/pages/apache-maven.html -->\n  <distributionManagement>\n    <snapshotRepository>\n      <id>sonatype-nexus-snapshots</id>\n      <url>https://oss.sonatype.org/content/repositories/snapshots</url>\n    </snapshotRepository>\n    <repository>\n      <id>sonatype-nexus-staging</id>\n      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n    </repository>\n  </distributionManagement>\n\n  <licenses>\n    <license>\n      <name>Apache 2</name>\n      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n      <distribution>manual</distribution>\n    </license>\n  </licenses>\n  \n  <modules>\n    <module>classloader-leak-prevention-core</module>\n    <module>classloader-leak-prevention-servlet</module>\n    <module>classloader-leak-prevention-servlet3</module>\n  </modules>\n\n  <developers>\n    <developer>\n      <id>mjiderhamn</id>\n      <name>Mattias Jiderhamn</name>\n    </developer>\n  </developers>   \n\n  <properties>\n    <!-- Disable strict JavaDoc checking, as per http://blog.joda.org/2014/02/turning-off-doclint-in-jdk-8-javadoc.html -->\n    <additionalparam>-Xdoclint:none</additionalparam>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n  </properties>\n\n  <repositories>\n    <!-- GeoTools -->\n    <repository>\n      <id>osgeo</id>\n      <name>Open Source Geospatial Foundation Repository</name>\n      <url>https://repo.osgeo.org/repository/release/</url>\n    </repository>\n  </repositories>\n\n  <dependencies>\n    <!-- Dependencies for creating tests -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.13.2</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.hamcrest</groupId>\n      <artifactId>hamcrest-library</artifactId>\n      <version>1.3</version>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <pluginManagement>\n      <plugins>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-release-plugin</artifactId>\n          <version>2.5.3</version>\n          <configuration>\n            <mavenExecutorId>forked-path</mavenExecutorId>\n            <useReleaseProfile>false</useReleaseProfile>\n            <arguments>-Prelease</arguments>\n            <autoVersionSubmodules>true</autoVersionSubmodules>\n            <!-- Avoid cloning from remote repo when releasing -->\n            <localCheckout>true</localCheckout>\n          </configuration>\n        </plugin>\n      </plugins>\n    </pluginManagement>\n\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <version>3.6.1</version>\n        <configuration>\n          <source>1.6</source>\n          <target>1.6</target>\n          <fork>true</fork>\n          <!-- Allow compiling against com.sun.xml.internal classes -->\n          <testCompilerArgument>-XDignore.symbol.file</testCompilerArgument>\n        </configuration>\n      </plugin>\n      <!-- Since the tests may register (leaking) references in system classes, we need a new JVM for each test -->\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-surefire-plugin</artifactId>\n        <version>2.19.1</version>\n        <configuration>\n          <forkCount>2</forkCount>\n          <reuseForks>false</reuseForks>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>release</id>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-source-plugin</artifactId>\n            <version>3.0.1</version>\n            <executions>\n              <execution>\n                <id>attach-sources</id>\n                <goals>\n                  <goal>jar-no-fork</goal>\n                </goals>\n              </execution>\n            </executions>\n          </plugin>\n\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-javadoc-plugin</artifactId>\n            <version>2.10.4</version>\n            <executions>\n              <execution>\n                <id>attach-javadocs</id>\n                <goals>\n                  <goal>jar</goal>\n                </goals>\n              </execution>\n            </executions>\n          </plugin>\n\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-gpg-plugin</artifactId>\n            <version>1.6</version>\n            <executions>\n              <execution>\n                <id>sign-artifacts</id>\n                <phase>verify</phase>\n                <goals>\n                  <goal>sign</goal>\n                </goals>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "classloader-leak-test-framework/README.md",
    "content": "# Classloader Leak test framework\n\nStand-alone test framework for detecting and/or verifying the existence or non-existence of Java ClassLoader leaks.\nIt is also possible to test leak prevention mechanisms to confirm that the leak really is avoided.\n\nThe [ClassLoader Leak Prevention library](../README.md) is supposed to be used to avoid the leaks causing problems during runtime.\nThe ClassLoader Leak Prevention library uses this test framework to confirm the effectiveness of it's leak countermeasures. \n\nThe framework is an built upon [JUnit](http://junit.org/) and supplies a `se.jiderhamn.classloader.leak.JUnitClassloaderRunner`,\nwhich is used to run each test in a separate classloader, that is then attempted to be garbage collected. The default \nassumption is that the test case will cause a classloader leak. A basic example would look like this\n\n```java\npackage se.jiderhamn.tests;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderhamn.classloader.leak.JUnitClassloaderRunner;\n\n@RunWith(JUnitClassloaderRunner.class)\npublic class LeakConfirmingTest {\n  \n  @Test\n  public void triggerLeak() {\n    // Do something that triggers the suspected leak\n  }\n}\n```\n\nIn case the test passes, it means the code inside the tested method does in fact cause classloader leaks.\n\nIn order to confirm that a piece of code does *not* cause leaks, add the `se.jiderhamn.classloader.leak.Leaks` annotation,\nwith a value of `false`.\n```java\n  @Test\n  @Leaks(false) // Should not leak\n  public void doesNotTriggerLeak() {\n    // Do something that should not trigger any leaks\n  }\n```\nIn this case, the test passes only in case a leak isn't triggered.\n\nIf you want to execute some code outside the per-test classloader, you can do that in an \n[`@Before`](http://junit.sourceforge.net/javadoc/org/junit/Before.html) annotated method.\n\n## Heap dump\nIn case you want a heap dump automatically generated when a leak is detected, you can use `@Leaks(dumpHeapOnError = true)` \nand then watch stdout for the name of the heap dump file.\n\nIn the heap dump, you can look for instances of `se.jiderhamn.classloader.ZombieMarker` and track their path to GC root.\n\n## Verifying prevention measures\n\nYou can also confirm that a leak workaround has the expected effect, by annotating the class with \n`se.jiderhamn.classloader.leak.LeakPreventor`, and set its value to a `Runnable` that fixes the leak.\n```java\n@RunWith(JUnitClassloaderRunner.class)\n@LeakPreventor(LeakThatCanBeFixedTest.Preventor.class)\npublic class LeakThatCanBeFixedTest {\n  \n  @Test\n  public void triggerLeak() {\n    // Do something that triggers the suspected leak\n  }\n  \n  public static class Preventor implements Runnable {\n    public void run() {\n      // Run cleanup code, that fixed the leak and allows the classloader to be GC:ed\n    }\n  }\n}\n```\nIn this case, a successful test means two things:\n1. the `@Test` method does cause a leak\n2. the leak is prevented by the code in the `Preventor`\nThat is, the test will fail if either there is no leak to begin with, or the leak is still present after executing the `Preventor`.\n\nNOTE: It is not yet determined whether multiple test cases in the same class works, so you should stick to one single `@Test` method per class for now.\n\n## Debugging\n\nIf you want the test framework to log (to stdout) when a class is being loaded, set the `ClassLoaderLeakTestFramework.debug`\nsystem property to `true` (i.e. `-DClassLoaderLeakTestFramework.debug=true`).\n\n## Maven\nThe test framework of the library is available in Maven Central with the following details:\n\n```xml\n<dependency>\n  <groupId>se.jiderhamn</groupId>\n  <artifactId>classloader-leak-test-framework</artifactId>\n  <version>1.1.2</version>\n</dependency>\n```\n\n## License\n\nThis 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.\n"
  },
  {
    "path": "classloader-leak-test-framework/pom.xml",
    "content": "<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 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>se.jiderhamn</groupId>\n  <artifactId>classloader-leak-test-framework</artifactId>\n  <version>1.1.3-SNAPSHOT</version>\n  <packaging>jar</packaging>\n  <name>ClassLoader leak test framework</name>\n  <description>Test framework to confirm suspected classloader leak, and create heap dumps to track the leaks</description>\n  <url>https://github.com/mjiderhamn/classloader-leak-prevention</url>\n  \n  <scm>\n    <connection>scm:git:https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/mjiderhamn/classloader-leak-prevention.git</connection>\n    <developerConnection>scm:git:https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/mjiderhamn/classloader-leak-prevention.git</developerConnection>\n    <url>https://github.com/mjiderhamn/classloader-leak-prevention.git</url>\n    <tag>HEAD</tag>\n  </scm>\n\n  <!-- Configure Release: http://central.sonatype.org/pages/apache-maven.html -->\n  <distributionManagement>\n    <snapshotRepository>\n      <id>sonatype-nexus-snapshots</id>\n      <url>https://oss.sonatype.org/content/repositories/snapshots</url>\n    </snapshotRepository>\n    <repository>\n      <id>sonatype-nexus-staging</id>\n      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n    </repository>\n  </distributionManagement>\n\n  <licenses>\n    <license>\n      <name>Apache 2</name>\n      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n      <distribution>manual</distribution>\n    </license>\n  </licenses>\n\n  <developers>\n    <developer>\n      <id>mjiderhamn</id>\n      <name>Mattias Jiderhamn</name>\n    </developer>\n  </developers>   \n\n  <properties>\n    <maven.compiler.source>1.6</maven.compiler.source>\n    <maven.compiler.target>1.6</maven.compiler.target>\n    <!-- Disable strict JavaDoc checking, as per http://blog.joda.org/2014/02/turning-off-doclint-in-jdk-8-javadoc.html -->\n    <additionalparam>-Xdoclint:none</additionalparam>\n  </properties>\n\n  <dependencies>\n    <!-- Dependencies for creating tests -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.13.2</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.bcel</groupId>\n      <artifactId>bcel</artifactId>\n      <version>6.6.0</version>\n    </dependency>\n    <!-- Test leak in EL implementation cache -->\n    <dependency>\n      <groupId>javax.el</groupId>\n      <artifactId>el-api</artifactId>\n      <version>2.2.1-b04</version>\n      <scope>test</scope>\n    </dependency> \n    <!-- Test leak in JSF api -->\n    <dependency>\n      <groupId>com.sun.faces</groupId>\n      <artifactId>jsf-api</artifactId>\n      <version>2.1.19</version>\n      <scope>test</scope>\n    </dependency>\n    <!--&lt;!&ndash; Could be removed if Mockito was used to mock ELContext &ndash;&gt;-->\n    <dependency>\n      <groupId>com.sun.faces</groupId>\n      <artifactId>jsf-impl</artifactId>\n      <version>2.1.19</version>\n      <scope>test</scope>\n    </dependency>\n    \n  </dependencies>\n\n  <build>\n    <pluginManagement>\n      <plugins>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-release-plugin</artifactId>\n          <version>2.5.3</version>\n          <configuration>\n            <mavenExecutorId>forked-path</mavenExecutorId>\n            <useReleaseProfile>false</useReleaseProfile>\n            <arguments>-Prelease</arguments>\n          </configuration>\n        </plugin>\n      </plugins>\n    </pluginManagement>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>release</id>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-source-plugin</artifactId>\n            <version>3.0.1</version>\n            <executions>\n              <execution>\n                <id>attach-sources</id>\n                <goals>\n                  <goal>jar-no-fork</goal>\n                </goals>\n              </execution>\n            </executions>\n          </plugin>\n\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-javadoc-plugin</artifactId>\n            <version>2.10.4</version>\n            <executions>\n              <execution>\n                <id>attach-javadocs</id>\n                <goals>\n                  <goal>jar</goal>\n                </goals>\n              </execution>\n            </executions>\n          </plugin>\n\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-gpg-plugin</artifactId>\n            <version>1.6</version>\n            <executions>\n              <execution>\n                <id>sign-artifacts</id>\n                <phase>verify</phase>\n                <goals>\n                  <goal>sign</goal>\n                </goals>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n</project>"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/HeapDumper.java",
    "content": "package se.jiderhamn;\n\nimport java.io.File;\nimport java.lang.management.ManagementFactory;\nimport javax.management.MBeanServer;\n\nimport com.sun.management.HotSpotDiagnosticMXBean;\n\n/**\n * Class that helps programatically dumping the heap.\n * Heavily inspired by https://blogs.oracle.com/sundararajan/entry/programmatically_dumping_heap_from_java\n * @author Mattias Jiderhamn\n */\npublic class HeapDumper {\n\n  /** The name of the HotSpot Diagnostic MBean */\n  private static final String HOTSPOT_BEAN_NAME = \"com.sun.management:type=HotSpotDiagnostic\";\n  \n  /** Filename extension for heap dumps */\n  public static final String HEAP_DUMP_EXTENSION = \".hprof\";\n\n  /** HotSpot diagnostic MBean */\n  private static volatile HotSpotDiagnosticMXBean hotSpotDiagnosticMBean;\n\n  /**\n   * Dump the heap snapshot into a file.\n   * @param file The file in which the dump will be stored\n   * @param live Dump only live objects?\n   */\n  public static void dumpHeap(File file, boolean live) throws ClassNotFoundException {\n    if(file.exists()) {\n      System.err.println(\"Cannot dump heap to '\" + file + \"' - file exists!\");\n      return;\n    }\n\n    try {\n      getHotSpotDiagnosticMBean().dumpHeap(file.getAbsolutePath(), live);\n    } catch (RuntimeException e) {\n      throw e;\n    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  /** Get HotSpot diagnostic MBean */\n  private static HotSpotDiagnosticMXBean getHotSpotDiagnosticMBean() {\n    if (hotSpotDiagnosticMBean == null) {\n      // synchronized (HeapDumper.class) {\n      //  if (hotspotMBean == null) {\n          try {\n            MBeanServer server = ManagementFactory.getPlatformMBeanServer();\n            hotSpotDiagnosticMBean = ManagementFactory.newPlatformMXBeanProxy(server,\n                    HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean.class);\n          } catch (RuntimeException e) {\n            throw e;\n          } catch (Exception e) {\n            throw new RuntimeException(e);\n          }\n      //   }\n      // }\n    }\n    \n    return hotSpotDiagnosticMBean;\n  }\n\n}"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/PackagesLoadedOutsideClassLoader.java",
    "content": "package se.jiderhamn.classloader;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/** \n * Annotation that defines what packages packages to be ignored by {@link RedefiningClassLoader}, so that they will \n * be loaded by the parent/system {@link ClassLoader}\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface PackagesLoadedOutsideClassLoader {\n  \n  /** Packages to be ignored by {@link RedefiningClassLoader}, on the form \"foo.bar.\" (note the ending dot!) */\n  String[] packages();\n  \n  /** \n   * Should the packages in {@link #packages()} be added to {@link RedefiningClassLoader#DEFAULT_IGNORED_PACKAGES}?\n   * {@code false} means {@link #packages()} will instead replace, and {@link RedefiningClassLoader#DEFAULT_IGNORED_PACKAGES}\n   * will be redefined by {@link RedefiningClassLoader} unless specified by {@link #packages()}.\n   */\n  boolean addToDefaults() default false;\n}\n"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/RedefiningClassLoader.java",
    "content": "package se.jiderhamn.classloader;\n\nimport org.apache.bcel.classfile.ClassFormatException;\nimport org.apache.bcel.classfile.JavaClass;\n\n/** Classloader that redefines classes even if existing in parent */\npublic class RedefiningClassLoader extends org.apache.bcel.util.ClassLoader {\n\n  private static final String DEBUG_SYSTEM_PROPERTY = \"ClassLoaderLeakTestFramework.debug\";\n\n  /** Override parents default and include  */\n  public static final String[] DEFAULT_IGNORED_PACKAGES = {\n          \"java.\", \"javax.\", \"jdk.\", \"com.sun.\", \"sun.\", \"org.w3c\", \"org.junit.\", \"junit.\",\n          \"com.apple.eawt.\", \"com.apple.eio.\", \"com.apple.laf.\" // Apple OpenJDK\n  };\n\n  /** Set to non-null to indicate it should be ready for garbage collection */\n  @SuppressWarnings({\"unused\", \"FieldCanBeLocal\"})\n  private ZombieMarker zombieMarker = null;\n  \n  private final String name;\n\n  private final boolean logRedefinitions;\n\n  public RedefiningClassLoader(ClassLoader parent) {\n    this(parent, null);\n  }\n\n  public RedefiningClassLoader() {\n    this((String) null);\n  }\n\n  public RedefiningClassLoader(ClassLoader parent, String name) {\n    this(parent, name, DEFAULT_IGNORED_PACKAGES);\n  }\n\n  RedefiningClassLoader(String name) {\n    this(name, DEFAULT_IGNORED_PACKAGES);\n  }\n\n  public RedefiningClassLoader(ClassLoader parent, String name, String[] ignoredPackages) {\n    super(parent, ignoredPackages);\n    this.name = name;\n    this.logRedefinitions = isDebugLoggingEnabled();\n  }\n\n  RedefiningClassLoader(String name, String[] ignoredPackages) {\n    super(ignoredPackages);\n    this.name = name;\n    this.logRedefinitions = isDebugLoggingEnabled();\n  }\n\n  public static boolean isDebugLoggingEnabled() {\n    return \"true\".equals(System.getProperty(DEBUG_SYSTEM_PROPERTY));\n  }\n\n  @Override\n  protected JavaClass modifyClass(JavaClass clazz) {\n    if (logRedefinitions) {\n      System.out.println(\"Loading \" + clazz.getClassName() + \" in \" + this);\n    }\n    return super.modifyClass(clazz);\n  }\n  \n  /** Mark this class loader as being ready for garbage collection */\n  public void markAsZombie() {\n    this.zombieMarker = new ZombieMarker();\n  }\n\n  @Override\n  public String toString() {\n    return (name != null) ? (this.getClass().getName() + '[' + name + \"]@\" + Integer.toHexString(System.identityHashCode(this))) :  \n        super.toString();\n  }\n\n  @Override\n  protected Class<?> loadClass(String class_name, boolean resolve) throws ClassNotFoundException {\n    try {\n      int i = class_name.lastIndexOf('.');\n      if (i != -1) {\n        String pkgName = class_name.substring(0, i);\n        if (getPackage(pkgName) == null) {\n          super.definePackage(pkgName, null, null, null, null,\n                  null, null, null);\n        }\n      }\n      return super.loadClass(class_name, resolve);\n    }\n    catch (ClassFormatException e) {\n      throw new RuntimeException(\"Unable to load class \" + class_name, e);\n    }\n  }\n  \n}"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/ZombieMarker.java",
    "content": "package se.jiderhamn.classloader;\n\n/**\n * Class used to help identify leaked class loaders in a heap dump.\n * Inspired by Caucho's Resin\n * @author Mattias Jiderhamn\n */\npublic class ZombieMarker {\n}"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/leak/JUnitClassloaderRunner.java",
    "content": "package se.jiderhamn.classloader.leak;\n\nimport java.io.File;\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Method;\nimport java.net.URL;\n\nimport org.junit.Assert;\nimport org.junit.internal.runners.statements.InvokeMethod;\nimport org.junit.runners.BlockJUnit4ClassRunner;\nimport org.junit.runners.model.FrameworkMethod;\nimport org.junit.runners.model.InitializationError;\nimport org.junit.runners.model.Statement;\nimport org.junit.runners.model.TestClass;\nimport se.jiderhamn.HeapDumper;\nimport se.jiderhamn.classloader.PackagesLoadedOutsideClassLoader;\nimport se.jiderhamn.classloader.RedefiningClassLoader;\nimport se.jiderhamn.classloader.ZombieMarker;\n\nimport static org.junit.Assert.fail;\nimport static se.jiderhamn.HeapDumper.HEAP_DUMP_EXTENSION;\n\n/**\n * @author Mattias Jiderhamn\n */\npublic class JUnitClassloaderRunner extends BlockJUnit4ClassRunner {\n\n  /** Number of seconds to halt to allow for heap dump aquirement, if that option is enabled */\n  private static final int HALT_TIME_S = 10;\n\n  public JUnitClassloaderRunner(Class<?> klass) throws InitializationError {\n    super(klass);\n    // TODO: Replace testclass here to support @Before, @After - alt throw exception if used\n  }\n\n  @Override\n  protected Statement methodInvoker(FrameworkMethod method, Object test) {\n    final LeakPreventor leakPreventorAnn = method.getMethod().getDeclaringClass().getAnnotation(LeakPreventor.class);\n    Class<? extends Runnable> preventorClass = (leakPreventorAnn != null) ? leakPreventorAnn.value() : null;\n\n    return new SeparateClassLoaderInvokeMethod(method, test, preventorClass, \n        test.getClass().getAnnotation(PackagesLoadedOutsideClassLoader.class));\n  }\n  \n  private class SeparateClassLoaderInvokeMethod extends InvokeMethod {\n    \n    /** The method to run for triggering potential leak, or verify non-leak */\n    private final Method originalMethod;\n\n    /** Is the test method expeced to leak? */\n    private final boolean expectedLeak;\n    \n    /** \n     * Should the thread pause for a couple of seconds before throwing the test failed error?\n     * Set this to true to allow some time to aquire a heap dump to track down leaks.\n     */\n    private final boolean haltBeforeError;\n    \n    /** Automatically generate a heap dump of classloader could not be garbage collected? */\n    private final boolean dumpHeapOnError;\n    \n    /** Class that can be used to remove the leak */\n    private Class<? extends Runnable> preventorClass;\n    \n    /** Packages to be ignored by {@link RedefiningClassLoader}. If null, will use defaults. */\n    private final String[] ignoredPackages;\n    \n    private SeparateClassLoaderInvokeMethod(FrameworkMethod testMethod, Object target) {\n      this(testMethod, target, null, null);\n    }\n    \n    private SeparateClassLoaderInvokeMethod(FrameworkMethod testMethod, Object target, \n                                            Class<? extends Runnable> preventorClass,\n                                            PackagesLoadedOutsideClassLoader packagesLoadedOutsideClassLoader) {\n      super(testMethod, target);\n      originalMethod = testMethod.getMethod();\n\n      final Leaks leakAnn = testMethod.getAnnotation(Leaks.class);\n      this.expectedLeak = (leakAnn == null || leakAnn.value()); // Default to true\n      this.haltBeforeError = (leakAnn != null && leakAnn.haltBeforeError()); // Default to false\n      this.dumpHeapOnError = (leakAnn != null && leakAnn.dumpHeapOnError()); // Default to false\n\n      this.preventorClass = preventorClass;\n      this.ignoredPackages = (packagesLoadedOutsideClassLoader == null) ? null :\n          packagesLoadedOutsideClassLoader.addToDefaults() ? \n              appendArrays(RedefiningClassLoader.DEFAULT_IGNORED_PACKAGES, packagesLoadedOutsideClassLoader.packages()) :\n          packagesLoadedOutsideClassLoader.packages();\n    }\n\n    @SuppressWarnings(\"UnusedAssignment\")\n    @Override\n    public void evaluate() throws Throwable {\n      final ClassLoader clBefore = Thread.currentThread().getContextClassLoader();\n\n      final String testName =  getTestClass().getName() + '.' + originalMethod.getName();\n      RedefiningClassLoader myClassLoader = (ignoredPackages != null) ? \n          new RedefiningClassLoader(clBefore, testName, ignoredPackages): \n          new RedefiningClassLoader(clBefore, testName);\n      \n      try {\n        Thread.currentThread().setContextClassLoader(myClassLoader);\n\n        // Load test class in our RedefiningClassLoader\n        TestClass myTestClass = new TestClass(myClassLoader.loadClass(getTestClass().getName()));\n\n        // Get test method in our RedefiningClassLoader (NOTE! can be in base class to test class)\n        Method myMethod = myClassLoader.loadClass(originalMethod.getDeclaringClass().getName())\n            .getDeclaredMethod(originalMethod.getName(), originalMethod.getParameterTypes());\n\n        if (RedefiningClassLoader.isDebugLoggingEnabled()) {\n          System.out.println(\"JUnit used \" + getTestClass().getJavaClass().getClassLoader());\n          System.out.println(\"SeparateClassLoaderInvokeMethod used \" + myTestClass.getJavaClass().getClassLoader());\n        }\n\n        // super.evaluate(); =\n        new FrameworkMethod(myMethod).invokeExplosively(myTestClass.getOnlyConstructor().newInstance());\n        \n        // Make available to Garbage Collector\n        myTestClass = null;\n        myMethod = null;\n      }\n      catch (Throwable e) {\n        e.printStackTrace(System.err); // Print here in case other exception is thrown in finally block\n        // Loose the original throwable as it or its backtrace may itself cause a leak\n        throw new RuntimeException(e.getClass().getName() + \": \" + e.getMessage());\n      }\n      finally {\n        Thread.currentThread().setContextClassLoader(clBefore);\n        \n        // TODO: It's possible that an exception, loaded by the redefining classloader, has been thrown...\n\n        final WeakReference<RedefiningClassLoader> weak = new WeakReference<RedefiningClassLoader>(myClassLoader);\n        myClassLoader.markAsZombie();\n        myClassLoader = null; // Make available to garbage collector\n        \n        forceGc(3);\n\n        if(expectedLeak) { // We expect this test to leak classloaders\n          RedefiningClassLoader redefiningClassLoader = weak.get();\n          Assert.assertNotNull(\"ClassLoader has been garbage collected, while test is expected to leak\", redefiningClassLoader);\n\n          if(redefiningClassLoader != null && // Always true, otherwise assertion failure above\n             preventorClass != null) {\n            try {\n              Thread.currentThread().setContextClassLoader(redefiningClassLoader);\n              Class<? extends Runnable> preventorInLeakedLoader = (Class<Runnable>) redefiningClassLoader.loadClass(preventorClass.getName());\n              Runnable leakPreventor = preventorInLeakedLoader.newInstance();\n              final String leakPreventorName = leakPreventor.toString();\n\n              leakPreventor.run(); // Try to prevent leak\n              \n              // Make available for Garbage Collection\n              leakPreventor = null;\n              preventorInLeakedLoader = null;\n              redefiningClassLoader = null;\n              Thread.currentThread().setContextClassLoader(clBefore);\n              \n              forceGc(3);\n\n              final boolean leak = (weak.get() != null); // Still not garbage collected\n              if(leak) {\n                final String message = \"ClassLoader (\" + weak.get() + \") has not been garbage collected, \" +\n                    \"despite running the leak preventor \" + leakPreventorName;\n                weak.clear(); // Avoid including this reference in the heap dump\n                performErrorActions(testName);\n\n                fail(message);\n              }\n            }\n            catch (Exception e) {\n              throw new RuntimeException(\"Leak prevention class \" + preventorClass.getName() + \" could not be used!\", e);\n            }\n            finally {\n              redefiningClassLoader = null;\n              Thread.currentThread().setContextClassLoader(clBefore); // Make sure it is reset, even if there is an error\n            }\n\n          }\n          else { // Leak was expected, but we had no prevention mechanism\n            final boolean leak = (weak.get() != null); // Still not garbage collected\n            if(leak) {\n              redefiningClassLoader = null; // Avoid including this reference in the heap dump \n              weak.clear(); // Avoid including this reference in the heap dump\n              performErrorActions(testName);\n            }\n          }\n\n        }\n        else { // We did not expect a leak\n          final boolean leak = (weak.get() != null); // Still not garbage collected\n          if(leak) {\n            final String message = \"ClassLoader has not been garbage collected \" + weak.get();\n            weak.clear(); // Avoid including this reference in the heap dump\n            performErrorActions(testName);\n            fail(message);\n          }\n        }\n      }\n    }\n\n    /** Call only if there is a leak */\n    private void performErrorActions(String testName) throws InterruptedException {\n      if(dumpHeapOnError) {\n        dumpHeap(testName);\n      }\n\n      if(haltBeforeError) {\n        waitForHeapDump();\n      }\n    }\n  }\n\n  /** Make sure Garbage Collection has been run N no of times */\n  public static void forceGc(int n) {\n    for(int i = 0; i < n; i++) {\n      forceGc();\n    }\n  }\n  \n  /** Make sure Garbage Collection has been run */\n  public static void forceGc() {\n    WeakReference<Object> ref = new WeakReference<Object>(new Object());\n    while(ref.get() != null) { // Until garbage collection has actually been run\n      System.gc();\n    }\n  }\n\n  private static void waitForHeapDump() throws InterruptedException {\n    System.out.println(\"Waiting \" + HALT_TIME_S + \" seconds to allow for heap dump acquirement\");\n    System.out.println(\"Tip: You can search for \" + ZombieMarker.class.getName() + \" in the dump\");\n    Thread.sleep(HALT_TIME_S * 1000);\n  }\n\n  /** Create heap dump in file with same name as the test */\n  private void dumpHeap(String testName) {\n    final File surefireReports = getSurefireReportsDirectory();\n    try {\n      File heapDump = (surefireReports != null) ? new File(surefireReports, testName + HEAP_DUMP_EXTENSION) : \n          new File(testName + HEAP_DUMP_EXTENSION);\n      HeapDumper.dumpHeap(heapDump, false);\n      System.out.println(\"Heaped dumped to \" + heapDump.getAbsolutePath());\n    }\n    catch (ClassNotFoundException e) {\n      System.out.println(\"Unable to dump heap - not Sun/Oracle JVM?\");\n    }\n  }\n\n  /** \n   * Try to find \"target/surefire-reports\" directory, assuming this is a Maven build. Returns null it not found,\n   * not writable or other error. */\n  private File getSurefireReportsDirectory() {\n    return getSurefireReportsDirectory(getTestClass().getJavaClass());\n  }\n  \n  /** \n   * Try to find \"target/surefire-reports\" directory, assuming this is a Maven build. Returns null it not found,\n   * not writable or other error. */\n  private static File getSurefireReportsDirectory(final Class<?> clazz) {\n    try {\n      final String absolutePath = clazz.getResource(clazz.getSimpleName() + \".class\").toString();\n      final String relativePath = clazz.getName().replace('.', '/') + \".class\";\n      final String classPath = absolutePath.substring(0, absolutePath.length() - relativePath.length());\n      \n     // Handle JAR files\n    if(classPath.startsWith(\"jar:\")) {\n      return null;\n    }\n      final File dir = new File(new URL(classPath).toURI());\n      final File sureFireReports = new File(dir.getParent(), \"surefire-reports\");\n      if(! sureFireReports.exists() && \"test-classes\".equals(dir.getName()) && \"target\".equals(dir.getParentFile().getName())) {\n        // Seems likely this is a Maven build, but surefire-reports have not been created yet (probably first test case)\n        try {\n          //noinspection ResultOfMethodCallIgnored\n          sureFireReports.mkdirs();\n        }\n        catch (Exception ignored) {\n          // Do nothing\n        }\n      }\n      \n      return sureFireReports.exists() && sureFireReports.isDirectory() && sureFireReports.canWrite() ? sureFireReports :\n          null;\n    }\n    catch (Exception e) {\n      return null;\n    }\n  }\n  \n  /** Append two arrays */\n  private <T> T[] appendArrays(T[] arr1, T[] arr2) {\n    T[] output = (T[]) Array.newInstance(arr1.getClass().getComponentType(), arr1.length + arr2.length);\n    System.arraycopy(arr1, 0, output, 0, arr1.length);\n    System.arraycopy(arr2, 0, output, arr1.length, arr2.length);\n    return output;\n  }\n\n}"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/leak/LeakPreventor.java",
    "content": "package se.jiderhamn.classloader.leak;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/** Configure the Runnable that can be used to prevent the leak */\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface LeakPreventor {\n  Class<? extends Runnable> value();\n}\n"
  },
  {
    "path": "classloader-leak-test-framework/src/main/java/se/jiderhamn/classloader/leak/Leaks.java",
    "content": "package se.jiderhamn.classloader.leak;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/** Annotation to indicate whether test case is expected to leak classloaders or not */\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Leaks {\n  /** Is this test expected to leak classloaders? */\n  boolean value() default true;\n  \n  /** \n   * Should the thread pause for a couple of seconds before throwing the test failed error?\n   * Set this to true to allow some time to aquire a heap dump to track down leaks.\n   */\n  boolean haltBeforeError() default false;\n  \n  /** \n   * Set this to true to automatically generate a heap dump of classloader could not be garbage collected. Only works\n   * on Sun/Oracle JVM. \n   */\n  boolean dumpHeapOnError() default false;\n  \n}\n"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/com/classloader/test/CustomClass.java",
    "content": "package com.classloader.test;\n\npublic class CustomClass {\n}\n"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/RedefiningClassLoaderTest.java",
    "content": "package se.jiderhamn.classloader;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderhamn.classloader.leak.JUnitClassloaderRunner;\nimport se.jiderhamn.classloader.leak.Leaks;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\n\n@RunWith(JUnitClassloaderRunner.class)\npublic class RedefiningClassLoaderTest {\n\n    @Test\n    @Leaks(false)\n    public void getPackage() {\n        Package aPackage = com.classloader.test.CustomClass.class.getPackage();\n        assertNotNull(\"Class should have non-null package\", aPackage);\n        assertEquals(\"com.classloader.test\", aPackage.getName());\n    }\n}\n"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/JUnitClassloaderRunnerTest.java",
    "content": "package se.jiderhamn.classloader.leak;\n\nimport java.io.FileNotFoundException;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\n/**\n * This test makes sure that the {@link JUnitClassloaderRunner} does not keep a reference to the classloader in case\n * an exception is thrown\n * @author Mattias Jiderhamn\n */\n@RunWith(JUnitClassloaderRunner.class)\npublic class JUnitClassloaderRunnerTest {\n  \n  @Test(expected = RuntimeException.class) // FileNotFoundException replaced by RuntimeException\n  @Leaks(false)\n  public void throwException() throws Exception {\n    throw new FileNotFoundException(\"foo.txt\");\n  }\n\n  @Test(expected = RuntimeException.class) // CustomError replaced by RuntimeException\n  @Leaks(false)\n  public void throwAssertionError() {\n    throw new CustomError();\n  }\n\n  public static class CustomError extends Error {\n\n  }\n}"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/NonLeakingTest.java",
    "content": "package se.jiderhamn.classloader.leak;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\n/**\n * Test that isn't supposed to leak, used to test the utility classes.\n * @author Mattias Jiderhamn\n */\n@RunWith(JUnitClassloaderRunner.class)\npublic class NonLeakingTest {\n  \n  @Test\n  @Leaks(false) // Should not leak\n  public void nonLeakingMethod() {\n    System.out.println(\"Hello world!\");\n  }\n}"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/accused/CustomThreadLocalTest.java",
    "content": "package se.jiderhamn.classloader.leak.accused;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderhamn.classloader.leak.JUnitClassloaderRunner;\nimport se.jiderhamn.classloader.leak.Leaks;\n\n/**\n * @author Mattias Jiderhamn\n */\n@RunWith(JUnitClassloaderRunner.class)\npublic class CustomThreadLocalTest {\n  \n  private static final ThreadLocal<Integer> customThreadLocal = new ThreadLocal<Integer>() {\n    /** Override method to create an anonymous subclass loaded by our classloader */\n    @Override\n    protected Integer initialValue() {\n      return Integer.MAX_VALUE;\n    }\n  };\n  \n  /** \n   * Having a custom ThreadLocal with at non-custom value does not leak, since the key in the ThreadLocalMap is weak\n   */\n  @Test\n  @Leaks(false)\n  public void setValueOfCustomThreadLocal() {\n    customThreadLocal.set(1);\n  }\n}"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/accused/package-info.java",
    "content": "package se.jiderhamn.classloader.leak.accused;\n\n/* Test cases in this package are used to confirm that code accused of causing leaks, does in fact <strong>not</strong> cause leaks */"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/known/CustomThreadLocalCustomValueTest.java",
    "content": "package se.jiderhamn.classloader.leak.known;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderhamn.classloader.leak.JUnitClassloaderRunner;\n\n/**\n * @author Mattias Jiderhamn\n */\n@RunWith(JUnitClassloaderRunner.class)\npublic class CustomThreadLocalCustomValueTest {\n  \n  private static final ThreadLocal<Value> customThreadLocal = new ThreadLocal<Value>() {\n    /** Override method to create an anonymous subclass loaded by our classloader */\n    @Override\n    protected Value initialValue() {\n      return new Value();\n    }\n  };\n  \n  @Test\n  public void setCustomThreadLocalValue() {\n    customThreadLocal.set(new Value());\n  }\n\n  /** Custom value class, that will prevent garbage collection */\n  private static class Value {\n    \n  }\n  \n  // TODO: Preventor\n}"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/known/JEditorPaneTest.java",
    "content": "package se.jiderhamn.classloader.leak.known;\n\nimport javax.swing.*;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport se.jiderhamn.classloader.leak.JUnitClassloaderRunner;\n    \n/**\n * Confirm leak caused by JEditorPane\n * @author Mattias Jiderhamn\n */\n@RunWith(JUnitClassloaderRunner.class)\npublic class JEditorPaneTest {\n\n  @Test\n  public void triggerJEditorPaneLeak() throws Exception {\n    new JEditorPane(\"text/plain\", \"dummy\");\n  }\n  \n}"
  },
  {
    "path": "classloader-leak-test-framework/src/test/java/se/jiderhamn/classloader/leak/known/package-info.java",
    "content": "package se.jiderhamn.classloader.leak.known;\n\n/** Test cases in this package are used to confirm the existence of known leaks */"
  },
  {
    "path": "mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Apache Maven Wrapper startup batch script, version 3.1.1\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /usr/local/etc/mavenrc ] ; then\n    . /usr/local/etc/mavenrc\n  fi\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        JAVA_HOME=\"`/usr/libexec/java_home`\"; export JAVA_HOME\n      else\n        JAVA_HOME=\"/Library/Java/Home\"; export JAVA_HOME\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`\\\\unset -f command; \\\\command -v java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  printf '%s' \"$(cd \"$basedir\"; pwd)\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=$(find_maven_basedir \"$(dirname $0)\")\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\nMAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}; export MAVEN_PROJECTBASEDIR\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nif [ -r \"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\" ]; then\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Found .mvn/wrapper/maven-wrapper.jar\"\n    fi\nelse\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ...\"\n    fi\n    if [ -n \"$MVNW_REPOURL\" ]; then\n      wrapperUrl=\"$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar\"\n    else\n      wrapperUrl=\"https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar\"\n    fi\n    while IFS=\"=\" read key value; do\n      case \"$key\" in (wrapperUrl) wrapperUrl=\"$value\"; break ;;\n      esac\n    done < \"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties\"\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Downloading from: $wrapperUrl\"\n    fi\n    wrapperJarPath=\"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\"\n    if $cygwin; then\n      wrapperJarPath=`cygpath --path --windows \"$wrapperJarPath\"`\n    fi\n\n    if command -v wget > /dev/null; then\n        QUIET=\"--quiet\"\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found wget ... using wget\"\n          QUIET=\"\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            wget $QUIET \"$wrapperUrl\" -O \"$wrapperJarPath\"\n        else\n            wget $QUIET --http-user=\"$MVNW_USERNAME\" --http-password=\"$MVNW_PASSWORD\" \"$wrapperUrl\" -O \"$wrapperJarPath\"\n        fi\n        [ $? -eq 0 ] || rm -f \"$wrapperJarPath\"\n    elif command -v curl > /dev/null; then\n        QUIET=\"--silent\"\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found curl ... using curl\"\n          QUIET=\"\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            curl $QUIET -o \"$wrapperJarPath\" \"$wrapperUrl\" -f -L\n        else\n            curl $QUIET --user \"$MVNW_USERNAME:$MVNW_PASSWORD\" -o \"$wrapperJarPath\" \"$wrapperUrl\" -f -L\n        fi\n        [ $? -eq 0 ] || rm -f \"$wrapperJarPath\"\n    else\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Falling back to using Java to download\"\n        fi\n        javaSource=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        javaClass=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\"\n        # For Cygwin, switch paths to Windows format before running javac\n        if $cygwin; then\n          javaSource=`cygpath --path --windows \"$javaSource\"`\n          javaClass=`cygpath --path --windows \"$javaClass\"`\n        fi\n        if [ -e \"$javaSource\" ]; then\n            if [ ! -e \"$javaClass\" ]; then\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Compiling MavenWrapperDownloader.java ...\"\n                fi\n                # Compiling the Java class\n                (\"$JAVA_HOME/bin/javac\" \"$javaSource\")\n            fi\n            if [ -e \"$javaClass\" ]; then\n                # Running the downloader\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Running MavenWrapperDownloader.java ...\"\n                fi\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$MAVEN_PROJECTBASEDIR\")\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  $MAVEN_DEBUG_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    http://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Apache Maven Wrapper startup batch script, version 3.1.1\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM set title of command window\ntitle %0\n@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%USERPROFILE%\\mavenrc_pre.bat\" call \"%USERPROFILE%\\mavenrc_pre.bat\" %*\nif exist \"%USERPROFILE%\\mavenrc_pre.cmd\" call \"%USERPROFILE%\\mavenrc_pre.cmd\" %*\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nset WRAPPER_URL=\"https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar\"\n\nFOR /F \"usebackq tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\n    IF \"%%A\"==\"wrapperUrl\" SET WRAPPER_URL=%%B\n)\n\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\nif exist %WRAPPER_JAR% (\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Found %WRAPPER_JAR%\n    )\n) else (\n    if not \"%MVNW_REPOURL%\" == \"\" (\n        SET WRAPPER_URL=\"%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar\"\n    )\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Couldn't find %WRAPPER_JAR%, downloading it ...\n        echo Downloading from: %WRAPPER_URL%\n    )\n\n    powershell -Command \"&{\"^\n\t\t\"$webclient = new-object System.Net.WebClient;\"^\n\t\t\"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {\"^\n\t\t\"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');\"^\n\t\t\"}\"^\n\t\t\"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')\"^\n\t\t\"}\"\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Finished downloading %WRAPPER_JAR%\n    )\n)\n@REM End of extension\n\n@REM Provide a \"standardized\" way to retrieve the CLI args that will\n@REM work with both Windows and non-Windows executions.\nset MAVEN_CMD_LINE_ARGS=%*\n\n%MAVEN_JAVA_EXE% ^\n  %JVM_CONFIG_MAVEN_PROPS% ^\n  %MAVEN_OPTS% ^\n  %MAVEN_DEBUG_OPTS% ^\n  -classpath %WRAPPER_JAR% ^\n  \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" ^\n  %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\"==\"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%USERPROFILE%\\mavenrc_post.bat\" call \"%USERPROFILE%\\mavenrc_post.bat\"\nif exist \"%USERPROFILE%\\mavenrc_post.cmd\" call \"%USERPROFILE%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\"==\"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\"==\"on\" exit %ERROR_CODE%\n\ncmd /C exit /B %ERROR_CODE%\n"
  },
  {
    "path": "pom.xml",
    "content": "<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 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>se.jiderhamn.classloader-leak-prevention</groupId>\n  <artifactId>classloader-leak-prevention-launcher</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  <packaging>pom</packaging>\n\n  <name>ClassLoader Leak Prevention Launcher</name>\n  <description>Launcher POM for ClassLoader Leak Prevention</description>\n  <url>https://github.com/mjiderhamn/classloader-leak-prevention</url>\n\n  <modules>\n    <module>classloader-leak-prevention</module>\n    <module>classloader-leak-test-framework</module>\n  </modules>\n \n </project>"
  }
]