├── .github ├── FUNDING.yml └── workflows │ ├── [A] build and test, release if requested.yml │ ├── [A] compute coverage.yml │ ├── [A] update documentation.yml │ └── [M] build and test, compute coverage, release.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── _config.yml ├── _layouts │ └── default.html ├── assets │ ├── css │ │ └── style.scss │ └── fonts │ │ ├── AldoPro-Black.ttf │ │ ├── AldoPro-Black.woff │ │ ├── AldoPro-Black.woff2 │ │ ├── AldoPro-Bold.ttf │ │ ├── AldoPro-Bold.woff │ │ ├── AldoPro-Bold.woff2 │ │ ├── AldoPro-Book.ttf │ │ ├── AldoPro-Book.woff │ │ ├── AldoPro-Book.woff2 │ │ ├── AldoPro-Hairline.ttf │ │ ├── AldoPro-Hairline.woff │ │ ├── AldoPro-Hairline.woff2 │ │ ├── AldoPro-Light.ttf │ │ ├── AldoPro-Light.woff │ │ ├── AldoPro-Light.woff2 │ │ ├── AldoPro-Medium.ttf │ │ ├── AldoPro-Medium.woff │ │ ├── AldoPro-Medium.woff2 │ │ ├── AldoPro-Regular.ttf │ │ ├── AldoPro-Regular.woff │ │ ├── AldoPro-Regular.woff2 │ │ ├── AldoPro-Thin.ttf │ │ ├── AldoPro-Thin.woff │ │ └── AldoPro-Thin.woff2 └── index.md ├── launcher └── eclipse │ └── Burningwave Tools - AllExceptHeavyTestsSuite.launch ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── burningwave │ │ └── tools │ │ ├── dependencies │ │ ├── Capturer.java │ │ ├── Sniffer.java │ │ └── TwoPassCapturer.java │ │ └── net │ │ ├── DNSClientHostResolver.java │ │ ├── DefaultHostResolver.java │ │ ├── HostResolutionRequestInterceptor.java │ │ ├── HostResolver.java │ │ ├── IPAddressUtil.java │ │ └── MappedHostResolver.java └── resources │ └── burningwave.static.properties └── test ├── java └── org │ └── burningwave │ └── tools │ ├── AllExceptHeavyTestsSuite.java │ ├── BaseTest.java │ ├── CapturerTest.java │ ├── HostsResolverServiceTest.java │ └── TwoPassCapturerTest.java └── resources ├── burningwave.properties └── burningwave.static.properties /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://www.paypal.com/donate/?cmd=_donations&business=EY4TMTW8SWDAC&item_name=Support+maintenance+and+improvement+of+Burningwave+Tools¤cy_code=EUR&source=url 2 | -------------------------------------------------------------------------------- /.github/workflows/[A] build and test, release if requested.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test -> Compute coverage -> Release if requested 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - "src/main/**.java" 9 | - "src/test/**.java" 10 | # - ".github/workflows/**" 11 | - "**.properties" 12 | - "**.xml" 13 | 14 | jobs: 15 | 16 | build-and-test-with-Java-8-and-later: 17 | name: Build -> Test (JVM ${{ matrix.java }}, ${{ matrix.os }}) 18 | strategy: 19 | fail-fast: true 20 | max-parallel: 16 21 | matrix: 22 | os: [ubuntu-latest, windows-latest, macOS-latest] 23 | java: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] 24 | architecture: [x64] 25 | exclude: 26 | - os: macOS-latest 27 | java: 13 28 | - os: macOS-latest 29 | java: 14 30 | - os: ubuntu-latest 31 | java: 10 32 | runs-on: ${{ matrix.os }} 33 | steps: 34 | - uses: actions/checkout@v3 35 | - name: Set up JDK ${{ matrix.java }} 36 | uses: actions/setup-java@v3 37 | with: 38 | java-version: ${{ matrix.java }} 39 | distribution: 'zulu' 40 | architecture: ${{ matrix.architecture }} 41 | - name: Build and test 42 | run: mvn -B clean test -Dproject_jdk_version=${{ matrix.java }} -DskipTests=false --file pom.xml -X -U 43 | 44 | release: 45 | name: Release if requested 46 | needs: [build-and-test-with-Java-8-and-later] 47 | runs-on: ubuntu-latest 48 | if: github.event_name == 'push' && endsWith(github.event.head_commit.message, 'Releasing new version') 49 | steps: 50 | - uses: actions/checkout@v3 51 | - name: Set up JDK 24 52 | uses: actions/setup-java@v3 53 | with: 54 | java-version: 24 55 | distribution: 'zulu' 56 | server-id: ossrh 57 | server-username: MAVEN_USERNAME 58 | server-password: MAVEN_PASSWORD 59 | - name: Publish to the Maven Central repository 60 | run: | 61 | export GPG_TTY=$(tty) 62 | echo "${{ secrets.gpg_private_key }}" | gpg --batch --import 63 | git config user.name "${{ github.event.head_commit.committer.name }}" 64 | git config user.email "${{ github.event.head_commit.committer.email }}" 65 | mvn -B release:prepare release:perform -Dproject_jdk_version=8 -DskipTests=true -Dgpg.passphrase=${{ secrets.gpg_passphrase }} -Dgpg.keyname=${{ secrets.gpg_key_id }} -Drepository.url=https://${GITHUB_ACTOR}:${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}.git 66 | env: 67 | MAVEN_USERNAME: ${{ secrets.nexus_username }} 68 | MAVEN_PASSWORD: ${{ secrets.nexus_password }} 69 | -------------------------------------------------------------------------------- /.github/workflows/[A] compute coverage.yml: -------------------------------------------------------------------------------- 1 | name: Compute coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - "src/main/**" 9 | - "src/test/**" 10 | # - ".github/workflows/**" 11 | - "**.properties" 12 | - "**.xml" 13 | 14 | jobs: 15 | compute-coverage: 16 | name: Compute coverage 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - uses: actions/setup-java@v3 21 | with: 22 | java-version: 8 23 | distribution: 'zulu' 24 | architecture: x64 25 | - name: Build and test 26 | run: mvn clean test -DskipTests=false -Dproject_jdk_version=8 -P run-coveralls jacoco:report coveralls:report -DrepoToken=${{ secrets.coveralls_repo_token }} 27 | 28 | -------------------------------------------------------------------------------- /.github/workflows/[A] update documentation.yml: -------------------------------------------------------------------------------- 1 | name: Update index page 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - "**README.md" 9 | 10 | jobs: 11 | update-index-page: 12 | runs-on: ubuntu-latest 13 | name: Update index page 14 | steps: 15 | - uses: actions/checkout@master 16 | - name: Overwrite the index.md 17 | run: | 18 | git config user.name "${{ github.event.head_commit.committer.name }}" 19 | git config user.email "${{ github.event.head_commit.committer.email }}" 20 | git pull origin ${{github.ref}} 21 | cp "./README.md" "./docs/index.md" 22 | git add . 23 | git commit -am "Update" --allow-empty 24 | git push 25 | -------------------------------------------------------------------------------- /.github/workflows/[M] build and test, compute coverage, release.yml: -------------------------------------------------------------------------------- 1 | name: Build and test -> Compute coverage -> Release 2 | 3 | on: 4 | watch: 5 | types: [started] 6 | 7 | jobs: 8 | 9 | ask-for-authorization: 10 | name: Ask for authorization 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: octokit/request-action@v2.0.0 14 | with: 15 | route: GET /repos/:repository/collaborators/${{ github.actor }} 16 | repository: ${{ github.repository }} 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | - name: Send push notification 20 | if: ${{ failure() }} 21 | uses: techulus/push-github-action@1.0.0 22 | env: 23 | API_KEY: ${{ secrets.PUSH_NOTIFICATION_API_KEY }} 24 | MESSAGE: ${{ format('New star for {0}!', github.repository) }} 25 | 26 | build-and-test-with-Java-8-and-later: 27 | name: Build -> Test (JVM ${{ matrix.java }}, ${{ matrix.os }}) 28 | needs: [ask-for-authorization] 29 | strategy: 30 | fail-fast: true 31 | max-parallel: 15 32 | matrix: 33 | os: [windows-latest, macOS-latest, ubuntu-latest] 34 | java: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] 35 | architecture: [x64] 36 | exclude: 37 | - os: macOS-latest 38 | java: 13 39 | - os: macOS-latest 40 | java: 14 41 | - os: ubuntu-latest 42 | java: 10 43 | runs-on: ${{ matrix.os }} 44 | steps: 45 | - uses: actions/checkout@v3 46 | - name: Set up JDK ${{ matrix.java }} 47 | uses: actions/setup-java@v3 48 | with: 49 | java-version: ${{ matrix.java }} 50 | distribution: 'zulu' 51 | architecture: ${{ matrix.architecture }} 52 | - name: Build and test with 53 | run: mvn -B clean test -DskipTests=false --file pom.xml 54 | 55 | test-and-compute-coverage: 56 | name: Test -> Compute coverage 57 | needs: [build-and-test-with-Java-8-and-later] 58 | runs-on: ubuntu-latest 59 | steps: 60 | - uses: actions/checkout@v3 61 | - uses: actions/setup-java@v3 62 | with: 63 | java-version: 8 64 | distribution: 'zulu' 65 | architecture: x64 66 | - name: Build and test 67 | run: mvn clean test -DskipTests=false -Dproject.test.testSuite=AllTestsSuite -P run-coveralls jacoco:report coveralls:report -DrepoToken=${{ secrets.coveralls_repo_token }} 68 | 69 | release: 70 | name: Release 71 | needs: [build-and-test-with-Java-8-and-later] 72 | # This is an organization variable: see https://docs.github.com/en/actions/learn-github-actions/variables 73 | if: ${{ fromJSON(vars.MANUAL_RELEASE_ENABLED) }} 74 | runs-on: ubuntu-latest 75 | steps: 76 | - uses: actions/checkout@v3 77 | - name: Set up JDK 24 78 | uses: actions/setup-java@v3 79 | with: 80 | java-version: 24 81 | distribution: 'zulu' 82 | server-id: ossrh 83 | server-username: MAVEN_USERNAME 84 | server-password: MAVEN_PASSWORD 85 | - name: Publish to the Maven Central repository 86 | run: | 87 | export GPG_TTY=$(tty) 88 | echo "${{ secrets.gpg_private_key }}" | gpg --batch --import 89 | git config user.name "${GITHUB_ACTOR}" 90 | git config user.email "info@burningwave.org" 91 | mvn -B release:prepare release:perform -Dproject_jdk_version=8 -DskipTests=true -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} -Dgpg.keyname=${{ secrets.gpg_key_id }} -Drepository.url=https://${GITHUB_ACTOR}:${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}.git 92 | env: 93 | MAVEN_USERNAME: ${{ secrets.nexus_username }} 94 | MAVEN_PASSWORD: ${{ secrets.nexus_password }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Log file 2 | *.log 3 | 4 | # BlueJ files 5 | *.ctxt 6 | 7 | # Mobile Tools for Java (J2ME) 8 | .mtj.tmp/ 9 | 10 | # Package Files # 11 | *.jar 12 | *.war 13 | *.nar 14 | *.ear 15 | *.zip 16 | *.tar.gz 17 | *.rar 18 | 19 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 20 | hs_err_pid* 21 | 22 | /target/ 23 | /.project 24 | /.settings 25 | /.classpath 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Roberto Gentili 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Burningwave Tools [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Dependencies%20shrinking%20and%20making%20applications%20created%20with%20old%20%23Java%20versions&url=https://burningwave.github.io/tools/) 2 | ========== 3 | 4 | 5 | Burningwave-logo.png 6 | 7 | 8 | [![Maven Central with version prefix filter](https://img.shields.io/maven-central/v/org.burningwave/tools/0)](https://maven-badges.herokuapp.com/maven-central/org.burningwave/tools/) 9 | [![GitHub](https://img.shields.io/github/license/burningwave/tools)](https://github.com/burningwave/tools/blob/master/LICENSE) 10 | 11 | [![Platforms](https://img.shields.io/badge/platforms-Windows%2C%20Mac%20OS%2C%20Linux-orange)](https://github.com/burningwave/tools/actions/runs/14547159555) 12 | 13 | [![Supported JVM](https://img.shields.io/badge/supported%20JVM-8%2C%209+%20(24)-blueviolet)](https://github.com/burningwave/tools/actions/runs/14547159555) 14 | 15 | [![Coveralls github branch](https://img.shields.io/coveralls/github/burningwave/tools/master)](https://coveralls.io/github/burningwave/tools) 16 | [![GitHub open issues](https://img.shields.io/github/issues/burningwave/tools)](https://github.com/burningwave/tools/issues) 17 | [![GitHub closed issues](https://img.shields.io/github/issues-closed/burningwave/tools)](https://github.com/burningwave/tools/issues?q=is%3Aissue+is%3Aclosed) 18 | 19 | [![ArtifactDownload](https://www.burningwave.org/generators/generate-burningwave-artifact-downloads-badge.php?artifactId=tools)](https://www.burningwave.org/artifact-downloads/?show-overall-trend-chart=false&artifactId=tools&startDate=2020-01) 20 | [![Repository dependents](https://badgen.net/github/dependents-repo/burningwave/tools)](https://github.com/burningwave/tools/network/dependents) 21 | [![HitCount](https://www.burningwave.org/generators/generate-visited-pages-badge.php)](https://www.burningwave.org#bw-counters) 22 | 23 | **Burningwave Tools** is a set of components based on [**Burningwave Core**](https://burningwave.github.io/core/) library that have high-level functionality 24 | 25 | # Dependencies shrinking 26 | By this functionality only the classes and resources strictly used by an application will be extracted and stored in a specified path. At the end of the execution of the task, a script will be created in the destination path to run the application using the extracted classes. **The dependency shrinkers can also be used to adapt applications written with Java old versions to Java 9 or later**. 27 | 28 | The classes that deal the dependencies extraction are: 29 | * **`org.burningwave.tools.dependencies.Capturer`** 30 | * **`org.burningwave.tools.dependencies.TwoPassCapturer`** 31 | 32 | It can be used indiscriminately or one or the other class: the first performs a normal scan, the second a deep scan. **When the operations are finished a batch will be generated in the destination path to run your application with the extracted dependencies**. 33 | 34 | To include Burningwave Tools in your projects simply use with **Apache Maven**: 35 | ```xml 36 | 37 | org.burningwave 38 | tools 39 | 0.27.2 40 | 41 | ``` 42 |
43 | 44 | ## Extractor mode 45 | To use this mode simply pass to the method **`captureAndStore`**, as first parameter, the name of the class of your application that contains the main method. 46 | ```java 47 | package org.burningwave.tools.examples.twopasscapturer; 48 | 49 | import static 50 | org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggerRepository; 51 | 52 | import java.util.Collection; 53 | 54 | import org.burningwave.core.assembler.ComponentContainer; 55 | import org.burningwave.core.assembler.ComponentSupplier; 56 | import org.burningwave.core.io.PathHelper; 57 | import org.burningwave.tools.dependencies.Capturer.Result; 58 | import org.burningwave.tools.dependencies.TwoPassCapturer; 59 | 60 | public class DependenciesExtractor { 61 | 62 | public static void main(String[] args) throws Exception { 63 | long initialTime = System.currentTimeMillis(); 64 | ComponentSupplier componentSupplier = ComponentContainer.getInstance(); 65 | PathHelper pathHelper = componentSupplier.getPathHelper(); 66 | Collection paths = pathHelper.getAllMainClassPaths(); 67 | Result result = TwoPassCapturer.getInstance().captureAndStore( 68 | //Here you indicate the main class of your application 69 | "my.class.that.contains.a.MainMethod", 70 | paths, 71 | //Here you indicate the destination path where extracted 72 | //classes and resources will be stored 73 | System.getProperty("user.home") + "/Desktop/dependencies", 74 | true, 75 | //Here you indicate the waiting time after the main of your 76 | //application has been executed. This is useful, for example, 77 | //for spring boot applications to make it possible, once started, 78 | //to run rest methods to continue extracting the dependencies 79 | 0L 80 | ); 81 | result.waitForTaskEnding(); 82 | ManagedLoggerRepository.logInfo( 83 | () -> DependenciesExtractor.class.getName(), 84 | "Elapsed time: " + getFormattedDifferenceOfMillis( 85 | System.currentTimeMillis(), initialTime 86 | ) 87 | ); 88 | } 89 | 90 | private static String getFormattedDifferenceOfMillis(long value1, long value2) { 91 | String valueFormatted = String.format("%04d", (value1 - value2)); 92 | return valueFormatted.substring(0, valueFormatted.length() - 3) + "," + 93 | valueFormatted.substring(valueFormatted.length() -3); 94 | } 95 | 96 | } 97 | ``` 98 |
99 | 100 | ## Adapter mode 101 | In this mode you can adapt a Java old version application to Java 9 or later. To use this mode you must **run the main of the application adapter with a jdk 9 or later**, load, by using `PathHelper`, the jdk libraries by which the target application was developed and pass to the method **`captureAndStore`**, as first parameter, the name of the class of your application that contains the main method. In the example below we adapt a Java 8 application to Java 9 or later. 102 | ```java 103 | package org.burningwave.tools.examples.twopasscapturer; 104 | 105 | import static 106 | org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggerRepository; 107 | 108 | import java.util.Collection; 109 | 110 | import org.burningwave.core.assembler.ComponentContainer; 111 | import org.burningwave.core.assembler.ComponentSupplier; 112 | import org.burningwave.core.io.PathHelper; 113 | import org.burningwave.tools.dependencies.Capturer.Result; 114 | import org.burningwave.tools.dependencies.TwoPassCapturer; 115 | 116 | public class ApplicationAdapter { 117 | 118 | public static void main(String[] args) throws Exception { 119 | long initialTime = System.currentTimeMillis(); 120 | ComponentSupplier componentSupplier = ComponentContainer.getInstance(); 121 | PathHelper pathHelper = componentSupplier.getPathHelper(); 122 | Collection paths = pathHelper.getAllMainClassPaths(); 123 | String jdk8Home = "C:/Program Files/Java/jdk1.8.0_172"; 124 | //Add jdk 8 library 125 | paths.addAll( 126 | pathHelper.loadAndMapPaths( 127 | "dependencies-capturer.additional-resources-path", 128 | "//" + jdk8Home + "/jre/lib//children:.*\\.jar;" + 129 | "//" + jdk8Home + "/jre/lib/ext//children:.*\\.jar;" 130 | ) 131 | ); 132 | Result result = TwoPassCapturer.getInstance().captureAndStore( 133 | //Here you indicate the main class of your application 134 | "my.class.that.contains.a.MainMethod", 135 | paths, 136 | //Here you indicate the destination path where extracted 137 | //classes and resources will be stored 138 | System.getProperty("user.home") + "/Desktop/dependencies", 139 | true, 140 | //Here you indicate the waiting time after the main of your 141 | //application has been executed. This is useful, for example, 142 | //for spring boot applications to make it possible, once started, 143 | //to run rest methods to continue extracting the dependencies 144 | 0L 145 | ); 146 | result.waitForTaskEnding(); 147 | ManagedLoggerRepository.logInfo( 148 | () -> ApplicationAdapter.class.getName(), 149 | "Elapsed time: " + getFormattedDifferenceOfMillis( 150 | System.currentTimeMillis(), 151 | initialTime 152 | ) 153 | ); 154 | } 155 | 156 | private static String getFormattedDifferenceOfMillis(long value1, long value2) { 157 | String valueFormatted = String.format("%04d", (value1 - value2)); 158 | return valueFormatted.substring(0, valueFormatted.length() - 3) + "," + 159 | valueFormatted.substring(valueFormatted.length() -3); 160 | } 161 | 162 | } 163 | ``` 164 | 165 |
166 | 167 | # Configuring host resolution 168 | 169 | With the **`org.burningwave.tools.net.HostResolutionRequestInterceptor`** you can modify the local machine's default host name resolution in a universal way: 170 | 171 | ```java 172 | Map hostAliases = new LinkedHashMap<>(); 173 | hostAliases.put("my.hostname.one", "123.123.123.123"); 174 | 175 | //Installing the host resolvers 176 | HostResolutionRequestInterceptor.INSTANCE.install( 177 | new MappedHostResolver(hostAliases), 178 | //This is the system default resolving wrapper 179 | DefaultHostResolver.INSTANCE 180 | ); 181 | 182 | InetAddress inetAddress = InetAddress.getByName("my.hostname.one"); 183 | ``` 184 |
185 | 186 | ## Host resolution via DNS server 187 | 188 | Burningwave Tools provides also a DNS client for host resolution: 189 | 190 | ```java 191 | HostResolutionRequestInterceptor.INSTANCE.install( 192 | new DNSClientHostResolver("208.67.222.222"), //Open DNS server 193 | new DNSClientHostResolver("208.67.222.220"), //Open DNS server 194 | new DNSClientHostResolver("8.8.8.8"), //Google DNS server 195 | new DNSClientHostResolver("8.8.4.4"), //Google DNS server 196 | DefaultHostResolver.INSTANCE 197 | ); 198 | InetAddress inetAddress = InetAddress.getByName("github.com"); 199 | ``` 200 |
201 | 202 | ## Implement a custom host resolver 203 | 204 | You can also define a new custom resolver by implementing the **`org.burningwave.tools.net.HostResolver`** interface: 205 | ```java 206 | HostResolutionRequestInterceptor.INSTANCE.install( 207 | new HostResolver() { 208 | 209 | @Override 210 | public Collection getAllAddressesForHostName(Map argumentMap) { 211 | String hostName = (String)super.getMethodArguments(argumentMap)[0] 212 | //Do the stuff... 213 | } 214 | 215 | @Override 216 | public Collection getAllHostNamesForHostAddress(Map argumentMap) { 217 | byte[] iPAddressAsByteArray = (byte[])super.getMethodArguments(argumentMap)[0]; 218 | String iPAddress = IPAddressUtil.INSTANCE.numericToTextFormat(iPAddressAsByteArray); 219 | //Do the stuff... 220 | } 221 | 222 | }, 223 | DefaultHostResolver.INSTANCE 224 | ); 225 | ``` 226 | 227 |
228 | 229 | # Ask for assistance 230 | **For assistance you can**: 231 | * [open a discussion](https://github.com/burningwave/tools/discussions) here on GitHub 232 | * [report a bug](https://github.com/burningwave/tools/issues) 233 | * ask on [Stack Overflow](https://stackoverflow.com/search?q=burningwave) 234 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | title: Burningwave Tools 3 | google_analytics: UA-154852845-4 4 | show_downloads: false 5 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% if site.google_analytics %} 6 | 7 | 13 | {% endif %} 14 | 15 | 16 | {% seo %} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 37 | 38 |
39 | {{ content }} 40 | 41 | 50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /docs/assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | .page-header { 6 | background-image: linear-gradient(120deg, #e54d1d, #f7bc12); 7 | } 8 | 9 | h1.project-name { 10 | font-family: 'Aldo Pro Book'; 11 | font-size: 4.25rem; 12 | font-style: italic; 13 | line-height: 1.00em; 14 | } 15 | 16 | .main-content { 17 | h1 { 18 | color: #e54d1d; 19 | } 20 | h2 { 21 | color: #e54d1d; 22 | } 23 | h3 { 24 | color: #e54d1d; 25 | } 26 | } 27 | 28 | @font-face { 29 | font-family: 'Aldo Pro Hairline'; 30 | src: local('Aldo Pro Hairline'), local('Aldo-Pro-Hairline'), 31 | url('./../fonts/AldoPro-Hairline.woff2') format('woff2'), 32 | url('./../fonts/AldoPro-Hairline.woff') format('woff'), 33 | url('./../fonts/AldoPro-Hairline.ttf') format('truetype'); 34 | font-weight: 100; 35 | font-style: normal; 36 | } 37 | 38 | @font-face { 39 | font-family: 'Aldo Pro Light'; 40 | src: local('Aldo Pro Light'), local('Aldo-Pro-Light'), 41 | url('./../fonts/AldoPro-Light.woff2') format('woff2'), 42 | url('./../fonts/AldoPro-Light.woff') format('woff'), 43 | url('./../fonts/AldoPro-Light.ttf') format('truetype'); 44 | font-weight: 300; 45 | font-style: normal; 46 | } 47 | 48 | @font-face { 49 | font-family: 'Aldo Pro Book'; 50 | src: local('Aldo Pro Book'), local('Aldo-Pro-Book'), 51 | url('./../fonts/AldoPro-Book.woff2') format('woff2'), 52 | url('./../fonts/AldoPro-Book.woff') format('woff'), 53 | url('./../fonts/AldoPro-Book.ttf') format('truetype'); 54 | font-weight: normal; 55 | font-style: normal; 56 | } 57 | 58 | @font-face { 59 | font-family: 'Aldo Pro Regular'; 60 | src: local('Aldo Pro Regular'), local('Aldo-Pro-Regular'), 61 | url('./../fonts/AldoPro-Regular.woff2') format('woff2'), 62 | url('./../fonts/AldoPro-Regular.woff') format('woff'), 63 | url('./../fonts/AldoPro-Regular.ttf') format('truetype'); 64 | font-weight: 400; 65 | font-style: normal; 66 | } 67 | 68 | @font-face { 69 | font-family: 'Aldo Pro Medium'; 70 | src: local('Aldo Pro Medium'), local('Aldo-Pro-Medium'), 71 | url('./../fonts/AldoPro-Medium.woff2') format('woff2'), 72 | url('./../fonts/AldoPro-Medium.woff') format('woff'), 73 | url('./../fonts/AldoPro-Medium.ttf') format('truetype'); 74 | font-weight: 500; 75 | font-style: normal; 76 | } 77 | 78 | @font-face { 79 | font-family: 'Aldo Pro Bold'; 80 | src: local('Aldo Pro Bold'), local('Aldo-Pro-Bold'), 81 | url('./../fonts/AldoPro-Bold.woff2') format('woff2'), 82 | url('./../fonts/AldoPro-Bold.woff') format('woff'), 83 | url('./../fonts/AldoPro-Bold.ttf') format('truetype'); 84 | font-weight: 700; 85 | font-style: normal; 86 | } 87 | 88 | @font-face { 89 | font-family: 'Aldo Pro Black'; 90 | src: local('Aldo Pro Black'), local('Aldo-Pro-Black'), 91 | url('./../fonts/AldoPro-Black.woff2') format('woff2'), 92 | url('./../fonts/AldoPro-Black.woff') format('woff'), 93 | url('./../fonts/AldoPro-Black.ttf') format('truetype'); 94 | font-weight: 900; 95 | font-style: normal; 96 | } 97 | -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Black.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Black.woff -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Black.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Black.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Bold.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Bold.woff -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Bold.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Book.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Book.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Book.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Book.woff -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Book.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Book.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Hairline.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Hairline.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Hairline.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Hairline.woff -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Hairline.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Hairline.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Light.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Light.woff -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Light.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Medium.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Medium.woff -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Medium.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Regular.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Regular.woff -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Regular.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Thin.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Thin.woff -------------------------------------------------------------------------------- /docs/assets/fonts/AldoPro-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burningwave/tools/ef831cc5337c41ef99dda4a219932cd243b0807f/docs/assets/fonts/AldoPro-Thin.woff2 -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | Burningwave Tools [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Dependencies%20shrinking%20and%20making%20applications%20created%20with%20old%20%23Java%20versions&url=https://burningwave.github.io/tools/) 2 | ========== 3 | 4 | 5 | Burningwave-logo.png 6 | 7 | 8 | [![Maven Central with version prefix filter](https://img.shields.io/maven-central/v/org.burningwave/tools/0)](https://maven-badges.herokuapp.com/maven-central/org.burningwave/tools/) 9 | [![GitHub](https://img.shields.io/github/license/burningwave/tools)](https://github.com/burningwave/tools/blob/master/LICENSE) 10 | 11 | [![Platforms](https://img.shields.io/badge/platforms-Windows%2C%20Mac%20OS%2C%20Linux-orange)](https://github.com/burningwave/tools/actions/runs/14547159555) 12 | 13 | [![Supported JVM](https://img.shields.io/badge/supported%20JVM-8%2C%209+%20(24)-blueviolet)](https://github.com/burningwave/tools/actions/runs/14547159555) 14 | 15 | [![Coveralls github branch](https://img.shields.io/coveralls/github/burningwave/tools/master)](https://coveralls.io/github/burningwave/tools) 16 | [![GitHub open issues](https://img.shields.io/github/issues/burningwave/tools)](https://github.com/burningwave/tools/issues) 17 | [![GitHub closed issues](https://img.shields.io/github/issues-closed/burningwave/tools)](https://github.com/burningwave/tools/issues?q=is%3Aissue+is%3Aclosed) 18 | 19 | [![ArtifactDownload](https://www.burningwave.org/generators/generate-burningwave-artifact-downloads-badge.php?artifactId=tools)](https://www.burningwave.org/artifact-downloads/?show-overall-trend-chart=false&artifactId=tools&startDate=2020-01) 20 | [![Repository dependents](https://badgen.net/github/dependents-repo/burningwave/tools)](https://github.com/burningwave/tools/network/dependents) 21 | [![HitCount](https://www.burningwave.org/generators/generate-visited-pages-badge.php)](https://www.burningwave.org#bw-counters) 22 | 23 | **Burningwave Tools** is a set of components based on [**Burningwave Core**](https://burningwave.github.io/core/) library that have high-level functionality 24 | 25 | # Dependencies shrinking 26 | By this functionality only the classes and resources strictly used by an application will be extracted and stored in a specified path. At the end of the execution of the task, a script will be created in the destination path to run the application using the extracted classes. **The dependency shrinkers can also be used to adapt applications written with Java old versions to Java 9 or later**. 27 | 28 | The classes that deal the dependencies extraction are: 29 | * **`org.burningwave.tools.dependencies.Capturer`** 30 | * **`org.burningwave.tools.dependencies.TwoPassCapturer`** 31 | 32 | It can be used indiscriminately or one or the other class: the first performs a normal scan, the second a deep scan. **When the operations are finished a batch will be generated in the destination path to run your application with the extracted dependencies**. 33 | 34 | To include Burningwave Tools in your projects simply use with **Apache Maven**: 35 | ```xml 36 | 37 | org.burningwave 38 | tools 39 | 0.27.2 40 | 41 | ``` 42 |
43 | 44 | ## Extractor mode 45 | To use this mode simply pass to the method **`captureAndStore`**, as first parameter, the name of the class of your application that contains the main method. 46 | ```java 47 | package org.burningwave.tools.examples.twopasscapturer; 48 | 49 | import static 50 | org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggerRepository; 51 | 52 | import java.util.Collection; 53 | 54 | import org.burningwave.core.assembler.ComponentContainer; 55 | import org.burningwave.core.assembler.ComponentSupplier; 56 | import org.burningwave.core.io.PathHelper; 57 | import org.burningwave.tools.dependencies.Capturer.Result; 58 | import org.burningwave.tools.dependencies.TwoPassCapturer; 59 | 60 | public class DependenciesExtractor { 61 | 62 | public static void main(String[] args) throws Exception { 63 | long initialTime = System.currentTimeMillis(); 64 | ComponentSupplier componentSupplier = ComponentContainer.getInstance(); 65 | PathHelper pathHelper = componentSupplier.getPathHelper(); 66 | Collection paths = pathHelper.getAllMainClassPaths(); 67 | Result result = TwoPassCapturer.getInstance().captureAndStore( 68 | //Here you indicate the main class of your application 69 | "my.class.that.contains.a.MainMethod", 70 | paths, 71 | //Here you indicate the destination path where extracted 72 | //classes and resources will be stored 73 | System.getProperty("user.home") + "/Desktop/dependencies", 74 | true, 75 | //Here you indicate the waiting time after the main of your 76 | //application has been executed. This is useful, for example, 77 | //for spring boot applications to make it possible, once started, 78 | //to run rest methods to continue extracting the dependencies 79 | 0L 80 | ); 81 | result.waitForTaskEnding(); 82 | ManagedLoggerRepository.logInfo( 83 | () -> DependenciesExtractor.class.getName(), 84 | "Elapsed time: " + getFormattedDifferenceOfMillis( 85 | System.currentTimeMillis(), initialTime 86 | ) 87 | ); 88 | } 89 | 90 | private static String getFormattedDifferenceOfMillis(long value1, long value2) { 91 | String valueFormatted = String.format("%04d", (value1 - value2)); 92 | return valueFormatted.substring(0, valueFormatted.length() - 3) + "," + 93 | valueFormatted.substring(valueFormatted.length() -3); 94 | } 95 | 96 | } 97 | ``` 98 |
99 | 100 | ## Adapter mode 101 | In this mode you can adapt a Java old version application to Java 9 or later. To use this mode you must **run the main of the application adapter with a jdk 9 or later**, load, by using `PathHelper`, the jdk libraries by which the target application was developed and pass to the method **`captureAndStore`**, as first parameter, the name of the class of your application that contains the main method. In the example below we adapt a Java 8 application to Java 9 or later. 102 | ```java 103 | package org.burningwave.tools.examples.twopasscapturer; 104 | 105 | import static 106 | org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggerRepository; 107 | 108 | import java.util.Collection; 109 | 110 | import org.burningwave.core.assembler.ComponentContainer; 111 | import org.burningwave.core.assembler.ComponentSupplier; 112 | import org.burningwave.core.io.PathHelper; 113 | import org.burningwave.tools.dependencies.Capturer.Result; 114 | import org.burningwave.tools.dependencies.TwoPassCapturer; 115 | 116 | public class ApplicationAdapter { 117 | 118 | public static void main(String[] args) throws Exception { 119 | long initialTime = System.currentTimeMillis(); 120 | ComponentSupplier componentSupplier = ComponentContainer.getInstance(); 121 | PathHelper pathHelper = componentSupplier.getPathHelper(); 122 | Collection paths = pathHelper.getAllMainClassPaths(); 123 | String jdk8Home = "C:/Program Files/Java/jdk1.8.0_172"; 124 | //Add jdk 8 library 125 | paths.addAll( 126 | pathHelper.loadAndMapPaths( 127 | "dependencies-capturer.additional-resources-path", 128 | "//" + jdk8Home + "/jre/lib//children:.*\\.jar;" + 129 | "//" + jdk8Home + "/jre/lib/ext//children:.*\\.jar;" 130 | ) 131 | ); 132 | Result result = TwoPassCapturer.getInstance().captureAndStore( 133 | //Here you indicate the main class of your application 134 | "my.class.that.contains.a.MainMethod", 135 | paths, 136 | //Here you indicate the destination path where extracted 137 | //classes and resources will be stored 138 | System.getProperty("user.home") + "/Desktop/dependencies", 139 | true, 140 | //Here you indicate the waiting time after the main of your 141 | //application has been executed. This is useful, for example, 142 | //for spring boot applications to make it possible, once started, 143 | //to run rest methods to continue extracting the dependencies 144 | 0L 145 | ); 146 | result.waitForTaskEnding(); 147 | ManagedLoggerRepository.logInfo( 148 | () -> ApplicationAdapter.class.getName(), 149 | "Elapsed time: " + getFormattedDifferenceOfMillis( 150 | System.currentTimeMillis(), 151 | initialTime 152 | ) 153 | ); 154 | } 155 | 156 | private static String getFormattedDifferenceOfMillis(long value1, long value2) { 157 | String valueFormatted = String.format("%04d", (value1 - value2)); 158 | return valueFormatted.substring(0, valueFormatted.length() - 3) + "," + 159 | valueFormatted.substring(valueFormatted.length() -3); 160 | } 161 | 162 | } 163 | ``` 164 | 165 |
166 | 167 | # Configuring host resolution 168 | 169 | With the **`org.burningwave.tools.net.HostResolutionRequestInterceptor`** you can modify the local machine's default host name resolution in a universal way: 170 | 171 | ```java 172 | Map hostAliases = new LinkedHashMap<>(); 173 | hostAliases.put("my.hostname.one", "123.123.123.123"); 174 | 175 | //Installing the host resolvers 176 | HostResolutionRequestInterceptor.INSTANCE.install( 177 | new MappedHostResolver(hostAliases), 178 | //This is the system default resolving wrapper 179 | DefaultHostResolver.INSTANCE 180 | ); 181 | 182 | InetAddress inetAddress = InetAddress.getByName("my.hostname.one"); 183 | ``` 184 |
185 | 186 | ## Host resolution via DNS server 187 | 188 | Burningwave Tools provides also a DNS client for host resolution: 189 | 190 | ```java 191 | HostResolutionRequestInterceptor.INSTANCE.install( 192 | new DNSClientHostResolver("208.67.222.222"), //Open DNS server 193 | new DNSClientHostResolver("208.67.222.220"), //Open DNS server 194 | new DNSClientHostResolver("8.8.8.8"), //Google DNS server 195 | new DNSClientHostResolver("8.8.4.4"), //Google DNS server 196 | DefaultHostResolver.INSTANCE 197 | ); 198 | InetAddress inetAddress = InetAddress.getByName("github.com"); 199 | ``` 200 |
201 | 202 | ## Implement a custom host resolver 203 | 204 | You can also define a new custom resolver by implementing the **`org.burningwave.tools.net.HostResolver`** interface: 205 | ```java 206 | HostResolutionRequestInterceptor.INSTANCE.install( 207 | new HostResolver() { 208 | 209 | @Override 210 | public Collection getAllAddressesForHostName(Map argumentMap) { 211 | String hostName = (String)super.getMethodArguments(argumentMap)[0] 212 | //Do the stuff... 213 | } 214 | 215 | @Override 216 | public Collection getAllHostNamesForHostAddress(Map argumentMap) { 217 | byte[] iPAddressAsByteArray = (byte[])super.getMethodArguments(argumentMap)[0]; 218 | String iPAddress = IPAddressUtil.INSTANCE.numericToTextFormat(iPAddressAsByteArray); 219 | //Do the stuff... 220 | } 221 | 222 | }, 223 | DefaultHostResolver.INSTANCE 224 | ); 225 | ``` 226 | 227 |
228 | 229 | # Ask for assistance 230 | **For assistance you can**: 231 | * [open a discussion](https://github.com/burningwave/tools/discussions) here on GitHub 232 | * [report a bug](https://github.com/burningwave/tools/issues) 233 | * ask on [Stack Overflow](https://stackoverflow.com/search?q=burningwave) 234 | -------------------------------------------------------------------------------- /launcher/eclipse/Burningwave Tools - AllExceptHeavyTestsSuite.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 29 | 30 | 4.0.0 31 | 32 | org.burningwave 33 | tools 34 | 35 | 0.27.3-SNAPSHOT 36 | jar 37 | 38 | Burningwave Tools 39 | 40 | A set of components based on Burningwave Core library that have high-level functionality such as a dependencies extractor and a Java old versions to Java 9 or later application converter 41 | 42 | https://burningwave.github.io/tools/ 43 | 44 | 45 | 46 | MIT License 47 | https://github.com/burningwave/tools/blob/master/LICENSE 48 | repo 49 | 50 | 51 | 52 | 53 | Burningwave 54 | https://www.burningwave.org/ 55 | 56 | 57 | 58 | 59 | Roberto Gentili 60 | roberto.gentili 61 | info@burningwave.org 62 | Burningwave 63 | https://www.burningwave.org/ 64 | 65 | Administrator 66 | Developer 67 | 68 | 69 | 70 | Alessio Perrotta 71 | info@burningwave.org 72 | Burningwave 73 | https://www.burningwave.org/ 74 | 75 | External relationship manager 76 | Developer 77 | 78 | 79 | 80 | 81 | 82 | Roberto Gentili 83 | UTF-8 84 | 8 85 | bin/javadoc 86 | true 87 | **/AllExceptHeavyTestsSuite.java 88 | **/*Test.java 89 | bw 90 | https://burningwave@github.com/burningwave/tools.git 91 | 92 | 12.66.2 93 | 4.3.0 94 | 0.7.6.201602180812 95 | 5.10.0 96 | 1.10.0 97 | 3.8.1 98 | 2.8.2 99 | 1.6 100 | 3.2.0 101 | 3.2.0 102 | 2.5 103 | 2.5.3 104 | 3.0.1 105 | 1.9.5 106 | 2.21.0 107 | 1.6.12 108 | 109 | 110 | 111 | github.com 112 | https://github.com/burningwave/tools/issues 113 | 114 | 115 | 116 | 117 | ossrh 118 | https://oss.sonatype.org/content/repositories/snapshots 119 | 120 | 121 | ossrh 122 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 123 | 124 | 125 | 126 | 127 | scm:git:${repository.url} 128 | scm:git:${repository.url} 129 | https://github.com/burningwave/tools 130 | tools-0.10.113 131 | 132 | 133 | 134 | 135 | 136 | org.burningwave 137 | core 138 | ${burningwave-core.version} 139 | 140 | 141 | 142 | org.junit.jupiter 143 | junit-jupiter-engine 144 | ${junit-jupiter.version} 145 | test 146 | 147 | 148 | 149 | org.junit.platform 150 | junit-platform-engine 151 | ${junit.version} 152 | test 153 | 154 | 155 | 156 | org.junit.platform 157 | junit-platform-commons 158 | ${junit.version} 159 | test 160 | 161 | 162 | 163 | org.junit.platform 164 | junit-platform-runner 165 | ${junit.version} 166 | test 167 | 168 | 169 | 170 | 171 | 172 | ${project.generated.artifacts.prefix}-${project.artifactId}-${project.version} 173 | 174 | 175 | ${project.basedir} 176 | 177 | **LICENSE 178 | 179 | META-INF 180 | 181 | 182 | ${project.basedir}/src/main/resources 183 | 184 | ** 185 | 186 | 187 | 188 | 189 | 190 | ${project.basedir}/src/test/java 191 | 192 | **/*.java 193 | 194 | 195 | 196 | ${project.basedir}/src/test/resources 197 | 198 | 199 | 200 | 201 | org.apache.maven.plugins 202 | maven-compiler-plugin 203 | ${maven-compiler-plugin.version} 204 | 205 | ${project_jdk_version} 206 | ${project_jdk_version} 207 | true 208 | 209 | 210 | 211 | org.apache.maven.plugins 212 | maven-surefire-plugin 213 | ${maven-surefire-plugin.version} 214 | 215 | ${skipTests} 216 | 217 | ${project.test.excludes} 218 | 219 | 220 | ${project.test.includes} 221 | 222 | 223 | 224 | 225 | maven-jar-plugin 226 | ${maven-jar-plugin.version} 227 | 228 | 229 | jdk/ 230 | META-INF/maven/ 231 | 232 | 233 | false 234 | 235 | Burningwave 236 | 237 | 238 | 239 | 240 | 241 | maven-deploy-plugin 242 | ${maven-deploy-plugin.version} 243 | 244 | 245 | default-deploy 246 | deploy 247 | 248 | deploy 249 | 250 | 251 | 252 | 253 | 254 | org.apache.maven.plugins 255 | maven-release-plugin 256 | ${maven-release-plugin.version} 257 | 258 | true 259 | true 260 | forked-path 261 | -Dgpg.passphrase=${gpg.passphrase} 262 | 263 | 264 | 265 | 266 | org.apache.maven.scm 267 | maven-scm-provider-gitexe 268 | ${maven-scm-provider-gitexe.version} 269 | 270 | 271 | 272 | 273 | org.sonatype.plugins 274 | nexus-staging-maven-plugin 275 | ${nexus-staging-maven-plugin.version} 276 | true 277 | 278 | 20 279 | ossrh 280 | https://oss.sonatype.org/ 281 | true 282 | 283 | 284 | 285 | org.apache.maven.plugins 286 | maven-source-plugin 287 | ${maven-source-plugin.version} 288 | 289 | 290 | org/burningwave/core/classes/ClassLoaderDelegate.bwc 291 | 292 | 293 | 294 | 295 | attach-sources 296 | 297 | jar 298 | 299 | 300 | 301 | 302 | 303 | 304 | org.apache.maven.plugins 305 | maven-javadoc-plugin 306 | ${maven-javadoc-plugin.version} 307 | 308 | ${java.home}/${javadocExecutable.relativePath} 309 | UTF-8 310 | ${project_jdk_version} 311 | 312 | 313 | 314 | attach-javadoc 315 | 316 | jar 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | org.apache.maven.plugins 328 | maven-jxr-plugin 329 | ${maven-jxr-plugin.version} 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | release-sign-artifacts 338 | 339 | 340 | performRelease 341 | true 342 | 343 | 344 | 345 | 346 | 347 | org.apache.maven.plugins 348 | maven-gpg-plugin 349 | ${maven-gpg-plugin.version} 350 | 351 | 352 | verify 353 | 354 | sign 355 | 356 | 357 | 358 | --pinentry-mode 359 | loopback 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | run-coveralls 370 | 371 | false 372 | 373 | 374 | 375 | 376 | 377 | org.eluder.coveralls 378 | coveralls-maven-plugin 379 | ${coveralls-maven-plugin.version} 380 | 381 | 382 | ${project.basedir}/src/main/java 383 | 384 | 385 | 386 | 387 | org.jacoco 388 | jacoco-maven-plugin 389 | ${jacoco-maven-plugin.version} 390 | 391 | 392 | prepare-agent 393 | 394 | prepare-agent 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | -------------------------------------------------------------------------------- /src/main/java/org/burningwave/tools/dependencies/Capturer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Burningwave Tools. 3 | * 4 | * Author: Roberto Gentili 5 | * 6 | * Hosted at: https://github.com/burningwave/tools 7 | * 8 | * -- 9 | * 10 | * The MIT License (MIT) 11 | * 12 | * Copyright (c) 2021 Roberto Gentili 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 15 | * documentation files (the "Software"), to deal in the Software without restriction, including without 16 | * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all copies or substantial 21 | * portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 24 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 25 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 27 | * OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | package org.burningwave.tools.dependencies; 30 | 31 | import static org.burningwave.core.assembler.StaticComponentContainer.BackgroundExecutor; 32 | import static org.burningwave.core.assembler.StaticComponentContainer.Driver; 33 | import static org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggerRepository; 34 | import static org.burningwave.core.assembler.StaticComponentContainer.Paths; 35 | import static org.burningwave.core.assembler.StaticComponentContainer.Streams; 36 | 37 | import java.io.File; 38 | import java.nio.ByteBuffer; 39 | import java.nio.file.Files; 40 | import java.util.Collection; 41 | import java.util.Set; 42 | import java.util.UUID; 43 | import java.util.concurrent.CopyOnWriteArrayList; 44 | import java.util.function.BiPredicate; 45 | import java.util.function.Function; 46 | import java.util.function.Predicate; 47 | import java.util.stream.Collectors; 48 | 49 | import org.burningwave.core.Component; 50 | import org.burningwave.core.assembler.ComponentContainer; 51 | import org.burningwave.core.assembler.ComponentSupplier; 52 | import org.burningwave.core.classes.ByteCodeHunter; 53 | import org.burningwave.core.classes.JavaClass; 54 | import org.burningwave.core.concurrent.QueuedTaskExecutor; 55 | import org.burningwave.core.concurrent.QueuedTaskExecutor.Task; 56 | import org.burningwave.core.function.TriConsumer; 57 | import org.burningwave.core.io.FileSystemItem; 58 | 59 | public class Capturer implements Component { 60 | protected static final String BURNINGWAVE_CLASSES_RELATIVE_DESTINATION_PATH = "[org.burningwave]"; 61 | protected static final String TOOLFACTORY_CLASSES_RELATIVE_DESTINATION_PATH = "[io.github.toolfactory]"; 62 | ByteCodeHunter byteCodeHunter; 63 | 64 | Capturer(ByteCodeHunter byteCodeHunter) { 65 | this.byteCodeHunter = byteCodeHunter; 66 | } 67 | 68 | public static Capturer create(ComponentSupplier componentSupplier) { 69 | return new Capturer(componentSupplier.getByteCodeHunter()); 70 | } 71 | 72 | public static Capturer getInstance() { 73 | return Holder.getCapturerInstance(); 74 | } 75 | 76 | public Result capture(String mainClassName, Collection baseClassPaths, 77 | TriConsumer resourceConsumer, boolean includeMainClass, 78 | Long continueToCaptureAfterSimulatorClassEndExecutionFor) { 79 | return capture(mainClassName, new String[0], baseClassPaths, resourceConsumer, includeMainClass, 80 | continueToCaptureAfterSimulatorClassEndExecutionFor); 81 | } 82 | 83 | @SuppressWarnings("resource") 84 | public Result capture(String mainClassName, String[] mainMethodAruments, Collection baseClassPaths, 85 | TriConsumer resourceConsumer, boolean includeMainClass, 86 | Long continueToCaptureAfterSimulatorClassEndExecutionFor) { 87 | final Result result = new Result(); 88 | Function javaClassAdder = includeMainClass ? (javaClass) -> { 89 | result.put(javaClass); 90 | return true; 91 | } : (javaClass) -> { 92 | if (!javaClass.getName().equals(mainClassName)) { 93 | result.put(javaClass); 94 | return true; 95 | } 96 | return false; 97 | }; 98 | result.findingTask = BackgroundExecutor.createTask(task -> { 99 | Class cls; 100 | try (Sniffer resourceSniffer = new Sniffer(null).init(false, baseClassPaths, javaClassAdder, 101 | fileSystemItem -> { 102 | result.putResource(fileSystemItem); 103 | return true; 104 | }, resourceConsumer)) { 105 | try { 106 | cls = Class.forName(mainClassName, false, resourceSniffer); 107 | cls.getMethod("main", String[].class).invoke(null, (Object) mainMethodAruments); 108 | if (continueToCaptureAfterSimulatorClassEndExecutionFor != null 109 | && continueToCaptureAfterSimulatorClassEndExecutionFor > 0) { 110 | Thread.sleep(continueToCaptureAfterSimulatorClassEndExecutionFor); 111 | } 112 | } catch (Throwable exc) { 113 | Driver.throwException(exc); 114 | } finally { 115 | createExecutor(result.getStore().getAbsolutePath(), mainClassName, mainMethodAruments, 116 | UUID.randomUUID().toString()); 117 | } 118 | } 119 | }).submit(); 120 | return result; 121 | } 122 | 123 | public Result captureAndStore(String mainClassName, Collection baseClassPaths, String destinationPath, 124 | boolean includeMainClass, Long continueToCaptureAfterSimulatorClassEndExecutionFor) { 125 | return captureAndStore(mainClassName, new String[0], baseClassPaths, destinationPath, includeMainClass, 126 | continueToCaptureAfterSimulatorClassEndExecutionFor); 127 | } 128 | 129 | public Result captureAndStore(String mainClassName, String[] mainMethodAruments, Collection baseClassPaths, 130 | String destinationPath, boolean includeMainClass, 131 | Long continueToCaptureAfterSimulatorClassEndExecutionFor) { 132 | Result dependencies = capture(mainClassName, mainMethodAruments, baseClassPaths, 133 | getStoreFunction(destinationPath), includeMainClass, 134 | continueToCaptureAfterSimulatorClassEndExecutionFor); 135 | dependencies.store = FileSystemItem.ofPath(destinationPath); 136 | return dependencies; 137 | } 138 | 139 | TriConsumer getStoreFunction(String destinationPath) { 140 | // Exclude the runtime jdk library 141 | final String javaHome = Paths.clean(System.getProperty("java.home")) + "/"; 142 | BiPredicate storePredicate = (resourceAbsolutePath, 143 | fileSystemItem) -> !resourceAbsolutePath.startsWith(javaHome) && !fileSystemItem.exists(); 144 | return (resourceAbsolutePath, resourceRelativePath, resourceContent) -> { 145 | String finalPath; 146 | if (resourceRelativePath.startsWith("io/github/toolfactory")) { 147 | finalPath = destinationPath + "/" + TOOLFACTORY_CLASSES_RELATIVE_DESTINATION_PATH; 148 | } else if (resourceRelativePath.startsWith("org/burningwave")) { 149 | finalPath = destinationPath + "/" + BURNINGWAVE_CLASSES_RELATIVE_DESTINATION_PATH; 150 | } else { 151 | finalPath = getStoreEntryBasePath(destinationPath, resourceAbsolutePath, resourceRelativePath); 152 | } 153 | FileSystemItem fileSystemItem = FileSystemItem.ofPath(finalPath + "/" + resourceRelativePath); 154 | if (storePredicate.test(resourceAbsolutePath, fileSystemItem)) { 155 | Streams.store(fileSystemItem.getAbsolutePath(), resourceContent); 156 | ManagedLoggerRepository.logInfo(getClass()::getName, "Resource {} has been stored to class path {}", 157 | resourceRelativePath, fileSystemItem.getAbsolutePath()); 158 | } 159 | }; 160 | } 161 | 162 | String getStoreEntryBasePath(String storeBasePath, String itemAbsolutePath, String ItemRelativePath) { 163 | String finalPath = itemAbsolutePath; 164 | if (finalPath.chars().filter(ch -> ch == '/').count() > 1) { 165 | finalPath = finalPath.substring(0, finalPath.lastIndexOf(ItemRelativePath) - 1) 166 | .substring(finalPath.indexOf("/") + 1); 167 | finalPath = "[" + finalPath.replace("/", "][") + "]"; 168 | } else { 169 | finalPath = finalPath.replace("/", ""); 170 | } 171 | return storeBasePath + "/" + getReducedPath(finalPath); 172 | } 173 | 174 | private String getReducedPath(String path) { 175 | String temp = path.substring(0, path.lastIndexOf("[")); 176 | temp = temp.substring(0, temp.lastIndexOf("[")); 177 | return path.substring(temp.lastIndexOf("[")); 178 | } 179 | 180 | void createExecutor(String destinationPath, String mainClassName, String[] mainMethodAruments, 181 | String executorSuffix) { 182 | if (System.getProperty("os.name").toLowerCase().contains("windows")) { 183 | createWindowsExecutor(destinationPath, mainClassName, mainMethodAruments, executorSuffix); 184 | } else { 185 | createUnixExecutor(destinationPath, mainClassName, mainMethodAruments, executorSuffix); 186 | } 187 | } 188 | 189 | void createWindowsExecutor(String destinationPath, String mainClassName, String[] mainMethodAruments, 190 | String executorSuffix) { 191 | try { 192 | Set classPathSet = FileSystemItem.ofPath(destinationPath).refresh() 193 | .findInChildren(FileSystemItem.Criteria.forAllFileThat(FileSystemItem::isFolder)).stream() 194 | .map(fileSystemItem -> fileSystemItem.getAbsolutePath().replace(destinationPath + "/", "%~dp0")) 195 | .collect(Collectors.toSet()); 196 | String externalExecutorForWindows = "@echo off\n\"" 197 | + FileSystemItem.ofPath(System.getProperty("java.home")).getAbsolutePath() 198 | + "/bin/java\" -classpath \"" + String.join(File.pathSeparator, classPathSet) 199 | + "\" " + mainClassName 200 | + (mainMethodAruments.length > 0 201 | ? " " + String.join(" ", 202 | toDoubleQuotedStringsForStringsThatContainEmptySpace(mainMethodAruments)) 203 | : ""); 204 | Files.write(java.nio.file.Paths.get(destinationPath + "/executor-" + executorSuffix + ".cmd"), 205 | externalExecutorForWindows.getBytes()); 206 | } catch (Throwable exc) { 207 | ManagedLoggerRepository.logError(getClass()::getName, "Exception occurred", exc); 208 | } 209 | } 210 | 211 | void createUnixExecutor(String destinationPath, String mainClassName, String[] mainMethodAruments, 212 | String executorSuffix) { 213 | try { 214 | Set classPathSet = FileSystemItem.ofPath(destinationPath).refresh() 215 | .findInChildren(FileSystemItem.Criteria.forAllFileThat(FileSystemItem::isFolder)).stream() 216 | .map(fileSystemItem -> fileSystemItem.getAbsolutePath()).collect(Collectors.toSet()); 217 | String externalExecutorForUnix = FileSystemItem.ofPath(System.getProperty("java.home")).getAbsolutePath() 218 | + "/bin/java -classpath " + String.join(File.pathSeparator, classPathSet) + " " 219 | + mainClassName 220 | + (mainMethodAruments.length > 0 221 | ? " " + String.join(" ", 222 | toDoubleQuotedStringsForStringsThatContainEmptySpace(mainMethodAruments)) 223 | : ""); 224 | Files.write(java.nio.file.Paths.get(destinationPath + "/executor-" + executorSuffix + ".sh"), 225 | externalExecutorForUnix.getBytes()); 226 | } catch (Throwable exc) { 227 | ManagedLoggerRepository.logError(getClass()::getName, "Exception occurred", exc); 228 | } 229 | } 230 | 231 | String[] toDoubleQuotedStringsForStringsThatContainEmptySpace(String[] values) { 232 | String[] newValues = new String[values.length]; 233 | for (int i = 0; i < values.length; i++) { 234 | newValues[i] = values[i].contains(" ") ? "\"" + values[i] + "\"" : values[i]; 235 | } 236 | return newValues; 237 | } 238 | 239 | public static class Result implements Component { 240 | QueuedTaskExecutor.Task findingTask; 241 | Collection resources; 242 | Collection javaClasses; 243 | FileSystemItem store; 244 | 245 | Result() { 246 | this.javaClasses = new CopyOnWriteArrayList<>(); 247 | this.resources = new CopyOnWriteArrayList<>(); 248 | } 249 | 250 | public void putResource(FileSystemItem fileSystemItem) { 251 | resources.add(fileSystemItem); 252 | } 253 | 254 | JavaClass put(JavaClass javaClass) { 255 | javaClasses.add(javaClass); 256 | return javaClass; 257 | } 258 | 259 | public Collection getJavaClasses() { 260 | return javaClasses; 261 | } 262 | 263 | public Collection getResources() { 264 | return resources; 265 | } 266 | 267 | public JavaClass getJavaClass(Predicate predicate) { 268 | return getJavaClasses().stream().filter(predicate).findFirst().orElseGet(() -> null); 269 | } 270 | 271 | public Collection getResources(Predicate predicate) { 272 | return getResources().stream().filter(predicate).collect(Collectors.toSet()); 273 | } 274 | 275 | public Task getFindingTask() { 276 | return this.findingTask; 277 | } 278 | 279 | public void waitForTaskEnding() { 280 | findingTask.waitForFinish(); 281 | } 282 | 283 | public FileSystemItem getStore() { 284 | return store; 285 | } 286 | 287 | @Override 288 | public void close() { 289 | findingTask.abort(); 290 | findingTask = null; 291 | resources.clear(); 292 | resources = null; 293 | javaClasses.clear(); 294 | javaClasses = null; 295 | store = null; 296 | } 297 | } 298 | 299 | static class Holder { 300 | static final Capturer CAPTURER_INSTANCE = Capturer.create(ComponentContainer.getInstance()); 301 | 302 | static Capturer getCapturerInstance() { 303 | return CAPTURER_INSTANCE; 304 | } 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /src/main/java/org/burningwave/tools/dependencies/Sniffer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Burningwave Tools. 3 | * 4 | * Author: Roberto Gentili 5 | * 6 | * Hosted at: https://github.com/burningwave/tools 7 | * 8 | * -- 9 | * 10 | * The MIT License (MIT) 11 | * 12 | * Copyright (c) 2021 Roberto Gentili 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 15 | * documentation files (the "Software"), to deal in the Software without restriction, including without 16 | * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all copies or substantial 21 | * portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 24 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 25 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 27 | * OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | package org.burningwave.tools.dependencies; 30 | 31 | import static org.burningwave.core.assembler.StaticComponentContainer.BackgroundExecutor; 32 | import static org.burningwave.core.assembler.StaticComponentContainer.ClassLoaders; 33 | import static org.burningwave.core.assembler.StaticComponentContainer.Classes; 34 | import static org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggerRepository; 35 | import static org.burningwave.core.assembler.StaticComponentContainer.Strings; 36 | 37 | import java.io.IOException; 38 | import java.io.InputStream; 39 | import java.net.URL; 40 | import java.nio.ByteBuffer; 41 | import java.util.Arrays; 42 | import java.util.Collection; 43 | import java.util.Collections; 44 | import java.util.Enumeration; 45 | import java.util.LinkedHashSet; 46 | import java.util.Map; 47 | import java.util.Set; 48 | import java.util.concurrent.ConcurrentHashMap; 49 | import java.util.function.Function; 50 | import java.util.stream.Collectors; 51 | 52 | import org.burningwave.core.classes.JavaClass; 53 | import org.burningwave.core.classes.MemoryClassLoader; 54 | import org.burningwave.core.concurrent.QueuedTaskExecutor.Task; 55 | import org.burningwave.core.function.ThrowingBiFunction; 56 | import org.burningwave.core.function.TriConsumer; 57 | import org.burningwave.core.io.FileSystemItem; 58 | 59 | public class Sniffer extends MemoryClassLoader { 60 | private Function javaClassFilterAndAdder; 61 | private Function resourceFilterAndAdder; 62 | private Map resources; 63 | // In this map the key is the absolute path 64 | private Map javaClasses; 65 | // In this map the key is the class name 66 | private Map bwJavaClasses; 67 | private TriConsumer resourcesConsumer; 68 | ClassLoader threadContextClassLoader; 69 | Function masterClassLoaderRetrieverAndResetter; 70 | ThrowingBiFunction, ClassNotFoundException> classLoadingFunction; 71 | private Collection tasksInExecution; 72 | 73 | public Sniffer(ClassLoader parent) { 74 | super(parent); 75 | } 76 | 77 | static { 78 | ClassLoader.registerAsParallelCapable(); 79 | } 80 | 81 | protected Sniffer init(boolean useAsMasterClassLoader, Collection baseClassPaths, 82 | Function javaClassAdder, Function resourceAdder, 83 | TriConsumer resourcesConsumer) { 84 | this.threadContextClassLoader = Thread.currentThread().getContextClassLoader(); 85 | this.javaClassFilterAndAdder = javaClassAdder; 86 | this.resourceFilterAndAdder = resourceAdder; 87 | this.resourcesConsumer = resourcesConsumer; 88 | this.tasksInExecution = ConcurrentHashMap.newKeySet(); 89 | initResourceLoader(baseClassPaths); 90 | if (useAsMasterClassLoader) { 91 | // Load in cache defineClass and definePackage methods for 92 | // threadContextClassLoader 93 | ClassLoaders.getDefineClassMethod(threadContextClassLoader); 94 | ClassLoaders.getDefinePackageMethod(threadContextClassLoader); 95 | classLoadingFunction = (className, resolve) -> { 96 | if ((!className.startsWith("org.burningwave.") && !className.startsWith("io.github.toolfactory."))) { 97 | return super.loadClass(className, resolve); 98 | } else { 99 | JavaClass javaClass = bwJavaClasses.get(className); 100 | try { 101 | return ClassLoaders.defineOrLoad(threadContextClassLoader, javaClass); 102 | } catch (NoClassDefFoundError | ReflectiveOperationException exc) { 103 | throw new ClassNotFoundException(Classes.retrieveName(exc)); 104 | } catch (NullPointerException exc) { 105 | if (javaClass == null) { 106 | throw new ClassNotFoundException(className); 107 | } 108 | throw exc; 109 | } 110 | } 111 | }; 112 | masterClassLoaderRetrieverAndResetter = ClassLoaders.setAsParent(threadContextClassLoader, this); 113 | } else { 114 | classLoadingFunction = (clsName, resolveFlag) -> { 115 | return super.loadClass(clsName, resolveFlag); 116 | }; 117 | Thread.currentThread().setContextClassLoader(this); 118 | } 119 | 120 | return this; 121 | } 122 | 123 | @Override 124 | public synchronized void addByteCode(String className, ByteBuffer byteCode) { 125 | super.addByteCode(className, byteCode); 126 | } 127 | 128 | private void initResourceLoader(Collection baseClassPaths) { 129 | this.resources = new ConcurrentHashMap<>(); 130 | this.javaClasses = new ConcurrentHashMap<>(); 131 | this.bwJavaClasses = new ConcurrentHashMap<>(); 132 | ManagedLoggerRepository.logInfo(getClass()::getName, "Scanning paths :\n{}", 133 | String.join("\n", baseClassPaths)); 134 | for (String classPath : baseClassPaths) { 135 | FileSystemItem.ofPath(classPath).refresh() 136 | .findInAllChildren(FileSystemItem.Criteria.forAllFileThat((fileSystemItem) -> { 137 | String absolutePath = fileSystemItem.getAbsolutePath(); 138 | resources.put(absolutePath, classPath); 139 | JavaClass javaClass = fileSystemItem.toJavaClass(); 140 | if (javaClass != null) { 141 | addByteCode(javaClass.getName(), javaClass.getByteCode()); 142 | javaClasses.put(absolutePath, javaClass); 143 | if (javaClass.getName().startsWith("org.burningwave.") 144 | || javaClass.getName().startsWith("io.github.toolfactory.")) { 145 | bwJavaClasses.put(javaClass.getName(), javaClass); 146 | } 147 | } 148 | return true; 149 | })); 150 | } 151 | } 152 | 153 | protected void consumeClass(String className) { 154 | consumeClasses(Arrays.asList(className)); 155 | } 156 | 157 | public void consumeClasses(Collection currentNotFoundClasses) { 158 | for (Map.Entry entry : javaClasses.entrySet()) { 159 | if (currentNotFoundClasses.contains(entry.getValue().getName())) { 160 | JavaClass javaClass = entry.getValue(); 161 | if (javaClassFilterAndAdder.apply(javaClass)) { 162 | Task tsk = BackgroundExecutor.createTask(task -> { 163 | try { 164 | resourcesConsumer.accept(entry.getKey(), javaClass.getPath(), javaClass.getByteCode()); 165 | } catch (Throwable exc) { 166 | try { 167 | FileSystemItem classPath = FileSystemItem.ofPath(resources.get(entry.getKey())); 168 | FileSystemItem javaClassFIS = FileSystemItem.ofPath(entry.getKey()); 169 | String itemRelativePath = javaClassFIS.getAbsolutePath().substring(classPath.getAbsolutePath().length() + 1); 170 | resourcesConsumer.accept(entry.getKey(), itemRelativePath, javaClass.getByteCode()); 171 | } catch (Throwable exception) { 172 | throw exc; 173 | } 174 | } 175 | tasksInExecution.remove(task); 176 | }); 177 | tasksInExecution.add(tsk); 178 | tsk.submit(); 179 | } 180 | } 181 | } 182 | } 183 | 184 | protected Collection consumeResource(String relativePath, boolean breakWhenFound) { 185 | Set founds = new LinkedHashSet<>(); 186 | if (Strings.isNotEmpty(relativePath)) { 187 | for (Map.Entry entry : resources.entrySet()) { 188 | if (entry.getKey().endsWith(relativePath)) { 189 | FileSystemItem fileSystemItem = FileSystemItem.ofPath(entry.getKey()); 190 | founds.add(fileSystemItem); 191 | if (resourceFilterAndAdder.apply(fileSystemItem)) { 192 | Task tsk = BackgroundExecutor.createTask(task -> { 193 | resourcesConsumer.accept(entry.getKey(), relativePath, fileSystemItem.toByteBuffer()); 194 | tasksInExecution.remove(task); 195 | }); 196 | tasksInExecution.add(tsk); 197 | tsk.submit(); 198 | } 199 | if (breakWhenFound) { 200 | break; 201 | } 202 | } 203 | } 204 | } 205 | return founds; 206 | } 207 | 208 | @Override 209 | public void addLoadedByteCode(String className, ByteBuffer byteCode) { 210 | super.addLoadedByteCode(className, byteCode); 211 | consumeClass(className); 212 | } 213 | 214 | @Override 215 | protected Class loadClass(String className, boolean resolve) throws ClassNotFoundException { 216 | Class cls = classLoadingFunction.apply(className, resolve); 217 | consumeClass(className); 218 | return cls; 219 | } 220 | 221 | public Class _loadClass(String className, boolean resolve) throws ClassNotFoundException { 222 | Class cls = classLoadingFunction.apply(className, resolve); 223 | consumeClass(className); 224 | return cls; 225 | } 226 | 227 | @Override 228 | public URL getResource(String name) { 229 | Enumeration urls = getResources(name, true); 230 | if (urls.hasMoreElements()) { 231 | return urls.nextElement(); 232 | } 233 | return null; 234 | } 235 | 236 | @Override 237 | public Enumeration getResources(String name) throws IOException { 238 | return getResources(name, false); 239 | } 240 | 241 | private Enumeration getResources(String name, boolean findFirst) { 242 | return Collections.enumeration(consumeResource(name, findFirst).stream().map(fileSystemItem -> { 243 | resourceFilterAndAdder.apply(fileSystemItem); 244 | return fileSystemItem.getURL(); 245 | }).collect(Collectors.toSet())); 246 | } 247 | 248 | @Override 249 | public InputStream getResourceAsStream(String name) { 250 | FileSystemItem fileSystemItem = consumeResource(name, true).stream().findFirst().orElseGet(() -> null); 251 | if (fileSystemItem != null) { 252 | return fileSystemItem.toInputStream(); 253 | } else { 254 | return getByteCodeAsInputStream(name); 255 | } 256 | } 257 | 258 | @Override 259 | public void close() { 260 | closeResources(() -> tasksInExecution == null, task -> { 261 | if (!tasksInExecution.isEmpty()) { 262 | tasksInExecution.stream().forEach(Task::waitForFinish); 263 | tasksInExecution = null; 264 | } 265 | if (threadContextClassLoader != null) { 266 | Thread.currentThread().setContextClassLoader(threadContextClassLoader); 267 | } 268 | if (masterClassLoaderRetrieverAndResetter != null) { 269 | masterClassLoaderRetrieverAndResetter.apply(true); 270 | masterClassLoaderRetrieverAndResetter = null; 271 | } 272 | resources.clear(); 273 | // Nulling resources will cause crash 274 | // resources = null; 275 | javaClasses.clear(); 276 | // Nulling javaClasses will cause crash 277 | // javaClasses = null; 278 | // javaClassFilterAndAdder = null; 279 | // resourceFilterAndAdder = null; 280 | // threadContextClassLoader = null; 281 | // classLoadingFunction = null; 282 | // clear(); 283 | unregister(); 284 | }); 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /src/main/java/org/burningwave/tools/dependencies/TwoPassCapturer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Burningwave Tools. 3 | * 4 | * Author: Roberto Gentili 5 | * 6 | * Hosted at: https://github.com/burningwave/tools 7 | * 8 | * -- 9 | * 10 | * The MIT License (MIT) 11 | * 12 | * Copyright (c) 2021 Roberto Gentili 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 15 | * documentation files (the "Software"), to deal in the Software without restriction, including without 16 | * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all copies or substantial 21 | * portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 24 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 25 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 27 | * OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | package org.burningwave.tools.dependencies; 30 | 31 | import static org.burningwave.core.assembler.StaticComponentContainer.BackgroundExecutor; 32 | import static org.burningwave.core.assembler.StaticComponentContainer.Driver; 33 | import static org.burningwave.core.assembler.StaticComponentContainer.FileSystemHelper; 34 | import static org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggerRepository; 35 | import static org.burningwave.core.assembler.StaticComponentContainer.Paths; 36 | 37 | import java.io.File; 38 | import java.io.IOException; 39 | import java.nio.ByteBuffer; 40 | import java.nio.file.Files; 41 | import java.util.AbstractMap; 42 | import java.util.Arrays; 43 | import java.util.Collection; 44 | import java.util.Iterator; 45 | import java.util.LinkedHashSet; 46 | import java.util.LinkedList; 47 | import java.util.List; 48 | import java.util.Map; 49 | import java.util.Set; 50 | import java.util.TreeSet; 51 | import java.util.UUID; 52 | import java.util.concurrent.ConcurrentHashMap; 53 | import java.util.function.Function; 54 | import java.util.stream.Collectors; 55 | 56 | import org.burningwave.core.assembler.ComponentContainer; 57 | import org.burningwave.core.assembler.ComponentSupplier; 58 | import org.burningwave.core.classes.ByteCodeHunter; 59 | import org.burningwave.core.classes.ClassCriteria; 60 | import org.burningwave.core.classes.ClassPathHunter; 61 | import org.burningwave.core.classes.JavaClass; 62 | import org.burningwave.core.classes.SearchConfig; 63 | import org.burningwave.core.function.ThrowingSupplier; 64 | import org.burningwave.core.function.TriConsumer; 65 | import org.burningwave.core.io.FileSystemItem; 66 | import org.burningwave.core.io.PathHelper; 67 | 68 | public class TwoPassCapturer extends Capturer { 69 | ClassPathHunter classPathHunter; 70 | PathHelper pathHelper; 71 | 72 | private TwoPassCapturer(PathHelper pathHelper, ByteCodeHunter byteCodeHunter, ClassPathHunter classPathHunter) { 73 | super(byteCodeHunter); 74 | this.pathHelper = pathHelper; 75 | this.classPathHunter = classPathHunter; 76 | } 77 | 78 | public static TwoPassCapturer create(ComponentSupplier componentSupplier) { 79 | return new TwoPassCapturer(componentSupplier.getPathHelper(), componentSupplier.getByteCodeHunter(), 80 | componentSupplier.getClassPathHunter()); 81 | } 82 | 83 | public static TwoPassCapturer getInstance() { 84 | return Holder.getCapturerInstance(); 85 | } 86 | 87 | @Override 88 | public Result capture(String mainClassName, String[] mainMethodAruments, Collection baseClassPaths, 89 | TriConsumer resourceConsumer, boolean includeMainClass, 90 | Long continueToCaptureAfterSimulatorClassEndExecutionFor) { 91 | return capture(mainClassName, mainMethodAruments, baseClassPaths, resourceConsumer, includeMainClass, 92 | continueToCaptureAfterSimulatorClassEndExecutionFor, true); 93 | } 94 | 95 | private Result capture(String mainClassName, String[] mainMethodAruments, Collection baseClassPaths, 96 | TriConsumer resourceConsumer, boolean includeMainClass, 97 | Long continueToCaptureAfterSimulatorClassEndExecutionFor, boolean recursive) { 98 | final Result result = new Result(javaClass -> true, fileSystemItem -> true); 99 | result.findingTask = BackgroundExecutor.createTask(task -> { 100 | try (Sniffer resourceSniffer = new Sniffer(null).init(!recursive, baseClassPaths, result.javaClassFilter, 101 | result.resourceFilter, resourceConsumer)) { 102 | ThrowingSupplier, ClassNotFoundException> mainClassSupplier = recursive 103 | ? () -> Class.forName(mainClassName, false, resourceSniffer) 104 | : () -> Class.forName(mainClassName); 105 | try { 106 | mainClassSupplier.get().getMethod("main", String[].class).invoke(null, (Object) mainMethodAruments); 107 | if (continueToCaptureAfterSimulatorClassEndExecutionFor != null 108 | && continueToCaptureAfterSimulatorClassEndExecutionFor > 0) { 109 | Thread.sleep(continueToCaptureAfterSimulatorClassEndExecutionFor); 110 | } 111 | } catch (Throwable exc) { 112 | ManagedLoggerRepository.logError(getClass()::getName, "Exception occurred", exc); 113 | Driver.throwException(exc); 114 | } 115 | } 116 | if (recursive) { 117 | try { 118 | launchExternalCapturer(mainClassName, mainMethodAruments, result.getStore().getAbsolutePath(), 119 | baseClassPaths, includeMainClass, continueToCaptureAfterSimulatorClassEndExecutionFor); 120 | } catch (IOException | InterruptedException exc) { 121 | Driver.throwException(exc); 122 | } 123 | } 124 | if (recursive && !includeMainClass) { 125 | JavaClass mainJavaClass = result.getJavaClass(javaClass -> javaClass.getName().equals(mainClassName)); 126 | Collection mainJavaClassesFiles = result.getResources( 127 | fileSystemItem -> fileSystemItem.getAbsolutePath().endsWith(mainJavaClass.getPath())); 128 | FileSystemItem store = result.getStore(); 129 | for (FileSystemItem fileSystemItem : mainJavaClassesFiles) { 130 | FileSystemHelper.delete(fileSystemItem.getAbsolutePath()); 131 | fileSystemItem = fileSystemItem.getParent(); 132 | while (fileSystemItem != null 133 | && !fileSystemItem.getAbsolutePath().equals(store.getAbsolutePath())) { 134 | if (fileSystemItem.getChildren().isEmpty()) { 135 | FileSystemHelper.delete(fileSystemItem.getAbsolutePath()); 136 | } else { 137 | break; 138 | } 139 | fileSystemItem = fileSystemItem.getParent(); 140 | } 141 | } 142 | } 143 | }).submit(); 144 | return result; 145 | } 146 | 147 | private Result captureAndStore(String mainClassName, String[] mainMethodAruments, Collection baseClassPaths, 148 | String destinationPath, boolean includeMainClass, Long continueToCaptureAfterSimulatorClassEndExecutionFor, 149 | boolean recursive) { 150 | Result dependencies = capture(mainClassName, mainMethodAruments, baseClassPaths, 151 | getStoreFunction(destinationPath), includeMainClass, 152 | continueToCaptureAfterSimulatorClassEndExecutionFor, recursive); 153 | dependencies.store = FileSystemItem.ofPath(destinationPath); 154 | return dependencies; 155 | } 156 | 157 | private void launchExternalCapturer(String mainClassName, String[] mainMethodAruments, String destinationPath, 158 | Collection baseClassPaths, boolean includeMainClass, 159 | Long continueToCaptureAfterSimulatorClassEndExecutionFor) throws IOException, InterruptedException { 160 | // Excluding Burningwave from next process classpath 161 | Set classPaths = FileSystemItem.ofPath(destinationPath).refresh() 162 | .findInChildren(FileSystemItem.Criteria.forAllFileThat(fileSystemItem -> !fileSystemItem 163 | .getAbsolutePath().endsWith(BURNINGWAVE_CLASSES_RELATIVE_DESTINATION_PATH) 164 | && !fileSystemItem.getAbsolutePath().endsWith(TOOLFACTORY_CLASSES_RELATIVE_DESTINATION_PATH))) 165 | .stream().map(child -> child.getAbsolutePath()).collect(Collectors.toSet()); 166 | 167 | // Adding Burningwave to next process scanning path 168 | ClassPathHunter.SearchResult searchResult = classPathHunter 169 | .findBy(SearchConfig.forPaths(pathHelper.getMainClassPaths()) 170 | .by(ClassCriteria.create() 171 | .packageName(packageName -> packageName.startsWith("io.github.toolfactory") 172 | || packageName.startsWith("org.burningwave.jvm") 173 | || packageName.startsWith("org.burningwave.core") 174 | || packageName.startsWith("org.burningwave.tools")))); 175 | Collection classPathsToBeScanned = new LinkedHashSet<>(baseClassPaths); 176 | classPathsToBeScanned.remove(destinationPath); 177 | Iterator classPathIterator = searchResult.getClassPaths().iterator(); 178 | while (classPathIterator.hasNext()) { 179 | FileSystemItem classPath = classPathIterator.next(); 180 | if (!classPaths.contains(classPath.getAbsolutePath())) { 181 | classPaths.add(classPath.getAbsolutePath()); 182 | // classPathsToBeScanned.remove(classPath.getAbsolutePath()); 183 | } 184 | } 185 | ProcessBuilder processBuilder = System.getProperty("os.name").toLowerCase().contains("windows") 186 | ? getProcessBuilderForWindows(classPaths, classPathsToBeScanned, mainClassName, mainMethodAruments, 187 | destinationPath, includeMainClass, continueToCaptureAfterSimulatorClassEndExecutionFor) 188 | : getProcessBuilderForUnix(classPaths, classPathsToBeScanned, mainClassName, mainMethodAruments, 189 | destinationPath, includeMainClass, continueToCaptureAfterSimulatorClassEndExecutionFor); 190 | Process process = processBuilder.start(); 191 | process.waitFor(); 192 | } 193 | 194 | private ProcessBuilder getProcessBuilderForWindows(Collection classPaths, 195 | Collection classPathsToBeScanned, String mainClassName, String[] mainMethodAruments, 196 | String destinationPath, boolean includeMainClass, Long continueToCaptureAfterSimulatorClassEndExecutionFor) 197 | throws IOException { 198 | String javaExecutablePath = System.getProperty("java.home") + "/bin/java"; 199 | List command = new LinkedList<>(); 200 | command.add(Paths.clean(javaExecutablePath)); 201 | command.add("-classpath"); 202 | StringBuffer generatedClassPath = new StringBuffer(); 203 | generatedClassPath.append("\""); 204 | if (!classPaths.isEmpty()) { 205 | generatedClassPath.append(String.join(File.pathSeparator, classPaths)); 206 | } 207 | generatedClassPath.append("\""); 208 | command.add(generatedClassPath.toString()); 209 | command.add(InternalLauncher.class.getName()); 210 | command.add("\"" + String.join(File.pathSeparator, classPathsToBeScanned) + "\""); 211 | command.add(mainClassName); 212 | command.add("\"" + destinationPath + "\""); 213 | command.add(Boolean.valueOf(includeMainClass).toString()); 214 | command.add(continueToCaptureAfterSimulatorClassEndExecutionFor.toString()); 215 | command.addAll(Arrays.asList(mainMethodAruments)); 216 | ProcessBuilder processBuilder = new ProcessBuilder(command); 217 | 218 | return processBuilder.inheritIO(); 219 | } 220 | 221 | private ProcessBuilder getProcessBuilderForUnix(Collection classPaths, 222 | Collection classPathsToBeScanned, String mainClassName, String[] mainMethodAruments, 223 | String destinationPath, boolean includeMainClass, Long continueToCaptureAfterSimulatorClassEndExecutionFor) 224 | throws IOException { 225 | List command = new LinkedList<>(); 226 | String javaExecutablePath = Paths.clean(System.getProperty("java.home") + "/bin/java"); 227 | command.add(javaExecutablePath); 228 | command.add("-classpath"); 229 | StringBuffer generatedClassPath = new StringBuffer(); 230 | if (!classPaths.isEmpty()) { 231 | generatedClassPath.append(String.join(File.pathSeparator, classPaths)); 232 | } 233 | command.add(generatedClassPath.toString()); 234 | command.add(InternalLauncher.class.getName()); 235 | command.add(String.join(File.pathSeparator, classPathsToBeScanned)); 236 | command.add(mainClassName); 237 | command.add(destinationPath); 238 | command.add(Boolean.valueOf(includeMainClass).toString()); 239 | command.add(continueToCaptureAfterSimulatorClassEndExecutionFor.toString()); 240 | command.addAll(Arrays.asList(mainMethodAruments)); 241 | ProcessBuilder processBuilder = new ProcessBuilder(command); 242 | 243 | return processBuilder.inheritIO(); 244 | } 245 | 246 | private void logReceivedParameters(String[] args, long wait, String fileSuffix) { 247 | try { 248 | 249 | String logs = String.join("\n\n", "classpath:\n\t" + String.join("\n\t", 250 | new TreeSet<>(Arrays.asList( 251 | System.getProperty("java.class.path").split(File.pathSeparator)))), 252 | "path to be scanned:\n\t" + String.join(File.pathSeparator + "\n\t", 253 | new TreeSet<>(Arrays.asList(args[0].split(File.pathSeparator)))), 254 | "mainClassName: " + args[1], "destinationPath: " + args[2], "includeMainClass: " + args[3], 255 | "continueToCaptureAfterSimulatorClassEndExecutionFor: " + args[4], 256 | (args.length > 5 ? "arguments: " + String.join(", ", Arrays.copyOfRange(args, 5, args.length)) 257 | : "")); 258 | 259 | Files.write(java.nio.file.Paths.get(args[2] + "/params-" + fileSuffix + ".txt"), logs.getBytes()); 260 | ManagedLoggerRepository.logDebug(() -> this.getClass().getName(), "\n\n" + logs + "\n\n"); 261 | if (wait > 0) { 262 | Thread.sleep(wait); 263 | } 264 | } catch (Throwable e) { 265 | e.printStackTrace(); 266 | } 267 | } 268 | 269 | private static class InternalLauncher { 270 | 271 | @SuppressWarnings("unused") 272 | public static void main(String[] args) { 273 | String[] mainMethodArguments = args.length > 5 ? Arrays.copyOfRange(args, 5, args.length) : new String[0]; 274 | TwoPassCapturer capturer = TwoPassCapturer.getInstance(); 275 | try { 276 | Collection paths = Arrays.asList(args[0].split(File.pathSeparator)); 277 | String mainClassName = args[1]; 278 | String destinationPath = args[2]; 279 | boolean includeMainClass = Boolean.valueOf(args[3]); 280 | long continueToCaptureAfterSimulatorClassEndExecutionFor = Long.valueOf(args[4]); 281 | capturer.captureAndStore(mainClassName, mainMethodArguments, paths, destinationPath, includeMainClass, 282 | continueToCaptureAfterSimulatorClassEndExecutionFor, false).waitForTaskEnding(); 283 | } catch (Throwable exc) { 284 | ManagedLoggerRepository.logError(() -> TwoPassCapturer.class.getName(), "Exception occurred", exc); 285 | } finally { 286 | String suffix = UUID.randomUUID().toString(); 287 | capturer.logReceivedParameters(args, 0, suffix); 288 | capturer.createExecutor(args[2], args[1], mainMethodArguments, suffix); 289 | } 290 | } 291 | } 292 | 293 | private static class Result extends Capturer.Result { 294 | Function javaClassFilter; 295 | Function resourceFilter; 296 | 297 | Result(Function javaClassFilter, Function resourceFilter) { 298 | this.javaClassFilter = javaClassFilter; 299 | this.resourceFilter = resourceFilter; 300 | this.javaClasses = null; 301 | this.resources = null; 302 | } 303 | 304 | @Override 305 | public Collection getJavaClasses() { 306 | if (javaClasses != null) { 307 | return javaClasses; 308 | } else { 309 | return loadResourcesAndJavaClasses().getValue(); 310 | } 311 | } 312 | 313 | @Override 314 | public Collection getResources() { 315 | if (resources != null) { 316 | return resources; 317 | } else { 318 | return loadResourcesAndJavaClasses().getKey(); 319 | } 320 | } 321 | 322 | public Map.Entry, Collection> loadResourcesAndJavaClasses() { 323 | Map.Entry, Collection> itemsFound = null; 324 | if (this.findingTask.hasFinished()) { 325 | if (this.resources == null) { 326 | synchronized (this) { 327 | if (this.resources == null) { 328 | itemsFound = retrieveResources(); 329 | this.resources = itemsFound.getKey(); 330 | this.javaClasses = itemsFound.getValue(); 331 | return itemsFound; 332 | } 333 | } 334 | } 335 | } 336 | return retrieveResources(); 337 | } 338 | 339 | private Map.Entry, Collection> retrieveResources() { 340 | Collection resources = ConcurrentHashMap.newKeySet(); 341 | Collection javaClasses = ConcurrentHashMap.newKeySet(); 342 | Map.Entry, Collection> itemsFound = new AbstractMap.SimpleEntry<>( 343 | resources, javaClasses); 344 | for (FileSystemItem fileSystemItem : store.refresh().findInAllChildren( 345 | FileSystemItem.Criteria.forAllFileThat(fileSystemItem -> resourceFilter.apply(fileSystemItem)))) { 346 | resources.add(fileSystemItem); 347 | if ("class".equals(fileSystemItem.getExtension())) { 348 | javaClasses.add(JavaClass.create(fileSystemItem.toByteBuffer())); 349 | } 350 | } 351 | return itemsFound; 352 | } 353 | } 354 | 355 | private static class Holder { 356 | private static final TwoPassCapturer CAPTURER_INSTANCE = TwoPassCapturer 357 | .create(ComponentContainer.getInstance()); 358 | 359 | private static TwoPassCapturer getCapturerInstance() { 360 | return CAPTURER_INSTANCE; 361 | } 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /src/main/java/org/burningwave/tools/net/DNSClientHostResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Burningwave Tools. 3 | * 4 | * Author: Roberto Gentili 5 | * 6 | * Hosted at: https://github.com/burningwave/tools 7 | * 8 | * -- 9 | * 10 | * The MIT License (MIT) 11 | * 12 | * Copyright (c) 2021 Roberto Gentili 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 15 | * documentation files (the "Software"), to deal in the Software without restriction, including without 16 | * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all copies or substantial 21 | * portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 24 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 25 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 27 | * OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | package org.burningwave.tools.net; 30 | 31 | import static org.burningwave.core.assembler.StaticComponentContainer.Driver; 32 | import static org.burningwave.core.assembler.StaticComponentContainer.Fields; 33 | import static org.burningwave.core.assembler.StaticComponentContainer.Strings; 34 | 35 | import java.io.ByteArrayInputStream; 36 | import java.io.ByteArrayOutputStream; 37 | import java.io.DataInputStream; 38 | import java.io.DataOutputStream; 39 | import java.io.IOException; 40 | import java.io.InputStream; 41 | import java.net.DatagramPacket; 42 | import java.net.DatagramSocket; 43 | import java.net.InetAddress; 44 | import java.net.UnknownHostException; 45 | import java.nio.ByteBuffer; 46 | import java.nio.charset.StandardCharsets; 47 | import java.util.ArrayList; 48 | import java.util.Arrays; 49 | import java.util.Collection; 50 | import java.util.LinkedHashMap; 51 | import java.util.List; 52 | import java.util.Map; 53 | import java.util.Map.Entry; 54 | import java.util.Random; 55 | import java.util.function.Supplier; 56 | 57 | import org.burningwave.core.function.ThrowingBiFunction; 58 | 59 | 60 | @SuppressWarnings("unchecked") 61 | public class DNSClientHostResolver implements HostResolver { 62 | public final static int DEFAULT_PORT; 63 | 64 | private static final String IPV6_DOMAIN; 65 | private static final String IPV4_DOMAIN; 66 | private static final short RECORD_TYPE_A; 67 | private static final short RECORD_TYPE_PTR; 68 | private static final short RECORD_TYPE_AAAA; 69 | 70 | public static final ThrowingBiFunction IPV4_RETRIEVER; 71 | public static final ThrowingBiFunction IPV6_RETRIEVER; 72 | 73 | static { 74 | DEFAULT_PORT = 53; 75 | IPV6_DOMAIN = "ip6.arpa."; 76 | IPV4_DOMAIN = "in-addr.arpa."; 77 | RECORD_TYPE_A = 1; 78 | RECORD_TYPE_PTR = 12; 79 | RECORD_TYPE_AAAA = 28; 80 | IPV4_RETRIEVER = (dNSServerHostResolver, hostName) -> 81 | dNSServerHostResolver.sendRequest(hostName, RECORD_TYPE_A); 82 | IPV6_RETRIEVER = (dNSServerHostResolver, hostName) -> 83 | dNSServerHostResolver.sendRequest(hostName, RECORD_TYPE_AAAA); 84 | } 85 | 86 | private ThrowingBiFunction[] resolveHostForNameRequestSenders; 87 | 88 | private static Random requestIdGenerator; 89 | 90 | static { 91 | requestIdGenerator = new Random(); 92 | } 93 | 94 | private InetAddress dNSServerIP; 95 | private int dNSServerPort; 96 | 97 | public DNSClientHostResolver(String dNSServerIP) { 98 | this(dNSServerIP, DEFAULT_PORT, IPV4_RETRIEVER, IPV6_RETRIEVER); 99 | } 100 | 101 | public DNSClientHostResolver(String dNSServerIP, int dNSServerPort) { 102 | this(dNSServerIP, dNSServerPort, IPV4_RETRIEVER, IPV6_RETRIEVER); 103 | } 104 | 105 | public DNSClientHostResolver(String dNSServerIP, ThrowingBiFunction... resolveHostForNameRequestSenders) { 106 | this(dNSServerIP, DEFAULT_PORT, resolveHostForNameRequestSenders); 107 | } 108 | 109 | public DNSClientHostResolver(String dNSServerIP, int dNSServerPort, ThrowingBiFunction... resolveHostForNameRequestSenders) { 110 | try { 111 | this.dNSServerIP = InetAddress.getByName(dNSServerIP); 112 | } catch (UnknownHostException exc) { 113 | Driver.throwException(exc); 114 | } 115 | this.dNSServerPort = dNSServerPort; 116 | this.resolveHostForNameRequestSenders = resolveHostForNameRequestSenders != null && resolveHostForNameRequestSenders.length > 0 ? 117 | resolveHostForNameRequestSenders : 118 | new ThrowingBiFunction[] {IPV4_RETRIEVER, IPV6_RETRIEVER}; 119 | } 120 | 121 | public static Collection newInstances(Supplier>> configuration) { 122 | Collection dNSClientHostResolvers = new ArrayList<>(); 123 | configuration.get().stream().forEach(serverMap -> 124 | dNSClientHostResolvers.add( 125 | new DNSClientHostResolver( 126 | (String)serverMap.get("ip"), 127 | (Integer)serverMap.getOrDefault("port", DEFAULT_PORT), 128 | ((List)serverMap.get("ipTypeToSearchFor")).stream() 129 | .map(ipType -> Fields.getStaticDirect(DNSClientHostResolver.class, Strings.compile("{}_RETRIEVER", ipType.toUpperCase()))) 130 | .map(ThrowingBiFunction.class::cast).toArray(size -> new ThrowingBiFunction[size]) 131 | ) 132 | ) 133 | ); 134 | return dNSClientHostResolvers; 135 | } 136 | 137 | @Override 138 | public Collection getAllAddressesForHostName(Map argumentMap) { 139 | return resolveHostForName((String)getMethodArguments(argumentMap)[0]); 140 | } 141 | 142 | public Collection resolveHostForName(String hostName) { 143 | try { 144 | Collection addresses = new ArrayList<>(); 145 | byte[][] responses = new byte[resolveHostForNameRequestSenders.length][]; 146 | for (int i = 0; i < resolveHostForNameRequestSenders.length; i++) { 147 | responses[i] = resolveHostForNameRequestSenders[i].apply(this, hostName); 148 | } 149 | Map iPToDomainMap = new LinkedHashMap<>(); 150 | for (byte[] response : responses) { 151 | iPToDomainMap.putAll(parseResponse(response)); 152 | } 153 | for (Entry iPToDomain : iPToDomainMap.entrySet()) { 154 | addresses.add(InetAddress.getByAddress(iPToDomain.getValue(), iPToDomain.getKey())); 155 | } 156 | return addresses; 157 | } catch (Throwable exc) { 158 | return Driver.throwException(exc); 159 | } 160 | } 161 | 162 | private byte[] sendRequest(String hostName, int recordType) throws IOException { 163 | short ID = (short)requestIdGenerator.nextInt(32767); 164 | try ( 165 | ByteArrayOutputStream requestContentStream = new ByteArrayOutputStream(); 166 | DataOutputStream requestWrapper = new DataOutputStream(requestContentStream); 167 | ) { 168 | short requestFlags = Short.parseShort("0000000100000000", 2); 169 | ByteBuffer byteBuffer = ByteBuffer.allocate(2).putShort(requestFlags); 170 | byte[] flagsByteArray = byteBuffer.array(); 171 | 172 | short QDCOUNT = 1; 173 | short ANCOUNT = 0; 174 | short NSCOUNT = 0; 175 | short ARCOUNT = 0; 176 | 177 | requestWrapper.writeShort(ID); 178 | requestWrapper.write(flagsByteArray); 179 | requestWrapper.writeShort(QDCOUNT); 180 | requestWrapper.writeShort(ANCOUNT); 181 | requestWrapper.writeShort(NSCOUNT); 182 | requestWrapper.writeShort(ARCOUNT); 183 | 184 | String[] domainParts = hostName.split("\\."); 185 | 186 | for (int i = 0; i < domainParts.length; i++) { 187 | byte[] domainBytes = domainParts[i].getBytes(StandardCharsets.UTF_8); 188 | requestWrapper.writeByte(domainBytes.length); 189 | requestWrapper.write(domainBytes); 190 | } 191 | requestWrapper.writeByte(0); 192 | requestWrapper.writeShort(recordType); 193 | requestWrapper.writeShort(1); 194 | byte[] dnsFrame = requestContentStream.toByteArray(); 195 | DatagramPacket packet; 196 | byte[] response; 197 | try (DatagramSocket socket = new DatagramSocket()){ 198 | DatagramPacket dnsReqPacket = new DatagramPacket(dnsFrame, dnsFrame.length, dNSServerIP, dNSServerPort); 199 | socket.send(dnsReqPacket); 200 | response = new byte[1024]; 201 | packet = new DatagramPacket(response, response.length); 202 | socket.receive(packet); 203 | } 204 | return response; 205 | } 206 | } 207 | 208 | private Map parseResponse(byte[] responseContent) throws IOException { 209 | try (InputStream responseContentStream = new ByteArrayInputStream(responseContent); 210 | DataInputStream responseWrapper = new DataInputStream(responseContentStream) 211 | ) { 212 | responseWrapper.skip(6); 213 | short ANCOUNT = responseWrapper.readShort(); 214 | responseWrapper.skip(4); 215 | int recLen; 216 | while ((recLen = responseWrapper.readByte()) > 0) { 217 | byte[] record = new byte[recLen]; 218 | for (int i = 0; i < recLen; i++) { 219 | record[i] = responseWrapper.readByte(); 220 | } 221 | } 222 | responseWrapper.skip(4); 223 | byte firstBytes = responseWrapper.readByte(); 224 | int firstTwoBits = (firstBytes & 0b11000000) >>> 6; 225 | Map valueToDomainMap = new LinkedHashMap<>(); 226 | try (ByteArrayOutputStream label = new ByteArrayOutputStream();) { 227 | for(int i = 0; i < ANCOUNT; i++) { 228 | if(firstTwoBits == 3) { 229 | byte currentByte = responseWrapper.readByte(); 230 | boolean stop = false; 231 | byte[] newArray = Arrays.copyOfRange(responseContent, currentByte, responseContent.length); 232 | try (InputStream responseSectionContentStream = new ByteArrayInputStream(newArray); 233 | DataInputStream responseSectionWrapper = new DataInputStream(responseSectionContentStream); 234 | ) { 235 | List RDATA = new ArrayList<>(); 236 | List DOMAINS = new ArrayList<>(); 237 | List labels = new ArrayList<>(); 238 | while(!stop) { 239 | byte nextByte = responseSectionWrapper.readByte(); 240 | if(nextByte != 0) { 241 | byte[] currentLabel = new byte[nextByte]; 242 | for(int j = 0; j < nextByte; j++) { 243 | currentLabel[j] = responseSectionWrapper.readByte(); 244 | } 245 | label.write(currentLabel); 246 | labels.add(currentLabel); 247 | } else { 248 | stop = true; 249 | responseWrapper.skip(8); 250 | int RDLENGTH = responseWrapper.readShort(); 251 | for(int s = 0; s < RDLENGTH; s++) { 252 | RDATA.add(responseWrapper.readByte()); 253 | } 254 | } 255 | DOMAINS.add(new String( label.toByteArray(), StandardCharsets.UTF_8)); 256 | label.reset(); 257 | } 258 | 259 | StringBuilder domainSb = new StringBuilder(); 260 | byte[] address = new byte[RDATA.size()]; 261 | for(int j = 0; j < RDATA.size(); j++) { 262 | address[j] = RDATA.get(j); 263 | } 264 | 265 | for(String domainPart:DOMAINS) { 266 | if(!domainPart.equals("")) { 267 | domainSb.append(domainPart).append("."); 268 | } 269 | } 270 | String domainFinal = domainSb.toString(); 271 | valueToDomainMap.put( 272 | address, 273 | domainFinal.substring(0, domainFinal.length()-1) 274 | ); 275 | } 276 | } 277 | firstBytes = responseWrapper.readByte(); 278 | firstTwoBits = (firstBytes & 0b11000000) >>> 6; 279 | } 280 | } 281 | return valueToDomainMap; 282 | } 283 | } 284 | 285 | 286 | @Override 287 | public Collection getAllHostNamesForHostAddress(Map argumentMap) { 288 | return resolveHostForAddress((byte[])getMethodArguments(argumentMap)[0]); 289 | } 290 | 291 | public Collection resolveHostForAddress(String iPAddress) { 292 | return resolveHostForAddress(IPAddressUtil.INSTANCE.textToNumericFormat(iPAddress)); 293 | } 294 | 295 | public Collection resolveHostForAddress(byte[] iPAddressAsBytes) { 296 | Map iPToDomainMap = new LinkedHashMap<>(); 297 | try { 298 | iPToDomainMap.putAll(parseResponse(sendRequest(iPAddressAsBytesToReversedString(iPAddressAsBytes), RECORD_TYPE_PTR))); 299 | } catch (IOException exc) { 300 | Driver.throwException(exc); 301 | } 302 | ArrayList domains = new ArrayList<>(); 303 | iPToDomainMap.forEach((key, value) -> { 304 | domains.add(hostNameAsBytesToString(key)); 305 | }); 306 | return domains; 307 | } 308 | 309 | private String iPAddressAsBytesToReversedString(byte[] iPAddressAsByte) { 310 | if (iPAddressAsByte.length != 4 && iPAddressAsByte.length != 16) { 311 | throw new IllegalArgumentException("array must contain 4 or 16 elements"); 312 | } 313 | 314 | StringBuilder sb = new StringBuilder(); 315 | if (iPAddressAsByte.length == 4) { 316 | for (int i = iPAddressAsByte.length - 1; i >= 0; i--) { 317 | sb.append(iPAddressAsByte[i] & 0xFF); 318 | if (i > 0) { 319 | sb.append("."); 320 | } 321 | } 322 | } else { 323 | int[] pieces = new int[2]; 324 | for (int i = iPAddressAsByte.length - 1; i >= 0; i--) { 325 | pieces[0] = (iPAddressAsByte[i] & 0xFF) >> 4; 326 | pieces[1] = iPAddressAsByte[i] & 0xF; 327 | for (int j = pieces.length - 1; j >= 0; j--) { 328 | sb.append(Integer.toHexString(pieces[j])); 329 | if (i > 0 || j > 0) { 330 | sb.append("."); 331 | } 332 | } 333 | } 334 | } 335 | if (iPAddressAsByte.length == 4) { 336 | return sb.toString() + "." + IPV4_DOMAIN; 337 | } else { 338 | return sb.toString() + "." + IPV6_DOMAIN; 339 | } 340 | } 341 | 342 | private String hostNameAsBytesToString(byte[] hostNameAsBytes) { 343 | StringBuilder sb = new StringBuilder(); 344 | int position = 0; 345 | while (true) { 346 | int len = hostNameAsBytes[position++]; 347 | for (int i = position; i < position + len; i++) { 348 | int b = hostNameAsBytes[i] & 0xFF; 349 | if (b <= 0x20 || b >= 0x7f) { 350 | sb.append('\\'); 351 | if (b < 10) { 352 | sb.append("00"); 353 | } else if (b < 100) { 354 | sb.append('0'); 355 | } 356 | sb.append(b); 357 | } else if (b == '"' || b == '(' || b == ')' || b == '.' || b == ';' || b == '\\' || b == '@' || b == '$') { 358 | sb.append('\\'); 359 | sb.append((char) b); 360 | } else { 361 | sb.append((char) b); 362 | } 363 | } 364 | position += len; 365 | if (position < hostNameAsBytes.length && hostNameAsBytes[position] != 0) { 366 | sb.append("."); 367 | } else { 368 | break; 369 | } 370 | } 371 | return sb.toString(); 372 | } 373 | } -------------------------------------------------------------------------------- /src/main/java/org/burningwave/tools/net/DefaultHostResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Burningwave Tools. 3 | * 4 | * Author: Roberto Gentili 5 | * 6 | * Hosted at: https://github.com/burningwave/tools 7 | * 8 | * -- 9 | * 10 | * The MIT License (MIT) 11 | * 12 | * Copyright (c) 2021 Roberto Gentili 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 15 | * documentation files (the "Software"), to deal in the Software without restriction, including without 16 | * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all copies or substantial 21 | * portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 24 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 25 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 27 | * OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | package org.burningwave.tools.net; 30 | 31 | import static org.burningwave.core.assembler.StaticComponentContainer.Driver; 32 | import static org.burningwave.core.assembler.StaticComponentContainer.Fields; 33 | import static org.burningwave.core.assembler.StaticComponentContainer.Methods; 34 | import static org.burningwave.core.assembler.StaticComponentContainer.Strings; 35 | 36 | import java.lang.reflect.Field; 37 | import java.lang.reflect.Method; 38 | import java.lang.reflect.ParameterizedType; 39 | import java.net.InetAddress; 40 | import java.net.UnknownHostException; 41 | import java.util.ArrayList; 42 | import java.util.Collection; 43 | import java.util.List; 44 | import java.util.Map; 45 | import java.util.concurrent.CopyOnWriteArrayList; 46 | import java.util.function.Function; 47 | import java.util.stream.Stream; 48 | 49 | import org.burningwave.core.classes.FieldCriteria; 50 | import org.burningwave.core.classes.MethodCriteria; 51 | 52 | import io.github.toolfactory.jvm.function.InitializeException; 53 | 54 | @SuppressWarnings("unchecked") 55 | public class DefaultHostResolver implements HostResolver { 56 | public final static HostResolver INSTANCE; 57 | static final Class inetAddressClass; 58 | static final Field nameServiceField; 59 | static final Class nameServiceFieldClass; 60 | static final Class nameServiceClass; 61 | static final Method getAllAddressesForHostNameMethod; 62 | static final Method getAllHostNamesForHostAddressMethod; 63 | static final List nameServices; 64 | private static final Function> inetAddressSupplier; 65 | 66 | static { 67 | inetAddressClass = InetAddress.class; 68 | nameServiceField = Fields.findFirst( 69 | FieldCriteria.withoutConsideringParentClasses().name(fieldName -> 70 | fieldName.equals("nameService") || fieldName.equals("nameServices") || fieldName.equals("resolver") 71 | ), 72 | inetAddressClass 73 | ); 74 | nameServiceFieldClass = nameServiceField.getType(); 75 | nameServiceClass = getNameServiceFieldClass(nameServiceField); 76 | getAllAddressesForHostNameMethod = Methods.findFirst( 77 | MethodCriteria.forEntireClassHierarchy().name(methodName -> 78 | methodName.equals("lookupAllHostAddr") || methodName.equals("lookupByName") 79 | ), 80 | nameServiceClass 81 | ); 82 | inetAddressSupplier = getAllAddressesForHostNameMethod.getReturnType().equals(InetAddress[].class) ? 83 | obj -> 84 | Stream.of((InetAddress[])obj) : 85 | obj -> 86 | (Stream)obj; 87 | getAllHostNamesForHostAddressMethod = Methods.findFirst( 88 | MethodCriteria.forEntireClassHierarchy().name(methodName -> 89 | methodName.equals("getHostByAddr") || methodName.equals("lookupByAddress") 90 | ), 91 | nameServiceClass 92 | ); 93 | nameServices = getNameServices(); 94 | if (nameServices.isEmpty()) { 95 | Driver.throwException( 96 | new InitializeException( 97 | Strings.compile( 98 | "No items found for field {}.{}", 99 | nameServiceField.getDeclaringClass(), 100 | nameServiceField.getName() 101 | ) 102 | ) 103 | ); 104 | } 105 | INSTANCE = new DefaultHostResolver(); 106 | } 107 | 108 | public DefaultHostResolver() {} 109 | 110 | private static Class getNameServiceFieldClass(Field nameServiceField) { 111 | if (Collection.class.isAssignableFrom(nameServiceField.getType())) { 112 | ParameterizedType stringListType = (ParameterizedType) nameServiceField.getGenericType(); 113 | return (Class) stringListType.getActualTypeArguments()[0]; 114 | } else { 115 | return nameServiceField.getType(); 116 | } 117 | } 118 | 119 | private static List getNameServices() { 120 | try { 121 | //Initializing the nameServiceField 122 | InetAddress.getAllByName("localhost"); 123 | } catch (UnknownHostException ecc) {} 124 | List nameServices = new CopyOnWriteArrayList<>(); 125 | if (Collection.class.isAssignableFrom(nameServiceFieldClass)) { 126 | nameServices.addAll(Fields.getStaticDirect(nameServiceField)); 127 | } else { 128 | Object nameService = Fields.getStaticDirect(nameServiceField); 129 | if (nameService != null) { 130 | nameServices.add(nameService); 131 | } 132 | } 133 | return nameServices; 134 | } 135 | 136 | @Override 137 | public Collection getAllAddressesForHostName(Map argumentMap) { 138 | Object[] arguments = getMethodArguments(argumentMap); 139 | List nameServices = (List)argumentMap.get("nameServices"); 140 | if (nameServices == null) { 141 | nameServices = DefaultHostResolver.nameServices; 142 | } 143 | Collection addresses = new ArrayList<>(); 144 | for (Object nameService : nameServices) { 145 | if (nameService != null) { 146 | try { 147 | Object inetAddresses = Methods.invokeDirect(nameService, getAllAddressesForHostNameMethod.getName(), arguments); 148 | if (inetAddresses != null) { 149 | inetAddressSupplier.apply(inetAddresses).forEach(addresses::add); 150 | } 151 | } catch (Throwable exc) { 152 | if (!(exc instanceof UnknownHostException)) { 153 | throw exc; 154 | } 155 | } 156 | } 157 | } 158 | return addresses; 159 | } 160 | 161 | @Override 162 | public Collection getAllHostNamesForHostAddress(Map argumentMap) { 163 | Object[] arguments = getMethodArguments(argumentMap); 164 | List nameServices = (List)argumentMap.get("nameServices"); 165 | if (nameServices == null) { 166 | nameServices = DefaultHostResolver.nameServices; 167 | } 168 | Collection hostNames = new ArrayList<>(); 169 | for (Object nameService : nameServices) { 170 | if (nameService != null) { 171 | try { 172 | String hostName = Methods.invokeDirect(nameService, getAllHostNamesForHostAddressMethod.getName(), arguments); 173 | if (hostName != null) { 174 | hostNames.add(hostName); 175 | } 176 | } catch (Throwable exc) { 177 | if (!(exc instanceof UnknownHostException)) { 178 | throw exc; 179 | } 180 | } 181 | } 182 | } 183 | return hostNames; 184 | } 185 | 186 | @Override 187 | public Object handle(Method method, Object... arguments) throws Throwable { 188 | for (Object nameService : nameServices) { 189 | if (nameService != null) { 190 | Object toRet = Methods.invokeDirect(nameService, method.getName(), arguments); 191 | if (toRet != null) { 192 | return toRet; 193 | } 194 | } 195 | } 196 | return null; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/main/java/org/burningwave/tools/net/HostResolutionRequestInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Burningwave Tools. 3 | * 4 | * Author: Roberto Gentili 5 | * 6 | * Hosted at: https://github.com/burningwave/tools 7 | * 8 | * -- 9 | * 10 | * The MIT License (MIT) 11 | * 12 | * Copyright (c) 2021 Roberto Gentili 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 15 | * documentation files (the "Software"), to deal in the Software without restriction, including without 16 | * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all copies or substantial 21 | * portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 24 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 25 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 27 | * OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | package org.burningwave.tools.net; 30 | 31 | import static org.burningwave.core.assembler.StaticComponentContainer.Fields; 32 | import static org.burningwave.core.assembler.StaticComponentContainer.Methods; 33 | import static org.burningwave.core.assembler.StaticComponentContainer.Strings; 34 | 35 | import java.lang.reflect.Field; 36 | import java.lang.reflect.InvocationHandler; 37 | import java.lang.reflect.Proxy; 38 | import java.net.InetAddress; 39 | import java.net.UnknownHostException; 40 | import java.util.ArrayList; 41 | import java.util.Arrays; 42 | import java.util.Collection; 43 | import java.util.LinkedHashMap; 44 | import java.util.List; 45 | import java.util.Map; 46 | import java.util.function.Function; 47 | 48 | import org.burningwave.core.classes.FieldCriteria; 49 | 50 | public class HostResolutionRequestInterceptor { 51 | public static final HostResolutionRequestInterceptor INSTANCE; 52 | private static final Function proxySupplier; 53 | private static final Function, Object> getAllAddressesForHostNameResultConverter; 54 | private static final Object cacheOne; 55 | private static final Object cacheTwo; 56 | 57 | Collection resolvers; 58 | 59 | 60 | static { 61 | proxySupplier = Collection.class.isAssignableFrom(DefaultHostResolver.nameServiceFieldClass) ? 62 | HostResolutionRequestInterceptor::buildProxies: 63 | HostResolutionRequestInterceptor::buildProxy; 64 | Field cacheOneField = Fields.findOne(FieldCriteria.withoutConsideringParentClasses().name(fieldName -> { 65 | return fieldName.equals("cache") || fieldName.equals("addressCache"); 66 | }), DefaultHostResolver.inetAddressClass); 67 | if (cacheOneField.getName().equals("addressCache")) { 68 | cacheOne = Fields.getDirect(Fields.getStaticDirect(cacheOneField), "cache"); 69 | cacheTwo = Fields.getDirect(Fields.getStaticDirect(DefaultHostResolver.inetAddressClass, "negativeCache"), "cache"); 70 | } else { 71 | cacheOne = Fields.getStaticDirect(DefaultHostResolver.inetAddressClass, "cache"); 72 | cacheTwo = Fields.getStaticDirect(DefaultHostResolver.inetAddressClass, "expirySet"); 73 | } 74 | getAllAddressesForHostNameResultConverter = DefaultHostResolver.getAllAddressesForHostNameMethod.getReturnType().equals(InetAddress[].class) ? 75 | addresses -> 76 | addresses.toArray(new InetAddress[addresses.size()]) : 77 | addresses -> 78 | addresses.stream(); 79 | INSTANCE = new HostResolutionRequestInterceptor(); 80 | } 81 | 82 | private HostResolutionRequestInterceptor() {} 83 | 84 | public HostResolutionRequestInterceptor install(HostResolver... resolvers) { 85 | return install(-1, 250, resolvers); 86 | } 87 | 88 | public HostResolutionRequestInterceptor install(long timeout, long sleepingTime, HostResolver... resolvers) { 89 | this.resolvers = checkResolvers(resolvers); 90 | synchronized (DefaultHostResolver.nameServices) { 91 | Fields.setStaticDirect( 92 | DefaultHostResolver.nameServiceField, 93 | proxySupplier.apply(this) 94 | ); 95 | } 96 | this.resolvers.stream().filter(MappedHostResolver.class::isInstance).findFirst() 97 | .map(MappedHostResolver.class::cast).ifPresent(hostResolver -> { 98 | Long startTime = System.currentTimeMillis(); 99 | Long expirationTime = startTime + timeout; 100 | while (!hostResolver.isReady(this) && (timeout < 0 || expirationTime > System.currentTimeMillis())) { 101 | try { 102 | Thread.sleep(sleepingTime); 103 | } catch (InterruptedException exc) {} 104 | } 105 | }); 106 | return this; 107 | } 108 | 109 | public HostResolutionRequestInterceptor uninstall() { 110 | Object nameServices; 111 | if (Collection.class.isAssignableFrom(DefaultHostResolver.nameServiceFieldClass)) { 112 | nameServices = DefaultHostResolver.nameServices; 113 | } else { 114 | nameServices = DefaultHostResolver.nameServices.iterator().next(); 115 | } 116 | synchronized (DefaultHostResolver.nameServices) { 117 | Fields.setStaticDirect(DefaultHostResolver.nameServiceField, nameServices); 118 | clearCache(); 119 | } 120 | return this; 121 | } 122 | 123 | public void clearCache() { 124 | synchronized (DefaultHostResolver.nameServices) { 125 | Methods.invokeDirect(cacheOne, "clear"); 126 | Methods.invokeDirect(cacheTwo, "clear"); 127 | } 128 | } 129 | 130 | private Collection checkResolvers(HostResolver[] resolvers) { 131 | if (resolvers == null || resolvers.length < 1) { 132 | throw new IllegalArgumentException("Resolvers are required"); 133 | } 134 | Collection resolverList = new ArrayList<>(); 135 | for (int index = 0; index < resolvers.length; index++) { 136 | if (resolvers[index] == null) { 137 | throw new IllegalArgumentException(Strings.compile("Resolver at index [{}] is null", index)); 138 | } 139 | resolverList.add(resolvers[index]); 140 | } 141 | return resolverList; 142 | } 143 | 144 | private List buildProxies() { 145 | List proxies = new ArrayList<>(); 146 | for (HostResolver resolver : resolvers) { 147 | if (resolver instanceof DefaultHostResolver) { 148 | for (Object nameService : DefaultHostResolver.nameServices) { 149 | proxies.add( 150 | Proxy.newProxyInstance( 151 | DefaultHostResolver.nameServiceClass.getClassLoader(), 152 | new Class[] { DefaultHostResolver.nameServiceClass }, 153 | buildOneToOneInvocationHandler(resolver, nameService) 154 | ) 155 | ); 156 | } 157 | } else { 158 | proxies.add( 159 | Proxy.newProxyInstance( 160 | DefaultHostResolver.nameServiceClass.getClassLoader(), 161 | new Class[] { DefaultHostResolver.nameServiceClass }, 162 | buildOneToOneInvocationHandler(resolver, null) 163 | ) 164 | ); 165 | } 166 | } 167 | return proxies; 168 | } 169 | 170 | public InvocationHandler buildOneToOneInvocationHandler(HostResolver resolver, Object nameService) { 171 | Function> argumentMapBuilder = 172 | nameService != null ? 173 | arguments -> { 174 | Map argumentMap = buildArgumentMap(arguments); 175 | argumentMap.put("nameServices", Arrays.asList(nameService)); 176 | return argumentMap; 177 | }: 178 | this::buildArgumentMap; 179 | 180 | return (proxy, method, arguments) -> { 181 | String methodName = method.getName(); 182 | if (methodName.equals(DefaultHostResolver.getAllAddressesForHostNameMethod.getName())) { 183 | return getAllAddressesForHostNameResultConverter.apply( 184 | resolver.checkAndGetAllAddressesForHostName(argumentMapBuilder.apply(arguments)) 185 | ); 186 | } else if (methodName.equals(DefaultHostResolver.getAllHostNamesForHostAddressMethod.getName())) { 187 | return resolver.checkAndGetAllHostNamesForHostAddress(argumentMapBuilder.apply(arguments)).iterator().next(); 188 | } 189 | Object toRet = resolver.handle(method, arguments); 190 | if (toRet != null) { 191 | return toRet; 192 | } 193 | throw new UnsupportedOperationException(method.getName() + " is not supported"); 194 | }; 195 | } 196 | 197 | private Object buildProxy() { 198 | return Proxy.newProxyInstance( 199 | DefaultHostResolver.nameServiceClass.getClassLoader(), 200 | new Class[] { DefaultHostResolver.nameServiceClass }, 201 | (proxy, method, arguments) -> { 202 | String methodName = method.getName(); 203 | if (methodName.equals(DefaultHostResolver.getAllAddressesForHostNameMethod.getName())) { 204 | return getAllAddressesForHostName(arguments); 205 | } else if (methodName.equals(DefaultHostResolver.getAllHostNamesForHostAddressMethod.getName())) { 206 | return getAllHostNamesForHostAddress(arguments).iterator().next(); 207 | } 208 | for (HostResolver resolver : resolvers) { 209 | Object toRet = resolver.handle(method, arguments); 210 | if (toRet != null) { 211 | return toRet; 212 | } 213 | } 214 | throw new UnsupportedOperationException(method.getName() + " is not supported"); 215 | } 216 | ); 217 | } 218 | 219 | private Object getAllAddressesForHostName( 220 | Object... args 221 | ) throws Throwable { 222 | Collection addresses = new ArrayList<>(); 223 | Map argumentMap = buildArgumentMap(args); 224 | for (HostResolver resolver : resolvers) { 225 | try { 226 | addresses.addAll(resolver.checkAndGetAllAddressesForHostName(argumentMap)); 227 | } catch (UnknownHostException exc) { 228 | 229 | } 230 | } 231 | if (addresses.isEmpty()) { 232 | throw new UnknownHostException((String)args[0]); 233 | } 234 | return getAllAddressesForHostNameResultConverter.apply(addresses); 235 | } 236 | 237 | private Map buildArgumentMap(Object[] args) { 238 | Map arguments = new LinkedHashMap<>(); 239 | arguments.put("methodArguments", args); 240 | return arguments; 241 | } 242 | 243 | 244 | private Collection getAllHostNamesForHostAddress( 245 | Object... args 246 | ) throws Throwable { 247 | Collection hostNames = new ArrayList<>(); 248 | Map argumentMap = buildArgumentMap(args); 249 | for (HostResolver resolver : resolvers) { 250 | try { 251 | hostNames.addAll(resolver.checkAndGetAllHostNamesForHostAddress(argumentMap)); 252 | } catch (UnknownHostException exc) { 253 | 254 | } 255 | } 256 | if (hostNames.isEmpty()) { 257 | throw new UnknownHostException(IPAddressUtil.INSTANCE.numericToTextFormat((byte[])args[0])); 258 | } 259 | return hostNames; 260 | } 261 | 262 | } -------------------------------------------------------------------------------- /src/main/java/org/burningwave/tools/net/HostResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Burningwave Tools. 3 | * 4 | * Author: Roberto Gentili 5 | * 6 | * Hosted at: https://github.com/burningwave/tools 7 | * 8 | * -- 9 | * 10 | * The MIT License (MIT) 11 | * 12 | * Copyright (c) 2021 Roberto Gentili 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 15 | * documentation files (the "Software"), to deal in the Software without restriction, including without 16 | * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all copies or substantial 21 | * portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 24 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 25 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 27 | * OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | package org.burningwave.tools.net; 30 | 31 | import java.lang.reflect.Method; 32 | import java.net.InetAddress; 33 | import java.net.UnknownHostException; 34 | import java.util.Collection; 35 | import java.util.Map; 36 | 37 | public interface HostResolver { 38 | 39 | public default Collection checkAndGetAllAddressesForHostName(Map argumentMap) throws UnknownHostException { 40 | String hostName = (String)getMethodArguments(argumentMap)[0]; 41 | Collection addresses = getAllAddressesForHostName(argumentMap); 42 | if (addresses.isEmpty()) { 43 | throw new UnknownHostException(hostName); 44 | } 45 | return addresses; 46 | } 47 | 48 | public default Collection checkAndGetAllHostNamesForHostAddress(Map argumentMap) throws UnknownHostException { 49 | byte[] address = (byte[])getMethodArguments(argumentMap)[0]; 50 | Collection hostNames = getAllHostNamesForHostAddress(argumentMap); 51 | if (hostNames.isEmpty()) { 52 | throw new UnknownHostException(IPAddressUtil.INSTANCE.numericToTextFormat(address)); 53 | } 54 | return hostNames; 55 | } 56 | 57 | public Collection getAllAddressesForHostName(Map arguments); 58 | 59 | public Collection getAllHostNamesForHostAddress(Map arguments); 60 | 61 | public default boolean isReady(HostResolutionRequestInterceptor hostResolverService) { 62 | return hostResolverService.resolvers.contains(this); 63 | } 64 | 65 | public default Object handle(Method method, Object... arguments) throws Throwable { 66 | throw new UnsupportedOperationException(method.getName() + " is not supported"); 67 | } 68 | 69 | public default Object[] getMethodArguments(Map arguments) { 70 | return (Object[])arguments.get("methodArguments"); 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/org/burningwave/tools/net/IPAddressUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Burningwave Tools. 3 | * 4 | * Author: Roberto Gentili 5 | * 6 | * Hosted at: https://github.com/burningwave/tools 7 | * 8 | * -- 9 | * 10 | * The MIT License (MIT) 11 | * 12 | * Copyright (c) 2021 Roberto Gentili 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 15 | * documentation files (the "Software"), to deal in the Software without restriction, including without 16 | * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all copies or substantial 21 | * portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 24 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 25 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 27 | * OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | package org.burningwave.tools.net; 30 | 31 | import static org.burningwave.core.assembler.StaticComponentContainer.Strings; 32 | 33 | import java.util.ArrayList; 34 | import java.util.List; 35 | import java.util.stream.Collectors; 36 | 37 | public class IPAddressUtil { 38 | public static final IPAddressUtil INSTANCE; 39 | 40 | private static final int IPV4_SIZE = 4; 41 | private static final int IPV6_SIZE = 16; 42 | private static final int INT_16_SIZE = 2; 43 | 44 | static { 45 | INSTANCE = new IPAddressUtil(); 46 | } 47 | 48 | private IPAddressUtil() {} 49 | 50 | public byte[] textToNumericFormat(String ip) { 51 | byte[] address = textToNumericFormatV4(ip); 52 | if (address != null) { 53 | return address; 54 | } 55 | return textToNumericFormatV6(ip); 56 | } 57 | 58 | public String numericToTextFormat(byte[] address) { 59 | if (address.length == IPV4_SIZE) { 60 | return numericToTextFormatV4(address); 61 | } else if (address.length == IPV6_SIZE) { 62 | return numericToTextFormatV6(address); 63 | } 64 | throw new IllegalArgumentException(Strings.compile("[{}] is not a valid ip address", String.join(",", convertToList(address).stream().map(value -> value.toString()).collect(Collectors.toList())))); 65 | } 66 | 67 | String numericToTextFormatV4(byte[] src) { 68 | int i = src.length; 69 | StringBuilder ipAddress = new StringBuilder(); 70 | for (byte raw : src) { 71 | ipAddress.append(raw & 0xFF); 72 | if (--i > 0) { 73 | ipAddress.append("."); 74 | } 75 | } 76 | return ipAddress.toString(); 77 | } 78 | 79 | String numericToTextFormatV6(byte[] src) { 80 | StringBuilder sb = new StringBuilder(39); 81 | for (int i = 0; i < (IPV6_SIZE / INT_16_SIZE); i++) { 82 | sb.append(Integer.toHexString(((src[i<<1]<<8) & 0xff00) 83 | | (src[(i<<1)+1] & 0xff))); 84 | if (i < (IPV6_SIZE / INT_16_SIZE) -1 ) { 85 | sb.append(":"); 86 | } 87 | } 88 | return sb.toString(); 89 | } 90 | 91 | byte[] textToNumericFormatV6(String src) { 92 | if (src.length() < 2) { 93 | return null; 94 | } 95 | 96 | int colonp; 97 | char ch; 98 | boolean sawXDigit; 99 | int val; 100 | char[] srcb = src.toCharArray(); 101 | byte[] dst = new byte[IPV6_SIZE]; 102 | 103 | int srcbLength = srcb.length; 104 | int pc = src.indexOf("%"); 105 | if (pc == srcbLength - 1) { 106 | return null; 107 | } 108 | if (pc != -1) { 109 | srcbLength = pc; 110 | } 111 | colonp = -1; 112 | int i = 0; 113 | int j = 0; 114 | if (srcb[i] == ':' && srcb[++i] != ':') { 115 | return null; 116 | } 117 | int curtok = i; 118 | sawXDigit = false; 119 | val = 0; 120 | while (i < srcbLength) { 121 | ch = srcb[i++]; 122 | int chval = Character.digit(ch, 16); 123 | if (chval != -1) { 124 | val <<= 4; 125 | val |= chval; 126 | if (val > 0xffff) { 127 | return null; 128 | } 129 | sawXDigit = true; 130 | continue; 131 | } 132 | if (ch == ':') { 133 | curtok = i; 134 | if (!sawXDigit) { 135 | if (colonp != -1) { 136 | return null; 137 | } 138 | colonp = j; 139 | continue; 140 | } else if (i == srcbLength) { 141 | return null; 142 | } 143 | if (j + INT_16_SIZE > IPV6_SIZE) { 144 | return null; 145 | } 146 | dst[j++] = (byte) ((val >> 8) & 0xff); 147 | dst[j++] = (byte) (val & 0xff); 148 | sawXDigit = false; 149 | val = 0; 150 | continue; 151 | } 152 | if (ch == '.' && ((j + IPV4_SIZE) <= IPV6_SIZE)) { 153 | String ia4 = src.substring(curtok, srcbLength); 154 | int dotCount = 0; 155 | int index = 0; 156 | while ((index = ia4.indexOf('.', index)) != -1) { 157 | dotCount++; 158 | index++; 159 | } 160 | if (dotCount != 3) { 161 | return null; 162 | } 163 | byte[] v4addr = textToNumericFormatV4(ia4); 164 | if (v4addr == null) { 165 | return null; 166 | } 167 | for (int k = 0; k < IPV4_SIZE; k++) { 168 | dst[j++] = v4addr[k]; 169 | } 170 | sawXDigit = false; 171 | break; 172 | } 173 | return null; 174 | } 175 | if (sawXDigit) { 176 | if (j + INT_16_SIZE > IPV6_SIZE) { 177 | return null; 178 | } 179 | dst[j++] = (byte) ((val >> 8) & 0xff); 180 | dst[j++] = (byte) (val & 0xff); 181 | } 182 | 183 | if (colonp != -1) { 184 | int n = j - colonp; 185 | if (j == IPV6_SIZE) { 186 | return null; 187 | } 188 | for (i = 1; i <= n; i++) { 189 | dst[IPV6_SIZE - i] = dst[colonp + n - i]; 190 | dst[colonp + n - i] = 0; 191 | } 192 | j = IPV6_SIZE; 193 | } 194 | if (j != IPV6_SIZE) { 195 | return null; 196 | } 197 | byte[] newdst = convertFromIPv4MappedAddress(dst); 198 | if (newdst != null) { 199 | return newdst; 200 | } else { 201 | return dst; 202 | } 203 | } 204 | 205 | byte[] textToNumericFormatV4(String src) { 206 | if (src.length() == 0) { 207 | return null; 208 | } 209 | 210 | byte[] res = new byte[IPV4_SIZE]; 211 | String[] s = src.split("\\.", -1); 212 | long val; 213 | try { 214 | switch (s.length) { 215 | case 1: 216 | val = Long.parseLong(s[0]); 217 | if (val < 0 || val > 0xffffffffL) 218 | return null; 219 | res[0] = (byte) ((val >> 24) & 0xff); 220 | res[1] = (byte) (((val & 0xffffff) >> 16) & 0xff); 221 | res[2] = (byte) (((val & 0xffff) >> 8) & 0xff); 222 | res[3] = (byte) (val & 0xff); 223 | break; 224 | case 2: 225 | val = Integer.parseInt(s[0]); 226 | if (val < 0 || val > 0xff) 227 | return null; 228 | res[0] = (byte) (val & 0xff); 229 | val = Integer.parseInt(s[1]); 230 | if (val < 0 || val > 0xffffff) 231 | return null; 232 | res[1] = (byte) ((val >> 16) & 0xff); 233 | res[2] = (byte) (((val & 0xffff) >> 8) & 0xff); 234 | res[3] = (byte) (val & 0xff); 235 | break; 236 | case 3: 237 | for (int i = 0; i < 2; i++) { 238 | val = Integer.parseInt(s[i]); 239 | if (val < 0 || val > 0xff) 240 | return null; 241 | res[i] = (byte) (val & 0xff); 242 | } 243 | val = Integer.parseInt(s[2]); 244 | if (val < 0 || val > 0xffff) 245 | return null; 246 | res[2] = (byte) ((val >> 8) & 0xff); 247 | res[3] = (byte) (val & 0xff); 248 | break; 249 | case 4: 250 | for (int i = 0; i < 4; i++) { 251 | val = Integer.parseInt(s[i]); 252 | if (val < 0 || val > 0xff) 253 | return null; 254 | res[i] = (byte) (val & 0xff); 255 | } 256 | break; 257 | default: 258 | return null; 259 | } 260 | } catch (NumberFormatException e) { 261 | return null; 262 | } 263 | return res; 264 | } 265 | 266 | byte[] convertFromIPv4MappedAddress(byte[] addr) { 267 | if (isIPv4MappedAddress(addr)) { 268 | byte[] newAddr = new byte[IPV4_SIZE]; 269 | System.arraycopy(addr, 12, newAddr, 0, IPV4_SIZE); 270 | return newAddr; 271 | } 272 | return null; 273 | } 274 | 275 | boolean isIPv4MappedAddress(byte[] addr) { 276 | if (addr.length < IPV6_SIZE) { 277 | return false; 278 | } 279 | return ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00) && (addr[4] == 0x00) 280 | && (addr[5] == 0x00) && (addr[6] == 0x00) && (addr[7] == 0x00) && (addr[8] == 0x00) 281 | && (addr[9] == 0x00) && (addr[10] == (byte) 0xff) && (addr[11] == (byte) 0xff)); 282 | } 283 | 284 | private List convertToList(byte[] bytes) { 285 | final List list = new ArrayList<>(); 286 | for (byte b : bytes) { 287 | list.add(b); 288 | } 289 | return list; 290 | } 291 | 292 | } -------------------------------------------------------------------------------- /src/main/java/org/burningwave/tools/net/MappedHostResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Burningwave Tools. 3 | * 4 | * Author: Roberto Gentili 5 | * 6 | * Hosted at: https://github.com/burningwave/tools 7 | * 8 | * -- 9 | * 10 | * The MIT License (MIT) 11 | * 12 | * Copyright (c) 2021 Roberto Gentili 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 15 | * documentation files (the "Software"), to deal in the Software without restriction, including without 16 | * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all copies or substantial 21 | * portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 24 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 25 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 27 | * OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | package org.burningwave.tools.net; 30 | 31 | import java.net.InetAddress; 32 | import java.net.UnknownHostException; 33 | import java.util.ArrayList; 34 | import java.util.Arrays; 35 | import java.util.Collection; 36 | import java.util.Iterator; 37 | import java.util.LinkedHashMap; 38 | import java.util.List; 39 | import java.util.Map; 40 | import java.util.UUID; 41 | import java.util.function.Supplier; 42 | 43 | @SuppressWarnings("unchecked") 44 | public class MappedHostResolver implements HostResolver { 45 | protected Map hostAliases; 46 | 47 | @SafeVarargs 48 | public MappedHostResolver(Supplier>>... hostAliasesYAMLFormatSuppliers) { 49 | this(Arrays.asList(hostAliasesYAMLFormatSuppliers)); 50 | } 51 | 52 | public MappedHostResolver(Collection>>> hostAliasesYAMLFormatSuppliers) { 53 | Map hostAliases = new LinkedHashMap<>(); 54 | for (Supplier>> hostAliasesYAMLFormatSupplier : hostAliasesYAMLFormatSuppliers) { 55 | for (Map addressesForIp : hostAliasesYAMLFormatSupplier.get()) { 56 | String iPAddress = (String)addressesForIp.get("ip"); 57 | Collection hostNames = (Collection)addressesForIp.get("hostnames"); 58 | for (String hostName : hostNames) { 59 | hostAliases.put(hostName, iPAddress); 60 | } 61 | } 62 | } 63 | this.hostAliases = hostAliases; 64 | } 65 | 66 | public MappedHostResolver(Map hostAliases) { 67 | this.hostAliases = new LinkedHashMap<>(hostAliases); 68 | } 69 | 70 | 71 | @Override 72 | public Collection getAllAddressesForHostName(Map argumentMap) { 73 | String hostName = (String)getMethodArguments(argumentMap)[0]; 74 | Collection addresses = new ArrayList<>(); 75 | String iPAddress = hostAliases.get(hostName); 76 | if (iPAddress != null) { 77 | try { 78 | addresses.add(InetAddress.getByAddress(hostName, IPAddressUtil.INSTANCE.textToNumericFormat(iPAddress))); 79 | } catch (UnknownHostException e) { 80 | 81 | } 82 | } 83 | return addresses; 84 | } 85 | 86 | @Override 87 | public Collection getAllHostNamesForHostAddress(Map argumentMap) { 88 | byte[] address = (byte[])getMethodArguments(argumentMap)[0]; 89 | Collection hostNames = new ArrayList<>(); 90 | String iPAddress = IPAddressUtil.INSTANCE.numericToTextFormat(address); 91 | for (Map.Entry addressForIp : hostAliases.entrySet()) { 92 | if (addressForIp.getValue().equals(iPAddress)) { 93 | hostNames.add(addressForIp.getKey()); 94 | } 95 | } 96 | return hostNames; 97 | } 98 | 99 | public synchronized MappedHostResolver putHost(String hostname, String iP) { 100 | Map hostAliases = new LinkedHashMap<>(this.hostAliases); 101 | hostAliases.put(hostname, iP); 102 | this.hostAliases = hostAliases; 103 | return this; 104 | } 105 | 106 | public synchronized MappedHostResolver removeHost(String hostname) { 107 | Map hostAliases = new LinkedHashMap<>(this.hostAliases); 108 | hostAliases.remove(hostname); 109 | this.hostAliases = hostAliases; 110 | return this; 111 | } 112 | 113 | public synchronized MappedHostResolver removeHostForIP(String iP) { 114 | Map hostAliases = new LinkedHashMap<>(this.hostAliases); 115 | Iterator> hostAliasesIterator = hostAliases.entrySet().iterator(); 116 | while (hostAliasesIterator.hasNext()) { 117 | Map.Entry host = hostAliasesIterator.next(); 118 | if (host.getValue().equals(iP)) { 119 | hostAliasesIterator.remove(); 120 | } 121 | } 122 | this.hostAliases = hostAliases; 123 | return this; 124 | } 125 | 126 | @Override 127 | public boolean isReady(HostResolutionRequestInterceptor hostResolverService) { 128 | return HostResolver.super.isReady(hostResolverService) && obtainsResponseForMappedHost(); 129 | } 130 | 131 | protected synchronized boolean obtainsResponseForMappedHost() { 132 | String hostNameForTest = null; 133 | if (hostAliases.isEmpty()) { 134 | putHost(hostNameForTest = UUID.randomUUID().toString(), "127.0.0.1"); 135 | } 136 | try { 137 | for (String hostname : hostAliases.keySet()) { 138 | InetAddress.getByName(hostname); 139 | } 140 | return true; 141 | } catch (UnknownHostException exc) { 142 | return false; 143 | } finally { 144 | if (hostNameForTest != null) { 145 | removeHost(hostNameForTest); 146 | } 147 | } 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/main/resources/burningwave.static.properties: -------------------------------------------------------------------------------- 1 | # This file is part of Burningwave Tools. 2 | # 3 | # Author: Roberto Gentili 4 | # 5 | # Hosted at: https://github.com/burningwave/tools 6 | # 7 | # -- 8 | # 9 | # The MIT License (MIT) 10 | # 11 | # Copyright (c) 2021 Roberto Gentili 12 | # 13 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 14 | # documentation files (the "Software"), to deal in the Software without restriction, including without 15 | # limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 16 | # the Software, and to permit persons to whom the Software is furnished to do so, subject to the following 17 | # conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in all copies or substantial 20 | # portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 23 | # LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 24 | # EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 25 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 26 | # OR OTHER DEALINGS IN THE SOFTWARE. 27 | priority-of-this-configuration=1 28 | buffer-handler.default-allocation-mode=ByteBuffer::allocateDirect 29 | buffer-handler.default-buffer-size=0.5Kb 30 | jvm.driver.init=true 31 | managed-logger.repository=org.burningwave.core.SimpleManagedLoggerRepository 32 | managed-logger.repository.enabled=true 33 | managed-logger.repository.logging.debug.disabled-for=\ 34 | org.burningwave.core.io.FileSystemItem;\ 35 | org.burningwave.core.classes.MemoryClassLoader;\ 36 | org.burningwave.core.classes.PathScannerClassLoader; 37 | synchronizer.all-threads-monitoring.enabled=false 38 | thread-supplier.default-daemon-flag-value=true -------------------------------------------------------------------------------- /src/test/java/org/burningwave/tools/AllExceptHeavyTestsSuite.java: -------------------------------------------------------------------------------- 1 | package org.burningwave.tools; 2 | 3 | import org.junit.platform.runner.JUnitPlatform; 4 | import org.junit.platform.suite.api.ExcludeTags; 5 | import org.junit.platform.suite.api.SelectClasses; 6 | import org.junit.runner.RunWith; 7 | 8 | @RunWith(JUnitPlatform.class) 9 | //@SelectPackages("org.burningwave.tools") 10 | @ExcludeTags("Heavy") 11 | @SelectClasses({ 12 | CapturerTest.class, 13 | TwoPassCapturerTest.class, 14 | HostsResolverServiceTest.class 15 | }) 16 | public class AllExceptHeavyTestsSuite { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/org/burningwave/tools/BaseTest.java: -------------------------------------------------------------------------------- 1 | package org.burningwave.tools; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertNotNull; 4 | import static org.junit.jupiter.api.Assertions.assertNull; 5 | import static org.junit.jupiter.api.Assertions.assertTrue; 6 | 7 | import java.util.Collection; 8 | import java.util.List; 9 | import java.util.Optional; 10 | import java.util.Set; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | import java.util.concurrent.CopyOnWriteArrayList; 13 | import java.util.function.Function; 14 | import java.util.function.Supplier; 15 | 16 | import org.burningwave.core.Component; 17 | import org.burningwave.core.ManagedLogger; 18 | import org.burningwave.core.assembler.ComponentContainer; 19 | import org.burningwave.core.assembler.ComponentSupplier; 20 | import org.junit.jupiter.api.function.Executable; 21 | import org.junit.jupiter.api.function.ThrowingSupplier; 22 | 23 | public class BaseTest implements Component, ManagedLogger { 24 | 25 | Collection componentSuppliers = new CopyOnWriteArrayList<>(); 26 | 27 | 28 | protected ComponentSupplier getComponentSupplier() { 29 | //Set componentSuppliers = getComponentSupplierSetForTest(); 30 | //return getNewComponentSupplier(); 31 | return ComponentSupplier.getInstance(); 32 | } 33 | 34 | 35 | protected Set getComponentSupplierSetForTest() { 36 | Set componentSuppliers = ConcurrentHashMap.newKeySet(); 37 | List threadList = new CopyOnWriteArrayList<>(); 38 | for (int i = 0; i < 1000; i++) { 39 | Thread thread = new Thread() { 40 | @Override 41 | public void run() { 42 | componentSuppliers.add(ComponentSupplier.getInstance()); 43 | } 44 | }; 45 | threadList.add(thread); 46 | thread.start(); 47 | } 48 | threadList.forEach(thr -> { 49 | try { 50 | thr.join(); 51 | } catch (InterruptedException e) { 52 | e.printStackTrace(); 53 | } 54 | }); 55 | return componentSuppliers; 56 | } 57 | 58 | 59 | protected ComponentSupplier getNewComponentSupplier() { 60 | ComponentSupplier componentSupplier = ComponentContainer.create("burningwave.properties"); 61 | componentSuppliers.add(componentSupplier); 62 | return componentSupplier; 63 | } 64 | 65 | 66 | void testNotNull(ThrowingSupplier supplier) { 67 | Object object = null; 68 | try { 69 | object = supplier.get(); 70 | } catch (Throwable exc) { 71 | logError("Exception occurred", exc); 72 | } 73 | assertNotNull(object); 74 | } 75 | 76 | 77 | protected void testNotEmpty(ThrowingSupplier> supplier) { 78 | testNotEmpty(supplier, false); 79 | } 80 | 81 | 82 | protected void testNotEmpty(ThrowingSupplier> supplier, boolean printAllElements) { 83 | long initialTime = System.currentTimeMillis(); 84 | Collection coll = null; 85 | boolean isNotEmpty = false; 86 | try { 87 | coll = supplier.get(); 88 | logInfo("Found " + coll.size() + " items in " + getFormattedDifferenceOfMillis(System.currentTimeMillis(), initialTime)); 89 | isNotEmpty = !coll.isEmpty(); 90 | if (isNotEmpty && printAllElements) { 91 | coll.forEach(element -> logDebug( 92 | Optional.ofNullable(element.toString()).orElseGet(() -> null) 93 | )); 94 | } 95 | } catch (Throwable exc) { 96 | logError("Exception occurred", exc); 97 | } 98 | assertNotNull(coll); 99 | assertTrue(!coll.isEmpty()); 100 | } 101 | 102 | 103 | void testNotEmpty(Supplier autoCloaseableSupplier, Function> collSupplier) { 104 | testNotEmpty(autoCloaseableSupplier, collSupplier, false); 105 | } 106 | 107 | 108 | void testNotEmpty(Supplier autoCloaseableSupplier, Function> collSupplier, boolean printAllElements) { 109 | long initialTime = System.currentTimeMillis(); 110 | Collection coll = null; 111 | boolean isNotEmpty = false; 112 | try (T collectionSupplier = autoCloaseableSupplier.get()){ 113 | coll = collSupplier.apply(collectionSupplier); 114 | logInfo("Found " + coll.size() + " items in " + getFormattedDifferenceOfMillis(System.currentTimeMillis(), initialTime)); 115 | isNotEmpty = !coll.isEmpty(); 116 | if (isNotEmpty && printAllElements) { 117 | coll.forEach(element -> logDebug( 118 | Optional.ofNullable(element.toString()).orElseGet(() -> null) 119 | )); 120 | } 121 | } catch (Throwable exc) { 122 | logError("Exception occurred", exc); 123 | } 124 | assertTrue(isNotEmpty); 125 | } 126 | 127 | 128 | void testNotNull( 129 | ThrowingSupplier autoCloseableSupplier, 130 | Function objectSupplier 131 | ) { 132 | long initialTime = System.currentTimeMillis(); 133 | try (T autoCloseable = autoCloseableSupplier.get()) { 134 | assertNotNull(objectSupplier.apply(autoCloseable)); 135 | logInfo("Elapsed time: " + getFormattedDifferenceOfMillis(System.currentTimeMillis(), initialTime)); 136 | } catch (Throwable exc) { 137 | logError("Exception occurred", exc); 138 | } 139 | } 140 | 141 | 142 | void testDoesNotThrow(Executable executable) { 143 | Throwable throwable = null; 144 | long initialTime = System.currentTimeMillis(); 145 | try { 146 | logDebug("Initializing logger"); 147 | executable.execute(); 148 | logInfo("Elapsed time: " + getFormattedDifferenceOfMillis(System.currentTimeMillis(), initialTime)); 149 | } catch (Throwable exc) { 150 | logError("Exception occurred", exc); 151 | throwable = exc; 152 | } 153 | assertNull(throwable); 154 | } 155 | 156 | void testDoesThrow(Executable executable, Class exceptionClass) { 157 | Throwable throwable = null; 158 | long initialTime = System.currentTimeMillis(); 159 | try { 160 | logDebug("Initializing logger"); 161 | executable.execute(); 162 | logInfo("Elapsed time: " + getFormattedDifferenceOfMillis(System.currentTimeMillis(), initialTime)); 163 | } catch (Throwable exc) { 164 | logInfo("Exception occurred", exc); 165 | throwable = exc; 166 | } 167 | assertNotNull(throwable); 168 | assertTrue(exceptionClass.isAssignableFrom(throwable.getClass())); 169 | } 170 | 171 | 172 | private String getFormattedDifferenceOfMillis(long value1, long value2) { 173 | String valueFormatted = String.format("%04d", (value1 - value2)); 174 | return valueFormatted.substring(0, valueFormatted.length() - 3) + "," + valueFormatted.substring(valueFormatted.length() -3); 175 | } 176 | 177 | 178 | @Override 179 | protected void finalize() throws Throwable { 180 | componentSuppliers.forEach(componentSupplier -> componentSupplier.close()); 181 | componentSuppliers.clear(); 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/test/java/org/burningwave/tools/CapturerTest.java: -------------------------------------------------------------------------------- 1 | package org.burningwave.tools; 2 | 3 | import static org.burningwave.core.assembler.StaticComponentContainer.JVMInfo; 4 | import static org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggerRepository; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | import org.burningwave.core.assembler.ComponentContainer; 12 | import org.burningwave.core.assembler.ComponentSupplier; 13 | import org.burningwave.core.io.FileSystemItem; 14 | import org.burningwave.core.io.PathHelper; 15 | import org.burningwave.tools.dependencies.Capturer; 16 | import org.burningwave.tools.dependencies.Capturer.Result; 17 | import org.junit.jupiter.api.Test; 18 | 19 | public class CapturerTest extends BaseTest { 20 | 21 | @Test 22 | public void storeDependenciesTestOne() { 23 | testNotEmpty(() -> { 24 | ComponentSupplier componentSupplier = ComponentContainer.getInstance(); 25 | PathHelper pathHelper = componentSupplier.getPathHelper(); 26 | Collection paths = pathHelper.getAllMainClassPaths(); 27 | if (JVMInfo.getVersion() > 8) { 28 | paths.addAll(pathHelper.getPaths("dependencies-capturer.additional-resources-path")); 29 | } 30 | List _paths = new ArrayList<>(paths); 31 | Collections.sort(_paths); 32 | Result dependencies = Capturer.getInstance().captureAndStore( 33 | "org.burningwave.tools.CapturerTest", 34 | _paths, 35 | System.getProperty("user.home") + "/Desktop/bw-tests/Capturer/testOne", 36 | true, 0L 37 | ); 38 | dependencies.waitForTaskEnding(); 39 | return dependencies.getStore().getAllChildren(); 40 | }); 41 | } 42 | 43 | 44 | public static void main(String[] args) { 45 | for (FileSystemItem fileSystemItem : FileSystemItem.ofPath(System.getProperty("user.home")).getChildren()) { 46 | ManagedLoggerRepository.logDebug(() -> CapturerTest.class.getName(), fileSystemItem.getAbsolutePath()); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/org/burningwave/tools/HostsResolverServiceTest.java: -------------------------------------------------------------------------------- 1 | package org.burningwave.tools; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertNotNull; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import java.net.InetAddress; 7 | import java.net.UnknownHostException; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.LinkedHashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; 15 | import org.burningwave.tools.net.DNSClientHostResolver; 16 | import org.burningwave.tools.net.DefaultHostResolver; 17 | import org.burningwave.tools.net.HostResolutionRequestInterceptor; 18 | import org.burningwave.tools.net.IPAddressUtil; 19 | import org.burningwave.tools.net.MappedHostResolver; 20 | import org.junit.jupiter.api.Order; 21 | import org.junit.jupiter.api.Test; 22 | import org.junit.jupiter.api.TestMethodOrder; 23 | 24 | @TestMethodOrder(OrderAnnotation.class) 25 | public class HostsResolverServiceTest extends BaseTest { 26 | 27 | @Test 28 | @Order(1) 29 | public void resolveTestOne() throws UnknownHostException { 30 | testDoesNotThrow(() -> { 31 | List> hostAliases = new ArrayList<>(); 32 | Map hostNamesForIp = new LinkedHashMap<>(); 33 | hostAliases.add(hostNamesForIp); 34 | hostNamesForIp.put("ip", "123.123.123.123"); 35 | hostNamesForIp.put("hostnames", Arrays.asList("hello.world.one", "hello.world.two")); 36 | HostResolutionRequestInterceptor.INSTANCE.install( 37 | new DNSClientHostResolver("208.67.222.222", 53), 38 | new MappedHostResolver(() -> hostAliases), 39 | DefaultHostResolver.INSTANCE 40 | ); 41 | 42 | InetAddress inetAddress = InetAddress.getByName("hello.world.one"); 43 | assertNotNull(inetAddress); 44 | assertTrue("123.123.123.123".equals(inetAddress.getHostAddress())); 45 | inetAddress = InetAddress.getByName("hello.world.two"); 46 | assertNotNull(inetAddress); 47 | assertTrue("123.123.123.123".equals(inetAddress.getHostAddress())); 48 | inetAddress = InetAddress.getByName("localhost"); 49 | assertNotNull(inetAddress); 50 | assertTrue("127.0.0.1".equals(inetAddress.getHostAddress())); 51 | inetAddress = InetAddress.getByName("google.com"); 52 | }); 53 | } 54 | 55 | @Test 56 | @Order(2) 57 | public void getByAddressTestOne() { 58 | testNotNull(() -> { 59 | return InetAddress.getByAddress(IPAddressUtil.INSTANCE.textToNumericFormat("127.0.0.1")); 60 | }); 61 | } 62 | 63 | @Test 64 | @Order(3) 65 | public void reset() { 66 | testDoesNotThrow(() -> { 67 | HostResolutionRequestInterceptor.INSTANCE.uninstall(); 68 | }); 69 | testDoesThrow( 70 | () -> { 71 | InetAddress.getByName("hello.world.one"); 72 | }, 73 | UnknownHostException.class 74 | ); 75 | } 76 | 77 | @Test 78 | @Order(4) 79 | public void resolveTestTwo() throws UnknownHostException { 80 | testDoesNotThrow(() -> { 81 | List> hostAliases = new ArrayList<>(); 82 | Map hostNamesForIp = new LinkedHashMap<>(); 83 | hostAliases.add(hostNamesForIp); 84 | hostNamesForIp.put("ip", "123.123.123.123"); 85 | hostNamesForIp.put("hostnames", Arrays.asList("hello.world.one", "hello.world.two")); 86 | HostResolutionRequestInterceptor.INSTANCE.install( 87 | new MappedHostResolver(() -> hostAliases), 88 | DefaultHostResolver.INSTANCE 89 | ); 90 | InetAddress inetAddress = InetAddress.getByName("hello.world.one"); 91 | assertNotNull(inetAddress); 92 | assertTrue("123.123.123.123".equals(inetAddress.getHostAddress())); 93 | inetAddress = InetAddress.getByName("hello.world.two"); 94 | assertNotNull(inetAddress); 95 | assertTrue("123.123.123.123".equals(inetAddress.getHostAddress())); 96 | inetAddress = InetAddress.getByName("localhost"); 97 | assertNotNull(inetAddress); 98 | assertTrue("127.0.0.1".equals(inetAddress.getHostAddress())); 99 | }); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/test/java/org/burningwave/tools/TwoPassCapturerTest.java: -------------------------------------------------------------------------------- 1 | package org.burningwave.tools; 2 | 3 | import static org.burningwave.core.assembler.StaticComponentContainer.JVMInfo; 4 | import static org.burningwave.core.assembler.StaticComponentContainer.ManagedLoggerRepository; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | import org.burningwave.core.assembler.ComponentContainer; 12 | import org.burningwave.core.assembler.ComponentSupplier; 13 | import org.burningwave.core.io.FileSystemItem; 14 | import org.burningwave.core.io.PathHelper; 15 | import org.burningwave.tools.dependencies.Capturer.Result; 16 | import org.burningwave.tools.dependencies.TwoPassCapturer; 17 | import org.junit.jupiter.api.Test; 18 | 19 | public class TwoPassCapturerTest extends BaseTest { 20 | 21 | @Test 22 | public void storeDependenciesTestOne() { 23 | testNotEmpty(() -> { 24 | ComponentSupplier componentSupplier = ComponentContainer.getInstance(); 25 | PathHelper pathHelper = componentSupplier.getPathHelper(); 26 | Collection paths = pathHelper.getAllMainClassPaths(); 27 | if (JVMInfo.getVersion() > 8) { 28 | paths.addAll(pathHelper.getPaths("dependencies-capturer.additional-resources-path")); 29 | } 30 | List _paths = new ArrayList<>(paths); 31 | Collections.sort(_paths); 32 | Result result = TwoPassCapturer.getInstance().captureAndStore( 33 | "org.burningwave.tools.TwoPassCapturerTest", 34 | new String[]{"\"" + System.getProperty("user.home") + "\""}, 35 | _paths, 36 | System.getProperty("user.home") + "/Desktop/bw-tests/TwoPassCapturer/testOne", 37 | true, 0L 38 | ); 39 | result.waitForTaskEnding(); 40 | return result.getJavaClasses(); 41 | }); 42 | } 43 | 44 | @Test 45 | public void storeDependenciesTestTwo() { 46 | testNotEmpty(() -> { 47 | ComponentSupplier componentSupplier = ComponentContainer.getInstance(); 48 | PathHelper pathHelper = componentSupplier.getPathHelper(); 49 | Collection paths = pathHelper.getAllMainClassPaths(); 50 | if (JVMInfo.getVersion() > 8) { 51 | paths.addAll(pathHelper.getPaths("dependencies-capturer.additional-resources-path")); 52 | } 53 | List _paths = new ArrayList<>(paths); 54 | Collections.sort(_paths); 55 | String[] args = System.getProperty("os.name").toLowerCase().contains("windows") ? 56 | new String[]{"\"C:\\Program Files (x86)\""} : 57 | new String[]{"\"/\""}; 58 | 59 | Result result = TwoPassCapturer.getInstance().captureAndStore( 60 | "org.burningwave.tools.TwoPassCapturerTest", 61 | args, 62 | _paths, 63 | System.getProperty("user.home") + "/Desktop/bw-tests/TwoPassCapturer/testTwo", 64 | true, 0L 65 | ); 66 | result.waitForTaskEnding(); 67 | return result.getJavaClasses(); 68 | }); 69 | } 70 | 71 | public static void main(String[] args) { 72 | String folderName = args[0]; 73 | if (folderName.startsWith("\"")) { 74 | folderName = args[0].substring(1); 75 | } 76 | if (folderName.endsWith("\"")) { 77 | folderName = folderName.substring(0, folderName.length() -1); 78 | } 79 | for (FileSystemItem fileSystemItem : FileSystemItem.ofPath(folderName).getChildren()) { 80 | ManagedLoggerRepository.logDebug(() -> TwoPassCapturerTest.class.getName(), fileSystemItem.getAbsolutePath()); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/test/resources/burningwave.properties: -------------------------------------------------------------------------------- 1 | #By this configuration an application will be converted from Java 8 to Java 13 2 | priority-of-this-configuration=2 3 | paths.dependencies-capturer.additional-resources-path=//${system.properties:java.home}/../1.8.0_172/jre/lib//children:.*?\\.jar; 4 | hunters.default-search-config.check-file-option=checkFileName -------------------------------------------------------------------------------- /src/test/resources/burningwave.static.properties: -------------------------------------------------------------------------------- 1 | priority-of-this-configuration=2 2 | managed-logger.repository=org.burningwave.core.SimpleManagedLoggerRepository 3 | managed-logger.repository.enabled=true 4 | managed-logger.repository.logging.debug.disabled-for=\ 5 | org.burningwave.core.io.FileSystemItem;\ 6 | org.burningwave.core.classes.PathScannerClassLoader;\ 7 | org.burningwave.core.classes.MemoryClassLoader;\ 8 | org.burningwave.core.classes.PropertyAccessor$ByMethodOrByField; 9 | managed-logger.repository.logging.info.disabled-for=\ 10 | org.burningwave.core.jvm.LowLevelObjectsHandler;\ 11 | org.burningwave.core.classes.MemoryClassLoader;\ 12 | org.burningwave.core.classes.PathScannerClassLoader; 13 | synchronizer.all-threads-monitoring.enabled=false 14 | banner.hide=true 15 | --------------------------------------------------------------------------------