Copybara import of the project:

  - 94bb93a20812b7e398669c3d0aa8f67bf503feff Initial contribution by Tomas Kraus <tomas.kraus@oracle.com>
  - 411b1d2271efc9af0db28c48a4a05d7273ac776f Cleanup of copyright-exclude file by Tomas Kraus <tomas.kraus@oracle.com>
  - 993fc6c941ba05b51f346f82944dfc670f07f5a6 Project information update by Tomas Kraus <tomas.kraus@oracle.com>
  - c688b139db8913dc08c1fdcea53f95a91a901931 Parent updated to 1.0.2.  (#10) by Tomáš Kraus <tomas.kraus@oracle.com>
  - a0353cffeef9f0013dfc420aa75e8d74ee40c046  JDK 11 preparation and jakarta uptake.  (#13) by Tomáš Kraus <tomas.kraus@oracle.com>
  - 7df4ed8940829fbe01968294f6df84a62a366f8b Merge pull request #16 from bravehorsie/master by Roman Grigoriadi <bravehorsie@gmail.com>
  - 41617854b4dd03be4be18dfcb7ab6fbe1b03f940 Fixed jar content: added LICENSE and NOTICE. (#20) by Tomáš Kraus <tomas.kraus@oracle.com>
  - ad51c42688568aab60e7fd687ee084c7a372f726 Fixed missing module-info issue. (#22) by Tomáš Kraus <tomas.kraus@oracle.com>
  - 60c0c5b7fe0d0ad28602df579ace3a03c4c2e483 fix up dependencies (#24) by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 02d87244d8848a1d193873eb98f8193f46af0e4b do not fail the build if resource folder does not exist (... by Lukas Jungmann <lukas.jungmann@oracle.com>
  - ee27612505a0b0e79c8cf9b483add8d811d40a2d remove dependency on dom4j (#32) by Lukas Jungmann <lukas.jungmann@oracle.com>
  - b9f61fda870a930d56d09d97ad80807dbcd36f81 moved sources to proper structure, coverage, dependency c... by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 1029b46055ca76cb6458ccf4558d2c2634f5f677 exclude generated file (#33) by Lukas Jungmann <lukas.jungmann@oracle.com>
  - d1d595641e8c84482a47812ab8457f850f483f6c fix cp year for the release (#34) by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 2931f6653df1320705cb4afa3cbb4bc9015ce2f8 remove emtpy folders by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 0acb83be8ad8ebb18fa6bb18f8a975d3b4d7453e Prepare release com.sun.istack:istack-commons:3.0.9 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 90a9b4456b1790ad26a894dcb46c2e03378657f8 Prepare next development cycle for 3.0.10-SNAPSHOT by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - a2bd12433fed99d92ab952ee5c61ce96f7d0c576 Next release cycle version updated to 3.1.0-SNAPSHOT by Tomas Kraus <Tomas.Kraus@oracle.com>
  - 5b898c5cac7475d16c48c234565ba46a04e7df5b StackWalker used in logger for caller method resolution #37 by Daniel Kec <daniel@kecovi.cz>
  - 2942ad3f3c1840b43b66c03468301658647982c2 update plugin versions, clean up poms, add missing module... by Lukas Jungmann <lukas.jungmann@oracle.com>
  - ed23d828118a0752f5a18bd538bf05a862b193de Integrate codemodel 2.3.2-1 (#44) by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 57171abaa2df83980618730916a920bf5e4bb98e fix vendor (#45) by Lukas Jungmann <lukas.jungmann@oracle.com>
  - b4f026b25249c6c9edf40d2c961ac4e974ea3738 update parent pom, dependencies, plugins, prepare for the... by Lukas Jungmann <lukas.jungmann@oracle.com>
  - cf98ff76cf0f9f9c94a35c8e549490e0bc6e1ff4 #51: XJC task is closing wrong ClassLoader - ClassNotFoun... by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 162bc1d03f6622a83b5a867a0471d6f2b58bbc75 Integrate codemodel 2.3.2-2 by Lukas Jungmann <lukas.jungmann@oracle.com>
  - d4a280da6a188eec6ed5dac772d5595d0aafecbe fix cp year by Lukas Jungmann <lukas.jungmann@oracle.com>
  - e2f21bf526e257abf7c1c74c03054f6fcb8fff2f Prepare release com.sun.istack:istack-commons:3.0.11 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 9c02bc5b425abd2c9c9a1beab9be3ae1d934e7f0 Prepare next development cycle for 3.1.0-SNAPSHOT by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 8ef227deb3e5f2ccc2c37c5d7e1c10460b62efa9 Update Jakarta Activation to 2.0.0-rc1 (#49) by Andy McCright <j.andrew.mccright@gmail.com>
  - 629b1083f37ea52d20c66693873c89fce143d4c4 update project version to 4.0.0-SNAPSHOT by Lukas Jungmann <lukas.jungmann@oracle.com>
  - e5bce223b3a12609c29984861a923eeeb3f26af8 prepare for jdk14 by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 3ba915fd13baf94e0af1982b958d2c0e0ede3d54 update build plugins by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 227267b8a1d43bfbea40c723625e067dc0965efd Prepare release com.sun.istack:istack-commons:4.0.0-M1 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - e1904a4633208ffd80ce98b59954b502cdaa3fb7 Prepare next development cycle for 4.0.0-SNAPSHOT by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 39a19b754583d1e9e09f12883ed6e15d1b6174fd integrate activation 2.0.0-RC3 by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 372be10d977d9f842412666df1f71140b7d28074 Prepare release com.sun.istack:istack-commons:4.0.0-M2 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 285d18c5daeb703da364d2e38aea55813ae5dd89 Prepare next development cycle for 4.0.0-SNAPSHOT by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 488c87a97446d6ef025c62ffc8a84174f3bbeca4 remove obsolete code from tools by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 4df583ade52296ad8b899a24ef000b1f0836d04f Should generate jakarta annotation by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 61fc9f14727b47e147f5a55e9fdb7f048939a01e #60: marking thread safety in maven plugins by Lukas Jungmann <lukas.jungmann@oracle.com>
  - e5eb55383a23aa51da83ba01a0f48fb6cffce7e0 Prepare release com.sun.istack:istack-commons:4.0.0-M3 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 24e2da887f05b976f37fbcc3419a3eb6ae67c77e Prepare next development cycle for 4.0.0-SNAPSHOT by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 4e72ea5d513c84a906dbb833ea32dde2aab23037 Versions update. by Tomas Kraus <Tomas.Kraus@oracle.com>
  - 0995d1253d0ad8c90d1b5c695a59301ccbe97c94 Compiler plugin configuration updated. (#65) by Tomáš Kraus <tomas.kraus@oracle.com>
  - c56ffe5fb517df99b39a097ab3abe2a252209326 Prepare release com.sun.istack:istack-commons:4.0.0 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 2e26ea2ddb48c7d9e967d88fece46c05d7822b01 Prepare next development cycle for 4.1.0-SNAPSHOT by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 984999f8d2df9720781fb6db4f5ecd6afecb29a9 move travis to jdk15 by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 719eb051891654609b810bf9c08f8751b5d56e22 Bump junit from 4.13 to 4.13.1 in /istack-commons by dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  - 17afd94e3ce57018c6143559e0277e99322307c6 Bump junit in /istack-commons/maven-plugin/src/test/it/sa... by dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  - 916a9a51a0e75c8e99cc1a30fac3e1d2a82491b1 Bump ant.version from 1.10.8 to 1.10.9 in /istack-commons by dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  - 45b45bc24b8120d6914101f8f1cbc865af006229 fix cp year by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 4f8109f71988232e2c1d3ac793f588a18923b990 update spotbugs, copyright plugin, testng by Lukas Jungmann <lukas.jungmann@oracle.com>
  - b1e6d05c124914b2d4dea2e8f186d69a1e2192ac Integrate activation 2.0.1 by Lukas Jungmann <lukas.jungmann@oracle.com>
  - cac71101470a880749d1ad0376c79e687d9a157f cp right by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 6902fb3ec533c9402daabd4b5317d2e7e7badafd copyright adjustments before merge by Maxim Nesen <maxim.nesen@oracle.com>
  - d0785e0627f4e053bcef8495cfc02f3a118654a2 add option to not generate javadoc by Lukas Jungmann <lukas.jungmann@oracle.com>
  - ef49e4840127f2095684788e3edecbf8aa023993 Merge pull request #78 from eclipse-ee4j/4.0.1-RELEASE by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 3e617cdc4da6c27b06ec0b53ec6116e68a27b4ce Enable latests JDK in Travis and GitHub actions by Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
  - 24d0234b7ec0d17e8e0c4317a2ee51f998b98f7a Remove Travis by Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
  - ca2a6a5848cfd57865f021ba3ea1aca0f6c88e07 fix warnings, update build plugins. by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 77cb74cef04ca61ea257b340b48187369f6d15be Jakarta Activation dependency update (2.0.2-SNAPSHOT). by Tomas Kraus <Tomas.Kraus@oracle.com>
  - 3ab17c9cb7b9e322903d82cd0a108fe2348fa9b9 Jakarta Activation API updated to 2.1.0-RC1. by Tomas Kraus <tomas.kraus@oracle.com>
  - 768b3a0dfaea9affcad7957ac2496d3b0a0cf7f1 Version updated to 4.1.0-SNAPSHOT. by Tomas Kraus <tomas.kraus@oracle.com>
  - e6dc260892c602d6509d4d9fa18d3ba4abca2364 Project cleanup. by Tomas Kraus <tomas.kraus@oracle.com>
  - e90b1f873e58e25b36eb34af88990a4077035c48 Fixed build issue. by Tomas Kraus <tomas.kraus@oracle.com>
  - 4ee8a19904bef8a057e49650b75675d888ad3b83 update dependencies, by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 4777b0cec99de7a2f54b0008277ff9c01d1c49df fix the path to the spotbugs filter file by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 0280e00888eefe733286c9c0605b7a4307aeff66 Prepare release com.sun.istack:istack-commons:4.1.0 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 39492d645d4d00be7a7905004eb89ec7f319f727 Prepare next development cycle for 4.1.1-SNAPSHOT by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - b039f7d9ba565a9a55993ef2608d38362545095a generate private constructor in localization class by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 81ebad83f8758ff448dff8acfcaeaab2b2af5b3b update dependencies, by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 3a81d48b2c41c602eb922db737661010ff19353f Prepare release com.sun.istack:istack-commons:4.1.1 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - e2e64a865ca40ef59efdfa115b743a751be5732b Prepare next development cycle for 4.1.2-SNAPSHOT by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 2625e8c71cf9bf6be123a659883c5325ef6cdded fix cpright by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 527fe11d187b1eba6e5d5f9d74b99e14105b4242 update gh action build by Lukas Jungmann <lukas.jungmann@oracle.com>
  - c96196f7ff3d2647ba5784cfc537317a679232b9 Bump testng from 7.5 to 7.7.0 in /istack-commons by dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  - 3bf4720adf99a7917e20959fe888f7295eb799f2 A mojo to generate implementations of jaxb Quick by Lukas Jungmann <lukas.jungmann@oracle.com>
  - b9357cc3d722827c6219038341abef35e3b60005 Update dependencies, build plugins by Lukas Jungmann <lukas.jungmann@oracle.com>
  - e4626a693aa49935e0b07411419006b9570f4734 update gh buld by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 1ee5fc6a67c50381512383e65e63aa81ea80cd5c Minor code cleanup by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 685bd782d32f9fa20670e0c5a9d7a2fc0b38845d Prepare release com.sun.istack:istack-commons:4.1.2 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - 4f63e8ebe2cdf5ab25a88f793ac06ce83265e42a Prepare next development cycle for 4.2.0-SNAPSHOT by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>
  - d80a798a4d4350f1f0d8afd91209edd935d0521a remove securitymanager by Lukas Jungmann <lukas.jungmann@oracle.com>
  - 19e68d9f7fc646987091a9e9bce87fd140d7d169 Prepare release com.sun.istack:istack-commons:4.2.0 by Eclipse JAXBimpl Bot <jaxb-impl-bot@eclipse.org>

GitOrigin-RevId: 19e68d9f7fc646987091a9e9bce87fd140d7d169
Change-Id: I3573feb82f076f83620efc8251edfa662a60d1e4
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000..679cac8
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0 which is available at
+# http://www.eclipse.org/legal/epl-2.0,
+# or the Eclipse Distribution License v. 1.0 which is available at
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+#
+
+name: Jakarta IStack Commons
+
+on:
+  pull_request:
+  push:
+  # Allows you to run this workflow manually from the Actions tab
+  workflow_dispatch:
+
+concurrency:
+  group: ${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  build:
+    name: Test on JDK ${{ matrix.java_version }} 
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        java_version: [ 11, 17 , 21-ea]
+
+    steps:
+    - name: Checkout for build
+      uses: actions/checkout@v3
+      with:
+        fetch-depth: 0
+    - name: Set up JDK
+      uses: actions/setup-java@v3
+      with:
+        distribution: 'zulu'
+        java-version: ${{ matrix.java_version }}
+        cache: maven
+    - name: Verify
+      run: |
+        cd istack-commons
+        mvn -B -V -U -C -Pstaging,oss-release,license-check clean verify org.glassfish.copyright:glassfish-copyright-maven-plugin:check -Dgpg.skip=true -Dittest=true -Dcopyright.ignoreyear=true
+    - name: Upload license-check info
+      uses: actions/upload-artifact@v3
+      with:
+        name: license-summary.txt
+        path: istack-commons/target/dash/summary
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9ad0824
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+target/
+.idea
+*.iml
+.classpath
+.project
+.settings/
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..c109340
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,51 @@
+[//]: # " Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. "
+[//]: # "  "
+[//]: # " This program and the accompanying materials are made available under the "
+[//]: # " terms of the Eclipse Distribution License v. 1.0, which is available at "
+[//]: # " http://www.eclipse.org/org/documents/edl-v10.php. "
+[//]: # "  "
+[//]: # " SPDX-License-Identifier: BSD-3-Clause "
+
+# Contributing to Eclipse Implementation of JAXB
+
+Thanks for your interest in this project.
+
+## Project description
+
+The Java™ Architecture for XML Binding (JAXB) provides an API and tools that
+automate the mapping between XML documents and Java objects. This project
+contains implementation of JAXB API.
+
+* https://projects.eclipse.org/projects/ee4j.jaxb-impl
+
+## Developer resources
+
+Information regarding source code management, builds, coding standards, and
+more.
+
+* https://projects.eclipse.org/projects/ee4j.jaxb-impl/developer
+
+The project maintains the following source code repositories
+
+
+## Eclipse Contributor Agreement
+
+Before your contribution can be accepted by the project team contributors must
+electronically sign the Eclipse Contributor Agreement (ECA).
+
+* http://www.eclipse.org/legal/ECA.php
+
+Commits that are provided by non-committers must have a Signed-off-by field in
+the footer indicating that the author is aware of the terms by which the
+contribution has been provided to the project. The non-committer must
+additionally have an Eclipse Foundation account and must have a signed Eclipse
+Contributor Agreement (ECA) on file.
+
+For more information, please see the Eclipse Committer Handbook:
+https://www.eclipse.org/projects/handbook/#resources-commit
+
+## Contact
+
+Contact the project developers via the project's "dev" list.
+
+* https://accounts.eclipse.org/mailing-list/jaxb-impl-dev
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..c739f78
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,29 @@
+
+    Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+   
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+   
+      - Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+   
+      - Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+   
+      - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+        contributors may be used to endorse or promote products derived
+        from this software without specific prior written permission.
+   
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/NOTICE.md b/NOTICE.md
new file mode 100644
index 0000000..95ad0b0
--- /dev/null
+++ b/NOTICE.md
@@ -0,0 +1,198 @@
+[//]: # " Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. "
+[//]: # "  "
+[//]: # " This program and the accompanying materials are made available under the "
+[//]: # " terms of the Eclipse Distribution License v. 1.0, which is available at "
+[//]: # " http://www.eclipse.org/org/documents/edl-v10.php. "
+[//]: # "  "
+[//]: # " SPDX-License-Identifier: BSD-3-Clause "
+
+# Notices for Eclipse Implementation of JAXB
+
+This content is produced and maintained by the Eclipse Implementation of JAXB
+project.
+
+* Project home: https://projects.eclipse.org/projects/ee4j.jaxb-impl
+
+## Trademarks
+
+Eclipse Implementation of JAXB is a trademark of the Eclipse Foundation.
+
+## Copyright
+
+All content is the property of the respective authors or their employers. For
+more information regarding authorship of content, please consult the listed
+source code repository logs.
+
+## Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Distribution License v. 1.0 which is available at
+http://www.eclipse.org/org/documents/edl-v10.php.
+
+SPDX-License-Identifier: BSD-3-Clause
+
+## Source Code
+
+The project maintains the following source code repositories:
+
+* https://github.com/eclipse-ee4j/jaxb-ri
+* https://github.com/eclipse-ee4j/jaxb-istack-commons
+* https://github.com/eclipse-ee4j/jaxb-dtd-parser
+* https://github.com/eclipse-ee4j/jaxb-fi
+* https://github.com/eclipse-ee4j/jaxb-stax-ex
+* https://github.com/eclipse-ee4j/jax-rpc-ri
+
+## Third-party Content
+
+This project leverages the following third party content.
+
+Apache Ant (1.10.2)
+
+* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain
+
+Apache Ant (1.10.2)
+
+* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain
+
+Apache Felix (1.2.0)
+
+* License: Apache License, 2.0
+
+args4j (2.33)
+
+* License: MIT License
+
+dom4j (1.6.1)
+
+* License: Custom license based on Apache 1.1
+
+file-management (3.0.0)
+
+* License: Apache-2.0
+* Project: https://maven.apache.org/shared/file-management/
+* Source:
+   https://svn.apache.org/viewvc/maven/shared/tags/file-management-3.0.0/
+
+JUnit (4.12)
+
+* License: Eclipse Public License
+
+JUnit (4.12)
+
+* License: Eclipse Public License
+
+maven-compat (3.5.2)
+
+* License: Apache-2.0
+* Project: https://maven.apache.org/ref/3.5.2/maven-compat/
+* Source:
+   https://mvnrepository.com/artifact/org.apache.maven/maven-compat/3.5.2
+
+maven-core (3.5.2)
+
+* License: Apache-2.0
+* Project: https://maven.apache.org/ref/3.5.2/maven-core/index.html
+* Source: https://mvnrepository.com/artifact/org.apache.maven/maven-core/3.5.2
+
+maven-plugin-annotations (3.5)
+
+* License: Apache-2.0
+* Project: https://maven.apache.org/plugin-tools/maven-plugin-annotations/
+* Source:
+   https://github.com/apache/maven-plugin-tools/tree/master/maven-plugin-annotations
+
+maven-plugin-api (3.5.2)
+
+* License: Apache-2.0
+
+maven-resolver-api (1.1.1)
+
+* License: Apache-2.0
+
+maven-resolver-api (1.1.1)
+
+* License: Apache-2.0
+
+maven-resolver-connector-basic (1.1.1)
+
+* License: Apache-2.0
+
+maven-resolver-impl (1.1.1)
+
+* License: Apache-2.0
+
+maven-resolver-spi (1.1.1)
+
+* License: Apache-2.0
+
+maven-resolver-transport-file (1.1.1)
+
+* License: Apache-2.0
+* Project: https://maven.apache.org/resolver/maven-resolver-transport-file/
+* Source:
+   https://github.com/apache/maven-resolver/tree/master/maven-resolver-transport-file
+
+maven-resolver-util (1.1.1)
+
+* License: Apache-2.0
+
+maven-settings (3.5.2)
+
+* License: Apache-2.0
+* Source:
+   https://mvnrepository.com/artifact/org.apache.maven/maven-settings/3.5.2
+
+OSGi Service Platform Core Companion Code (6.0)
+
+* License: Apache License, 2.0
+
+plexus-archiver (3.5)
+
+* License: Apache-2.0
+* Project: https://codehaus-plexus.github.io/plexus-archiver/
+* Source: https://github.com/codehaus-plexus/plexus-archiver
+
+plexus-io (3.0.0)
+
+* License: Apache-2.0
+
+plexus-utils (3.1.0)
+
+* License: Apache- 2.0 or Apache- 1.1 or BSD or Public Domain or Indiana
+   University Extreme! Lab Software License V1.1.1 (Apache 1.1 style)
+
+relaxng-datatype (1.0)
+
+* License: New BSD license
+
+Sax (0.2)
+
+* License: SAX-PD
+* Project: http://www.megginson.com/downloads/SAX/
+* Source: http://sourceforge.net/project/showfiles.php?group_id=29449
+
+testng (6.14.2)
+
+* License: Apache-2.0 AND (MIT OR GPL-1.0+)
+* Project: https://testng.org/doc/index.html
+* Source: https://github.com/cbeust/testng
+
+wagon-http-lightweight (3.0.0)
+
+* License: Pending
+* Project: https://maven.apache.org/wagon/
+* Source:
+   https://mvnrepository.com/artifact/org.apache.maven.wagon/wagon-http-lightweight/3.0.0
+
+xz for java (1.8)
+
+* License: LicenseRef-Public-Domain
+
+## Cryptography
+
+Content may contain encryption software. The country in which you are currently
+may have restrictions on the import, possession, and use, and/or re-export to
+another country, of encryption software. BEFORE using any encryption software,
+please check the country's laws, regulations and policies concerning the import,
+possession, or use, and re-export of encryption software, to see if this is
+permitted.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ff22bb2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,30 @@
+[//]: # " Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved. "
+[//]: # "  "
+[//]: # " This program and the accompanying materials are made available under the "
+[//]: # " terms of the Eclipse Distribution License v. 1.0, which is available at "
+[//]: # " http://www.eclipse.org/org/documents/edl-v10.php. "
+[//]: # "  "
+[//]: # " SPDX-License-Identifier: BSD-3-Clause "
+
+# iStack Common Utility Code
+
+[![Build Status](https://github.com/eclipse-ee4j/jaxb-istack-commons/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/eclipse-ee4j/jaxb-istack-commons/actions/workflows/maven.yml?branch=master)
+[![Jakarta Staging (Snapshots)](https://img.shields.io/nexus/s/https/jakarta.oss.sonatype.org/com.sun.istack/istack-commons.svg)](https://jakarta.oss.sonatype.org/content/repositories/staging/com/sun/istack/istack-commons/)
+
+This project is part of [Eclipse Implementation of JAXB](https://projects.eclipse.org/projects/ee4j.jaxb-impl).
+
+## License
+
+iStack Common Utility Code is licensed under a license - [EDL 1.0](LICENSE.md).
+
+## Contributing
+
+We use [contribution policy](CONTRIBUTING.md), which means we can only accept contributions under
+the terms of [Eclipse Contributor Agreement](http://www.eclipse.org/legal/ECA.php).
+
+## Links
+
+* [Runtime Utilities](https://javadoc.io/doc/com.sun.istack/istack-commons-runtime/latest/com.sun.istack.runtime/module-summary.html)
+* [Tooltime Utilities](https://javadoc.io/doc/com.sun.istack/istack-commons-tools/latest/com.sun.istack.tools/module-summary.html)
+* [Test Utilities](https://javadoc.io/doc/com.sun.istack/istack-commons-test/latest/com.sun.istack.test/module-summary.html)
+* [Mailing list](https://accounts.eclipse.org/mailing-list/jaxb-impl-dev)
diff --git a/istack-commons/buildtools/pom.xml b/istack-commons/buildtools/pom.xml
new file mode 100644
index 0000000..70d9c01
--- /dev/null
+++ b/istack-commons/buildtools/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.sun.istack</groupId>
+        <artifactId>istack-commons</artifactId>
+        <version>4.2.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>istack-commons-buildtools</artifactId>
+    <name>istack common utility buildtools</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jaxb</groupId>
+            <artifactId>codemodel</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/istack-commons/buildtools/src/main/java/com/sun/istack/build/NameConverter.java b/istack-commons/buildtools/src/main/java/com/sun/istack/build/NameConverter.java
new file mode 100644
index 0000000..847f469
--- /dev/null
+++ b/istack-commons/buildtools/src/main/java/com/sun/istack/build/NameConverter.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.build;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+/**
+ * Converts arbitrary strings into Java identifiers.
+ *
+ * @author
+ *    <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a>
+ */
+public interface NameConverter
+{
+    /**
+     * converts a string into an identifier suitable for classes.
+     *
+     * In general, this operation should generate "NamesLikeThis".
+     * @param token string to convert
+     * @return converted token
+     */
+    String toClassName( String token );
+
+    /**
+     * converts a string into an identifier suitable for interfaces.
+     *
+     * In general, this operation should generate "NamesLikeThis".
+     * But for example, it can prepend every interface with 'I'.
+     * @param token string to convert
+     * @return converted token
+     */
+    String toInterfaceName( String token );
+
+    /**
+     * converts a string into an identifier suitable for properties.
+     *
+     * In general, this operation should generate "NamesLikeThis",
+     * which will be used with known prefixes like "get" or "set".
+     * @param token string to convert
+     * @return converted token
+     */
+    String toPropertyName( String token );
+
+    /**
+     * converts a string into an identifier suitable for constants.
+     *
+     * In the standard Java naming convention, this operation should
+     * generate "NAMES_LIKE_THIS".
+     * @param token string to convert
+     * @return converted token
+     */
+    String toConstantName( String token );
+
+    /**
+     * Converts a string into an identifier suitable for variables.
+     *
+     * In general it should generate "namesLikeThis".
+     * @param token string to convert
+     * @return converted token
+     */
+    String toVariableName( String token );
+
+    /**
+     * Converts a namespace URI into a package name.
+     * This method should expect strings like
+     * "http://foo.bar.zot/org", "urn:abc:def:ghi" "", or even "###"
+     * (basically anything) and expected to return a package name,
+     * liks "org.acme.foo".
+     *
+     * @param namespaceUri ns uri to convert
+     * @return converted uri
+     */
+    String toPackageName( String namespaceUri );
+
+    /**
+     * The name converter implemented by Code Model.
+     *
+     * This is the standard name conversion for JAXB.
+     */
+    NameConverter standard = new Standard();
+
+    /**
+     * Default implementation of {@link NameConverter}.
+     */
+    class Standard extends NameUtil implements NameConverter {
+        @Override
+        public String toClassName(String s) {
+            return toMixedCaseName(toWordList(s), true);
+        }
+        @Override
+        public String toVariableName(String s) {
+            return toMixedCaseName(toWordList(s), false);
+        }
+        @Override
+        public String toInterfaceName( String token ) {
+            return toClassName(token);
+        }
+        @Override
+        public String toPropertyName(String s) {
+            String prop = toClassName(s);
+            // property name "Class" with collide with Object.getClass,
+            // so escape this.
+            if(prop.equals("Class"))
+                prop = "Clazz";
+            return prop;
+        }
+        @Override
+        public String toConstantName( String token ) {
+            return super.toConstantName(token);
+        }
+        /**
+         * Computes a Java package name from a namespace URI,
+         * as specified in the spec.
+         *
+         * @param nsUri to convert
+         * @return
+         *      null if it fails to derive a package name.
+         */
+        @Override
+        public String toPackageName( String nsUri ) {
+            // remove scheme and :, if present
+            // spec only requires us to remove 'http' and 'urn'...
+            int idx = nsUri.indexOf(':');
+            String scheme = "";
+            if(idx>=0) {
+                scheme = nsUri.substring(0,idx);
+                if( scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("urn") )
+                    nsUri = nsUri.substring(idx+1);
+            }
+
+            // tokenize string
+            ArrayList<String> tokens = tokenize( nsUri, "/: " );
+            if( tokens.isEmpty() ) {
+                return null;
+            }
+
+            // remove trailing file type, if necessary
+            if( tokens.size() > 1 ) {
+                // for uri's like "www.foo.com" and "foo.com", there is no trailing
+                // file, so there's no need to look at the last '.' and substring
+                // otherwise, we loose the "com" (which would be wrong)
+                String lastToken = tokens.get( tokens.size()-1 );
+                idx = lastToken.lastIndexOf( '.' );
+                if( idx > 0 ) {
+                    lastToken = lastToken.substring( 0, idx );
+                    tokens.set( tokens.size()-1, lastToken );
+                }
+            }
+
+            // tokenize domain name and reverse.  Also remove :port if it exists
+            String domain = tokens.get( 0 );
+            idx = domain.indexOf(':');
+            if( idx >= 0) domain = domain.substring(0, idx);
+            ArrayList<String> r = reverse( tokenize( domain, scheme.equals("urn")?".-":"." ) );
+            if( r.get( r.size()-1 ).equalsIgnoreCase( "www" ) ) {
+                // remove leading www
+                r.remove( r.size()-1 );
+            }
+
+            // replace the domain name with tokenized items
+            tokens.addAll( 1, r );
+            tokens.remove( 0 );
+
+            // iterate through the tokens and apply xml->java name algorithm
+            for( int i = 0; i < tokens.size(); i++ ) {
+
+                // get the token and remove illegal chars
+                String token = tokens.get( i );
+                token = removeIllegalIdentifierChars( token );
+
+                // this will check for reserved keywords
+                if( !NameUtil.isJavaIdentifier( token ) ) {
+                    token = '_' + token;
+                }
+
+                tokens.set( i, token.toLowerCase(Locale.ENGLISH) );
+            }
+
+            // concat all the pieces and return it
+            return combine( tokens, '.' );
+        }
+
+
+        private static String removeIllegalIdentifierChars(String token) {
+            StringBuilder newToken = new StringBuilder();
+            for( int i = 0; i < token.length(); i++ ) {
+                char c = token.charAt( i );
+
+                if( i ==0 && !Character.isJavaIdentifierStart( c ) ) {
+                    // prefix an '_' if the first char is illegal
+                    newToken.append('_').append(c);
+                } else if( !Character.isJavaIdentifierPart( c ) ) {
+                    // replace the char with an '_' if it is illegal
+                    newToken.append( '_' );
+                } else {
+                    // add the legal char
+                    newToken.append( c );
+                }
+            }
+            return newToken.toString();
+        }
+
+
+        private static ArrayList<String> tokenize( String str, String sep ) {
+            StringTokenizer tokens = new StringTokenizer(str,sep);
+            ArrayList<String> r = new ArrayList<>();
+
+            while(tokens.hasMoreTokens())
+                r.add( tokens.nextToken() );
+
+            return r;
+        }
+
+        private static <T> ArrayList<T> reverse( List<T> a ) {
+            ArrayList<T> r = new ArrayList<>();
+
+            for( int i=a.size()-1; i>=0; i-- )
+                r.add( a.get(i) );
+
+            return r;
+        }
+
+        private static String combine( List<String> r, char sep ) {
+            StringBuilder buf = new StringBuilder(r.get(0));
+
+            for( int i=1; i<r.size(); i++ ) {
+                buf.append(sep);
+                buf.append(r.get(i));
+            }
+
+            return buf.toString();
+        }
+    }
+
+    /**
+     * JAX-PRC compatible name converter implementation.
+     *
+     * The only difference is that we treat '_' as a valid character
+     * and not as a word separator.
+     */
+    NameConverter jaxrpcCompatible = new Standard() {
+        @Override
+        protected boolean isPunct(char c) {
+            return (c == '.' || c == '-' || c == ';' /*|| c == '_'*/ || c == '\u00b7'
+                    || c == '\u0387' || c == '\u06dd' || c == '\u06de');
+        }
+        @Override
+        protected boolean isLetter(char c) {
+            return super.isLetter(c) || c=='_';
+        }
+
+        @Override
+        protected int classify(char c0) {
+            if(c0=='_') return NameUtil.OTHER_LETTER;
+            return super.classify(c0);
+        }
+    };
+
+    /**
+     * Smarter converter used for RELAX NG support.
+     */
+    NameConverter smart = new Standard() {
+        @Override
+        public String toConstantName( String token ) {
+            String name = super.toConstantName(token);
+            if( NameUtil.isJavaIdentifier(name) )
+                return name;
+            else
+                return '_'+name;
+        }
+    };
+}
diff --git a/istack-commons/buildtools/src/main/java/com/sun/istack/build/NameUtil.java b/istack-commons/buildtools/src/main/java/com/sun/istack/build/NameUtil.java
new file mode 100644
index 0000000..bac6ef4
--- /dev/null
+++ b/istack-commons/buildtools/src/main/java/com/sun/istack/build/NameUtil.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.build;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Methods that convert strings into various formats.
+ *
+ * <p>
+ * What JAX-RPC name binding tells us is that even such basic method
+ * like "isLetter" can be different depending on the situation.
+ *
+ * For this reason, a whole lot of methods are made non-static,
+ * even though they look like they should be static.
+ */
+class NameUtil {
+    protected boolean isPunct(char c) {
+        return c == '-' || c == '.' || c == ':' || c == '_' || c == '\u00b7' || c == '\u0387' || c == '\u06dd' || c == '\u06de';
+    }
+
+    protected static boolean isDigit(char c) {
+        return c >= '0' && c <= '9' || Character.isDigit(c);
+    }
+
+    protected static boolean isUpper(char c) {
+        return c >= 'A' && c <= 'Z' || Character.isUpperCase(c);
+    }
+
+    protected static boolean isLower(char c) {
+        return c >= 'a' && c <= 'z' || Character.isLowerCase(c);
+    }
+
+    protected boolean isLetter(char c) {
+        return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || Character.isLetter(c);
+    }
+
+    /**
+     * Capitalizes the first character of the specified string,
+     * and de-capitalize the rest of characters.
+     */
+    public String capitalize(String s) {
+        if (!isLower(s.charAt(0))) {
+            return s;
+        }
+        StringBuilder sb = new StringBuilder(s.length());
+        sb.append(Character.toUpperCase(s.charAt(0)));
+        sb.append(s.substring(1).toLowerCase(Locale.ENGLISH));
+        return sb.toString();
+    }
+
+    // Precondition: s[start] is not punctuation
+    private int nextBreak(String s, int start) {
+        int n = s.length();
+
+        char c1 = s.charAt(start);
+        int t1 = classify(c1);
+
+        for (int i=start+1; i<n; i++) {
+            // shift (c1,t1) into (c0,t0)
+            // char c0 = c1;  --- conceptually, but c0 won't be used
+            int t0 = t1;
+
+            c1 = s.charAt(i);
+            t1 = classify(c1);
+
+            switch(actionTable[t0*5+t1]) {
+            case ACTION_CHECK_PUNCT:
+                if(isPunct(c1)) return i;
+                break;
+            case ACTION_CHECK_C2:
+                if (i < n-1) {
+                    char c2 = s.charAt(i+1);
+                    if (isLower(c2))
+                        return i;
+                }
+                break;
+            case ACTION_BREAK:
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    // the 5-category classification that we use in this code
+    // to find work breaks
+    static protected final int UPPER_LETTER = 0;
+    static protected final int LOWER_LETTER = 1;
+    static protected final int OTHER_LETTER = 2;
+    static protected final int DIGIT = 3;
+    static protected final int OTHER = 4;
+
+    /**
+     * Look up table for actions.
+     * type0*5+type1 would yield the action to be taken.
+     */
+    private static final byte[] actionTable = new byte[5*5];
+
+    // action constants. see nextBreak for the meaning
+    static private final byte ACTION_CHECK_PUNCT = 0;
+    static private final byte ACTION_CHECK_C2 = 1;
+    static private final byte ACTION_BREAK = 2;
+    static private final byte ACTION_NOBREAK = 3;
+
+    /**
+     * Decide the action to be taken given
+     * the classification of the preceding character 't0' and
+     * the classification of the next character 't1'.
+     */
+    private static byte decideAction( int t0, int t1 ) {
+        if(t0==OTHER && t1==OTHER)  return ACTION_CHECK_PUNCT;
+        if(!xor(t0==DIGIT,t1==DIGIT))  return ACTION_BREAK;
+        if(t0==LOWER_LETTER && t1!=LOWER_LETTER)    return ACTION_BREAK;
+        if(!xor(t0<=OTHER_LETTER,t1<=OTHER_LETTER)) return ACTION_BREAK;
+        if(!xor(t0==OTHER_LETTER,t1==OTHER_LETTER)) return ACTION_BREAK;
+
+        if(t0==UPPER_LETTER && t1==UPPER_LETTER)    return ACTION_CHECK_C2;
+
+        return ACTION_NOBREAK;
+    }
+
+    private static boolean xor(boolean x,boolean y) {
+        return (x&&y) || (!x&&!y);
+    }
+
+    static {
+        // initialize the action table
+        for( int t0=0; t0<5; t0++ )
+            for( int t1=0; t1<5; t1++ )
+                actionTable[t0*5+t1] = decideAction(t0,t1);
+    }
+
+    /**
+     * Classify a character into 5 categories that determine the word break.
+     */
+    protected int classify(char c0) {
+        switch(Character.getType(c0)) {
+        case Character.UPPERCASE_LETTER:        return UPPER_LETTER;
+        case Character.LOWERCASE_LETTER:        return LOWER_LETTER;
+        case Character.TITLECASE_LETTER:
+        case Character.MODIFIER_LETTER:
+        case Character.OTHER_LETTER:            return OTHER_LETTER;
+        case Character.DECIMAL_DIGIT_NUMBER:    return DIGIT;
+        default:                                return OTHER;
+        }
+    }
+
+
+    /**
+     * Tokenizes a string into words and capitalizes the first
+     * character of each word.
+     *
+     * <p>
+     * This method uses a change in character type as a splitter
+     * of two words. For example, "abc100ghi" will be splitted into
+     * {"Abc", "100","Ghi"}.
+     */
+    public List<String> toWordList(String s) {
+        ArrayList<String> ss = new ArrayList<>();
+        int n = s.length();
+        for (int i = 0; i < n;) {
+
+            // Skip punctuation
+            while (i < n) {
+                if (!isPunct(s.charAt(i)))
+                    break;
+                i++;
+            }
+            if (i >= n) break;
+
+            // Find next break and collect word
+            int b = nextBreak(s, i);
+            String w = (b == -1) ? s.substring(i) : s.substring(i, b);
+            ss.add(escape(capitalize(w)));
+            if (b == -1) break;
+            i = b;
+        }
+
+//      we can't guarantee a valid Java identifier anyway,
+//      so there's not much point in rejecting things in this way.
+//        if (ss.size() == 0)
+//            throw new IllegalArgumentException("Zero-length identifier");
+        return ss;
+    }
+
+    protected String toMixedCaseName(List<String> ss, boolean startUpper) {
+        StringBuilder sb = new StringBuilder();
+        if(!ss.isEmpty()) {
+            sb.append(startUpper ? ss.get(0) : ss.get(0).toLowerCase(Locale.ENGLISH));
+            for (int i = 1; i < ss.size(); i++)
+                sb.append(ss.get(i));
+        }
+        return sb.toString();
+    }
+
+    protected String toMixedCaseVariableName(String[] ss,
+                                                  boolean startUpper,
+                                                  boolean cdrUpper) {
+        if (cdrUpper)
+            for (int i = 1; i < ss.length; i++)
+                ss[i] = capitalize(ss[i]);
+        StringBuilder sb = new StringBuilder();
+        if( ss.length>0 ) {
+            sb.append(startUpper ? ss[0] : ss[0].toLowerCase(Locale.ENGLISH));
+            for (int i = 1; i < ss.length; i++)
+                sb.append(ss[i]);
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * Formats a string into "THIS_KIND_OF_FORMAT_ABC_DEF".
+     *
+     * @return
+     *      Always return a string but there's no guarantee that
+     *      the generated code is a valid Java identifier.
+     */
+    public String toConstantName(String s) {
+        return toConstantName(toWordList(s));
+    }
+
+    /**
+     * Formats a string into "THIS_KIND_OF_FORMAT_ABC_DEF".
+     *
+     * @return
+     *      Always return a string but there's no guarantee that
+     *      the generated code is a valid Java identifier.
+     */
+    public String toConstantName(List<String> ss) {
+        StringBuilder sb = new StringBuilder();
+        if( !ss.isEmpty() ) {
+            sb.append(ss.get(0).toUpperCase(Locale.ENGLISH));
+            for (int i = 1; i < ss.size(); i++) {
+                sb.append('_');
+                sb.append(ss.get(i).toUpperCase(Locale.ENGLISH));
+            }
+        }
+        return sb.toString();
+    }
+
+
+
+    /**
+     * Escapes characters is the given string so that they can be
+     * printed by only using US-ASCII characters.
+     *
+     * The escaped characters will be appended to the given
+     * StringBuffer.
+     *
+     * @param sb
+     *      StringBuffer that receives escaped string.
+     * @param s
+     *      String to be escaped. <code>s.substring(start)</code>
+     *      will be escaped and copied to the string buffer.
+     */
+    public static void escape(StringBuilder sb, String s, int start) {
+        int n = s.length();
+        for (int i = start; i < n; i++) {
+            char c = s.charAt(i);
+            if (Character.isJavaIdentifierPart(c))
+                sb.append(c);
+            else {
+                sb.append('_');
+                if (c <= '\u000f') sb.append("000");
+                else if (c <= '\u00ff') sb.append("00");
+                else if (c <= '\u0fff') sb.append('0');
+                sb.append(Integer.toString(c, 16));
+            }
+        }
+    }
+
+    /**
+     * Escapes characters that are unusable as Java identifiers
+     * by replacing unsafe characters with safe characters.
+     */
+    private static String escape(String s) {
+        int n = s.length();
+        for (int i = 0; i < n; i++)
+            if (!Character.isJavaIdentifierPart(s.charAt(i))) {
+                StringBuilder sb = new StringBuilder(s.substring(0, i));
+                escape(sb, s, i);
+                return sb.toString();
+            }
+        return s;
+    }
+
+
+    /**
+     * Checks if a given string is usable as a Java identifier.
+     */
+    public static boolean isJavaIdentifier(String s) {
+        if(s.length()==0)   return false;
+        if( reservedKeywords.contains(s) )  return false;
+
+        if(!Character.isJavaIdentifierStart(s.charAt(0)))   return false;
+
+        for (int i = 1; i < s.length(); i++)
+            if (!Character.isJavaIdentifierPart(s.charAt(i)))
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Checks if the given string is a valid Java package name.
+     */
+    public static boolean isJavaPackageName(String s) {
+        while(s.length()!=0) {
+            int idx = s.indexOf('.');
+            if(idx==-1) idx=s.length();
+            if( !isJavaIdentifier(s.substring(0,idx)) )
+                return false;
+
+            s = s.substring(idx);
+            if(s.length()!=0)    s = s.substring(1);    // remove '.'
+        }
+        return true;
+    }
+
+
+    /** All reserved keywords of Java. */
+    private static HashSet<String> reservedKeywords = new HashSet<>();
+
+    static {
+        // see http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html
+        String[] words = new String[]{
+            "abstract",
+            "boolean",
+            "break",
+            "byte",
+            "case",
+            "catch",
+            "char",
+            "class",
+            "const",
+            "continue",
+            "default",
+            "do",
+            "double",
+            "else",
+            "extends",
+            "final",
+            "finally",
+            "float",
+            "for",
+            "goto",
+            "if",
+            "implements",
+            "import",
+            "instanceof",
+            "int",
+            "interface",
+            "long",
+            "native",
+            "new",
+            "package",
+            "private",
+            "protected",
+            "public",
+            "return",
+            "short",
+            "static",
+            "strictfp",
+            "super",
+            "switch",
+            "synchronized",
+            "this",
+            "throw",
+            "throws",
+            "transient",
+            "try",
+            "void",
+            "volatile",
+            "while",
+
+            // technically these are not reserved words but they cannot be used as identifiers.
+            "true",
+            "false",
+            "null",
+
+            // and I believe assert is also a new keyword
+            "assert",
+
+            // and 5.0 keywords
+            "enum"
+            };
+        reservedKeywords.addAll(Arrays.asList(words));
+    }
+}
diff --git a/istack-commons/buildtools/src/main/java/com/sun/istack/build/ResourceGenTask.java b/istack-commons/buildtools/src/main/java/com/sun/istack/build/ResourceGenTask.java
new file mode 100644
index 0000000..73a242f
--- /dev/null
+++ b/istack-commons/buildtools/src/main/java/com/sun/istack/build/ResourceGenTask.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.build;
+
+import com.sun.codemodel.CodeWriter;
+import com.sun.codemodel.JClass;
+import com.sun.codemodel.JClassAlreadyExistsException;
+import com.sun.codemodel.JCodeModel;
+import com.sun.codemodel.JDefinedClass;
+import com.sun.codemodel.JExpr;
+import com.sun.codemodel.JFieldVar;
+import com.sun.codemodel.JInvocation;
+import com.sun.codemodel.JMethod;
+import com.sun.codemodel.JMod;
+import com.sun.codemodel.JPackage;
+import com.sun.codemodel.writer.FileCodeWriter;
+import com.sun.codemodel.writer.FilterCodeWriter;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Generate source files from resource bundles,
+ * so that code can refer to resources as methods,
+ * instead of hard-coding string constants, which is
+ * much harder to search.
+ *
+ * @author Lukas Jungmann
+ * @author Kohsuke Kawaguchi
+ */
+public class ResourceGenTask extends Task {
+    /**
+     * Resource files to be compiled
+     */
+    private FileSet resources;
+
+    private File destDir;
+
+    /**
+     * @since 2.12
+     */
+    private File license;
+
+    /**
+     * @since 2.12
+     */
+    private String localizationUtilitiesPkgName;
+
+    /**
+     * @since 2.12
+     */
+    private String encoding;
+
+    public void addConfiguredResource( FileSet fs ) {
+        resources = fs;
+    }
+
+    public void setDestDir(File dir) {
+        this.destDir = dir;
+    }
+
+    /**
+     * @since 2.12
+     */
+    public void setLicense(File license) {
+        this.license = license;
+    }
+
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * @since 2.12
+     */
+    public void setLocalizationUtilitiesPkgName(String localizationUtilitiesPkgName) {
+        this.localizationUtilitiesPkgName = localizationUtilitiesPkgName;
+    }
+
+    @Override
+    public void execute() throws BuildException {
+        if(resources==null)
+            throw new BuildException("No resource file is specified");
+        if(destDir==null)
+            throw new BuildException("No destdir attribute is specified");
+
+        if(localizationUtilitiesPkgName == null) {
+            localizationUtilitiesPkgName = "com.sun.istack.localization";
+        }
+
+        if (!destDir.exists() && !destDir.mkdirs()) {
+                throw new BuildException("Cannot create destdir");
+        }
+
+        if (!destDir.canWrite()) {
+            throw new BuildException("Cannot write to destdir");
+        }
+
+        if (encoding == null || encoding.trim().length() == 0) {
+            encoding =  System.getProperty("file.encoding");
+            log("File encoding has not been set, using platform encoding "
+                    + encoding + ", i.e. build is platform dependent!",
+                    Project.MSG_WARN);
+        }
+
+        JCodeModel cm = new JCodeModel();
+
+        DirectoryScanner ds = resources.getDirectoryScanner(getProject());
+        String[] includedFiles = ds.getIncludedFiles();
+        File baseDir = ds.getBasedir();
+
+        for (String value : includedFiles) {
+            File res = new File(baseDir, value);
+
+            if(res.getName().contains("_"))
+                continue;   // this is a localized bundle, so ignore.
+
+            String className = getClassName(res);
+
+            String bundleName = value.substring(0, value.lastIndexOf('.')).replace('/', '.').replace('\\', '.');// cut off '.properties'
+            String dirName = bundleName.substring(0, bundleName.lastIndexOf('.'));
+
+            File destFile = new File(new File(destDir,dirName.replace('.','/')),className+".java");
+            if(destFile.lastModified() >= res.lastModified()) {
+                log("Skipping "+res,Project.MSG_INFO);
+                continue;
+            }
+
+            log("Processing "+res,Project.MSG_INFO);
+            JPackage pkg = cm._package(dirName);
+
+            Properties props = new Properties();
+            FileInputStream in = null;
+            try {
+                in = new FileInputStream(res);
+                props.load(in);
+            } catch (IOException e) {
+                throw new BuildException(e.getMessage(), e);
+            } finally {
+                if (in != null) {
+                    try {
+                        in.close();
+                    } catch (IOException ioe) {
+                        throw new BuildException(ioe.getMessage(), ioe);
+                    }
+                }
+            }
+
+            JDefinedClass clazz;
+            try {
+                clazz = pkg._class(JMod.PUBLIC | JMod.FINAL, className);
+            } catch (JClassAlreadyExistsException e) {
+                throw new BuildException("Name conflict "+className);
+            }
+
+            clazz.javadoc().add(
+                "Defines string formatting method for each constant in the resource file"
+            );
+
+            /*
+              [RESULT]
+
+                LocalizableMessageFactory messageFactory =
+                    new LocalizableMessageFactory("com.sun.xml.ws.resources.client");
+                Localizer localizer = new Localizer();
+            */
+
+            JClass lmf_class;
+            JClass l_class;
+            JClass lable_class;
+            try {
+                lmf_class = cm.parseType(addLocalizationUtilityPackageName("LocalizableMessageFactory")).boxify();
+                l_class = cm.parseType(addLocalizationUtilityPackageName("Localizer")).boxify();
+                lable_class = cm.parseType(addLocalizationUtilityPackageName("Localizable")).boxify();
+            } catch (Throwable e) {
+                throw new BuildException(e); // impossible -- but why parseType throwing Exception!?
+            }
+
+            JFieldVar $msgFactory = clazz.field(JMod.PRIVATE|JMod.STATIC|JMod.FINAL,
+                lmf_class, "messageFactory", JExpr._new(lmf_class).arg(JExpr.lit(bundleName)));
+
+            JFieldVar $localizer = clazz.field(JMod.PRIVATE|JMod.STATIC|JMod.FINAL,
+                l_class, "localizer", JExpr._new(l_class));
+
+            for (Map.Entry<Object,Object> e : props.entrySet()) {
+                // [RESULT]
+                // Localizable METHOD_localizable(Object arg1, Object arg2, ...) {
+                //   return messageFactory.getMessage("servlet.html.notFound", message));
+                // }
+                // String METHOD(Object arg1, Object arg2, ...) {
+                //   return localizer.localize(METHOD_localizable(arg1,arg2,...));
+                // }
+                String methodBaseName = NameConverter.smart.toConstantName(e.getKey().toString());
+
+                JMethod method = clazz.method(JMod.PUBLIC | JMod.STATIC, lable_class, "localizable"+methodBaseName);
+
+                int countArgs = countArgs(e.getValue().toString());
+
+                JInvocation format = $msgFactory.invoke("getMessage").arg(
+                    JExpr.lit(e.getKey().toString()));
+
+                for( int i=0; i<countArgs; i++ ) {
+                    format.arg( method.param(Object.class,"arg"+i));
+                }
+                method.body()._return(format);
+
+                JMethod method2 = clazz.method(JMod.PUBLIC|JMod.STATIC, String.class, methodBaseName);
+                method2.javadoc().add(e.getValue());
+
+                JInvocation localize = JExpr.invoke(method);
+                for( int i=0; i<countArgs; i++ ) {
+                    localize.arg( method2.param(Object.class,"arg"+i));
+                }
+
+                method2.body()._return($localizer.invoke("localize").arg(localize));
+            }
+        }
+
+        try {
+            CodeWriter core = new FileCodeWriter(destDir, encoding);
+            if (license != null) {
+                core = new LicenseCodeWriter(core, license, encoding);
+            }
+            cm.build(core);
+        } catch (IOException e) {
+            throw new BuildException("Failed to generate code",e);
+        }
+    }
+
+    private String addLocalizationUtilityPackageName(final String className) {
+        return String.format("%s.%s", localizationUtilitiesPkgName, className);
+    }
+
+    /**
+     * Counts the number of arguments.
+     */
+    private int countArgs(String value) {
+        List<String> x = new ArrayList<>();
+
+        while(true) {
+            String r1 = MessageFormat.format(value, x.toArray());
+            x.add("xxxx");
+            String r2 = MessageFormat.format(value, x.toArray());
+
+            if(r1.equals(r2))
+                return x.size()-1;
+        }
+    }
+
+    /**
+     * Computes the class name from the resource bundle name.
+     */
+    private String getClassName(File res) {
+        String name = res.getName();
+        int suffixIndex = name.lastIndexOf('.');
+        name = name.substring(0,suffixIndex);
+        return NameConverter.smart.toClassName(name)+"Messages";
+    }
+
+    /**
+     * Writes all the source files under the specified file folder and
+     * inserts a license file each java source file.
+     *
+     * @author Jitendra Kotamraju
+     *
+     */
+    public static class LicenseCodeWriter extends FilterCodeWriter {
+        private final File license;
+
+        /**
+         * @param core
+         *      This CodeWriter will be used to actually create a storage for files.
+         *      LicenseCodeWriter simply decorates this underlying CodeWriter by
+         *      adding prolog comments.
+         * @param license license File
+         */
+        public LicenseCodeWriter(CodeWriter core, File license, String encoding) {
+            super(core);
+            this.license = license;
+            this.encoding = encoding;
+        }
+
+        @Override
+        public Writer openSource(JPackage pkg, String fileName) throws IOException {
+            Writer w = super.openSource(pkg,fileName);
+
+            PrintWriter out = new PrintWriter(w);
+            try (FileInputStream fin = new FileInputStream(license)) {
+                byte[] buf = new byte[8192];
+                int len;
+                while ((len = fin.read(buf)) != -1) {
+                    out.write(new String(buf, 0, len));
+                }
+            }
+            out.flush();    // we can't close the stream for that would close the undelying stream.
+
+            return w;
+        }
+    }
+}
diff --git a/istack-commons/import-properties-plugin/exclude.xml b/istack-commons/import-properties-plugin/exclude.xml
new file mode 100644
index 0000000..43ee8b0
--- /dev/null
+++ b/istack-commons/import-properties-plugin/exclude.xml
@@ -0,0 +1,22 @@
+<!--
+
+    Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<FindBugsFilter>
+    <!--
+    Generated by Maven.
+    -->
+    <Match>
+        <Or>
+            <Class name="com.oracle.istack.maven.HelpMojo"/>
+        </Or>
+    </Match>    
+</FindBugsFilter>
diff --git a/istack-commons/import-properties-plugin/pom.xml b/istack-commons/import-properties-plugin/pom.xml
new file mode 100644
index 0000000..1c90108
--- /dev/null
+++ b/istack-commons/import-properties-plugin/pom.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>istack-commons</artifactId>
+        <groupId>com.sun.istack</groupId>
+        <version>4.2.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.sun.istack</groupId>
+    <artifactId>import-properties-plugin</artifactId>
+    <packaging>maven-plugin</packaging>
+    <name>istack common import properties plugin</name>
+
+    <prerequisites>
+        <maven>3.0</maven>
+    </prerequisites>
+
+    <properties>
+        <findbugs.exclude>${project.basedir}/exclude.xml</findbugs.exclude>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-utils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-tools</groupId>
+            <artifactId>maven-plugin-annotations</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-model</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>mojo-descriptor</id>
+                        <goals>
+                            <goal>descriptor</goal>
+                            <goal>helpmojo</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>ittest</id>
+            <activation>
+                <property>
+                    <name>ittest</name>
+                    <value>true</value>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.gmaven</groupId>
+                        <artifactId>gmaven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>set-proxy</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>execute</goal>
+                                </goals>
+                                <configuration>
+                                    <source>${project.basedir}/src/test/script/setproxy.groovy</source>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-invoker-plugin</artifactId>
+                        <configuration>
+                            <localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
+                            <streamLogs>true</streamLogs>
+                            <addTestClassPath>true</addTestClassPath>
+                            <settingsFile>${project.build.directory}/it-settings.xml</settingsFile>
+                            <mavenOpts>${ittest-proxy}</mavenOpts>
+                            <properties>
+                                <ip.plugin.version>${project.version}</ip.plugin.version>
+                            </properties>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>integration-test-installdeps</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>install</goal>
+                                </goals>
+                            </execution>
+                            <execution>
+                                <id>integration-test</id>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <projectsDirectory>src/test/it</projectsDirectory>
+                                    <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration-test-verify</id>
+                                <phase>post-integration-test</phase>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                                <configuration>
+                                    <systemPropertyVariables>
+                                        <it.projects.dir>${project.build.directory}/it</it.projects.dir>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/CommonLogger.java b/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/CommonLogger.java
new file mode 100644
index 0000000..aa0e1de
--- /dev/null
+++ b/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/CommonLogger.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.oracle.istack.maven;
+
+import org.apache.maven.plugin.logging.Log;
+
+/**
+ *
+ * @author Martin Grebac
+ */
+public class CommonLogger {
+
+    private final Log log;
+
+    public CommonLogger(Log log) {
+        this.log = log;
+    }
+
+    public void warn(String s) {
+        if (log != null) {
+            log.warn(s);
+        }
+    }
+
+    public void info(String s) {
+        if (log != null) {
+            log.info(s);
+        }
+    }
+}
diff --git a/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/DependencyResolver.java b/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/DependencyResolver.java
new file mode 100644
index 0000000..d102621
--- /dev/null
+++ b/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/DependencyResolver.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.oracle.istack.maven;
+
+import java.util.List;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.DependencyRequest;
+import org.eclipse.aether.resolution.DependencyResolutionException;
+import org.eclipse.aether.resolution.DependencyResult;
+import org.eclipse.aether.artifact.DefaultArtifact;
+
+/**
+ *
+ * @author lukas
+ */
+final class DependencyResolver {
+
+    public static DependencyResult resolve(CollectRequest collectRequest, List<RemoteRepository> remoteRepos,
+            RepositorySystem repoSystem, RepositorySystemSession repoSession) throws DependencyResolutionException {
+        DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, null);
+        return repoSystem.resolveDependencies(repoSession, dependencyRequest);
+    }
+
+    public static DependencyResult resolve(org.apache.maven.model.Dependency dependency, List<RemoteRepository> remoteRepos,
+            RepositorySystem repoSystem, RepositorySystemSession repoSession) throws DependencyResolutionException {
+        CollectRequest collectRequest = new CollectRequest(createDependency(dependency), remoteRepos);
+        return resolve(collectRequest, remoteRepos, repoSystem, repoSession);
+    }
+
+    private static Dependency createDependency(org.apache.maven.model.Dependency d) {
+        Artifact artifact = new DefaultArtifact(d.getGroupId(), d.getArtifactId(), "pom", d.getVersion());
+        return new Dependency(artifact, d.getScope(), d.isOptional(), null);
+    }
+
+}
diff --git a/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/ImportPropertiesMojo.java b/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/ImportPropertiesMojo.java
new file mode 100644
index 0000000..29a3d0d
--- /dev/null
+++ b/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/ImportPropertiesMojo.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.oracle.istack.maven;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * The import-properties goal imports all properties from scope-import poms
+ * (boms) and sets them as project properties.
+ *
+ * @author Martin Grebac
+ */
+@Mojo(name = "import-pom-properties", threadSafe = true,
+        defaultPhase = LifecyclePhase.COMPILE, requiresDependencyResolution = ResolutionScope.NONE)
+public class ImportPropertiesMojo extends AbstractMojo {
+
+    /**
+     * The Maven Project Object.
+     */
+    @Parameter(defaultValue = "${project}", readonly = true)
+    protected MavenProject project;
+
+    /**
+     * The entry point to Aether, i.e. the component doing all the work.
+     *
+     * @since 2.3.1
+     */
+    @Component
+    private RepositorySystem repoSystem;
+
+    /**
+     * The current repository/network configuration of Maven.
+     *
+     * @since 2.3.1
+     */
+    @Parameter(defaultValue = "${repositorySystemSession}", readonly = true)
+    private RepositorySystemSession repoSession;
+
+    /**
+     * The project's remote repositories to use for the resolution of project
+     * and its dependencies.
+     *
+     * @since 2.3.1
+     */
+    @Parameter(defaultValue = "${project.remoteProjectRepositories}", readonly = true)
+    private List<RemoteRepository> projectRepos;
+
+    private Properties projectProperties = null;
+
+    @Override
+    public void execute() throws MojoExecutionException {
+        try {
+            projectProperties = project.getProperties();
+
+            MavenProject bomProject = project;
+            while (bomProject != null && !bomProject.getArtifactId().endsWith("-bom")) {
+                bomProject = bomProject.getParent();
+            }
+
+            if (bomProject == null || !bomProject.getArtifactId().endsWith("-bom")) {
+                getLog().warn("No '*-bom' project found in project hierarchy, using this project's pom for import search.");
+                bomProject = project;
+            }
+
+            getLog().warn("Searching project: " + bomProject.getArtifactId());
+
+            PropertyResolver resolver = new PropertyResolver(new CommonLogger(getLog()), projectProperties, repoSession, repoSystem, projectRepos);
+            resolver.resolveProperties(bomProject);
+
+        } catch (XmlPullParserException | IOException ex) {
+            Logger.getLogger(ImportPropertiesMojo.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+
+}
diff --git a/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/PropertyResolver.java b/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/PropertyResolver.java
new file mode 100644
index 0000000..16e4834
--- /dev/null
+++ b/istack-commons/import-properties-plugin/src/main/java/com/oracle/istack/maven/PropertyResolver.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.oracle.istack.maven;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.DependencyResolutionException;
+import org.eclipse.aether.resolution.DependencyResult;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Martin Grebac
+ */
+public class PropertyResolver {
+
+    private final CommonLogger logger;
+
+    private final MavenXpp3Reader mavenreader = new MavenXpp3Reader();
+
+    private final Properties properties;
+
+    private final RepositorySystemSession repoSession;
+
+    private final RepositorySystem repoSystem;
+
+    private final List<RemoteRepository> pluginRepos;
+
+    PropertyResolver(CommonLogger logger, Properties properties, RepositorySystemSession session,
+            RepositorySystem repoSystem, List<RemoteRepository> pluginRepositories) {
+        this.logger = logger;
+        this.properties = properties;
+        this.repoSession = session;
+        this.repoSystem = repoSystem;
+        this.pluginRepos = pluginRepositories;
+    }
+
+    /**
+     *
+     * @param project maven project
+     * @throws FileNotFoundException properties not found
+     * @throws IOException IO error
+     * @throws XmlPullParserException error parsing xml
+     */
+    public void resolveProperties(MavenProject project) throws FileNotFoundException, IOException, XmlPullParserException {
+        logger.info("Resolving properties for " + project.getGroupId() + ":" + project.getArtifactId());
+
+        Model model = null;
+        FileReader reader;
+        try {
+            reader = new FileReader(project.getFile());
+            model = mavenreader.read(reader);
+        } catch (IOException ex) {
+            Logger.getLogger(ImportPropertiesMojo.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        MavenProject loadedProject = new MavenProject(model);
+
+        DependencyManagement dm = loadedProject.getDependencyManagement();
+        if (dm == null) {
+            logger.warn("No dependency management section found in: "  + loadedProject.getGroupId() + ":" + loadedProject.getArtifactId());
+            return;
+        }
+
+        List<Dependency> depList = dm.getDependencies();
+
+        DependencyResult result;
+        for (Dependency d : depList) {
+            if ("import".equals(d.getScope())) {
+                try {
+                    String version = d.getVersion();
+                    logger.info("Imported via import-scope: " + d.getGroupId() + ":" + d.getArtifactId() + ":" + version);
+                    if (version.contains("$")) {
+                        version = properties.getProperty(version.substring(version.indexOf('{')+1, version.lastIndexOf('}')));
+                        logger.info("Imported version resolved to: " + version);
+                    }
+                    d.setVersion(version);
+                    d.setType("pom");
+                    d.setClassifier("pom");
+                    result = DependencyResolver.resolve(d, pluginRepos, repoSystem, repoSession);
+                    Artifact a = result.getArtifactResults().get(0).getArtifact();
+                    reader = new FileReader(a.getFile());
+                    Model m = mavenreader.read(reader);
+                    MavenProject p = new MavenProject(m);
+                    p.setFile(a.getFile());
+                    for (Map.Entry<Object,Object> e : p.getProperties().entrySet()) {
+                        logger.info("Setting property: " + e.getKey() + ":" + e.getValue());
+                        properties.setProperty((String)e.getKey(), (String)e.getValue());
+                    }
+
+                    resolveProperties(p);
+                } catch (DependencyResolutionException ex) {
+                    Logger.getLogger(ImportPropertiesMojo.class.getName()).log(Level.SEVERE, null, ex);
+                }
+            }
+        }
+    }
+
+
+}
diff --git a/istack-commons/import-properties-plugin/src/test/it/sample/bom/pom.xml b/istack-commons/import-properties-plugin/src/test/it/sample/bom/pom.xml
new file mode 100644
index 0000000..97651e8
--- /dev/null
+++ b/istack-commons/import-properties-plugin/src/test/it/sample/bom/pom.xml
@@ -0,0 +1,28 @@
+<!--
+
+    Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.sun.xml.ws</groupId>
+    <artifactId>imported-bom</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>sample bom</name>
+
+    <properties>
+        <tested.property>IMPORTED</tested.property>
+    </properties>
+
+</project>
diff --git a/istack-commons/import-properties-plugin/src/test/it/sample/pom.xml b/istack-commons/import-properties-plugin/src/test/it/sample/pom.xml
new file mode 100644
index 0000000..a483be4
--- /dev/null
+++ b/istack-commons/import-properties-plugin/src/test/it/sample/pom.xml
@@ -0,0 +1,98 @@
+<!--
+
+    Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.sun.xml.ws</groupId>
+    <artifactId>importsample-bom</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>sample main</name>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>com.sun.xml.ws</groupId>
+                <artifactId>imported-bom</artifactId>
+                <version>1.0-SNAPSHOT</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <modules>
+        <module>bom</module>
+    </modules>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <ip.plugin.version>4.0.0-SNAPSHOT</ip.plugin.version>
+    </properties>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>com.sun.istack</groupId>
+                    <artifactId>import-properties-plugin</artifactId>
+                    <version>${ip.plugin.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-enforcer-plugin</artifactId>
+                    <version>3.3.0</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        <plugins>
+            <plugin>
+                <groupId>com.sun.istack</groupId>
+                <artifactId>import-properties-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>compile</phase>
+                        <goals>
+                            <goal>import-pom-properties</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>enforce-property</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <phase>compile</phase>
+                        <configuration>
+                            <rules>
+                                <requireProperty>
+                                    <property>tested.property</property>
+                                    <message>Property not imported!</message>
+                                </requireProperty>
+                            </rules>
+                            <fail>true</fail>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/istack-commons/import-properties-plugin/src/test/resources/it-settings.xml b/istack-commons/import-properties-plugin/src/test/resources/it-settings.xml
new file mode 100644
index 0000000..d4f5aa2
--- /dev/null
+++ b/istack-commons/import-properties-plugin/src/test/resources/it-settings.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!--
+
+    Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<settings>
+    <profiles>
+        <profile>
+            <id>it-repo</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <repositories>
+                <repository>
+                    <id>local.central</id>
+                    <url>@localRepositoryUrl@</url>
+                    <releases>
+                        <enabled>true</enabled>
+                    </releases>
+                    <snapshots>
+                        <enabled>true</enabled>
+                    </snapshots>
+                </repository>
+                <repository>
+                    <id>jakarta-sonatype-nexus</id>
+                    <url>https://jakarta.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+                    <layout>default</layout>
+                </repository>
+                <repository>
+                    <id>jakarta-sonatype-nexus-staging</id>
+                    <url>https://jakarta.oss.sonatype.org/content/repositories/staging/</url>
+                    <layout>default</layout>
+                </repository>
+            </repositories>
+            <pluginRepositories>
+                <pluginRepository>
+                    <id>local.central</id>
+                    <url>@localRepositoryUrl@</url>
+                    <releases>
+                        <enabled>true</enabled>
+                    </releases>
+                    <snapshots>
+                        <enabled>true</enabled>
+                    </snapshots>
+                </pluginRepository>
+                <pluginRepository>
+                    <id>jakarta-sonatype-nexus-plugins</id>
+                    <url>https://jakarta.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+                    <layout>default</layout>
+                </pluginRepository>
+                <pluginRepository>
+                    <id>jakarta-sonatype-nexus-staging-plugins</id>
+                    <url>https://jakarta.oss.sonatype.org/content/repositories/staging/</url>
+                    <layout>default</layout>
+                </pluginRepository>
+            </pluginRepositories>
+        </profile>
+    </profiles>
+</settings>
diff --git a/istack-commons/import-properties-plugin/src/test/script/setproxy.groovy b/istack-commons/import-properties-plugin/src/test/script/setproxy.groovy
new file mode 100644
index 0000000..241003e
--- /dev/null
+++ b/istack-commons/import-properties-plugin/src/test/script/setproxy.groovy
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+log.info("Checking proxy...")
+def itsettings = new XmlParser().parse(project.build.testResources.directory[0] + "/it-settings.xml")
+def itproxy = ""
+if (settings?.proxies) {
+    Node proxies = new Node(itsettings, "proxies")
+    settings?.proxies?.each { proxy ->
+        if (proxy.active) {
+            if ("http".equals(proxy.protocol)) {
+                itproxy +=  " -Dhttp.proxyHost=" + proxy.host
+                if (proxy.port) {
+                    itproxy += " -Dhttp.proxyPort=" + proxy.port
+                }
+            } else if ("https".equals(proxy.protocol)) {
+                itproxy +=  " -Dhttps.proxyHost=" + proxy.host
+                if (proxy.port) {
+                    itproxy += " -Dhttps.proxyPort=" + proxy.port
+                }
+            }
+            def p = new Node(proxies, "proxy")
+            new Node(p, "protocol", proxy.protocol)
+            new Node(p, "port", proxy.port)
+            if (proxy.username) {new Node(p, "username", proxy.username)}
+            if (proxy.password) {new Node(p, "password", proxy.password)}
+            if (proxy.id) {new Node(p, "id", proxy.id)} else {new Node(p, "id", proxy.protocol)}
+            new Node(p, "host", proxy.host)
+            new Node(p, "active", proxy.active)
+            new Node(p, "nonProxyHosts", proxy.nonProxyHosts)
+        }
+    }
+}
+
+if (itproxy.trim().length() > 0) {
+    log.info("Setting: " + itproxy.trim())
+} else {
+    log.info("No proxy found")
+}
+
+def writer = new FileWriter(new File(project.build.directory, "it-settings.xml"))
+groovy.xml.XmlNodePrinter printer = new groovy.xml.XmlNodePrinter(new PrintWriter(writer))
+printer.setPreserveWhitespace(true)
+printer.print(itsettings)
+
+project.getModel().addProperty("ittest-proxy", itproxy.trim())
diff --git a/istack-commons/maven-plugin/pom.xml b/istack-commons/maven-plugin/pom.xml
new file mode 100644
index 0000000..48d8f3a
--- /dev/null
+++ b/istack-commons/maven-plugin/pom.xml
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>istack-commons</artifactId>
+        <groupId>com.sun.istack</groupId>
+        <version>4.2.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.sun.istack</groupId>
+    <artifactId>istack-commons-maven-plugin</artifactId>
+    <packaging>maven-plugin</packaging>
+    <name>istack common maven mojo</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-artifact</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-tools</groupId>
+            <artifactId>maven-plugin-annotations</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jaxb</groupId>
+            <artifactId>codemodel</artifactId>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>ittest</id>
+            <activation>
+                <property>
+                    <name>ittest</name>
+                    <value>true</value>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.gmaven</groupId>
+                        <artifactId>gmaven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>set-proxy</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>execute</goal>
+                                </goals>
+                                <configuration>
+                                    <source>${project.basedir}/src/test/script/setproxy.groovy</source>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-invoker-plugin</artifactId>
+                        <configuration>
+                            <localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
+                            <streamLogs>true</streamLogs>
+                            <addTestClassPath>true</addTestClassPath>
+                            <settingsFile>${project.build.directory}/it-settings.xml</settingsFile>
+                            <mavenOpts>${ittest-proxy}</mavenOpts>
+                            <properties>
+                                <resgen.plugin.version>${project.version}</resgen.plugin.version>
+                                <tp.compiler.release>${maven.compiler.release}</tp.compiler.release>
+                            </properties>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>integration-test-installdeps</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>install</goal>
+                                </goals>
+                            </execution>
+                            <execution>
+                                <id>integration-test</id>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <projectsDirectory>src/test/it</projectsDirectory>
+                                    <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration-test-verify</id>
+                                <phase>post-integration-test</phase>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                                <configuration>
+                                    <systemPropertyVariables>
+                                        <it.projects.dir>${project.build.directory}/it</it.projects.dir>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>descriptors</id>
+                        <goals>
+                            <goal>descriptor</goal>
+                            <goal>helpmojo</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/ArtifactItem.java b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/ArtifactItem.java
new file mode 100644
index 0000000..630404d
--- /dev/null
+++ b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/ArtifactItem.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+/**
+ *
+ * @author japod
+ */
+public class ArtifactItem {
+
+    private String artifactId;
+    private String groupId;
+    private String version;
+
+    public String getVersion() {
+        return version;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("{groupId=%s, artifactId=%s, version=%s}", groupId, artifactId, version);
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(String artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+}
diff --git a/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/LicenseCodeWriter.java b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/LicenseCodeWriter.java
new file mode 100644
index 0000000..8037dbc
--- /dev/null
+++ b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/LicenseCodeWriter.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+import com.sun.codemodel.CodeWriter;
+import com.sun.codemodel.JPackage;
+import com.sun.codemodel.writer.FilterCodeWriter;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Calendar;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Writes all the source files under the specified file folder and inserts a
+ * license file each java source file.
+ */
+final class LicenseCodeWriter extends FilterCodeWriter {
+
+    private static final String COPYRIGHT_LINE_TEMPLATE = "^.*Copyright \\(c\\) (YYYY) (by )?([A-Za-z].*)$";
+    private static final Pattern PATTERN = Pattern.compile(COPYRIGHT_LINE_TEMPLATE, Pattern.MULTILINE);
+    private static final String CURRENT_YEAR = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
+
+    private final Path license;
+
+    /**
+     * @param core     This CodeWriter will be used to actually create a storage
+     *                 for files. LicenseCodeWriter simply decorates this underlying
+     *                 CodeWriter by adding prolog comments.
+     * @param license  license File
+     * @param encoding encoding
+     */
+    public LicenseCodeWriter(CodeWriter core, File license, String encoding) {
+        super(core);
+        this.license = license.toPath();
+        this.encoding = encoding;
+    }
+
+    @Override
+    public Writer openSource(JPackage pkg, String fileName) throws IOException {
+        Writer w = super.openSource(pkg, fileName);
+
+        PrintWriter out = new PrintWriter(w);
+        try (BufferedReader br = Files.newBufferedReader(license, Charset.forName(encoding))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                Matcher m = PATTERN.matcher(line);
+                if (m.matches()) {
+                    out.write(line, 0, m.start(1));
+                    out.write(CURRENT_YEAR);
+                    out.write(line, m.end(1), line.length() - m.end(1));
+                } else {
+                    out.write(line);
+                }
+                out.write(System.lineSeparator());
+            }
+        }
+
+        out.flush();    // we can't close the stream for that would close the underlying stream.
+
+        return w;
+    }
+}
diff --git a/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/MetainfServicesCompilerMojo.java b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/MetainfServicesCompilerMojo.java
new file mode 100644
index 0000000..13c0236
--- /dev/null
+++ b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/MetainfServicesCompilerMojo.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.impl.ArtifactResolver;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * Goal which compiles META-INF/services files from various dependencies
+ *
+ * @author japod
+ *
+ * Goal: metainf-services
+ *
+ * Phase: generate-sources
+ */
+@Mojo(name = "metainf-services", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true)
+public class MetainfServicesCompilerMojo extends AbstractMojo {
+
+    /**
+     * Collection of ArtifactItems to take the META-INF/services from. (ArtifactItem contains groupId,
+     * artifactId, version)
+     *
+     * parameter
+     * required
+     * @since 1.0
+     */
+    private List<ArtifactItem> artifactItems;
+    /**
+     * Collection of files from META-INF/services to compile
+     *
+     * parameter
+     * required
+     * @since 1.0
+     */
+    private List<String> providers;
+    /**
+     * Destination for the generated service registry files
+     *
+     * parameter
+     * required
+     * @since 1.0
+     */
+    private File destDir;
+
+    /**
+     * component role="org.apache.maven.artifact.resolver.ArtifactResolver"
+     * required
+     * readonly
+     */
+    protected ArtifactResolver artifactResolver;
+    /**
+     * parameter expression="${project.remoteArtifactRepositories}"
+     * readonly
+     * required
+     */
+    protected List<RemoteRepository> remoteRepositories;
+
+    /**
+     * The current repository/network configuration of Maven.
+     *
+     * parameter default-value="${repositorySystemSession}"
+     * readonly
+     */
+    private RepositorySystemSession repoSession;
+
+    @Override
+    public void execute() throws MojoExecutionException {
+        getLog().info("About to compile META-INF/services files");
+        getLog().info("Artifact Items = " + artifactItems);
+        getLog().info("SPIs = " + providers);
+        getLog().info("dest dir = " + destDir);
+        File msDir = new File(destDir, "META-INF/services");
+        boolean created =msDir.mkdirs();
+        if (!created) {
+            Logger.getLogger(MetainfServicesCompilerMojo.class.getName()).log(Level.FINE, "Cannot create directory: {0}", msDir);
+        }
+        for (String spi : providers) {
+            PrintWriter registryWriter = null;
+            try {
+                File spiRegistry = new File(msDir, spi);
+                if (spiRegistry.exists()) {
+                    boolean deleted = spiRegistry.delete();
+                    if (!deleted) {
+                        Logger.getLogger(MetainfServicesCompilerMojo.class.getName()).log(Level.FINE, "Cannot delete file: {0}", spiRegistry);
+                    }
+                }
+                created = spiRegistry.createNewFile();
+                if (!created) {
+                    Logger.getLogger(MetainfServicesCompilerMojo.class.getName()).log(Level.FINE, "Cannot create file: {0}", spiRegistry);
+                }
+                registryWriter = new PrintWriter(spiRegistry);
+                ZipFile zipFile = null;
+                try {
+                    BufferedReader reader = null;
+                    InputStreamReader isReader = null;
+                    for (ArtifactItem ai : artifactItems) {
+                        Artifact artifact;
+                        artifact = new DefaultArtifact(ai.getGroupId(), ai.getArtifactId(), null, ai.getVersion());
+//                        artifact = artifactFactory.createExtensionArtifact(ai.getGroupId(), ai.getArtifactId(), VersionRange.createFromVersion(ai.getVersion()));
+
+                        ArtifactRequest request = new ArtifactRequest();
+                        request.setArtifact( artifact );
+                        request.setRepositories(remoteRepositories);
+                        artifactResolver.resolveArtifact(repoSession, request);
+                        zipFile = new ZipFile(artifact.getFile());
+                        final ZipEntry servicesEntry = zipFile.getEntry("META-INF/services/" + spi);
+                        if (servicesEntry != null) {
+                            try {
+                                final InputStream inputStream = zipFile.getInputStream(servicesEntry);
+                                isReader = new InputStreamReader(inputStream);
+                                reader = new BufferedReader(isReader);
+                                while (reader.ready()) {
+                                    registryWriter.println(reader.readLine());
+                                }
+                            } finally {
+                                if (reader != null) {
+                                    reader.close();
+                                }
+                                if (isReader != null) {
+                                    isReader.close();
+                                }
+                            }
+                        }
+                    }
+                } catch (ArtifactResolutionException ex) {
+                    Logger.getLogger(MetainfServicesCompilerMojo.class.getName()).log(Level.SEVERE, null, ex);
+                    throw new MojoExecutionException("Can not resolve artifact!", ex);
+                } finally {
+                    if (zipFile != null) {
+                        zipFile.close();
+                    }
+                }
+            } catch (IOException ex) {
+                    throw new MojoExecutionException("Can not create spi registry file!", ex);
+            } finally {
+                if (registryWriter != null) {
+                    registryWriter.close();
+                }
+            }
+        }
+    }
+}
diff --git a/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/NameConverter.java b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/NameConverter.java
new file mode 100644
index 0000000..6ad2194
--- /dev/null
+++ b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/NameConverter.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+/**
+ * Converts arbitrary strings into Java identifiers.
+ *
+ * @author
+ *    <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a>
+ */
+public interface NameConverter
+{
+    /**
+     * converts a string into an identifier suitable for classes.
+     *
+     * In general, this operation should generate "NamesLikeThis".
+     * @param token string to convert
+     * @return converted token
+     */
+    String toClassName( String token );
+
+    /**
+     * converts a string into an identifier suitable for interfaces.
+     *
+     * In general, this operation should generate "NamesLikeThis".
+     * But for example, it can prepend every interface with 'I'.
+     * @param token string to convert
+     * @return converted token
+     */
+    String toInterfaceName( String token );
+
+    /**
+     * converts a string into an identifier suitable for properties.
+     *
+     * In general, this operation should generate "NamesLikeThis",
+     * which will be used with known prefixes like "get" or "set".
+     * @param token string to convert
+     * @return converted token
+     */
+    String toPropertyName( String token );
+
+    /**
+     * converts a string into an identifier suitable for constants.
+     *
+     * In the standard Java naming convention, this operation should
+     * generate "NAMES_LIKE_THIS".
+     * @param token string to convert
+     * @return converted token
+     */
+    String toConstantName( String token );
+
+    /**
+     * Converts a string into an identifier suitable for variables.
+     *
+     * In general it should generate "namesLikeThis".
+     * @param token string to convert
+     * @return converted token
+     */
+    String toVariableName( String token );
+
+    /**
+     * Converts a namespace URI into a package name.
+     * This method should expect strings like
+     * "http://foo.bar.zot/org", "urn:abc:def:ghi" "", or even "###"
+     * (basically anything) and expected to return a package name,
+     * liks "org.acme.foo".
+     *
+     * @param namespaceUri ns uri to convert
+     * @return converted uri
+     */
+    String toPackageName( String namespaceUri );
+
+    /**
+     * The name converter implemented by Code Model.
+     *
+     * This is the standard name conversion for JAXB.
+     */
+    NameConverter standard = new Standard();
+
+    /**
+     * Default implementation of {@link NameConverter}.
+     */
+    class Standard extends NameUtil implements NameConverter {
+        @Override
+        public String toClassName(String s) {
+            return toMixedCaseName(toWordList(s), true);
+        }
+        @Override
+        public String toVariableName(String s) {
+            return toMixedCaseName(toWordList(s), false);
+        }
+        @Override
+        public String toInterfaceName( String token ) {
+            return toClassName(token);
+        }
+        @Override
+        public String toPropertyName(String s) {
+            String prop = toClassName(s);
+            // property name "Class" with collide with Object.getClass,
+            // so escape this.
+            if(prop.equals("Class"))
+                prop = "Clazz";
+            return prop;
+        }
+        @Override
+        public String toConstantName( String token ) {
+            return super.toConstantName(token);
+        }
+        /**
+         * Computes a Java package name from a namespace URI,
+         * as specified in the spec.
+         *
+         * @param nsUri to convert
+         * @return
+         *      null if it fails to derive a package name.
+         */
+        @Override
+        public String toPackageName( String nsUri ) {
+            // remove scheme and :, if present
+            // spec only requires us to remove 'http' and 'urn'...
+            int idx = nsUri.indexOf(':');
+            String scheme = "";
+            if(idx>=0) {
+                scheme = nsUri.substring(0,idx);
+                if( scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("urn") )
+                    nsUri = nsUri.substring(idx+1);
+            }
+
+            // tokenize string
+            ArrayList<String> tokens = tokenize( nsUri, "/: " );
+            if( tokens.isEmpty() ) {
+                return null;
+            }
+
+            // remove trailing file type, if necessary
+            if( tokens.size() > 1 ) {
+                // for uri's like "www.foo.com" and "foo.com", there is no trailing
+                // file, so there's no need to look at the last '.' and substring
+                // otherwise, we loose the "com" (which would be wrong)
+                String lastToken = tokens.get( tokens.size()-1 );
+                idx = lastToken.lastIndexOf( '.' );
+                if( idx > 0 ) {
+                    lastToken = lastToken.substring( 0, idx );
+                    tokens.set( tokens.size()-1, lastToken );
+                }
+            }
+
+            // tokenize domain name and reverse.  Also remove :port if it exists
+            String domain = tokens.get( 0 );
+            idx = domain.indexOf(':');
+            if( idx >= 0) domain = domain.substring(0, idx);
+            ArrayList<String> r = reverse( tokenize( domain, scheme.equals("urn")?".-":"." ) );
+            if( r.get( r.size()-1 ).equalsIgnoreCase( "www" ) ) {
+                // remove leading www
+                r.remove( r.size()-1 );
+            }
+
+            // replace the domain name with tokenized items
+            tokens.addAll( 1, r );
+            tokens.remove( 0 );
+
+            // iterate through the tokens and apply xml->java name algorithm
+            for( int i = 0; i < tokens.size(); i++ ) {
+
+                // get the token and remove illegal chars
+                String token = tokens.get( i );
+                token = removeIllegalIdentifierChars( token );
+
+                // this will check for reserved keywords
+                if( !NameUtil.isJavaIdentifier( token ) ) {
+                    token = '_' + token;
+                }
+
+                tokens.set( i, token.toLowerCase(Locale.ENGLISH) );
+            }
+
+            // concat all the pieces and return it
+            return combine( tokens, '.' );
+        }
+
+
+        private static String removeIllegalIdentifierChars(String token) {
+            StringBuilder newToken = new StringBuilder();
+            for( int i = 0; i < token.length(); i++ ) {
+                char c = token.charAt( i );
+
+                if( i ==0 && !Character.isJavaIdentifierStart( c ) ) {
+                    // prefix an '_' if the first char is illegal
+                    newToken.append('_').append(c);
+                } else if( !Character.isJavaIdentifierPart( c ) ) {
+                    // replace the char with an '_' if it is illegal
+                    newToken.append( '_' );
+                } else {
+                    // add the legal char
+                    newToken.append( c );
+                }
+            }
+            return newToken.toString();
+        }
+
+
+        private static ArrayList<String> tokenize( String str, String sep ) {
+            StringTokenizer tokens = new StringTokenizer(str,sep);
+            ArrayList<String> r = new ArrayList<>();
+
+            while(tokens.hasMoreTokens())
+                r.add( tokens.nextToken() );
+
+            return r;
+        }
+
+        private static <T> ArrayList<T> reverse( List<T> a ) {
+            ArrayList<T> r = new ArrayList<>();
+
+            for( int i=a.size()-1; i>=0; i-- )
+                r.add( a.get(i) );
+
+            return r;
+        }
+
+        private static String combine( List<String> r, char sep ) {
+            StringBuilder buf = new StringBuilder(r.get(0));
+
+            for( int i=1; i<r.size(); i++ ) {
+                buf.append(sep);
+                buf.append(r.get(i));
+            }
+
+            return buf.toString();
+        }
+    }
+
+    /**
+     * JAX-PRC compatible name converter implementation.
+     *
+     * The only difference is that we treat '_' as a valid character
+     * and not as a word separator.
+     */
+    NameConverter jaxrpcCompatible = new Standard() {
+        @Override
+        protected boolean isPunct(char c) {
+            return (c == '.' || c == '-' || c == ';' /*|| c == '_'*/ || c == '\u00b7'
+                    || c == '\u0387' || c == '\u06dd' || c == '\u06de');
+        }
+        @Override
+        protected boolean isLetter(char c) {
+            return super.isLetter(c) || c=='_';
+        }
+
+        @Override
+        protected int classify(char c0) {
+            if(c0=='_') return NameUtil.OTHER_LETTER;
+            return super.classify(c0);
+        }
+    };
+
+    /**
+     * Smarter converter used for RELAX NG support.
+     */
+    NameConverter smart = new Standard() {
+        @Override
+        public String toConstantName( String token ) {
+            String name = super.toConstantName(token);
+            if( NameUtil.isJavaIdentifier(name) )
+                return name;
+            else
+                return '_'+name;
+        }
+    };
+}
diff --git a/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/NameUtil.java b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/NameUtil.java
new file mode 100644
index 0000000..adcc12e
--- /dev/null
+++ b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/NameUtil.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Methods that convert strings into various formats.
+ *
+ * <p>
+ * What JAX-RPC name binding tells us is that even such basic method
+ * like "isLetter" can be different depending on the situation.
+ *
+ * For this reason, a whole lot of methods are made non-static,
+ * even though they look like they should be static.
+ */
+class NameUtil {
+    protected boolean isPunct(char c) {
+        return c == '-' || c == '.' || c == ':' || c == '_' || c == '\u00b7' || c == '\u0387' || c == '\u06dd' || c == '\u06de';
+    }
+
+    protected static boolean isDigit(char c) {
+        return c >= '0' && c <= '9' || Character.isDigit(c);
+    }
+
+    protected static boolean isUpper(char c) {
+        return c >= 'A' && c <= 'Z' || Character.isUpperCase(c);
+    }
+
+    protected static boolean isLower(char c) {
+        return c >= 'a' && c <= 'z' || Character.isLowerCase(c);
+    }
+
+    protected boolean isLetter(char c) {
+        return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || Character.isLetter(c);
+    }
+
+    /**
+     * Capitalizes the first character of the specified string,
+     * and de-capitalize the rest of characters.
+     */
+    public String capitalize(String s) {
+        if (!isLower(s.charAt(0)))
+            return s;
+        StringBuilder sb = new StringBuilder(s.length());
+        sb.append(Character.toUpperCase(s.charAt(0)));
+        sb.append(s.substring(1).toLowerCase(Locale.ENGLISH));
+        return sb.toString();
+    }
+
+    // Precondition: s[start] is not punctuation
+    private int nextBreak(String s, int start) {
+        int n = s.length();
+
+        char c1 = s.charAt(start);
+        int t1 = classify(c1);
+
+        for (int i=start+1; i<n; i++) {
+            // shift (c1,t1) into (c0,t0)
+            // char c0 = c1;  --- conceptually, but c0 won't be used
+            int t0 = t1;
+
+            c1 = s.charAt(i);
+            t1 = classify(c1);
+
+            switch(actionTable[t0*5+t1]) {
+            case ACTION_CHECK_PUNCT:
+                if(isPunct(c1)) return i;
+                break;
+            case ACTION_CHECK_C2:
+                if (i < n-1) {
+                    char c2 = s.charAt(i+1);
+                    if (isLower(c2))
+                        return i;
+                }
+                break;
+            case ACTION_BREAK:
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    // the 5-category classification that we use in this code
+    // to find work breaks
+    static protected final int UPPER_LETTER = 0;
+    static protected final int LOWER_LETTER = 1;
+    static protected final int OTHER_LETTER = 2;
+    static protected final int DIGIT = 3;
+    static protected final int OTHER = 4;
+
+    /**
+     * Look up table for actions.
+     * type0*5+type1 would yield the action to be taken.
+     */
+    private static final byte[] actionTable = new byte[5*5];
+
+    // action constants. see nextBreak for the meaning
+    static private final byte ACTION_CHECK_PUNCT = 0;
+    static private final byte ACTION_CHECK_C2 = 1;
+    static private final byte ACTION_BREAK = 2;
+    static private final byte ACTION_NOBREAK = 3;
+
+    /**
+     * Decide the action to be taken given
+     * the classification of the preceding character 't0' and
+     * the classification of the next character 't1'.
+     */
+    private static byte decideAction( int t0, int t1 ) {
+        if(t0==OTHER && t1==OTHER)  return ACTION_CHECK_PUNCT;
+        if(!xor(t0==DIGIT,t1==DIGIT))  return ACTION_BREAK;
+        if(t0==LOWER_LETTER && t1!=LOWER_LETTER)    return ACTION_BREAK;
+        if(!xor(t0<=OTHER_LETTER,t1<=OTHER_LETTER)) return ACTION_BREAK;
+        if(!xor(t0==OTHER_LETTER,t1==OTHER_LETTER)) return ACTION_BREAK;
+
+        if(t0==UPPER_LETTER && t1==UPPER_LETTER)    return ACTION_CHECK_C2;
+
+        return ACTION_NOBREAK;
+    }
+
+    private static boolean xor(boolean x,boolean y) {
+        return (x&&y) || (!x&&!y);
+    }
+
+    static {
+        // initialize the action table
+        for( int t0=0; t0<5; t0++ )
+            for( int t1=0; t1<5; t1++ )
+                actionTable[t0*5+t1] = decideAction(t0,t1);
+    }
+
+    /**
+     * Classify a character into 5 categories that determine the word break.
+     */
+    protected int classify(char c0) {
+        switch(Character.getType(c0)) {
+        case Character.UPPERCASE_LETTER:        return UPPER_LETTER;
+        case Character.LOWERCASE_LETTER:        return LOWER_LETTER;
+        case Character.TITLECASE_LETTER:
+        case Character.MODIFIER_LETTER:
+        case Character.OTHER_LETTER:            return OTHER_LETTER;
+        case Character.DECIMAL_DIGIT_NUMBER:    return DIGIT;
+        default:                                return OTHER;
+        }
+    }
+
+
+    /**
+     * Tokenizes a string into words and capitalizes the first
+     * character of each word.
+     *
+     * <p>
+     * This method uses a change in character type as a splitter
+     * of two words. For example, "abc100ghi" will be splitted into
+     * {"Abc", "100","Ghi"}.
+     */
+    public List<String> toWordList(String s) {
+        ArrayList<String> ss = new ArrayList<>();
+        int n = s.length();
+        for (int i = 0; i < n;) {
+
+            // Skip punctuation
+            while (i < n) {
+                if (!isPunct(s.charAt(i)))
+                    break;
+                i++;
+            }
+            if (i >= n) break;
+
+            // Find next break and collect word
+            int b = nextBreak(s, i);
+            String w = (b == -1) ? s.substring(i) : s.substring(i, b);
+            ss.add(escape(capitalize(w)));
+            if (b == -1) break;
+            i = b;
+        }
+
+//      we can't guarantee a valid Java identifier anyway,
+//      so there's not much point in rejecting things in this way.
+//        if (ss.size() == 0)
+//            throw new IllegalArgumentException("Zero-length identifier");
+        return ss;
+    }
+
+    protected String toMixedCaseName(List<String> ss, boolean startUpper) {
+        StringBuilder sb = new StringBuilder();
+        if(!ss.isEmpty()) {
+            sb.append(startUpper ? ss.get(0) : ss.get(0).toLowerCase(Locale.ENGLISH));
+            for (int i = 1; i < ss.size(); i++)
+                sb.append(ss.get(i));
+        }
+        return sb.toString();
+    }
+
+    protected String toMixedCaseVariableName(String[] ss,
+                                                  boolean startUpper,
+                                                  boolean cdrUpper) {
+        if (cdrUpper)
+            for (int i = 1; i < ss.length; i++)
+                ss[i] = capitalize(ss[i]);
+        StringBuilder sb = new StringBuilder();
+        if( ss.length>0 ) {
+            sb.append(startUpper ? ss[0] : ss[0].toLowerCase(Locale.ENGLISH));
+            for (int i = 1; i < ss.length; i++)
+                sb.append(ss[i]);
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * Formats a string into "THIS_KIND_OF_FORMAT_ABC_DEF".
+     *
+     * @return
+     *      Always return a string but there's no guarantee that
+     *      the generated code is a valid Java identifier.
+     */
+    public String toConstantName(String s) {
+        return toConstantName(toWordList(s));
+    }
+
+    /**
+     * Formats a string into "THIS_KIND_OF_FORMAT_ABC_DEF".
+     *
+     * @return
+     *      Always return a string but there's no guarantee that
+     *      the generated code is a valid Java identifier.
+     */
+    public String toConstantName(List<String> ss) {
+        StringBuilder sb = new StringBuilder();
+        if( !ss.isEmpty() ) {
+            sb.append(ss.get(0).toUpperCase(Locale.ENGLISH));
+            for (int i = 1; i < ss.size(); i++) {
+                sb.append('_');
+                sb.append(ss.get(i).toUpperCase(Locale.ENGLISH));
+            }
+        }
+        return sb.toString();
+    }
+
+
+
+    /**
+     * Escapes characters is the given string so that they can be
+     * printed by only using US-ASCII characters.
+     *
+     * The escaped characters will be appended to the given
+     * StringBuffer.
+     *
+     * @param sb
+     *      StringBuffer that receives escaped string.
+     * @param s
+     *      String to be escaped. <code>s.substring(start)</code>
+     *      will be escaped and copied to the string buffer.
+     */
+    public static void escape(StringBuilder sb, String s, int start) {
+        int n = s.length();
+        for (int i = start; i < n; i++) {
+            char c = s.charAt(i);
+            if (Character.isJavaIdentifierPart(c))
+                sb.append(c);
+            else {
+                sb.append('_');
+                if (c <= '\u000f') sb.append("000");
+                else if (c <= '\u00ff') sb.append("00");
+                else if (c <= '\u0fff') sb.append('0');
+                sb.append(Integer.toString(c, 16));
+            }
+        }
+    }
+
+    /**
+     * Escapes characters that are unusable as Java identifiers
+     * by replacing unsafe characters with safe characters.
+     */
+    private static String escape(String s) {
+        int n = s.length();
+        for (int i = 0; i < n; i++)
+            if (!Character.isJavaIdentifierPart(s.charAt(i))) {
+                StringBuilder sb = new StringBuilder(s.substring(0, i));
+                escape(sb, s, i);
+                return sb.toString();
+            }
+        return s;
+    }
+
+
+    /**
+     * Checks if a given string is usable as a Java identifier.
+     */
+    public static boolean isJavaIdentifier(String s) {
+        if(s.length()==0)   return false;
+        if( reservedKeywords.contains(s) )  return false;
+
+        if(!Character.isJavaIdentifierStart(s.charAt(0)))   return false;
+
+        for (int i = 1; i < s.length(); i++)
+            if (!Character.isJavaIdentifierPart(s.charAt(i)))
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Checks if the given string is a valid Java package name.
+     */
+    public static boolean isJavaPackageName(String s) {
+        while(s.length()!=0) {
+            int idx = s.indexOf('.');
+            if(idx==-1) idx=s.length();
+            if( !isJavaIdentifier(s.substring(0,idx)) )
+                return false;
+
+            s = s.substring(idx);
+            if(s.length()!=0)    s = s.substring(1);    // remove '.'
+        }
+        return true;
+    }
+
+
+    /** All reserved keywords of Java. */
+    private static HashSet<String> reservedKeywords = new HashSet<>();
+
+    static {
+        // see http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html
+        String[] words = new String[]{
+            "abstract",
+            "boolean",
+            "break",
+            "byte",
+            "case",
+            "catch",
+            "char",
+            "class",
+            "const",
+            "continue",
+            "default",
+            "do",
+            "double",
+            "else",
+            "extends",
+            "final",
+            "finally",
+            "float",
+            "for",
+            "goto",
+            "if",
+            "implements",
+            "import",
+            "instanceof",
+            "int",
+            "interface",
+            "long",
+            "native",
+            "new",
+            "package",
+            "private",
+            "protected",
+            "public",
+            "return",
+            "short",
+            "static",
+            "strictfp",
+            "super",
+            "switch",
+            "synchronized",
+            "this",
+            "throw",
+            "throws",
+            "transient",
+            "try",
+            "void",
+            "volatile",
+            "while",
+
+            // technically these are not reserved words but they cannot be used as identifiers.
+            "true",
+            "false",
+            "null",
+
+            // and I believe assert is also a new keyword
+            "assert",
+
+            // and 5.0 keywords
+            "enum"
+            };
+        reservedKeywords.addAll(Arrays.asList(words));
+    }
+}
diff --git a/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/QuickGenMojo.java b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/QuickGenMojo.java
new file mode 100644
index 0000000..634ab59
--- /dev/null
+++ b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/QuickGenMojo.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+import com.sun.codemodel.CodeWriter;
+import com.sun.codemodel.JArray;
+import com.sun.codemodel.JClass;
+import com.sun.codemodel.JClassAlreadyExistsException;
+import com.sun.codemodel.JCodeModel;
+import com.sun.codemodel.JDefinedClass;
+import com.sun.codemodel.JExpr;
+import com.sun.codemodel.JFieldVar;
+import com.sun.codemodel.JMethod;
+import com.sun.codemodel.JMod;
+import com.sun.codemodel.JPackage;
+import com.sun.codemodel.writer.FileCodeWriter;
+import org.apache.maven.artifact.DependencyResolutionRequiredException;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.regex.Pattern;
+
+/**
+ * Generates implementations of {@code org.glassfish.jaxb.runtime.v2.model.annotation.Quick} classes
+ * for XML Binding annotations. Used exclusively by jaxb-ri project.
+ *
+ */
+@Mojo(name = "quick-gen",
+      defaultPhase = LifecyclePhase.GENERATE_SOURCES,
+      requiresDependencyResolution = ResolutionScope.COMPILE,
+      threadSafe = true)
+public class QuickGenMojo extends AbstractMojo {
+
+    private static final String LOCATABLE = "org.glassfish.jaxb.core.v2.model.annotation.Locatable";
+    private static final String QUICK = "org.glassfish.jaxb.runtime.v2.model.annotation.Quick";
+
+    @Parameter(defaultValue = "false")
+    private boolean skip;
+
+    /**
+     * Location of the destination directory.
+     */
+    @Parameter(defaultValue = "${project.build.directory}/generated-sources/quick-sources")
+    private File destDir;
+
+    /**
+     * File encoding for generated sources.
+     * @since 2.12
+     */
+    @Parameter(defaultValue = "${project.build.sourceEncoding}")
+    private String encoding;
+
+    /**
+     * Annotations to generate implementations of {@code org.glassfish.jaxb.runtime.v2.model.annotation.Quick} for.
+     */
+    @Parameter(required = true)
+    private List<String> classes;
+
+    /**
+     * License file to use in generated sources.
+     */
+    @Parameter
+    private File license;
+
+    /**
+     * Package for generated implementations.
+     */
+    @Parameter(required = true)
+    private String packageName;
+
+    /**
+     * Attach generated sources to project sources.
+     */
+    @Parameter(defaultValue = "true")
+    private boolean attach;
+
+    @Parameter(defaultValue = "${project}", required = true, readonly = true)
+    private MavenProject project;
+
+    private final List<Pattern> patterns = new ArrayList<>();
+
+    /**
+     * Used during the build to load annotation classes.
+     */
+    private ClassLoader userLoader;
+
+    /**
+     * Generated interfaces go into this codeModel.
+     */
+    private JCodeModel codeModel = new JCodeModel();
+
+    /**
+     * Avoid compile-time dependency on {@code org.glassfish.jaxb.core.v2.model.annotation.Locatable}
+     */
+    private final JClass locatable = codeModel.ref(LOCATABLE);
+
+    /**
+     * Avoid compile-time dependency on {@code org.glassfish.jaxb.core.v2.model.annotation.Quick}
+     */
+    private final JClass quick = codeModel.ref(QUICK);
+
+    /**
+     * The writers will be generated into this package.
+     */
+    private JPackage pkg = codeModel.rootPackage();
+
+    /**
+     * Map from annotation classes to their writers.
+     */
+    private final Map<Class<? extends Annotation>, JDefinedClass> queue = new TreeMap<>(Comparator.comparing(Class::getName));
+
+    public QuickGenMojo() {
+    }
+
+    @Override
+    public void execute() throws MojoExecutionException {
+        if (skip) {
+            getLog().info("Skipping execution.");
+            return;
+        }
+
+        for (String s : classes) {
+            patterns.add(Pattern.compile(convertToRegex(s)));
+        }
+        pkg = codeModel._package(packageName);
+        try {
+            List<String> classpath = project.getCompileClasspathElements();
+            Set<File> files = new HashSet<>();
+            List<URL> cp = new ArrayList<>();
+            for (String s : classpath) {
+                File f = new File(s);
+                files.add(f);
+                cp.add(f.toURI().toURL());
+            }
+            userLoader = new URLClassLoader(cp.toArray(new URL[] {}));
+
+            // find classes to be bound
+            for (File f : files) {
+                if (f.exists()) {
+                    if (f.isDirectory()) {
+                        processDir(f, "");
+                    } else {
+                        processJar(f);
+                    }
+                }
+            }
+
+            // [RESULT]
+            // class Init {
+            //    static Quick[] getAll() {
+            //       ... return all Quick classes ...
+            //    }
+            // }
+            try {
+                JArray all = JExpr.newArray(quick);
+                JDefinedClass init = pkg._class(0, "Init");
+                init.method(JMod.STATIC, quick.array(), "getAll").body()._return(all);
+
+                for (Map.Entry<Class<? extends Annotation>, JDefinedClass> e : queue.entrySet()) {
+                    process(e.getKey(), e.getValue());
+                    all.add(JExpr._new(e.getValue()).arg(JExpr._null()).arg(JExpr._null()));
+                }
+            } catch (JClassAlreadyExistsException e) {
+                throw new MojoExecutionException(e);
+            }
+
+            if (!destDir.mkdirs()) {
+                getLog().warn(destDir + " failed to be created.");
+            }
+            CodeWriter core = new FileCodeWriter(destDir, encoding);
+            if (license != null) {
+                core = new LicenseCodeWriter(core, license, encoding);
+            }
+
+            codeModel.build(core);
+
+            if (attach) {
+                project.addCompileSourceRoot(destDir.getAbsolutePath());
+            }
+        } catch (IOException | DependencyResolutionRequiredException e) {
+            throw new MojoExecutionException(e);
+        } finally {
+            userLoader = null;
+        }
+    }
+
+    /**
+     * Generate a {@code org.glassfish.jaxb.runtime.v2.model.annotation.Quick} implementation
+     * of the specified annotation in the specified package.
+     *
+     * @param ann
+     *      annotation type to
+     */
+    private void process(Class<? extends Annotation> ann, JDefinedClass c) {
+        // XXX - adding javax.annotation.processing.Generated implies dep on java.compiler,
+        //adding jakarta.annotation.Generated implies dep on jakarta.annotation
+        // => we don't want any of them
+        // [RESULT]
+        // public final class XmlAttributeQuick extends Quick implements XmlAttribute {
+        c.javadoc().add("<p><b>Auto-generated, do not edit.</b></p>");
+        c._extends(quick);
+        c._implements(ann);
+
+        // [RESULT]
+        //     private final XmlAttribute core;
+        JFieldVar $core = c.field(JMod.PRIVATE | JMod.FINAL, ann, "core");
+
+        // [RESULT]
+        // public XmlAttributeQuick(Locatable upstream, XmlAttribute core) {
+        //     super(upstream);
+        //     this.core = core;
+        // }
+        {
+            JMethod m = c.constructor(JMod.PUBLIC);
+            m.body().invoke("super").arg(m.param(locatable, "upstream"));
+            m.body().assign(JExpr._this().ref($core), m.param(ann, "core"));
+        }
+
+        // [RESULT]
+        // @Override
+        // protected Annotation getAnnotation() {
+        //     return core;
+        // }
+        {
+            JMethod m = c.method(JMod.PROTECTED, Annotation.class, "getAnnotation");
+            m.annotate(Override.class);
+            m.body()._return($core);
+        }
+
+        // [RESULT]
+        // @Override
+        // protected Quick newInstance(Locatable upstream,Annotation core) {
+        //     return new XmlAttributeQuick(upstream,(XmlAttribute)core);
+        // }
+        {
+            JMethod m = c.method(JMod.PROTECTED, quick, "newInstance");
+            m.annotate(Override.class);
+            m.body()._return(JExpr._new(c).arg(m.param(locatable, "upstream")).arg(JExpr.cast(codeModel.ref(ann), m.param(Annotation.class, "core"))));
+        }
+
+        // [RESULT]
+        // @Override
+        // public Class<XmlAttribute> annotationType() {
+        //     return XmlAttribute.class;
+        // }
+        {
+            JMethod m = c.method(JMod.PUBLIC,
+                    codeModel.ref(Class.class).narrow(ann), "annotationType");
+            m.annotate(Override.class);
+            m.body()._return(codeModel.ref(ann).dotclass());
+        }
+
+
+        // then for each annotation parameter just generate a delegation method
+        Method[] methods = ann.getDeclaredMethods();
+        Arrays.sort(methods, Comparator.comparing(Method::getName));
+        for (Method method : methods) {
+            // [RESULT]
+            // @Override
+            // public String name() {
+            //    return core.name();
+            //}
+            JMethod m = c.method(JMod.PUBLIC, method.getReturnType(), method.getName());
+            m.annotate(Override.class);
+            m.body()._return($core.invoke(method.getName()));
+        }
+    }
+
+    /**
+     * Gets the short name from a fully-qualified name.
+     */
+    private static String getShortName(String className) {
+        int idx = className.lastIndexOf('.');
+        return className.substring(idx + 1);
+    }
+
+    private String convertToRegex(String pattern) {
+        StringBuilder regex = new StringBuilder();
+        char nc = ' ';
+        if (pattern.length() > 0) {
+            for (int i = 0; i < pattern.length(); i++) {
+                char c = pattern.charAt(i);
+                nc = ' ';
+                if ((i + 1) != pattern.length()) {
+                    nc = pattern.charAt(i + 1);
+                }
+                //escape single '.'
+                if ((c == '.') && (nc != '.')) {
+                    regex.append('\\');
+                    regex.append('.');
+                    //do not allow patterns like a..b
+                } else if ((c == '.') && (nc == '.')) {
+                    continue;
+                    // "**" gets replaced by ".*"
+                } else if ((c == '*') && (nc == '*')) {
+                    regex.append(".*");
+                    break;
+                    //'*' replaced by anything but '.' i.e [^\\.]+
+                } else if (c == '*') {
+                    regex.append("[^\\.]+");
+                    continue;
+                    //'?' replaced by anything but '.' i.e [^\\.]
+                } else if (c == '?') {
+                    regex.append("[^\\.]");
+                    //else leave the chars as they occur in the pattern
+                } else {
+                    regex.append(c);
+                }
+            }
+        }
+        return regex.toString();
+    }
+
+
+    /**
+     * Visits a jar file and looks for classes that match the specified pattern.
+     */
+    private void processJar(File jarfile) throws MojoExecutionException {
+        try (JarFile jar = new JarFile(jarfile)) {
+            for (Enumeration<JarEntry> en = jar.entries(); en.hasMoreElements(); ) {
+                JarEntry e = en.nextElement();
+                process(e.getName(), e.getTime());
+            }
+        } catch (IOException e) {
+            throw new MojoExecutionException("Unable to process " + jarfile, e);
+        }
+    }
+
+    /**
+     * Visits a directory and looks for classes that match the specified pattern.
+     *
+     * @param prefix
+     *      the package name prefix like "" or "foo/bar/"
+     */
+    private void processDir(File dir, String prefix) throws MojoExecutionException {
+        // look for class files
+        String[] classes = dir.list((d, name) -> name.endsWith(".class"));
+        if (classes != null) {
+            for (String c : classes) {
+                process(prefix + c, new File(dir, c).lastModified());
+            }
+        }
+
+        // look for subdirectories
+        File[] subdirs = dir.listFiles(File::isDirectory);
+        if (subdirs != null) {
+            for (File f : subdirs) {
+                processDir(f, prefix + f.getName() + '/');
+            }
+        }
+    }
+
+    /**
+     * Process a file.
+     *
+     * @param name such as "jakarta/xml/bind/Abc.class"
+     */
+    private void process(String name, long timestamp) throws MojoExecutionException {
+        if (!name.endsWith(".class")) {
+            return; // not a class
+        }
+        name = name.substring(0, name.length() - 6);
+        name = name.replace('/', '.'); // make it a class naem
+        // find a match
+        for (Pattern p : patterns) {
+            if (p.matcher(name).matches()) {
+                queue(name, timestamp);
+                return;
+            }
+        }
+    }
+
+    /**
+     * Queues a file for generation.
+     */
+    @SuppressWarnings({"unchecked"})
+    private void queue(String className, long timestamp) throws MojoExecutionException {
+        getLog().debug("Processing " + className);
+        Class<? extends Annotation> ann;
+        try {
+            ann = (Class<? extends Annotation>) userLoader.loadClass(className);
+        } catch (ClassNotFoundException e) {
+            throw new MojoExecutionException(e);
+        }
+
+        if (!Annotation.class.isAssignableFrom(ann)) {
+            getLog().debug("Skipping " + className + ". Not an annotation");
+            return;
+        }
+
+        JDefinedClass w;
+        try {
+            w = pkg._class(JMod.FINAL, getShortName(ann.getName()) + "Quick");
+        } catch (JClassAlreadyExistsException e) {
+            throw new MojoExecutionException("Class name collision on " + className, e);
+        }
+
+        // up to date check
+        String name = pkg.name();
+        if (name.length() == 0) {
+            name = getShortName(className);
+        } else {
+            name += '.' + getShortName(className);
+        }
+
+        File dst = new File(destDir, name.replace('.', File.separatorChar) + "Quick.java");
+        if (dst.exists() && dst.lastModified() > timestamp) {
+            getLog().debug("Skipping " + className + ". Up to date.");
+            w.hide();
+        }
+
+        queue.put(ann, w);
+    }
+}
diff --git a/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/RSFileSet.java b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/RSFileSet.java
new file mode 100644
index 0000000..02dd7b2
--- /dev/null
+++ b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/RSFileSet.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import static java.nio.file.FileVisitResult.CONTINUE;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author lukas
+ */
+public class RSFileSet {
+
+    private Path root;
+    private List<String> inc;
+    private final PathMatcher exMatcher;
+
+    public RSFileSet() {
+        inc = new ArrayList<>();
+        exMatcher = FileSystems.getDefault().getPathMatcher("glob:*_*.properties");
+    }
+
+    public void setDirectory(String dir) {
+        root = Paths.get(dir);
+    }
+
+    public String getDirectory() {
+        return root.toString();
+    }
+
+    public boolean exists() {
+        return Files.isDirectory(root, LinkOption.NOFOLLOW_LINKS);
+    }
+    public void addInclude(String include) {
+        inc.add(include);
+    }
+
+    public List<String> getIncludes() {
+        return inc;
+    }
+
+    public void setIncludes(List<String> inc) {
+        this.inc = inc;
+    }
+
+    public Path resolve(Path path) {
+        return root.resolve(path);
+    }
+
+    public List<Path> getIncludedFiles() {
+        final List<Path> result = new ArrayList<>();
+        if (inc.isEmpty()) {
+            inc.add("**");
+        }
+        FileSystem fs = FileSystems.getDefault();
+        for (final String i : inc) {
+            int idx = i.indexOf('/');
+            final PathMatcher matcher;
+            final PathMatcher dirMatcher;
+            if (idx < 0) {
+                matcher = fs.getPathMatcher("glob:" + i);
+                dirMatcher = null;
+            } else {
+                matcher = fs.getPathMatcher("glob:" + i.substring(idx + 1));
+                dirMatcher = fs.getPathMatcher("glob:" + i.substring(0, idx));
+            }
+            try {
+                Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
+
+                    @Override
+                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+                        if (dirMatcher == null || (dirMatcher.matches(file.getParent()))) {
+                            Path name = file.getFileName();
+                            if (name != null && matcher.matches(name) && !exMatcher.matches(name)) {
+                                result.add(root.relativize(file));
+                            }
+                        }
+                        return CONTINUE;
+                    }
+                });
+            } catch (IOException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        return result;
+    }
+}
diff --git a/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/ResourceGenMojo.java b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/ResourceGenMojo.java
new file mode 100644
index 0000000..f45e60c
--- /dev/null
+++ b/istack-commons/maven-plugin/src/main/java/com/sun/istack/maven/ResourceGenMojo.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+import com.sun.codemodel.CodeWriter;
+import com.sun.codemodel.JAnnotationUse;
+import com.sun.codemodel.JClass;
+import com.sun.codemodel.JClassAlreadyExistsException;
+import com.sun.codemodel.JCodeModel;
+import com.sun.codemodel.JDefinedClass;
+import com.sun.codemodel.JExpr;
+import com.sun.codemodel.JFieldVar;
+import com.sun.codemodel.JInvocation;
+import com.sun.codemodel.JMethod;
+import com.sun.codemodel.JMod;
+import com.sun.codemodel.JPackage;
+import com.sun.codemodel.JVar;
+import com.sun.codemodel.writer.FileCodeWriter;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * Goal which generates source files from resource bundles.
+ * You can then refer to resources as methods rather than hard-coding string constants.
+ *
+ * @author Lukas Jungmann
+ * @author Jakub Podlesak
+ * @author Kohsuke Kawaguchi
+ *
+ * Goal: rs-gen
+ * RequiresProject: false
+ * Phase: process-sources
+ */
+@Mojo(name = "rs-gen", requiresProject = false, threadSafe = true,
+        defaultPhase = LifecyclePhase.PROCESS_SOURCES)
+public class ResourceGenMojo extends AbstractMojo {
+
+    /**
+     * Location of the destination directory.
+     */
+    @Parameter(required = true, property = "destDir", defaultValue = "${project.build.directory}/generated-sources/resources")
+    private File destDir;
+
+    /**
+     * File set of the properties files to be processed.
+     */
+    @Parameter
+    private RSFileSet resources;
+
+    /**
+     * Directory with properties files to be processed from the command line.
+     * @since 2.12
+     */
+    @Parameter(property = "resources")
+    private String cliResource;
+
+    /**
+     * Package to be used for the localization utility classes.
+     */
+    @Parameter(property = "localizationUtilitiesPkgName", defaultValue = "com.sun.istack.localization")
+    private String localizationUtilitiesPkgName;
+
+    /**
+     * License file to use in generated sources.
+     * @since 2.12
+     */
+    @Parameter(property = "license")
+    private File license;
+
+    /**
+     * Mark generated sources with {@code @jakarta.annotation.Generated}.
+     * @since 3.0.5
+     */
+    @Parameter(property = "atGenerated", defaultValue = "false")
+    private boolean atGenerated;
+
+    /**
+     * Generate javadoc comments.
+     * @since 4.0.1
+     */
+    @Parameter(property = "rs.javadoc", defaultValue = "true")
+    private boolean javadoc;
+
+    /**
+     * File encoding for generated sources.
+     * @since 2.12
+     */
+    @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}")
+    private String encoding;
+
+    /**
+     * @since 2.12
+     */
+    @Parameter(property = "project", readonly = true)
+    private MavenProject project;
+
+    @Override
+    public void execute() throws MojoExecutionException {
+
+        if(resources == null && cliResource == null) {
+            throw new MojoExecutionException("No resource file is specified");
+        }
+        if(destDir == null) {
+            throw new MojoExecutionException("No destdir attribute is specified");
+        }
+
+        if(localizationUtilitiesPkgName == null) {
+            localizationUtilitiesPkgName = "com.sun.istack.localization";
+        }
+
+        if (!destDir.exists() && !destDir.mkdirs()) {
+                throw new MojoExecutionException("Cannot create destdir");
+        }
+
+        if (!destDir.canWrite()) {
+            throw new MojoExecutionException("Cannot write to destdir");
+        }
+
+        if (encoding == null || encoding.trim().isEmpty()) {
+            encoding =  System.getProperty("file.encoding");
+            getLog().warn("File encoding has not been set, using platform encoding "
+                    + encoding + ", i.e. build is platform dependent!");
+        }
+
+        if (resources == null && cliResource != null) {
+            RSFileSet fs = new RSFileSet();
+            fs.setDirectory(System.getProperty("user.dir"));
+            List<String> l = new ArrayList<>();
+            l.add(cliResource);
+            fs.setIncludes(l);
+            resources = fs;
+        }
+
+        if (resources == null || !resources.exists()) {
+            getLog().info("No resources specified.");
+            return;
+        }
+
+        List<Path> includedFiles = resources.getIncludedFiles();
+
+        getLog().info("Resources:");
+        for(Path s : includedFiles) {
+            getLog().info(s.toString());
+        }
+
+        JCodeModel cm = new JCodeModel();
+
+        for (Path p : includedFiles) {
+            File res = resources.resolve(p).toFile();
+            String value = p.toString();
+
+            String className = getClassName(res);
+
+            String bundleName = value.substring(0, value.lastIndexOf('.')).replace('/', '.').replace('\\', '.');// cut off '.properties'
+            String dirName = bundleName.substring(0, bundleName.lastIndexOf('.'));
+
+            File destFile = destDir.toPath().resolve(dirName.replace('.', '/')).resolve(className+".java").toFile();
+            if(destFile.exists() && (destFile.lastModified() >= res.lastModified())) {
+                getLog().info("Skipping " + res);
+                continue;
+            }
+
+            getLog().info("Processing "+res);
+
+            if (!destFile.getParentFile().mkdirs()) {
+                if (getLog().isDebugEnabled()) {
+                    getLog().debug("Reusing existing " + destFile.getParentFile().getAbsolutePath() + " directory.");
+                }
+            }
+            JPackage pkg = cm._package(dirName);
+
+            Properties props = new Properties();
+            FileInputStream in = null;
+            try {
+                in = new FileInputStream(res);
+                props.load(in);
+            } catch (IOException e) {
+                throw new MojoExecutionException(e.getMessage(), e);
+            } finally {
+                if (in != null) {
+                    try {
+                        in.close();
+                    } catch (IOException ioe) {
+                        throw new MojoExecutionException(ioe.getMessage(), ioe);
+                    }
+                }
+            }
+
+            JDefinedClass clazz;
+            try {
+                clazz = pkg._class(JMod.PUBLIC | JMod.FINAL, className);
+            } catch (JClassAlreadyExistsException e) {
+                throw new MojoExecutionException("Name conflict "+className);
+            }
+
+            if (javadoc) {
+                clazz.javadoc().add(
+                        "Defines string formatting method for each constant in the resource file"
+                );
+            }
+
+            if (atGenerated) {
+                // no direct dependency on Jakarta annotations API
+                JClass annotation = cm.ref("jakarta.annotation.Generated");
+                JAnnotationUse generated = clazz.annotate(annotation);
+                generated.param("value", ResourceGenMojo.class.getName());
+            }
+
+            /*
+              [RESULT]
+
+            String BUNDLE_NAME = "com.sun.xml.ws.resources.client";
+            LocalizableMessageFactory MESSAGE_FACTORY =
+                    new LocalizableMessageFactory(BUNDLE_NAME, new BundleSupplier());
+            Localizer LOCALIZER = new Localizer();
+
+            class BundleSupplier implements ResourceBundleSupplier {
+
+                public ResourceBundle getResourceBundle(Locale locale) {
+                    return ResourceBundle.getBundle(BUNDLE_NAME, locale);
+                }
+            }
+            */
+
+            JClass lmf_class, l_class, lable_class;
+            JClass supplier_class, rbundle_class, locale_class;
+            try {
+                lmf_class = cm.parseType(addLocalizationUtilityPackageName("LocalizableMessageFactory")).boxify();
+                l_class = cm.parseType(addLocalizationUtilityPackageName("Localizer")).boxify();
+                lable_class = cm.parseType(addLocalizationUtilityPackageName("Localizable")).boxify();
+                supplier_class = cm.parseType(addLocalizationUtilityPackageName("LocalizableMessageFactory.ResourceBundleSupplier")).boxify();
+                rbundle_class = cm.parseType("java.util.ResourceBundle").boxify();
+                locale_class = cm.parseType("java.util.Locale").boxify();
+            } catch (Throwable e) {
+                throw new MojoExecutionException(e.getMessage(), e); // impossible -- but why parseType throwing Exception!?
+            }
+
+            JFieldVar $bundle = clazz.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL,
+                    String.class, "BUNDLE_NAME", JExpr.lit(bundleName));
+
+            JDefinedClass supplier;
+            try {
+                supplier = clazz._class(JMod.PRIVATE | JMod.STATIC, "BundleSupplier");
+                supplier._implements(supplier_class);
+                JMethod rb = supplier.method(JMod.PUBLIC, rbundle_class, "getResourceBundle");
+                JVar ploc = rb.param(locale_class, "locale");
+                rb.body()._return(rbundle_class.staticInvoke("getBundle").arg($bundle).arg(ploc));
+            } catch (JClassAlreadyExistsException e) {
+                throw new MojoExecutionException(e.getMessage(), e);
+            }
+
+            JFieldVar $msgFactory = clazz.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL,
+                lmf_class, "MESSAGE_FACTORY", JExpr._new(lmf_class).arg($bundle).arg(JExpr._new(supplier)));
+            JFieldVar $localizer = clazz.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL,
+                l_class, "LOCALIZER", JExpr._new(l_class));
+
+            // [RESULT]
+            // private CLASS() {}
+            clazz.constructor(JMod.PRIVATE);
+
+            for (Map.Entry<Object,Object> e : props.entrySet()) {
+                // [RESULT]
+                // Localizable METHOD_localizable(Object arg1, Object arg2, ...) {
+                //   return messageFactory.getMessage("servlet.html.notFound", message));
+                // }
+                // String METHOD(Object arg1, Object arg2, ...) {
+                //   return localizer.localize(METHOD_localizable(arg1,arg2,...));
+                // }
+                String methodBaseName = NameConverter.smart.toConstantName(e.getKey().toString());
+
+                JMethod method = clazz.method(JMod.PUBLIC | JMod.STATIC, lable_class, "localizable"+methodBaseName);
+
+                int countArgs = countArgs(e.getValue().toString());
+
+                JInvocation format = $msgFactory.invoke("getMessage").arg(
+                    JExpr.lit(e.getKey().toString()));
+
+                for( int i=0; i<countArgs; i++ ) {
+                    format.arg( method.param(Object.class,"arg"+i));
+                }
+                method.body()._return(format);
+
+                JMethod method2 = clazz.method(JMod.PUBLIC|JMod.STATIC, String.class, methodBaseName);
+                if (javadoc) {
+                    method2.javadoc().add(escape(e.getValue().toString()));
+                }
+
+                JInvocation localize = JExpr.invoke(method);
+                for( int i=0; i<countArgs; i++ ) {
+                    localize.arg( method2.param(Object.class,"arg"+i));
+                }
+
+                method2.body()._return($localizer.invoke("localize").arg(localize));
+            }
+        }
+
+        try {
+            CodeWriter core = new FileCodeWriter(destDir, encoding);
+            if (license != null) {
+                core = new LicenseCodeWriter(core, license, encoding);
+            }
+            cm.build(core);
+        } catch (IOException e) {
+            throw new MojoExecutionException("Failed to generate code",e);
+        }
+
+        if (project != null) {
+            project.addCompileSourceRoot(destDir.getAbsolutePath());
+        }
+    }
+
+    private String addLocalizationUtilityPackageName(final String className) {
+        return String.format("%s.%s", localizationUtilitiesPkgName, className);
+    }
+
+    private int countArgs(String value) {
+        List<String> x = new ArrayList<>();
+
+        while(true) {
+            String r1 = MessageFormat.format(value, x.toArray());
+            x.add("xxxx");
+            String r2 = MessageFormat.format(value, x.toArray());
+
+            if(r1.equals(r2))
+                return x.size()-1;
+        }
+    }
+
+    /**
+     * Computes the class name from the resource bundle name.
+     */
+    private String getClassName(File res) {
+        String name = res.getName();
+        int suffixIndex = name.lastIndexOf('.');
+        name = name.substring(0,suffixIndex);
+        return NameConverter.smart.toClassName(name)+"Messages";
+    }
+
+    private String escape(String s) {
+        return s.replaceAll("<", "{@code <}").replaceAll(">", "{@code >}");
+    }
+
+}
diff --git a/istack-commons/maven-plugin/src/test/it/sample/pom.xml b/istack-commons/maven-plugin/src/test/it/sample/pom.xml
new file mode 100644
index 0000000..ab9aab9
--- /dev/null
+++ b/istack-commons/maven-plugin/src/test/it/sample/pom.xml
@@ -0,0 +1,109 @@
+<!--
+
+    Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.sun.xml.ws</groupId>
+    <artifactId>sample</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <name>sample</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <resgen.plugin.version>4.0.0-SNAPSHOT</resgen.plugin.version>
+        <maven.compiler.release>${tp.compiler.release}</maven.compiler.release>
+        <maven.compiler.testRelease>${maven.compiler.release}</maven.compiler.testRelease>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.sun.istack</groupId>
+            <artifactId>istack-commons-runtime</artifactId>
+            <version>${resgen.plugin.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.xml.bind</groupId>
+            <artifactId>jakarta.xml.bind-api</artifactId>
+            <version>4.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.13.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>com.sun.istack</groupId>
+                    <artifactId>istack-commons-maven-plugin</artifactId>
+                    <version>${resgen.plugin.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>3.11.0</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        <plugins>
+            <plugin>
+                <groupId>com.sun.istack</groupId>
+                <artifactId>istack-commons-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>resource-gen</id>
+                        <goals>
+                            <goal>rs-gen</goal>
+                        </goals>
+                        <configuration>
+                            <resources>
+                                <directory>${project.basedir}/src/main/resources</directory>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>quick-gen</id>
+                        <goals>
+                            <goal>quick-gen</goal>
+                        </goals>
+                        <configuration>
+                            <packageName>org.app.annotation</packageName>
+                            <classes>
+                                <class>jakarta.xml.bind.annotation.XmlAttribute</class>
+                                <class>jakarta.xml.bind.annotation.XmlElement</class>
+                                <class>jakarta.xml.bind.annotation.XmlElementDecl</class>
+                                <class>jakarta.xml.bind.annotation.XmlElementRef</class>
+                                <class>jakarta.xml.bind.annotation.XmlElementRefs</class>
+                                <class>jakarta.xml.bind.annotation.XmlEnum</class>
+                                <class>jakarta.xml.bind.annotation.XmlRootElement</class>
+                                <class>jakarta.xml.bind.annotation.XmlSchema</class>
+                                <class>jakarta.xml.bind.annotation.XmlSchemaType</class>
+                                <class>jakarta.xml.bind.annotation.XmlTransient</class>
+                                <class>jakarta.xml.bind.annotation.XmlType</class>
+                                <class>jakarta.xml.bind.annotation.XmlValue</class>
+                            </classes>
+                            <attach>false</attach>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/istack-commons/maven-plugin/src/test/it/sample/src/main/java/com/sun/xml/ws/App.java b/istack-commons/maven-plugin/src/test/it/sample/src/main/java/com/sun/xml/ws/App.java
new file mode 100644
index 0000000..7b6492b
--- /dev/null
+++ b/istack-commons/maven-plugin/src/test/it/sample/src/main/java/com/sun/xml/ws/App.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.xml.ws;
+
+/**
+ * Hello world!
+ *
+ */
+public class App 
+{
+    public static void main( String[] args )
+    {
+        System.out.println( "Hello World!" );
+    }
+}
diff --git a/istack-commons/maven-plugin/src/test/it/sample/src/main/resources/org/aaa/aprop.properties b/istack-commons/maven-plugin/src/test/it/sample/src/main/resources/org/aaa/aprop.properties
new file mode 100644
index 0000000..c82c9e6
--- /dev/null
+++ b/istack-commons/maven-plugin/src/test/it/sample/src/main/resources/org/aaa/aprop.properties
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Distribution License v. 1.0, which is available at
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+aaa=fdsa
+bb.d=rewq
diff --git a/istack-commons/maven-plugin/src/test/it/sample/src/main/resources/org/aaa/aprop_de.properties b/istack-commons/maven-plugin/src/test/it/sample/src/main/resources/org/aaa/aprop_de.properties
new file mode 100644
index 0000000..b8d21f7
--- /dev/null
+++ b/istack-commons/maven-plugin/src/test/it/sample/src/main/resources/org/aaa/aprop_de.properties
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Distribution License v. 1.0, which is available at
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+aaa=fdsa-de
+bb.d=rewq-de
diff --git a/istack-commons/maven-plugin/src/test/java/com/sun/istack/maven/QuickGenMojoITCase.java b/istack-commons/maven-plugin/src/test/java/com/sun/istack/maven/QuickGenMojoITCase.java
new file mode 100644
index 0000000..706e737
--- /dev/null
+++ b/istack-commons/maven-plugin/src/test/java/com/sun/istack/maven/QuickGenMojoITCase.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.File;
+
+public class QuickGenMojoITCase {
+
+    private static final File PROJECTS_DIR = new File(System.getProperty("it.projects.dir"));
+
+    public QuickGenMojoITCase() {
+    }
+
+    @Test
+    public void testGeneration() {
+        File project = new File(PROJECTS_DIR, "sample");
+        File f = new File(project, "target/generated-sources/quick-sources/org/app/annotation/XmlEnumQuick.java");
+        Assert.assertTrue("Not found " + f.getAbsolutePath(), f.exists());
+        f = new File(project, "target/classes/org/app/annotation/Init.class");
+        Assert.assertFalse("Found " + f.getAbsolutePath(), f.exists());
+    }
+}
diff --git a/istack-commons/maven-plugin/src/test/java/com/sun/istack/maven/ResourceGenMojoITCase.java b/istack-commons/maven-plugin/src/test/java/com/sun/istack/maven/ResourceGenMojoITCase.java
new file mode 100644
index 0000000..44a6615
--- /dev/null
+++ b/istack-commons/maven-plugin/src/test/java/com/sun/istack/maven/ResourceGenMojoITCase.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.maven;
+
+import java.io.File;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ * @author Lukas Jungmann
+ */
+public class ResourceGenMojoITCase {
+
+    private static final File PROJECTS_DIR = new File(System.getProperty("it.projects.dir"));
+
+    public ResourceGenMojoITCase() {
+    }
+
+    @Test
+    public void testGeneration() {
+        File project = new File(PROJECTS_DIR, "sample");
+        File f = new File(project, "target/generated-sources/resources/org/aaa/ApropMessages.java");
+        Assert.assertTrue("Not found " + f.getAbsolutePath(), f.exists());
+        f = new File(project, "target/classes/org/aaa/ApropMessages.class");
+        Assert.assertTrue("Not found " + f.getAbsolutePath(), f.exists());
+    }
+}
diff --git a/istack-commons/maven-plugin/src/test/resources/it-settings.xml b/istack-commons/maven-plugin/src/test/resources/it-settings.xml
new file mode 100644
index 0000000..d4f5aa2
--- /dev/null
+++ b/istack-commons/maven-plugin/src/test/resources/it-settings.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!--
+
+    Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<settings>
+    <profiles>
+        <profile>
+            <id>it-repo</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <repositories>
+                <repository>
+                    <id>local.central</id>
+                    <url>@localRepositoryUrl@</url>
+                    <releases>
+                        <enabled>true</enabled>
+                    </releases>
+                    <snapshots>
+                        <enabled>true</enabled>
+                    </snapshots>
+                </repository>
+                <repository>
+                    <id>jakarta-sonatype-nexus</id>
+                    <url>https://jakarta.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+                    <layout>default</layout>
+                </repository>
+                <repository>
+                    <id>jakarta-sonatype-nexus-staging</id>
+                    <url>https://jakarta.oss.sonatype.org/content/repositories/staging/</url>
+                    <layout>default</layout>
+                </repository>
+            </repositories>
+            <pluginRepositories>
+                <pluginRepository>
+                    <id>local.central</id>
+                    <url>@localRepositoryUrl@</url>
+                    <releases>
+                        <enabled>true</enabled>
+                    </releases>
+                    <snapshots>
+                        <enabled>true</enabled>
+                    </snapshots>
+                </pluginRepository>
+                <pluginRepository>
+                    <id>jakarta-sonatype-nexus-plugins</id>
+                    <url>https://jakarta.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+                    <layout>default</layout>
+                </pluginRepository>
+                <pluginRepository>
+                    <id>jakarta-sonatype-nexus-staging-plugins</id>
+                    <url>https://jakarta.oss.sonatype.org/content/repositories/staging/</url>
+                    <layout>default</layout>
+                </pluginRepository>
+            </pluginRepositories>
+        </profile>
+    </profiles>
+</settings>
diff --git a/istack-commons/maven-plugin/src/test/script/setproxy.groovy b/istack-commons/maven-plugin/src/test/script/setproxy.groovy
new file mode 100644
index 0000000..241003e
--- /dev/null
+++ b/istack-commons/maven-plugin/src/test/script/setproxy.groovy
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+log.info("Checking proxy...")
+def itsettings = new XmlParser().parse(project.build.testResources.directory[0] + "/it-settings.xml")
+def itproxy = ""
+if (settings?.proxies) {
+    Node proxies = new Node(itsettings, "proxies")
+    settings?.proxies?.each { proxy ->
+        if (proxy.active) {
+            if ("http".equals(proxy.protocol)) {
+                itproxy +=  " -Dhttp.proxyHost=" + proxy.host
+                if (proxy.port) {
+                    itproxy += " -Dhttp.proxyPort=" + proxy.port
+                }
+            } else if ("https".equals(proxy.protocol)) {
+                itproxy +=  " -Dhttps.proxyHost=" + proxy.host
+                if (proxy.port) {
+                    itproxy += " -Dhttps.proxyPort=" + proxy.port
+                }
+            }
+            def p = new Node(proxies, "proxy")
+            new Node(p, "protocol", proxy.protocol)
+            new Node(p, "port", proxy.port)
+            if (proxy.username) {new Node(p, "username", proxy.username)}
+            if (proxy.password) {new Node(p, "password", proxy.password)}
+            if (proxy.id) {new Node(p, "id", proxy.id)} else {new Node(p, "id", proxy.protocol)}
+            new Node(p, "host", proxy.host)
+            new Node(p, "active", proxy.active)
+            new Node(p, "nonProxyHosts", proxy.nonProxyHosts)
+        }
+    }
+}
+
+if (itproxy.trim().length() > 0) {
+    log.info("Setting: " + itproxy.trim())
+} else {
+    log.info("No proxy found")
+}
+
+def writer = new FileWriter(new File(project.build.directory, "it-settings.xml"))
+groovy.xml.XmlNodePrinter printer = new groovy.xml.XmlNodePrinter(new PrintWriter(writer))
+printer.setPreserveWhitespace(true)
+printer.print(itsettings)
+
+project.getModel().addProperty("ittest-proxy", itproxy.trim())
diff --git a/istack-commons/pom.xml b/istack-commons/pom.xml
new file mode 100644
index 0000000..f875b83
--- /dev/null
+++ b/istack-commons/pom.xml
@@ -0,0 +1,624 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.eclipse.ee4j</groupId>
+        <artifactId>project</artifactId>
+        <version>1.0.7</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>com.sun.istack</groupId>
+    <artifactId>istack-commons</artifactId>
+    <version>4.2.0</version>
+    <packaging>pom</packaging>
+    <name>iStack Common Utility Code</name>
+    <description>istack common utility code</description>
+
+    <scm>
+        <connection>scm:git:ssh://git@github.com/eclipse-ee4j/jaxb-istack-commons.git</connection>
+        <developerConnection>scm:git:ssh://git@github.com/eclipse-ee4j/jaxb-istack-commons.git</developerConnection>
+        <url>https://github.com/eclipse-ee4j/jaxb-istack-commons</url>
+        <tag>HEAD</tag>
+    </scm>
+
+    <licenses>
+        <license>
+            <name>Eclipse Distribution License - v 1.0</name>
+            <url>http://www.eclipse.org/org/documents/edl-v10.php</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <developers>
+        <developer>
+            <name>Lukas Jungmann</name>
+            <email>lukas.jungmann@oracle.com</email>
+            <organization>Oracle Corporation</organization>
+        </developer>
+    </developers>
+
+    <issueManagement>
+        <system>github</system>
+        <url>https://github.com/eclipse-ee4j/jaxb-istack-commons/issues</url>
+    </issueManagement>
+
+    <mailingLists>
+        <mailingList>
+            <name>Eclipse Implementation of JAXB mailing list</name>
+            <post>jaxb-impl-dev@eclipse.org</post>
+            <subscribe>https://dev.eclipse.org/mailman/listinfo/jaxb-impl-dev</subscribe>
+            <unsubscribe>https://dev.eclipse.org/mailman/listinfo/jaxb-impl-dev</unsubscribe>
+            <archive>https://dev.eclipse.org/mhonarc/lists/jaxb-impl-dev</archive>
+        </mailingList>
+    </mailingLists>
+
+    <properties>
+        <project.build.commonResourcesDirectory>${project.build.directory}/common-resources</project.build.commonResourcesDirectory>
+        <legal.doc.source>${project.build.commonResourcesDirectory}/legal</legal.doc.source>
+        <config.dir>${project.build.commonResourcesDirectory}/config</config.dir>
+        <copyright.exclude>${config.dir}/copyright-exclude</copyright.exclude>
+        <copyright.ignoreyear>false</copyright.ignoreyear>
+        <copyright.scmonly>true</copyright.scmonly>
+        <copyright.update>false</copyright.update>
+        <spotbugs.exclude>${config.dir}/spotbugs-exclude.xml</spotbugs.exclude>
+        <spotbugs.skip>false</spotbugs.skip>
+        <spotbugs.threshold>Low</spotbugs.threshold>
+        <spotbugs.version>4.7.3.4</spotbugs.version>
+
+        <activation.version>2.1.1</activation.version>
+        <maven.api.version>3.9.1</maven.api.version>
+        <maven.resolver.version>1.9.7</maven.resolver.version>
+        <junit.version>4.13.2</junit.version>
+        <ant.version>1.10.13</ant.version>
+        <codemodel.version>4.0.2</codemodel.version>
+        <plexus-utils.version>3.5.1</plexus-utils.version>
+        <maven-plugin-annotations.version>3.8.1</maven-plugin-annotations.version>
+        <testng.version>7.7.1</testng.version>
+        <args4j.version>2.33</args4j.version>
+
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>${project.build.sourceEncoding}</project.reporting.outputEncoding>
+        <maven.compiler.release>11</maven.compiler.release>
+        <maven.compiler.testRelease>${maven.compiler.release}</maven.compiler.testRelease>
+        <vendor.name>Eclipse Foundation</vendor.name>
+    </properties>
+
+    <modules>
+        <module>buildtools</module>
+        <module>runtime</module>
+        <module>test</module>
+        <module>tools</module>
+        <module>maven-plugin</module>
+        <module>import-properties-plugin</module>
+        <module>soimp</module>
+    </modules>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>jakarta.activation</groupId>
+                <artifactId>jakarta.activation-api</artifactId>
+                <version>${activation.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <version>${junit.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.ant</groupId>
+                <artifactId>ant</artifactId>
+                <version>${ant.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.ant</groupId>
+                <artifactId>ant-junit</artifactId>
+                <version>${ant.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.glassfish.jaxb</groupId>
+                <artifactId>codemodel</artifactId>
+                <version>${codemodel.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-plugin-api</artifactId>
+                <version>${maven.api.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>*</groupId>
+                        <artifactId>*</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-core</artifactId>
+                <version>${maven.api.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>*</groupId>
+                        <artifactId>*</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-artifact</artifactId>
+                <version>${maven.api.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>*</groupId>
+                        <artifactId>*</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-model</artifactId>
+                <version>${maven.api.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>*</groupId>
+                        <artifactId>*</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.codehaus.plexus</groupId>
+                <artifactId>plexus-utils</artifactId>
+                <version>${plexus-utils.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven.plugin-tools</groupId>
+                <artifactId>maven-plugin-annotations</artifactId>
+                <version>${maven-plugin-annotations.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>*</groupId>
+                        <artifactId>*</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.testng</groupId>
+                <artifactId>testng</artifactId>
+                <version>${testng.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-settings</artifactId>
+                <version>${maven.api.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven.resolver</groupId>
+                <artifactId>maven-resolver-api</artifactId>
+                <version>${maven.resolver.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>*</groupId>
+                        <artifactId>*</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven.resolver</groupId>
+                <artifactId>maven-resolver-impl</artifactId>
+                <version>${maven.resolver.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>*</groupId>
+                        <artifactId>*</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>args4j</groupId>
+                <artifactId>args4j</artifactId>
+                <version>${args4j.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>build-helper-maven-plugin</artifactId>
+                    <version>3.3.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>buildnumber-maven-plugin</artifactId>
+                    <version>3.0.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>3.11.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>3.0.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.glassfish.copyright</groupId>
+                    <artifactId>glassfish-copyright-maven-plugin</artifactId>
+                    <version>2.4</version>
+                </plugin>
+                <plugin>
+                    <groupId>com.github.spotbugs</groupId>
+                    <artifactId>spotbugs-maven-plugin</artifactId>
+                    <version>${spotbugs.version}</version>
+                    <configuration>
+                        <skip>${spotbugs.skip}</skip>
+                        <threshold>${spotbugs.threshold}</threshold>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-source-plugin</artifactId>
+                    <version>3.2.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-jar-plugin</artifactId>
+                    <version>3.3.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>maven-bundle-plugin</artifactId>
+                    <version>5.1.8</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-javadoc-plugin</artifactId>
+                    <version>3.5.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-enforcer-plugin</artifactId>
+                    <version>3.3.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-assembly-plugin</artifactId>
+                    <version>3.5.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <version>3.5.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.codehaus.gmaven</groupId>
+                    <artifactId>gmaven-plugin</artifactId>
+                    <version>1.5</version>
+                    <dependencies>
+                        <dependency>
+                            <groupId>org.apache.groovy</groupId>
+                            <artifactId>groovy</artifactId>
+                            <version>4.0.11</version>
+                        </dependency>
+                        <dependency>
+                            <groupId>org.apache.groovy</groupId>
+                            <artifactId>groovy-xml</artifactId>
+                            <version>4.0.11</version>
+                        </dependency>
+                    </dependencies>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-invoker-plugin</artifactId>
+                    <version>3.5.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-failsafe-plugin</artifactId>
+                    <version>3.0.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-plugin-plugin</artifactId>
+                    <version>3.8.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.jacoco</groupId>
+                    <artifactId>jacoco-maven-plugin</artifactId>
+                    <version>0.8.9</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>enforce-maven</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireJavaVersion>
+                                    <version>[${maven.compiler.release},)</version>
+                                </requireJavaVersion>
+                                <requireMavenVersion>
+                                    <version>[3.6.0,)</version>
+                                </requireMavenVersion>
+                            </rules>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>buildnumber-maven-plugin</artifactId>
+                <configuration>
+                    <getRevisionOnlyOnce>true</getRevisionOnlyOnce>
+                    <revisionOnScmFailure>false</revisionOnScmFailure>
+                    <shortRevisionLength>7</shortRevisionLength>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>create</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.glassfish.copyright</groupId>
+                <artifactId>glassfish-copyright-maven-plugin</artifactId>
+                <configuration>
+                    <excludeFile>${copyright.exclude}</excludeFile>
+                    <!-- skip files not under SCM-->
+                    <scmOnly>${copyright.scmonly}</scmOnly>
+                    <!-- for use with repair -->
+                    <update>${copyright.update}</update>
+                    <!-- check that year is correct -->
+                    <ignoreYear>${copyright.ignoreyear}</ignoreYear>
+                    <quiet>false</quiet>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>common-resources</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <inherited>false</inherited>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/assembly/resources.xml</descriptor>
+                            </descriptors>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack-resource</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>istack-commons</artifactId>
+                                    <version>${project.version}</version>
+                                    <classifier>resources</classifier>
+                                    <type>zip</type>
+                                    <outputDirectory>${project.build.commonResourcesDirectory}</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <compilerArgs>
+                        <arg>-Xlint:all</arg>
+                        <arg>-Xdoclint:all,-missing</arg>
+                        <arg>-Werror</arg>
+                    </compilerArgs>
+                    <showDeprecation>true</showDeprecation>
+                    <createMissingPackageInfoClass>false</createMissingPackageInfoClass>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addDefaultEntries>false</addDefaultEntries>
+                        </manifest>
+                    </archive>
+                    <instructions>
+                        <Implementation-Vendor>${vendor.name}</Implementation-Vendor>
+                        <Implementation-Vendor-Id>${project.groupId}</Implementation-Vendor-Id>
+                        <Implementation-Build-Id>${project.version} - ${buildNumber}</Implementation-Build-Id>
+                    </instructions>
+                    <niceManifest>true</niceManifest>
+                    <noWarningProjectTypes>
+                        <noWarningProjectType>pom</noWarningProjectType>
+                        <noWarningProjectType>maven-plugin</noWarningProjectType>
+                    </noWarningProjectTypes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>bundle-manifest</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>manifest</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addDefaultEntries>false</addDefaultEntries>
+                        </manifest>
+                    </archive>
+                    <excludes>
+                        <exclude>META-INF/jpms.args</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <notimestamp>true</notimestamp>
+                    <doclint>all,-missing</doclint>
+                    <quiet>true</quiet>
+                    <failOnWarnings>true</failOnWarnings>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addDefaultEntries>false</addDefaultEntries>
+                        </manifest>
+                        <manifestEntries>
+                            <Implementation-Build-Id>${project.version} - ${buildNumber}</Implementation-Build-Id>
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>com.github.spotbugs</groupId>
+                <artifactId>spotbugs-maven-plugin</artifactId>
+                <configuration>
+                    <fork>true</fork>
+                    <excludeFilterFile>${spotbugs.exclude}</excludeFilterFile>
+                    <failThreshold>High</failThreshold>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <configuration>
+                    <extractors>
+                        <extractor>java-annotations</extractor>
+                    </extractors>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>coverage</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.jacoco</groupId>
+                        <artifactId>jacoco-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-prepare-agent</id>
+                                <goals>
+                                    <goal>prepare-agent</goal>
+                                </goals>
+                            </execution>
+                            <execution>
+                                <id>default-report</id>
+                                <goals>
+                                    <goal>report</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>license-check</id>
+            <pluginRepositories>
+                <pluginRepository>
+                    <!-- org.eclipse.dash:license-tool-plugin is nor final nor in central yet -->
+                    <id>dash-licenses-snapshots</id>
+                    <url>https://repo.eclipse.org/content/repositories/dash-licenses-snapshots/</url>
+                    <snapshots>
+                        <enabled>true</enabled>
+                    </snapshots>
+                </pluginRepository>
+            </pluginRepositories>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.eclipse.dash</groupId>
+                            <artifactId>license-tool-plugin</artifactId>
+                            <version>0.0.1-SNAPSHOT</version>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+                <plugins>
+                    <plugin>
+                        <groupId>org.eclipse.dash</groupId>
+                        <artifactId>license-tool-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>license-check</id>
+                                <phase>validate</phase>
+                                <goals>
+                                    <goal>license-check</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/istack-commons/runtime/pom.xml b/istack-commons/runtime/pom.xml
new file mode 100644
index 0000000..37f14d8
--- /dev/null
+++ b/istack-commons/runtime/pom.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.sun.istack</groupId>
+        <artifactId>istack-commons</artifactId>
+        <version>4.2.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>istack-commons-runtime</artifactId>
+
+    <name>istack common utility code runtime</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>jakarta.activation</groupId>
+            <artifactId>jakarta.activation-api</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
+
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/Builder.java b/istack-commons/runtime/src/main/java/com/sun/istack/Builder.java
new file mode 100644
index 0000000..fe4b72d
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/Builder.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+/**
+ *
+ * @author Martin Grebac
+ * @param <T> type of the Builder
+ */
+public interface Builder<T> {
+    T build();
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/ByteArrayDataSource.java b/istack-commons/runtime/src/main/java/com/sun/istack/ByteArrayDataSource.java
new file mode 100644
index 0000000..11a529d
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/ByteArrayDataSource.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import jakarta.activation.DataSource;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.OutputStream;
+
+/**
+ * {@link DataSource} backed by a byte buffer.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public final class ByteArrayDataSource implements DataSource {
+
+    private final String contentType;
+    private final byte[] buf;
+    private final int len;
+
+    /**
+     * @param buf input buffer - the byte array isn't being copied; used directly
+     * @param contentType content type
+     */
+    public ByteArrayDataSource(byte[] buf, String contentType) {
+        this(buf,buf.length,contentType);
+    }
+
+    /**
+     * @param buf input buffer - the byte array isn't being copied; used directly
+     * @param length length
+     * @param contentType content type
+     */
+    public ByteArrayDataSource(byte[] buf, int length, String contentType) {
+        this.buf = buf;
+        this.len = length;
+        this.contentType = contentType;
+    }
+
+    @Override
+    public String getContentType() {
+        if(contentType==null)
+            return "application/octet-stream";
+        return contentType;
+    }
+
+    @Override
+    public InputStream getInputStream() {
+        return new ByteArrayInputStream(buf,0,len);
+    }
+
+    @Override
+    public String getName() {
+        return null;
+    }
+
+    @Override
+    public OutputStream getOutputStream() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/FinalArrayList.java b/istack-commons/runtime/src/main/java/com/sun/istack/FinalArrayList.java
new file mode 100644
index 0000000..542db9f
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/FinalArrayList.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * {@link ArrayList} with the final keyword.
+ *
+ * <p>
+ * This gives HotSpot a better hint that all methods can be inlined.
+ *
+ * @author Kohsuke Kawaguchi
+ * @param <T> element type
+ */
+public final class FinalArrayList<T> extends ArrayList<T> {
+
+    private static final long serialVersionUID = -540534530037816397L;
+
+    public FinalArrayList(int initialCapacity) {
+        super(initialCapacity);
+    }
+
+    public FinalArrayList() {
+    }
+
+    public FinalArrayList(Collection<? extends T> ts) {
+        super(ts);
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/FragmentContentHandler.java b/istack-commons/runtime/src/main/java/com/sun/istack/FragmentContentHandler.java
new file mode 100644
index 0000000..26ab3f7
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/FragmentContentHandler.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import org.xml.sax.helpers.XMLFilterImpl;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ContentHandler;
+
+/**
+ * {@link XMLFilterImpl} that masks start/end document SAX events.
+ * @author Kohsuke Kawaguchi
+ */
+public class FragmentContentHandler extends XMLFilterImpl {
+    public FragmentContentHandler() {
+    }
+
+    public FragmentContentHandler(XMLReader parent) {
+        super(parent);
+    }
+
+    @SuppressWarnings({"this-escape"})
+    public FragmentContentHandler(ContentHandler handler) {
+        super();
+        setContentHandler(handler);
+    }
+
+    @Override
+    public void startDocument() throws SAXException {
+        // noop
+    }
+
+    @Override
+    public void endDocument() throws SAXException {
+        // noop
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/Interned.java b/istack-commons/runtime/src/main/java/com/sun/istack/Interned.java
new file mode 100644
index 0000000..9c88b42
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/Interned.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Designates that a field, return value, argument, or a variable is supposed
+ * to be an {@link String#intern() interned} string.
+ *
+ * <p>
+ * In many places in the istack, we assume Strings to be interned for
+ * the performance reason. Similarly, In many other places, we don't
+ * make such an assumption for the performance reason (because intern
+ * isn't free.)
+ *
+ * <p>
+ * Therefore, distinguishing which part is supposed to be interned and
+ * which part is supposed to be not is important. This annotation
+ * allows us to capture that in the code.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
+public @interface Interned {
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/NotNull.java b/istack-commons/runtime/src/main/java/com/sun/istack/NotNull.java
new file mode 100644
index 0000000..e5a3d1a
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/NotNull.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Designates that a field, return value, argument, or a variable is guaranteed to be non-null.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
+public @interface NotNull {
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/Nullable.java b/istack-commons/runtime/src/main/java/com/sun/istack/Nullable.java
new file mode 100644
index 0000000..d52e3b3
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/Nullable.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Designates that a field, return value, argument, or a variable may be null.
+ * 
+ * @author Kohsuke Kawaguchi
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
+public @interface Nullable {
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/Pool.java b/istack-commons/runtime/src/main/java/com/sun/istack/Pool.java
new file mode 100644
index 0000000..525f537
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/Pool.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.lang.ref.WeakReference;
+
+/**
+ * Pool of reusable objects that are indistinguishable from each other,
+ * such as JAXB marshallers.
+ *
+ * @author Kohsuke Kawaguchi
+ * @param <T> type
+ */
+public interface Pool<T> {
+
+    /**
+     * Gets a new object from the pool.
+     *
+     * <p>
+     * If no object is available in the pool, this method creates a new one.
+     * @return an object from the pool
+     */
+    @NotNull T take();
+
+    /**
+     * Returns an object back to the pool.
+     * @param t object to put back to pool
+     */
+    void recycle(@NotNull T t);
+
+    /**
+     * Default implementation that uses {@link ConcurrentLinkedQueue}
+     * as the data store.
+     *
+     * <h2>Note for Implementors</h2>
+     * <p>
+     * Don't rely on the fact that this class extends from {@link ConcurrentLinkedQueue}.
+     * @param <T> type
+     */
+    abstract class Impl<T> implements Pool<T> {
+
+        private volatile WeakReference<ConcurrentLinkedQueue<T>> queue;
+
+        /**
+         * Create new Impl
+         */
+        protected Impl() {
+        }
+
+        /**
+         * Gets a new object from the pool.
+         *
+         * <p>
+         * If no object is available in the pool, this method creates a new one.
+         *
+         * @return
+         *      always non-null.
+         */
+        @Override
+        public final @NotNull T take() {
+            T t = getQueue().poll();
+            if(t==null) {
+                return create();
+            }
+            return t;
+        }
+
+        /**
+         * Returns an object back to the pool.
+         * @param t object to put back to the pool
+         */
+        @Override
+        public final void recycle(T t) {
+            getQueue().offer(t);
+        }
+
+        private ConcurrentLinkedQueue<T> getQueue() {
+            WeakReference<ConcurrentLinkedQueue<T>> q = queue;
+            if (q != null) {
+                ConcurrentLinkedQueue<T> d = q.get();
+                if (d != null) {
+                    return d;
+                }
+            }
+            // overwrite the queue
+            ConcurrentLinkedQueue<T> d = new ConcurrentLinkedQueue<>();
+            queue = new WeakReference<>(d);
+
+            return d;
+        }
+
+        /**
+         * Creates a new instance of object.
+         *
+         * <p>
+         * This method is used when someone wants to
+         * {@link #take() take} an object from an empty pool.
+         *
+         * <p>
+         * Also note that multiple threads may call this method
+         * concurrently.
+         * @return an object from an empty pool
+         */
+        protected abstract @NotNull T create();
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/SAXException2.java b/istack-commons/runtime/src/main/java/com/sun/istack/SAXException2.java
new file mode 100644
index 0000000..7673034
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/SAXException2.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import org.xml.sax.SAXException;
+
+/**
+ * {@link SAXException} that handles exception chaining correctly.
+ *
+ * @author Kohsuke Kawaguchi
+ * @since 2.0 FCS
+ */
+public class SAXException2 extends SAXException {
+
+    private static final long serialVersionUID = -707119042406163844L;
+
+    public SAXException2(String message) {
+        super(message);
+    }
+
+    public SAXException2(Exception e) {
+        super(e);
+    }
+
+    public SAXException2(String message, Exception e) {
+        super(message, e);
+    }
+
+    @Override
+    public Throwable getCause() {
+        return getException();
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/SAXParseException2.java b/istack-commons/runtime/src/main/java/com/sun/istack/SAXParseException2.java
new file mode 100644
index 0000000..fb8d743
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/SAXParseException2.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import org.xml.sax.SAXParseException;
+import org.xml.sax.Locator;
+
+/**
+ * {@link SAXParseException} that handles exception chaining correctly.
+ *
+ * @author Kohsuke Kawaguchi
+ * @since 2.0 FCS
+ */
+public class SAXParseException2 extends SAXParseException {
+
+    private static final long serialVersionUID = 1304853690034671001L;
+
+    public SAXParseException2(String message, Locator locator) {
+        super(message, locator);
+    }
+
+    public SAXParseException2(String message, Locator locator, Exception e) {
+        super(message, locator, e);
+    }
+
+    public SAXParseException2(String message, String publicId, String systemId, int lineNumber, int columnNumber) {
+        super(message, publicId, systemId, lineNumber, columnNumber);
+    }
+
+    public SAXParseException2(String message, String publicId, String systemId, int lineNumber, int columnNumber, Exception e) {
+        super(message, publicId, systemId, lineNumber, columnNumber, e);
+    }
+
+    @Override
+    public Throwable getCause() {
+        return getException();
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/XMLStreamException2.java b/istack-commons/runtime/src/main/java/com/sun/istack/XMLStreamException2.java
new file mode 100644
index 0000000..301274f
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/XMLStreamException2.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.Location;
+
+/**
+ * {@link XMLStreamException} that properly handles exception chaining.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class XMLStreamException2 extends XMLStreamException {
+
+    private static final long serialVersionUID = 1409033131880742500L;
+
+    public XMLStreamException2(String msg) {
+        super(msg);
+    }
+
+    public XMLStreamException2(Throwable th) {
+        super(th);
+    }
+
+    public XMLStreamException2(String msg, Throwable th) {
+        super(msg, th);
+    }
+
+    public XMLStreamException2(String msg, Location location) {
+        super(msg, location);
+    }
+
+    public XMLStreamException2(String msg, Location location, Throwable th) {
+        super(msg, location, th);
+    }
+
+    /**
+     * {@link XMLStreamException} doesn't return the correct cause.
+     */
+    @Override
+    public Throwable getCause() {
+        return getNestedException();
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/XMLStreamReaderToContentHandler.java b/istack-commons/runtime/src/main/java/com/sun/istack/XMLStreamReaderToContentHandler.java
new file mode 100644
index 0000000..a4d0fdf
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/XMLStreamReaderToContentHandler.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
+
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.namespace.QName;
+
+/**
+ * This is a simple utility class that adapts StAX events from an
+ * {@link XMLStreamReader} to SAX events on a
+ * {@link ContentHandler}, bridging between the two
+ * parser technologies.
+ *
+ * @author Ryan.Shoemaker@Sun.COM
+ * @version 1.0
+ */
+public class XMLStreamReaderToContentHandler {
+
+    // StAX event source
+    private final XMLStreamReader staxStreamReader;
+
+    // SAX event sink
+    private final ContentHandler saxHandler;
+
+    // if true, when the conversion is completed, leave the cursor to the last
+    // event that was fired (such as end element)
+    private final boolean eagerQuit;
+
+    /**
+     * If true, not start/endDocument event.
+     */
+    private final boolean fragment;
+
+    // array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }
+    private final String[] inscopeNamespaces;
+
+    /**
+     * @param staxCore
+     *                StAX event source
+     * @param saxCore
+     *                SAXevent sink
+     * @see #XMLStreamReaderToContentHandler(XMLStreamReader, ContentHandler, boolean, boolean, String[])
+     */
+    public XMLStreamReaderToContentHandler(XMLStreamReader staxCore, ContentHandler saxCore, boolean eagerQuit, boolean fragment) {
+        this(staxCore, saxCore, eagerQuit, fragment, new String[0]);
+    }
+
+    /**
+     * Construct a new StAX to SAX adapter that will convert a StAX event
+     * stream into a SAX event stream.
+     *
+     * @param staxCore
+     *                StAX event source
+     * @param saxCore
+     *                SAXevent sink
+     * @param inscopeNamespaces
+     *                array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }
+     */
+    public XMLStreamReaderToContentHandler(XMLStreamReader staxCore, ContentHandler saxCore,
+            boolean eagerQuit, boolean fragment, String[] inscopeNamespaces) {
+        this.staxStreamReader = staxCore;
+        this.saxHandler = saxCore;
+        this.eagerQuit = eagerQuit;
+        this.fragment = fragment;
+        this.inscopeNamespaces = inscopeNamespaces.clone();
+        assert inscopeNamespaces.length%2 == 0;
+    }
+
+
+    /*
+     * @see StAXReaderToContentHandler#bridge()
+     */
+    public void bridge() throws XMLStreamException {
+
+        try {
+            // remembers the nest level of elements to know when we are done.
+            int depth=0;
+
+            // if the parser is at the start tag, proceed to the first element
+            int event = staxStreamReader.getEventType();
+            if(event == XMLStreamConstants.START_DOCUMENT) {
+                // nextTag doesn't correctly handle DTDs
+                while( !staxStreamReader.isStartElement() )
+                    event = staxStreamReader.next();
+            }
+
+
+            if( event!=XMLStreamConstants.START_ELEMENT)
+                throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event);
+
+            handleStartDocument();
+
+            for(int i=0; i < inscopeNamespaces.length; i+=2) {
+                saxHandler.startPrefixMapping(inscopeNamespaces[i], inscopeNamespaces[i+1]);
+            }
+
+            OUTER:
+            do {
+                // These are all of the events listed in the javadoc for
+                // XMLEvent.
+                // The spec only really describes 11 of them.
+                switch (event) {
+                    case XMLStreamConstants.START_ELEMENT :
+                        depth++;
+                        handleStartElement();
+                        break;
+                    case XMLStreamConstants.END_ELEMENT :
+                        handleEndElement();
+                        depth--;
+                        if(depth==0 && eagerQuit)
+                            break OUTER;
+                        break;
+                    case XMLStreamConstants.CHARACTERS :
+                        handleCharacters();
+                        break;
+                    case XMLStreamConstants.ENTITY_REFERENCE :
+                        handleEntityReference();
+                        break;
+                    case XMLStreamConstants.PROCESSING_INSTRUCTION :
+                        handlePI();
+                        break;
+                    case XMLStreamConstants.COMMENT :
+                        handleComment();
+                        break;
+                    case XMLStreamConstants.DTD :
+                        handleDTD();
+                        break;
+                    case XMLStreamConstants.ATTRIBUTE :
+                        handleAttribute();
+                        break;
+                    case XMLStreamConstants.NAMESPACE :
+                        handleNamespace();
+                        break;
+                    case XMLStreamConstants.CDATA :
+                        handleCDATA();
+                        break;
+                    case XMLStreamConstants.ENTITY_DECLARATION :
+                        handleEntityDecl();
+                        break;
+                    case XMLStreamConstants.NOTATION_DECLARATION :
+                        handleNotationDecl();
+                        break;
+                    case XMLStreamConstants.SPACE :
+                        handleSpace();
+                        break;
+                    default :
+                        throw new InternalError("processing event: " + event);
+                }
+
+                event=staxStreamReader.next();
+            } while (depth!=0);
+
+            for(int i=0; i < inscopeNamespaces.length; i+=2) {
+                saxHandler.endPrefixMapping(inscopeNamespaces[i]);
+            }
+
+            handleEndDocument();
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private void handleEndDocument() throws SAXException {
+        if(fragment)
+            return;
+
+        saxHandler.endDocument();
+    }
+
+    private void handleStartDocument() throws SAXException {
+        if(fragment)
+            return;
+
+        saxHandler.setDocumentLocator(new Locator() {
+            @Override
+            public int getColumnNumber() {
+                return staxStreamReader.getLocation().getColumnNumber();
+            }
+            @Override
+            public int getLineNumber() {
+                return staxStreamReader.getLocation().getLineNumber();
+            }
+            @Override
+            public String getPublicId() {
+                return staxStreamReader.getLocation().getPublicId();
+            }
+            @Override
+            public String getSystemId() {
+                return staxStreamReader.getLocation().getSystemId();
+            }
+        });
+        saxHandler.startDocument();
+    }
+
+    private void handlePI() throws XMLStreamException {
+        try {
+            saxHandler.processingInstruction(
+                staxStreamReader.getPITarget(),
+                staxStreamReader.getPIData());
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private void handleCharacters() throws XMLStreamException {
+        try {
+            saxHandler.characters(
+                staxStreamReader.getTextCharacters(),
+                staxStreamReader.getTextStart(),
+                staxStreamReader.getTextLength() );
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private void handleEndElement() throws XMLStreamException {
+        QName qName = staxStreamReader.getName();
+
+        try {
+            String pfix = qName.getPrefix();
+            String rawname = (pfix == null || pfix.length() == 0)
+                    ? qName.getLocalPart()
+                    : pfix + ':' + qName.getLocalPart();
+            // fire endElement
+            saxHandler.endElement(
+                qName.getNamespaceURI(),
+                qName.getLocalPart(),
+                rawname);
+
+            // end namespace bindings
+            int nsCount = staxStreamReader.getNamespaceCount();
+            for (int i = nsCount - 1; i >= 0; i--) {
+                String prefix = staxStreamReader.getNamespacePrefix(i);
+                if (prefix == null) { // true for default namespace
+                    prefix = "";
+                }
+                saxHandler.endPrefixMapping(prefix);
+            }
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private void handleStartElement() throws XMLStreamException {
+
+        try {
+            // start namespace bindings
+            int nsCount = staxStreamReader.getNamespaceCount();
+            for (int i = 0; i < nsCount; i++) {
+                saxHandler.startPrefixMapping(
+                    fixNull(staxStreamReader.getNamespacePrefix(i)),
+                    fixNull(staxStreamReader.getNamespaceURI(i)));
+            }
+
+            // fire startElement
+            QName qName = staxStreamReader.getName();
+            String prefix = qName.getPrefix();
+            String rawname;
+            if(prefix==null || prefix.length()==0)
+                rawname = qName.getLocalPart();
+            else
+                rawname = prefix + ':' + qName.getLocalPart();
+            Attributes attrs = getAttributes();
+            saxHandler.startElement(
+                qName.getNamespaceURI(),
+                qName.getLocalPart(),
+                rawname,
+                attrs);
+        } catch (SAXException e) {
+            throw new XMLStreamException2(e);
+        }
+    }
+
+    private static String fixNull(String s) {
+        if(s==null)     return "";
+        else            return s;
+    }
+
+    /**
+     * Get the attributes associated with the given START_ELEMENT or ATTRIBUTE
+     * StAXevent.
+     *
+     * @return the StAX attributes converted to an org.xml.sax.Attributes
+     */
+    private Attributes getAttributes() {
+        AttributesImpl attrs = new AttributesImpl();
+
+        int eventType = staxStreamReader.getEventType();
+        if (eventType != XMLStreamConstants.ATTRIBUTE
+            && eventType != XMLStreamConstants.START_ELEMENT) {
+            throw new InternalError(
+                "getAttributes() attempting to process: " + eventType);
+        }
+
+        // in SAX, namespace declarations are not part of attributes by default.
+        // (there's a property to control that, but as far as we are concerned
+        // we don't use it.) So don't add xmlns:* to attributes.
+
+        // gather non-namespace attrs
+        for (int i = 0; i < staxStreamReader.getAttributeCount(); i++) {
+            String uri = staxStreamReader.getAttributeNamespace(i);
+            if(uri==null)   uri="";
+            String localName = staxStreamReader.getAttributeLocalName(i);
+            String prefix = staxStreamReader.getAttributePrefix(i);
+            String qName;
+            if(prefix==null || prefix.length()==0)
+                qName = localName;
+            else
+                qName = prefix + ':' + localName;
+            String type = staxStreamReader.getAttributeType(i);
+            String value = staxStreamReader.getAttributeValue(i);
+
+            attrs.addAttribute(uri, localName, qName, type, value);
+        }
+
+        return attrs;
+    }
+
+    private void handleNamespace() {
+        // no-op ???
+        // namespace events don't normally occur outside of a startElement
+        // or endElement
+    }
+
+    private void handleAttribute() {
+        // no-op ???
+        // attribute events don't normally occur outside of a startElement
+        // or endElement
+    }
+
+    private void handleDTD() {
+        // no-op ???
+        // it seems like we need to pass this info along, but how?
+    }
+
+    private void handleComment() {
+        // no-op ???
+    }
+
+    private void handleEntityReference() {
+        // no-op ???
+    }
+
+    private void handleSpace() {
+        // no-op ???
+        // this event is listed in the javadoc, but not in the spec.
+    }
+
+    private void handleNotationDecl() {
+        // no-op ???
+        // this event is listed in the javadoc, but not in the spec.
+    }
+
+    private void handleEntityDecl() {
+        // no-op ???
+        // this event is listed in the javadoc, but not in the spec.
+    }
+
+    private void handleCDATA() {
+        // no-op ???
+        // this event is listed in the javadoc, but not in the spec.
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/localization/Localizable.java b/istack-commons/runtime/src/main/java/com/sun/istack/localization/Localizable.java
new file mode 100644
index 0000000..d29f9b3
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/localization/Localizable.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.localization;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * Localizable message.
+ *
+ * @author WS Development Team
+ */
+public interface Localizable {
+    /**
+     * Gets the key in the resource bundle.
+     *
+     * @return
+     *      if this method returns {@link #NOT_LOCALIZABLE},
+     *      that means the message is not localizable, and
+     *      the first item of {@link #getArguments()} array
+     *      holds a String.
+     */
+    String getKey();
+
+    /**
+     * Returns the arguments for message formatting.
+     *
+     * @return
+     *      can be an array of length 0 but never be null.
+     */
+    Object[] getArguments();
+    String getResourceBundleName();
+
+    ResourceBundle getResourceBundle(Locale locale);
+
+    /**
+     * Special constant that represents a message that
+     * is not localizable.
+     *
+     * <p>
+     * Use of "new" is to create an unique instance.
+     */
+    String NOT_LOCALIZABLE = "\u0000";
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/localization/LocalizableMessage.java b/istack-commons/runtime/src/main/java/com/sun/istack/localization/LocalizableMessage.java
new file mode 100644
index 0000000..fa44fa1
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/localization/LocalizableMessage.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.localization;
+
+import com.sun.istack.localization.LocalizableMessageFactory.ResourceBundleSupplier;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+
+/**
+ * @author WS Development Team
+ */
+public final class LocalizableMessage implements Localizable {
+
+    private final String _bundlename;
+    private final ResourceBundleSupplier _rbSupplier;
+
+    private final String _key;
+    private final Object[] _args;
+
+    @Deprecated
+    public LocalizableMessage(String bundlename, String key, Object... args) {
+        this(bundlename, null, key, args);
+    }
+
+    public LocalizableMessage(String bundlename, ResourceBundleSupplier rbSupplier,
+                              String key, Object... args) {
+        _bundlename = bundlename;
+        _rbSupplier = rbSupplier;
+        _key = key;
+        if(args==null)
+            args = new Object[0];
+        _args = args;
+    }
+
+    @Override
+    public String getKey() {
+        return _key;
+    }
+
+    @Override
+    public Object[] getArguments() {
+        return Arrays.copyOf(_args, _args.length);
+    }
+
+    @Override
+    public String getResourceBundleName() {
+        return _bundlename;
+    }
+
+    @Override
+    public ResourceBundle getResourceBundle(Locale locale) {
+        if (_rbSupplier == null)
+            return null;
+
+        return _rbSupplier.getResourceBundle(locale);
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/localization/LocalizableMessageFactory.java b/istack-commons/runtime/src/main/java/com/sun/istack/localization/LocalizableMessageFactory.java
new file mode 100644
index 0000000..d40e3ae
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/localization/LocalizableMessageFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.localization;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * @author WS Development Team
+ */
+public class LocalizableMessageFactory {
+
+    private final String _bundlename;
+    private final ResourceBundleSupplier _rbSupplier;
+
+    @Deprecated
+    public LocalizableMessageFactory(String bundlename) {
+        _bundlename = bundlename;
+        _rbSupplier = null;
+    }
+
+    public LocalizableMessageFactory(String bundlename, ResourceBundleSupplier rbSupplier) {
+        _bundlename = bundlename;
+        _rbSupplier = rbSupplier;
+    }
+
+    public Localizable getMessage(String key, Object... args) {
+        return new LocalizableMessage(_bundlename, _rbSupplier, key, args);
+    }
+
+    public interface ResourceBundleSupplier {
+        /**
+         * Gets the ResourceBundle.
+         * @param locale the requested bundle's locale
+         * @return ResourceBundle
+         */
+        ResourceBundle getResourceBundle(Locale locale);
+    }
+
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/localization/Localizer.java b/istack-commons/runtime/src/main/java/com/sun/istack/localization/Localizer.java
new file mode 100644
index 0000000..07b1edf
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/localization/Localizer.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.localization;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Localizes the {@link Localizable} into a message
+ * by using a configured {@link Locale}.
+ *
+ * @author WS Development Team
+ */
+public class Localizer {
+
+    private final Locale _locale;
+    private final HashMap<String, ResourceBundle> _resourceBundles;
+
+    public Localizer() {
+        this(Locale.getDefault());
+    }
+
+    public Localizer(Locale l) {
+        _locale = l;
+        _resourceBundles = new HashMap<>();
+    }
+
+    public Locale getLocale() {
+        return _locale;
+    }
+
+    public String localize(Localizable l) {
+        String key = l.getKey();
+        if (key == Localizable.NOT_LOCALIZABLE) {
+            // this message is not localizable
+            return (String) l.getArguments()[0];
+        }
+
+        String bundlename = l.getResourceBundleName();
+
+        try {
+            ResourceBundle bundle =
+                    _resourceBundles.get(bundlename);
+
+            if (bundle == null) {
+                bundle = l.getResourceBundle(_locale);
+                if (bundle != null) {
+                    _resourceBundles.put(bundlename, bundle);
+                }
+            }
+
+            if (bundle == null) {
+                try {
+                    bundle = ResourceBundle.getBundle(bundlename, _locale);
+                } catch (MissingResourceException e) {
+                    // work around a bug in the com.sun.enterprise.deployment.WebBundleArchivist:
+                    //   all files with an extension different from .class (hence all the .properties files)
+                    //   get copied to the top level directory instead of being in the package where they
+                    //   are defined
+                    // so, since we can't find the bundle under its proper name, we look for it under
+                    //   the top-level package
+
+                    int i = bundlename.lastIndexOf('.');
+                    if (i != -1) {
+                        String alternateBundleName =
+                            bundlename.substring(i + 1);
+                        try {
+                            bundle =
+                                ResourceBundle.getBundle(
+                                    alternateBundleName,
+                                    _locale);
+                        } catch (MissingResourceException e2) {
+                            //try context classloader
+                            try {
+                                bundle = ResourceBundle.getBundle(bundlename, _locale, Thread.currentThread().getContextClassLoader());
+                            } catch (MissingResourceException e3) {
+                                // give up
+                                return getDefaultMessage(l);
+                            }
+
+                        }
+                    }
+                }
+
+                _resourceBundles.put(bundlename, bundle);
+            }
+
+            if (bundle == null) {
+                return getDefaultMessage(l);
+            }
+
+            if (key == null)
+                key = "undefined";
+
+            String msg;
+            try {
+                msg = bundle.getString(key);
+            } catch (MissingResourceException e) {
+                // notice that this may throw a MissingResourceException of its own (caught below)
+                msg = bundle.getString("undefined");
+            }
+
+            // localize all arguments to the given localizable object
+            Object[] args = l.getArguments();
+            for (int i = 0; i < args.length; ++i) {
+                if (args[i] instanceof Localizable)
+                    args[i] = localize((Localizable) args[i]);
+            }
+
+            return MessageFormat.format(msg, args);
+
+        } catch (MissingResourceException e) {
+            return getDefaultMessage(l);
+        }
+
+    }
+
+    private String getDefaultMessage(Localizable l) {
+        String key = l.getKey();
+        Object[] args = l.getArguments();
+        StringBuilder sb = new StringBuilder();
+        sb.append("[failed to localize] ");
+        sb.append(key);
+        if (args != null) {
+            sb.append('(');
+            for (int i = 0; i < args.length; ++i) {
+                if (i != 0)
+                    sb.append(", ");
+                sb.append(String.valueOf(args[i]));
+            }
+            sb.append(')');
+        }
+        return sb.toString();
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/localization/NullLocalizable.java b/istack-commons/runtime/src/main/java/com/sun/istack/localization/NullLocalizable.java
new file mode 100644
index 0000000..01566cc
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/localization/NullLocalizable.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.localization;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * {@link Localizable} that wraps a non-localizable string.
+ *
+ * @author WS Development Team
+ */
+public final class NullLocalizable implements Localizable {
+    private final String msg;
+
+    public NullLocalizable(String msg) {
+        if(msg==null)
+            throw new IllegalArgumentException();
+        this.msg = msg;
+    }
+
+    @Override
+    public String getKey() {
+        return Localizable.NOT_LOCALIZABLE;
+    }
+    @Override
+    public Object[] getArguments() {
+        return new Object[]{msg};
+    }
+    @Override
+    public String getResourceBundleName() {
+        return "";
+    }
+    @Override
+    public ResourceBundle getResourceBundle(Locale locale) {
+        return null;
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/logging/Logger.java b/istack-commons/runtime/src/main/java/com/sun/istack/logging/Logger.java
new file mode 100644
index 0000000..7f4aa3c
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/logging/Logger.java
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.logging;
+
+import com.sun.istack.NotNull;
+
+import java.util.StringTokenizer;
+import java.util.logging.Level;
+
+/**
+ * This is a helper class that provides some convenience methods wrapped around the
+ * standard {@link java.util.logging.Logger} interface.
+ *
+ * The class also makes sure that logger names of each Metro subsystem are consistent
+ * with each other.
+ *
+ * @author Marek Potociar
+ * @author Fabian Ritzmann
+ */
+public class Logger {
+
+    private static final String WS_LOGGING_SUBSYSTEM_NAME_ROOT = "com.sun.metro";
+    private static final String ROOT_WS_PACKAGE = "com.sun.xml.ws.";
+    //
+    private static final Level METHOD_CALL_LEVEL_VALUE = Level.FINEST;
+    //
+    private final String componentClassName;
+    private final java.util.logging.Logger logger;
+
+    /**
+     * Prevents creation of a new instance of this Logger unless used by a subclass.
+     * @param systemLoggerName system logger name
+     * @param componentName component name
+     */
+    protected Logger(final String systemLoggerName, final String componentName) {
+        this.componentClassName = "[" + componentName + "] ";
+        this.logger = java.util.logging.Logger.getLogger(systemLoggerName);
+    }
+
+    /**
+     * <p>
+     * The factory method returns preconfigured Logger wrapper for the class. Method calls
+     * {@link #getSystemLoggerName(java.lang.Class)} to generate default logger name.
+     * </p>
+     * <p>
+     * Since there is no caching implemented, it is advised that the method is called only once
+     * per a class in order to initialize a final static logger variable, which is then used
+     * through the class to perform actual logging tasks.
+     * </p>
+     *
+     * @param componentClass class of the component that will use the logger instance. Must not be {@code null}.
+     * @return logger instance preconfigured for use with the component
+     * @throws NullPointerException if the componentClass parameter is {@code null}.
+     */
+    public static @NotNull Logger getLogger(final @NotNull Class<?> componentClass) {
+        return new Logger(getSystemLoggerName(componentClass), componentClass.getName());
+    }
+
+    /**
+     * The factory method returns preconfigured Logger wrapper for the class. Since there is no caching implemented,
+     * it is advised that the method is called only once per a class in order to initialize a final static logger variable,
+     * which is then used through the class to perform actual logging tasks.
+     *
+     * This method should be only used in a special cases when overriding of a default logger name derived from the
+     * package of the component class is needed. For all common use cases please use {@link #getLogger(java.lang.Class)}
+     * method.
+     *
+     * @param customLoggerName custom name of the logger.
+     * @param componentClass class of the component that will use the logger instance. Must not be {@code null}.
+     * @return logger instance preconfigured for use with the component
+     * @throws NullPointerException if the componentClass parameter is {@code null}.
+     *
+     * @see #getLogger(java.lang.Class)
+     */
+    public static @NotNull Logger getLogger(final @NotNull String customLoggerName, final @NotNull Class<?> componentClass) {
+        return new Logger(customLoggerName, componentClass.getName());
+    }
+
+    /**
+     * Calculates the subsystem suffix based on the package of the component class
+     * @param componentClass class of the component that will use the logger instance. Must not be {@code null}.
+     * @return system logger name for the given {@code componentClass} instance
+     */
+    static final String getSystemLoggerName(@NotNull Class<?> componentClass) {
+        StringBuilder sb = new StringBuilder(componentClass.getPackage().getName());
+        final int lastIndexOfWsPackage = sb.lastIndexOf(ROOT_WS_PACKAGE);
+        if (lastIndexOfWsPackage > -1) {
+            sb.replace(0, lastIndexOfWsPackage + ROOT_WS_PACKAGE.length(), "");
+
+            StringTokenizer st = new StringTokenizer(sb.toString(), ".");
+            sb = new StringBuilder(WS_LOGGING_SUBSYSTEM_NAME_ROOT).append(".");
+            if (st.hasMoreTokens()) {
+                String token = st.nextToken();
+                if ("api".equals(token)) {
+                    token = st.nextToken();
+                }
+                sb.append(token);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    public void log(final Level level, final String message) {
+        if (!this.logger.isLoggable(level)) {
+            return;
+        }
+        logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), message);
+    }
+
+    public void log(final Level level, final String message, Object param1) {
+        if (!this.logger.isLoggable(level)) {
+            return;
+        }
+        logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), message, param1);
+    }
+
+    public void log(final Level level, final String message, Object[] params) {
+        if (!this.logger.isLoggable(level)) {
+            return;
+        }
+        logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), message, params);
+    }
+
+    public void log(final Level level, final String message, final Throwable thrown) {
+        if (!this.logger.isLoggable(level)) {
+            return;
+        }
+        logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), message, thrown);
+    }
+
+    public void finest(final String message) {
+        if (!this.logger.isLoggable(Level.FINEST)) {
+            return;
+        }
+        logger.logp(Level.FINEST, componentClassName, StackHelper.getCallerMethodName(), message);
+    }
+
+    public void finest(final String message, Object[] params) {
+        if (!this.logger.isLoggable(Level.FINEST)) {
+            return;
+        }
+        logger.logp(Level.FINEST, componentClassName, StackHelper.getCallerMethodName(), message, params);
+    }
+    
+    public void finest(final String message, final Throwable thrown) {
+        if (!this.logger.isLoggable(Level.FINEST)) {
+            return;
+        }
+        logger.logp(Level.FINEST, componentClassName, StackHelper.getCallerMethodName(), message, thrown);
+    }
+
+    public void finer(final String message) {
+        if (!this.logger.isLoggable(Level.FINER)) {
+            return;
+        }
+        logger.logp(Level.FINER, componentClassName, StackHelper.getCallerMethodName(), message);
+    }
+
+    public void finer(final String message, Object[] params) {
+        if (!this.logger.isLoggable(Level.FINER)) {
+            return;
+        }
+        logger.logp(Level.FINER, componentClassName, StackHelper.getCallerMethodName(), message, params);
+    }
+
+    public void finer(final String message, final Throwable thrown) {
+        if (!this.logger.isLoggable(Level.FINER)) {
+            return;
+        }
+        logger.logp(Level.FINER, componentClassName, StackHelper.getCallerMethodName(), message, thrown);
+    }
+
+    public void fine(final String message) {
+        if (!this.logger.isLoggable(Level.FINE)) {
+            return;
+        }
+        logger.logp(Level.FINE, componentClassName, StackHelper.getCallerMethodName(), message);
+    }
+
+    public void fine(final String message, final Throwable thrown) {
+        if (!this.logger.isLoggable(Level.FINE)) {
+            return;
+        }
+        logger.logp(Level.FINE, componentClassName, StackHelper.getCallerMethodName(), message, thrown);
+    }
+
+    public void info(final String message) {
+        if (!this.logger.isLoggable(Level.INFO)) {
+            return;
+        }
+        logger.logp(Level.INFO, componentClassName, StackHelper.getCallerMethodName(), message);
+    }
+
+    public void info(final String message, Object[] params) {
+        if (!this.logger.isLoggable(Level.INFO)) {
+            return;
+        }
+        logger.logp(Level.INFO, componentClassName, StackHelper.getCallerMethodName(), message, params);
+    }
+
+    public void info(final String message, final Throwable thrown) {
+        if (!this.logger.isLoggable(Level.INFO)) {
+            return;
+        }
+        logger.logp(Level.INFO, componentClassName, StackHelper.getCallerMethodName(), message, thrown);
+    }
+
+    public void config(final String message) {
+        if (!this.logger.isLoggable(Level.CONFIG)) {
+            return;
+        }
+        logger.logp(Level.CONFIG, componentClassName, StackHelper.getCallerMethodName(), message);
+    }
+
+    public void config(final String message, Object[] params) {
+        if (!this.logger.isLoggable(Level.CONFIG)) {
+            return;
+        }
+        logger.logp(Level.CONFIG, componentClassName, StackHelper.getCallerMethodName(), message, params);
+    }
+
+    public void config(final String message, final Throwable thrown) {
+        if (!this.logger.isLoggable(Level.CONFIG)) {
+            return;
+        }
+        logger.logp(Level.CONFIG, componentClassName, StackHelper.getCallerMethodName(), message, thrown);
+    }
+
+    public void warning(final String message) {
+        if (!this.logger.isLoggable(Level.WARNING)) {
+            return;
+        }
+        logger.logp(Level.WARNING, componentClassName, StackHelper.getCallerMethodName(), message);
+    }
+
+    public void warning(final String message, Object[] params) {
+        if (!this.logger.isLoggable(Level.WARNING)) {
+            return;
+        }
+        logger.logp(Level.WARNING, componentClassName, StackHelper.getCallerMethodName(), message, params);
+    }
+
+    public void warning(final String message, final Throwable thrown) {
+        if (!this.logger.isLoggable(Level.WARNING)) {
+            return;
+        }
+        logger.logp(Level.WARNING, componentClassName, StackHelper.getCallerMethodName(), message, thrown);
+    }
+
+    public void severe(final String message) {
+        if (!this.logger.isLoggable(Level.SEVERE)) {
+            return;
+        }
+        logger.logp(Level.SEVERE, componentClassName, StackHelper.getCallerMethodName(), message);
+    }
+
+    public void severe(final String message, Object[] params) {
+        if (!this.logger.isLoggable(Level.SEVERE)) {
+            return;
+        }
+        logger.logp(Level.SEVERE, componentClassName, StackHelper.getCallerMethodName(), message, params);
+    }
+
+    public void severe(final String message, final Throwable thrown) {
+        if (!this.logger.isLoggable(Level.SEVERE)) {
+            return;
+        }
+        logger.logp(Level.SEVERE, componentClassName, StackHelper.getCallerMethodName(), message, thrown);
+    }
+
+    public boolean isMethodCallLoggable() {
+        return this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE);
+    }
+
+    public boolean isLoggable(final Level level) {
+        return this.logger.isLoggable(level);
+    }
+
+    public void setLevel(final Level level) {
+        this.logger.setLevel(level);
+    }
+
+    public void entering() {
+        if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) {
+            return;
+        }
+
+        logger.entering(componentClassName, StackHelper.getCallerMethodName());
+    }
+
+    public void entering(final Object... parameters) {
+        if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) {
+            return;
+        }
+
+        logger.entering(componentClassName, StackHelper.getCallerMethodName(), parameters);
+    }
+
+    public void exiting() {
+        if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) {
+            return;
+        }
+        logger.exiting(componentClassName, StackHelper.getCallerMethodName());
+    }
+
+    public void exiting(final Object result) {
+        if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) {
+            return;
+        }
+        logger.exiting(componentClassName, StackHelper.getCallerMethodName(), result);
+    }
+
+    /**
+     * Method logs {@code exception}'s message as a {@code SEVERE} logging level
+     * message.
+     * <p>
+     * If {@code cause} parameter is not {@code null}, it is logged as well and
+     * {@code exception} original cause is initialized with instance referenced
+     * by {@code cause} parameter.
+     *
+     * @param <T> type
+     * @param exception exception whose message should be logged. Must not be
+     *        {@code null}.
+     * @param cause initial cause of the exception that should be logged as well
+     *        and set as {@code exception}'s original cause. May be {@code null}.
+     * @return the same exception instance that was passed in as the {@code exception}
+     *         parameter.
+     */
+    public <T extends Throwable> T logSevereException(final T exception, final Throwable cause) {
+        if (this.logger.isLoggable(Level.SEVERE)) {
+            if (cause == null) {
+                logger.logp(Level.SEVERE, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage());
+            } else {
+                exception.initCause(cause);
+                logger.logp(Level.SEVERE, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage(), cause);
+            }
+        }
+
+        return exception;
+    }
+
+    /**
+     * Method logs {@code exception}'s message as a {@code SEVERE} logging level
+     * message.
+     * <p>
+     * If {@code logCause} parameter is {@code true}, {@code exception}'s original
+     * cause is logged as well (if exists). This may be used in cases when
+     * {@code exception}'s class provides constructor to initialize the original
+     * cause. In such case you do not need to use
+     * {@link #logSevereException(Throwable, Throwable)}
+     * method version but you might still want to log the original cause as well.
+     *
+     * @param <T> type
+     * @param exception exception whose message should be logged. Must not be
+     *        {@code null}.
+     * @param logCause deterimnes whether initial cause of the exception should
+     *        be logged as well
+     * @return the same exception instance that was passed in as the {@code exception}
+     *         parameter.
+     */
+    public <T extends Throwable> T logSevereException(final T exception, final boolean logCause) {
+        if (this.logger.isLoggable(Level.SEVERE)) {
+            if (logCause && exception.getCause() != null) {
+                logger.logp(Level.SEVERE, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage(), exception.getCause());
+            } else {
+                logger.logp(Level.SEVERE, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage());
+            }
+        }
+
+        return exception;
+    }
+
+    /**
+     * Same as {@link #logSevereException(Throwable, boolean) logSevereException(exception, true)}.
+     * @param <T> type
+     * @param exception exception whose message should be logged. Must not be
+     *        {@code null}.
+     * @return the same exception instance that was passed in as the {@code exception}
+     *         parameter.
+     */
+    public <T extends Throwable> T logSevereException(final T exception) {
+        if (this.logger.isLoggable(Level.SEVERE)) {
+            if (exception.getCause() == null) {
+                logger.logp(Level.SEVERE, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage());
+            } else {
+                logger.logp(Level.SEVERE, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage(), exception.getCause());
+            }
+        }
+
+        return exception;
+    }
+
+    /**
+     * Method logs {@code exception}'s message at the logging level specified by the
+     * {@code level} argument.
+     * <p>
+     * If {@code cause} parameter is not {@code null}, it is logged as well and
+     * {@code exception} original cause is initialized with instance referenced
+     * by {@code cause} parameter.
+     *
+     * @param <T> type
+     * @param exception exception whose message should be logged. Must not be
+     *        {@code null}.
+     * @param cause initial cause of the exception that should be logged as well
+     *        and set as {@code exception}'s original cause. May be {@code null}.
+     * @param level loging level which should be used for logging
+     * @return the same exception instance that was passed in as the {@code exception}
+     *         parameter.
+     */
+    public <T extends Throwable> T logException(final T exception, final Throwable cause, final Level level) {
+        if (this.logger.isLoggable(level)) {
+            if (cause == null) {
+                logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage());
+            } else {
+                exception.initCause(cause);
+                logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage(), cause);
+            }
+        }
+
+        return exception;
+    }
+
+    /**
+     * Method logs {@code exception}'s message at the logging level specified by the
+     * {@code level} argument.
+     * <p>
+     * If {@code logCause} parameter is {@code true}, {@code exception}'s original
+     * cause is logged as well (if exists). This may be used in cases when
+     * {@code exception}'s class provides constructor to initialize the original
+     * cause. In such case you do not need to use
+     * {@link #logException(Throwable, Throwable, Level) logException(exception, cause, level)}
+     * method version but you might still want to log the original cause as well.
+     *
+     * @param <T> type
+     * @param exception exception whose message should be logged. Must not be
+     *        {@code null}.
+     * @param logCause deterimnes whether initial cause of the exception should
+     *        be logged as well
+     * @param level loging level which should be used for logging
+     * @return the same exception instance that was passed in as the {@code exception}
+     *         parameter.
+     */
+    public <T extends Throwable> T logException(final T exception, final boolean logCause, final Level level) {
+        if (this.logger.isLoggable(level)) {
+            if (logCause && exception.getCause() != null) {
+                logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage(), exception.getCause());
+            } else {
+                logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage());
+            }
+        }
+
+        return exception;
+    }
+
+    /**
+     * Same as {@link #logException(Throwable, Throwable, Level)
+     * logException(exception, true, level)}.
+     * @param <T> type
+     * @param exception exception whose message should be logged. Must not be
+     *        {@code null}.
+     * @param level loging level which should be used for logging
+     * @return the same exception instance that was passed in as the {@code exception}
+     *         parameter.
+     */
+    public <T extends Throwable> T logException(final T exception, final Level level) {
+        if (this.logger.isLoggable(level)) {
+            if (exception.getCause() == null) {
+                logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage());
+            } else {
+                logger.logp(level, componentClassName, StackHelper.getCallerMethodName(), exception.getMessage(), exception.getCause());
+            }
+        }
+
+        return exception;
+    }
+
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/logging/StackHelper.java b/istack-commons/runtime/src/main/java/com/sun/istack/logging/StackHelper.java
new file mode 100644
index 0000000..580bfb9
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/logging/StackHelper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.logging;
+
+/**
+ * Utils for stack trace analysis
+ *
+ * @author Daniel Kec
+ */
+class StackHelper {
+
+    /**
+     * Function returns the name of the caller method for the method executing this
+     * function.
+     *
+     * @return caller method name from the call stack of the current {@link Thread}.
+     */
+    static String getCallerMethodName() {
+        return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
+                .walk(frames -> frames
+                        //Its a method of first declaring class after istack Logger class
+                        .dropWhile(f -> !Logger.class.equals(f.getDeclaringClass()))
+                        .dropWhile(f -> Logger.class.equals(f.getDeclaringClass()))
+                        .findFirst()
+                        .map(StackWalker.StackFrame::getMethodName)
+                        .orElse("UNKNOWN METHOD"));
+    }
+}
diff --git a/istack-commons/runtime/src/main/java/com/sun/istack/package-info.java b/istack-commons/runtime/src/main/java/com/sun/istack/package-info.java
new file mode 100644
index 0000000..3177984
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/com/sun/istack/package-info.java
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * istack-commons runtime utilities.
+ */
+package com.sun.istack;
diff --git a/istack-commons/runtime/src/main/java/module-info.java b/istack-commons/runtime/src/main/java/module-info.java
new file mode 100644
index 0000000..5eff19d
--- /dev/null
+++ b/istack-commons/runtime/src/main/java/module-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * istack-commons runtime utilities.
+ */
+module com.sun.istack.runtime {
+    requires transitive java.logging;
+    requires transitive java.xml;
+    requires static transitive jakarta.activation;
+
+    exports com.sun.istack;
+    exports com.sun.istack.localization;
+    exports com.sun.istack.logging;
+}
diff --git a/istack-commons/runtime/src/test/java/com/sun/istack/logging/LoggerTest.java b/istack-commons/runtime/src/test/java/com/sun/istack/logging/LoggerTest.java
new file mode 100644
index 0000000..15e0085
--- /dev/null
+++ b/istack-commons/runtime/src/test/java/com/sun/istack/logging/LoggerTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.logging;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.logging.Formatter;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.StreamHandler;
+
+/**
+ *
+ * @author Marek Potociar
+ */
+public class LoggerTest {
+
+    public LoggerTest() {
+    }
+
+    /**
+     * Test of getLogger method, of class Logger.
+     */
+    @Test
+    public void testGetLogger() {
+        Logger result = Logger.getLogger(LoggerTest.class);
+        Assert.assertNotNull(result);
+    }
+
+    /**
+     * Test of getSystemLoggerName method, of class Logger.
+     */
+    @Test
+    public void testGetSubsystemName() {
+        String result = Logger.getSystemLoggerName(LoggerTest.class);
+        Assert.assertEquals("com.sun.istack.logging", result);
+    }
+
+    /**
+     * Test source method name resolution
+     */
+    @Test
+    public void testGetCallerMethodName() {
+        Logger istackLogger = Logger.getLogger(LoggerTest.class);
+        java.util.logging.Logger utilLogger =
+                java.util.logging.Logger.getLogger(Logger.getSystemLoggerName(LoggerTest.class));
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        StreamHandler streamHandler = new StreamHandler(outputStream, new Formatter() {
+            @Override
+            public String format(LogRecord record) {
+                return record.getSourceMethodName();
+            }
+        });
+        utilLogger.addHandler(streamHandler);
+
+        istackLogger.logException(new Exception("This LOG entry is part of the test"), Level.INFO);
+
+        streamHandler.flush();
+
+        String logText = outputStream.toString(StandardCharsets.UTF_8);
+        Assert.assertEquals("testGetCallerMethodName", logText);
+    }
+
+}
diff --git a/istack-commons/soimp/pom.xml b/istack-commons/soimp/pom.xml
new file mode 100644
index 0000000..3c2ca00
--- /dev/null
+++ b/istack-commons/soimp/pom.xml
@@ -0,0 +1,36 @@
+<!--
+
+    Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.sun.istack</groupId>
+        <artifactId>istack-commons</artifactId>
+        <version>4.2.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>istack-commons-soimp</artifactId>
+
+    <name>istack common utility code soimp</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>args4j</groupId>
+            <artifactId>args4j</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Listener.java b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Listener.java
new file mode 100644
index 0000000..d9e19f3
--- /dev/null
+++ b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Listener.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.soimp;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+public interface Listener {
+    void info(String line);
+
+    Listener CONSOLE = new Listener() {
+        @Override
+        public void info(String line) {
+            System.out.println(line);
+        }
+    };
+}
diff --git a/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Mode.java b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Mode.java
new file mode 100644
index 0000000..3c6cd3b
--- /dev/null
+++ b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Mode.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.soimp;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+enum Mode {
+    NEW, DELETED, UPDATED;
+
+    static Mode parse(char ch) {
+        switch(ch) {
+        case 'M':
+            return UPDATED;
+        case '!':
+            return DELETED;
+        case '?':
+            return NEW;
+        }
+        return null;
+    }
+}
diff --git a/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Proc.java b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Proc.java
new file mode 100644
index 0000000..fa54cd3
--- /dev/null
+++ b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Proc.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.soimp;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class Proc {
+    private final Process proc;
+    private final Thread t1,t2;
+
+    public Proc(String cmd,String[] env,OutputStream out, File workDir) throws IOException {
+        this( Runtime.getRuntime().exec(new String [] {cmd},env,workDir), null, out );
+    }
+
+    public Proc(String[] cmd,String[] env,OutputStream out, File workDir) throws IOException {
+        this( Runtime.getRuntime().exec(cmd,env,workDir), null, out );
+    }
+
+    public Proc(String[] cmd,String[] env,InputStream in,OutputStream out) throws IOException {
+        this( Runtime.getRuntime().exec(cmd,env), in, out );
+    }
+
+    private Proc( Process proc, InputStream in, OutputStream out ) throws IOException {
+        this.proc = proc;
+        t1 = new Copier(proc.getInputStream(), out);
+        t1.start();
+        t2 = new Copier(proc.getErrorStream(), out);
+        t2.start();
+        if(in!=null)
+            new ByteCopier(in,proc.getOutputStream()).start();
+        else
+            proc.getOutputStream().close();
+    }
+
+    public int join() {
+        try {
+            t1.join();
+            t2.join();
+            return proc.waitFor();
+        } catch (InterruptedException e) {
+            // aborting. kill the process
+            proc.destroy();
+            return -1;
+        }
+    }
+
+    private static class Copier extends Thread {
+        private final InputStream in;
+        private final OutputStream out;
+
+        public Copier(InputStream in, OutputStream out) {
+            this.in = in;
+            this.out = out;
+        }
+
+        @Override
+        public void run() {
+            try {
+                copyStream(in,out);
+                in.close();
+            } catch (IOException e) {
+                // TODO: what to do?
+            }
+        }
+    }
+
+    private static class ByteCopier extends Thread {
+        private final InputStream in;
+        private final OutputStream out;
+
+        public ByteCopier(InputStream in, OutputStream out) {
+            this.in = in;
+            this.out = out;
+        }
+
+        @Override
+        public void run() {
+            try {
+                while(true) {
+                    int ch = in.read();
+                    if(ch==-1)  break;
+                    out.write(ch);
+                }
+                in.close();
+                out.close();
+            } catch (IOException e) {
+                // TODO: what to do?
+            }
+        }
+    }
+
+    public static void copyStream(InputStream in,OutputStream out) throws IOException {
+        byte[] buf = new byte[256];
+        int len;
+        while((len=in.read(buf))>0)
+            out.write(buf,0,len);
+    }
+}
diff --git a/istack-commons/soimp/src/main/java/com/sun/istack/soimp/ProcessingException.java b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/ProcessingException.java
new file mode 100644
index 0000000..4bee1a6
--- /dev/null
+++ b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/ProcessingException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.soimp;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+public class ProcessingException extends Exception {
+
+    private static final long serialVersionUID = -6214429602282488762L;
+
+    public ProcessingException(String message) {
+        super(message);
+    }
+
+    public ProcessingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Soimp.java b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Soimp.java
new file mode 100644
index 0000000..8c08cf1
--- /dev/null
+++ b/istack-commons/soimp/src/main/java/com/sun/istack/soimp/Soimp.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.soimp;
+
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.Option;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.taskdefs.Copy;
+import org.apache.tools.ant.taskdefs.Delete;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Subversion overwriting import tool.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class Soimp extends Task {
+
+    public static void main(String[] args) throws IOException, ProcessingException {
+        System.exit(new Soimp().runCLI(args));
+    }
+
+    // either this, or ...
+    @Argument
+    List<String> pathArgs = new ArrayList<>();
+    // these (for Ant)
+    private File wsDir;
+    private String remoteURL;
+
+    @Option(name = "-x", usage="specifies the svn command executable to run")
+    String svn = "svn";
+
+    @Option(name="-m", usage="specifies the commit message")
+    String commitMessage = "imported by soimp";
+
+    @Option(name="-p", usage="create the repository by 'svn mkdir' if necessary")
+    boolean create = false;
+
+    @Option(name="-u", usage="specify a username")
+    String username = null;
+
+    @Option(name="-P", usage="specify a password")
+    String password = null;
+
+    @Option(name="-o", usage="provide additional options for 'svn' command")
+    String additionalOptions = null;
+
+    private Listener listener = Listener.CONSOLE;
+
+    public void setSvn(String svn) {
+        this.svn = svn;
+    }
+
+    public void setCommitMessage(String commitMessage) {
+        this.commitMessage = commitMessage;
+    }
+
+    public void setCreate(boolean create) {
+        this.create = create;
+    }
+
+    public void setUsername(String userName) {
+        this.username = userName;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public void setDir(File dir) {
+        wsDir = dir;
+    }
+
+    public void setRepository(String repository) {
+        this.remoteURL = repository;
+    }
+
+    public void setAdditionalOptions(String additionalOptions) {
+        this.additionalOptions = additionalOptions;
+    }
+
+    /**
+     * Command line tool entry point.
+     *
+     * @return
+     *      0 if success. Non-zero if failed.
+     * @throws IOException for errors
+     * @throws ProcessingException for errors
+     */
+    public int runCLI(String[] args) throws IOException, ProcessingException {
+        CmdLineParser p = new CmdLineParser(this);
+        try {
+            p.parseArgument(args);
+        } catch (CmdLineException e) {
+            System.err.println(e.getMessage());
+            printUsage(p);
+            return -1;
+        }
+
+        if(pathArgs.size()>2 || pathArgs.isEmpty()) {
+            printUsage(p);
+            return -1;
+        }
+
+        File src = new File(pathArgs.get(0));
+        if(!src.exists()) {
+            System.err.println("No such directory "+src);
+            return -1;
+        }
+
+        if(pathArgs.size()==1) {
+            // just one argument. simply update the state of the existing workspace
+            svnUpdate(src);
+        } else {
+            // two arguments
+            // checkout -> copy -> import -> commit
+            svnImport(src,pathArgs.get(1));
+        }
+
+        return 0;
+    }
+
+    /**
+     * Ant entry point.
+     */
+    @Override
+    public void execute() throws BuildException {
+        String svnExe = getProject().getProperty("svn.executable");
+        if(svnExe!=null)
+            svn = svnExe;
+
+        listener = new Listener() {
+            @Override
+            public void info(String line) {
+                log(line,Project.MSG_INFO);
+            }
+        };
+        if(wsDir==null)
+            throw new BuildException("Required @dir is missing");
+        if(!wsDir.exists())
+            throw new BuildException("No such directory "+wsDir);
+
+        try {
+            if(remoteURL==null)
+                svnUpdate(wsDir);
+            else
+                svnImport(wsDir,remoteURL);
+        } catch (ProcessingException | IOException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    private void svnImport(File src, String repository) throws IOException, ProcessingException {
+        File tmp = File.createTempFile("soimp","tmp");
+        boolean deleted = tmp.delete();
+        if (!deleted) {
+            Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Cannot delete file: {0}", tmp);
+        }
+        boolean created = tmp.mkdir();
+        if (!created) {
+            Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Cannot create directory: {0}", tmp);
+        }
+        listener.info("Using "+tmp);
+
+        Project p = new Project(); // dummy ant projcet
+
+        try {
+            // check if the directory exists
+            if(create)
+                createRepository(new URL(repository));
+
+            // check out to tmp
+            exec(buildSvnWithUsername("co "+repository+" ."),tmp,"failed to check out");
+
+            FileSet fs = new FileSet();
+            fs.setProject(p);
+            fs.setDir(src);
+
+            // copy all files from src -> tmp
+            Copy cpTask = new Copy();
+            cpTask.setProject(p);
+            cpTask.setOverwrite(true);
+            cpTask.setTodir(tmp);
+            cpTask.addFileset(fs);
+            cpTask.execute();
+
+            // update
+            svnUpdate(tmp);
+
+            // then commit
+            exec(buildSvnWithUsername("commit -m \""+commitMessage+"\""),tmp,"Failed to commit");
+        } finally{
+            // clean up
+            Delete delTask = new Delete();
+            delTask.setProject(p);
+            delTask.setDir(tmp);
+            delTask.execute();
+        }
+    }
+
+    /**
+     * Creates directories in the repository if necessary
+     */
+    private void createRepository(URL repository) throws IOException, ProcessingException {
+        if(repository.getPath().equals("/"))
+            throw new ProcessingException("Illegal repository name");
+        try {
+            exec(buildSvnWithUsername("proplist "+repository),new File("."),"N/A");
+        } catch (ProcessingException e) {
+            // directory doesn't exist
+            URL parent;
+            if(repository.getPath().endsWith("/"))
+                parent = new URL(repository, "..");
+            else
+                parent = new URL(repository, ".");
+            createRepository(parent);
+
+            listener.info(repository+" doesn't exist. creating");
+            exec(buildSvnWithUsername("mkdir -m \""+commitMessage+"\" "+repository),new File("."),"Failed to create directory");
+        }
+    }
+
+    private void printUsage(CmdLineParser p) {
+        System.err.println("Usage: soimp [options ...] <PATH> <URL>");
+        System.err.println("Works like 'svn import PATH URL', but overwrites remote files by local files.");
+        p.printUsage(System.err);
+    }
+
+    public void svnUpdate( File ws ) throws ProcessingException, IOException {
+
+        String log = exec(buildSvnWithUsername("status"), ws, "Failed to stat the workspace");
+
+        List<String> newFiles = new ArrayList<>();
+        List<String> deletedFiles = new ArrayList<>();
+        // % svn status
+        // ?      xyz
+        // M      abc
+        // !      def
+        BufferedReader in = new BufferedReader(new StringReader(log));
+        String line;
+        while((line=in.readLine())!=null) {
+            Mode m = Mode.parse(line.charAt(0));
+            String file = line.substring(1).trim();
+            if(m==null)     continue;
+
+            switch(m) {
+            case NEW:
+                newFiles.add(file);
+                break;
+            case DELETED:
+                deletedFiles.add(file);
+                break;
+            default:
+                break;
+            }
+        }
+
+        // update accordingly
+        runSvnBatch("add",ws,newFiles);
+        runSvnBatch("remove",ws,deletedFiles);
+    }
+
+    /**
+     * Run svn command in a batch.
+     */
+    private void runSvnBatch(String subCmd, File ws, List<String> files) throws IOException, ProcessingException {
+        while(!files.isEmpty()) {
+            // build up command line
+            StringBuilder cmd = new StringBuilder(buildSvnCommand(subCmd));
+            for( int i=0; i<20 && !files.isEmpty(); i++ ) {
+                cmd.append(' ').append(files.remove(0));
+            }
+
+            exec(cmd.toString(),ws,"Failed to "+subCmd);
+        }
+    }
+
+    /**
+     * Concatenate svn executable name with svn global options (username/password)
+     * and the svn command.
+     *
+     * @param subCmd The svn command
+     * @return The complete executable command
+     */
+    private String buildSvnWithUsername(final String subCmd) {
+        final StringBuilder command = new StringBuilder();
+        if (username != null) {
+            command.append("--username ").append(username).append(' ');
+        }
+        if (password != null) {
+            command.append("--password ").append(password).append(' ');
+        }
+        command.append(subCmd);
+        return buildSvnCommand(command.toString());
+    }
+
+    /**
+     * Concatenate svn executable name with the svn command.
+     *
+     * @param subCmd The svn command
+     * @return The complete executable command
+     */
+    private String buildSvnCommand(final String subCmd) {
+        final StringBuilder command = new StringBuilder(svn + ' ');
+        addAdditionalOptionsToCommand(command);
+        command.append(subCmd);
+        return command.toString();
+    }
+
+    private void addAdditionalOptionsToCommand(final StringBuilder command) {
+        if (additionalOptions != null) {
+            command.append(additionalOptions);
+            command.append(' ');
+        }
+    }
+
+    /**
+     * Executes subversion and returns its output.
+     */
+    private String exec(String cmd, File ws, String errorMessage) throws IOException, ProcessingException {
+        listener.info("Executing: "+cmd);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        int r = new Proc(cmd, null, baos, ws).join();
+        if(r!=0) {
+            listener.info(baos.toString());
+            throw new ProcessingException(errorMessage);
+        }
+        return baos.toString();
+    }
+
+}
diff --git a/istack-commons/src/main/assembly/resources.xml b/istack-commons/src/main/assembly/resources.xml
new file mode 100644
index 0000000..ecc103e
--- /dev/null
+++ b/istack-commons/src/main/assembly/resources.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
+    <id>resources</id>
+    <formats>
+        <format>zip</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+    <fileSets>
+        <fileSet>
+            <directory>${project.basedir}/..</directory>
+            <outputDirectory>legal</outputDirectory>
+            <includes>
+                <include>LICENSE.md</include>
+                <include>NOTICE.md</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>${project.basedir}/src/main/resources</directory>
+            <outputDirectory>config</outputDirectory>
+            <includes>
+                <include>*</include>
+            </includes>
+        </fileSet>
+    </fileSets>
+</assembly>
\ No newline at end of file
diff --git a/istack-commons/src/main/resources/copyright-exclude b/istack-commons/src/main/resources/copyright-exclude
new file mode 100644
index 0000000..d9610f8
--- /dev/null
+++ b/istack-commons/src/main/resources/copyright-exclude
@@ -0,0 +1,37 @@
+/MANIFEST.MF
+/META-INF/services/
+/README
+.gif
+.jpg
+.jpeg
+.jpeg1
+.jpeg2
+.png
+.svg
+.tif
+.exe
+.ico
+.jar
+.zip
+.war
+.sql
+.jks
+.json
+.class
+.bin
+.iml
+.ipr
+.envelope
+.txt
+.bat
+.sh
+/copyright-exclude
+/LICENSE
+/copyright.txt
+.commented
+/.auth
+.svnignore
+.svn
+www
+site
+.resource
diff --git a/istack-commons/src/main/resources/spotbugs-exclude.xml b/istack-commons/src/main/resources/spotbugs-exclude.xml
new file mode 100644
index 0000000..5885564
--- /dev/null
+++ b/istack-commons/src/main/resources/spotbugs-exclude.xml
@@ -0,0 +1,49 @@
+<!--
+
+    Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<FindBugsFilter>
+    <!--
+    As designed
+    -->
+    <Match>
+        <Or>
+            <Class name="com.sun.istack.maven.ResourceGenMojo$LicenseCodeWriter"/>
+            <Class name="com.sun.istack.build.ResourceGenTask$LicenseCodeWriter"/>
+        </Or>
+        <Bug pattern="OS_OPEN_STREAM"/>
+    </Match>
+    
+    <!--
+    As designed - performance
+    -->
+    <Match>
+        <Class name="com.sun.istack.localization.Localizer"/>
+        <Bug pattern="ES_COMPARING_STRINGS_WITH_EQ"/>
+    </Match>
+    
+    <!--
+    Safer for any code changes
+    -->
+    <Match>
+        <Class name="com.sun.istack.tools.ParallelWorldClassLoader"/>
+        <Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/>
+    </Match>
+    
+    <!--
+    Code generated by maven - ignore
+    -->
+    <Match>
+        <Class name="com.sun.istack.maven.HelpMojo"/>
+        <Bug pattern="UI_INHERITANCE_UNSAFE_GETRESOURCE"/>
+    </Match>
+    
+</FindBugsFilter>
diff --git a/istack-commons/test/pom.xml b/istack-commons/test/pom.xml
new file mode 100644
index 0000000..0793e0c
--- /dev/null
+++ b/istack-commons/test/pom.xml
@@ -0,0 +1,77 @@
+<!--
+
+    Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.sun.istack</groupId>
+        <artifactId>istack-commons</artifactId>
+        <version>4.2.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>istack-commons-test</artifactId>
+
+    <name>istack common utility code test</name>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>default-compile</id>
+                        <configuration>
+                            <compilerArgs>
+                                <arg>--add-reads</arg>
+                                <arg>com.sun.istack.test=ALL-UNNAMED</arg>
+                            </compilerArgs>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <additionalJOptions>
+                        <additionalJOption>--add-reads</additionalJOption>
+                        <additionalJOption>com.sun.istack.test=ALL-UNNAMED</additionalJOption>
+                    </additionalJOptions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant-junit</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/istack-commons/test/src/main/java/com/sun/istack/test/AntXmlFormatter.java b/istack-commons/test/src/main/java/com/sun/istack/test/AntXmlFormatter.java
new file mode 100644
index 0000000..da9c68c
--- /dev/null
+++ b/istack-commons/test/src/main/java/com/sun/istack/test/AntXmlFormatter.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.test;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestListener;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitVersionHelper;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * {@link TestListener} that bridges to {@link JUnitResultFormatter}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class AntXmlFormatter implements TestListener,Closeable {
+    private JUnitResultFormatter antf;
+    private JUnitTest antTest; // Ant wants this
+    private final Class<? extends JUnitResultFormatter> formatter;
+    private long startTime;
+
+    private final File dir;
+
+    FileOutputStream outStream = null;
+            
+    /**
+     * Stdout, stderr that were replaced. Kept so that we can restore them in {@link #close()}.
+     */
+    private final PrintStream out,err;
+
+    private final ByteArrayOutputStream outBuf = new ByteArrayOutputStream();
+    private final ByteArrayOutputStream errBuf = new ByteArrayOutputStream();
+
+    private int id = 0;
+
+    public AntXmlFormatter(Class<? extends JUnitResultFormatter> formatter, File dir) {
+        this.formatter = formatter;
+        this.dir = dir;
+
+        out = System.out;
+        err = System.err;
+        System.setOut(new PrintStream(new ForkOutputStream(outBuf,out)));
+        System.setErr(new PrintStream(new ForkOutputStream(errBuf,err)));
+    }
+
+    @Override
+    public void close() {
+        // restore
+        System.setOut(out);
+        System.setErr(err);
+    }
+
+    public void addError(Test test, Throwable t) {
+        antf.addError(test,t);
+        antTest.setCounts(1,0,1);
+    }
+
+    public void addFailure(Test test, AssertionFailedError t) {
+        antf.addFailure(test,t);
+        antTest.setCounts(1,1,0);
+    }
+
+    public void startTest(Test test) {
+        assert antf==null;
+        try {
+            antf = formatter.getConstructor().newInstance();
+        } catch (IllegalAccessException e) {
+            throw new IllegalAccessError(e.getMessage());
+        } catch (ReflectiveOperationException e) {
+            throw new InstantiationError(e.getMessage());
+        }
+
+        String testName = getTestName(test);
+
+        antTest = new JUnitTest(testName);
+        antTest.setCounts(1,0,0);
+        try {
+            outStream = new FileOutputStream(new File(dir,getResultFileName(testName)));
+            antf.setOutput(outStream);
+        } catch (FileNotFoundException e) {
+            throw new Error(e);
+        }
+        antf.startTestSuite(antTest);
+        antf.startTest(test);
+        outBuf.reset();
+        errBuf.reset();
+        startTime = System.currentTimeMillis();
+    }
+
+    private String getTestName(Test test) {
+        String testName = JUnitVersionHelper.getTestCaseName(test);
+        if(testName==null)      testName="unknown";
+
+        // if you extend from junit.framework.TestCase where you have public testXXX methods,
+        // those test names are just the method name, and doesn't include the package name.
+        // this doesn't work well with our harness, which uses the fully-qualified name as the
+        // test names. To bridge this gap, detect the plain TestCase classes and fix up
+        // the package name.
+        if(testName.indexOf('.')==-1)
+            testName = test.getClass().getPackage().getName()+"."+testName;
+
+        return testName;
+    }
+
+    private String getResultFileName(String testName) {
+        // try to use a test name.
+        StringBuilder sb = new StringBuilder(testName);
+        if(sb.length()>70)
+            sb.delete(0,sb.length()-70);   // remove any portion longer than 70 to avoid file names that are too long
+
+        for(int i=0; i<sb.length(); i++ ) {
+            char ch = sb.charAt(i);
+            if(!inRange(ch,'0','9') && !inRange(ch,'a','z') && !inRange(ch,'A','Z') && ch!='.')
+                sb.setCharAt(i,'_');
+        }
+        sb.append('.');
+        sb.append(id++);
+        sb.append(".xml");
+        return sb.toString();
+    }
+
+    private static boolean inRange(char ch, char start, char end) {
+        return start<=ch && ch<=end;
+    }
+
+    public void endTest(Test test) {
+        antf.endTest(test);
+
+        antf.setSystemOutput(outBuf.toString());
+        antf.setSystemError(errBuf.toString());
+        antTest.setRunTime(System.currentTimeMillis()-startTime);
+        antf.endTestSuite(antTest);
+
+        if (out != null) {
+            try {
+                outStream.close();
+            } catch (IOException ex) {
+                Logger.getLogger(AntXmlFormatter.class.getName()).log(Level.SEVERE, null, ex);
+            }
+        }
+        antf = null;
+        antTest = null;
+    }
+
+}
diff --git a/istack-commons/test/src/main/java/com/sun/istack/test/ForkOutputStream.java b/istack-commons/test/src/main/java/com/sun/istack/test/ForkOutputStream.java
new file mode 100644
index 0000000..72be74d
--- /dev/null
+++ b/istack-commons/test/src/main/java/com/sun/istack/test/ForkOutputStream.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.test;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * {@link OutputStream} splitter.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public final class ForkOutputStream extends OutputStream {
+    final OutputStream out1,out2;
+
+    public ForkOutputStream(OutputStream out1,OutputStream out2) {
+        this.out1 = out1;
+        this.out2 = out2;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        out1.write(b);
+        out2.write(b);
+    }
+
+    @Override
+    public void close() throws IOException {
+        out1.close();
+        out2.close();
+    }
+
+    @Override
+    public void flush() throws IOException {
+        out1.flush();
+        out2.flush();
+    }
+
+    @Override
+    public void write(byte[] b) throws IOException {
+        out1.write(b);
+        out2.write(b);
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        out1.write(b,off,len);
+        out2.write(b,off,len);
+    }
+}
diff --git a/istack-commons/test/src/main/java/com/sun/istack/test/VersionNumber.java b/istack-commons/test/src/main/java/com/sun/istack/test/VersionNumber.java
new file mode 100644
index 0000000..83bc842
--- /dev/null
+++ b/istack-commons/test/src/main/java/com/sun/istack/test/VersionNumber.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.test;
+
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+/**
+ * Immutable representation of a dot-separated digits (such as "1.0.1").
+ *
+ * {@link VersionNumber}s are {@link Comparable}.
+ *
+ * <p>
+ * We allow a component to be not just a number, but also "ea", "ea1", "ea2".
+ * "ea" is treated as "ea0", and {@code eaN < M for any M > 0}.
+ *
+ * <p>
+ * '*' is also allowed as a component, and {@code '*' > M} for any {@code M > 0}.
+ *
+ * <pre>
+ * {@code 2.0.* > 2.0.1 > 2.0.0 > 2.0.ea > 2.0 }
+ * </pre>
+ *
+ * @author
+ *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
+ */
+public class VersionNumber implements Comparable<VersionNumber> {
+
+    public static final VersionNumber v1_0   = new VersionNumber("1.0");
+    public static final VersionNumber v1_0_1 = new VersionNumber("1.0.1");
+    public static final VersionNumber v1_0_2 = new VersionNumber("1.0.2");
+    public static final VersionNumber v1_0_3 = new VersionNumber("1.0.3");
+    public static final VersionNumber v2_0   = new VersionNumber("2.0");
+    public static final VersionNumber v2_1   = new VersionNumber("2.1");
+
+    private final int[] digits;
+
+    /**
+     * Parses a string like "1.0.2" into the version number.
+     *
+     * @param num string to parse
+     * @throws IllegalArgumentException
+     *      if the parsing fails.
+     */
+    public VersionNumber( String num ) {
+        StringTokenizer tokens = new StringTokenizer(num,".");
+        digits = new int[tokens.countTokens()];
+        if(digits.length<2)
+            throw new IllegalArgumentException();
+
+        int i=0;
+        while( tokens.hasMoreTokens() ) {
+            String token = tokens.nextToken().toLowerCase(Locale.ENGLISH);
+            if(token.equals("*")) {
+                digits[i++] = 1000;
+            } else
+            if(token.startsWith("ea")) {
+                if(token.length()==2)
+                    digits[i++] = -1000;    // just "ea"
+                else
+                    digits[i++] = -1000 + Integer.parseInt(token.substring(2)); // "eaNNN"
+            } else {
+                digits[i++] = Integer.parseInt(token);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        for( int i=0; i<digits.length; i++ ) {
+            if(i!=0)    buf.append('.');
+            buf.append( Integer.toString(digits[i]) );
+        }
+        return buf.toString();
+    }
+
+    public boolean isOlderThan( VersionNumber rhs ) {
+        return compareTo(rhs)<0;
+    }
+
+    public boolean isNewerThan( VersionNumber rhs ) {
+        return compareTo(rhs)>0;
+    }
+
+
+    @Override
+    public boolean equals( Object o ) {
+        if (o instanceof VersionNumber) {
+            return compareTo((VersionNumber)o)==0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        int x=0;
+        for (int i : digits)
+            x = (x << 1) | i;
+        return x;
+    }
+
+    @Override
+    public int compareTo(VersionNumber rhs) {
+        for( int i=0; ; i++ ) {
+            if( i==this.digits.length && i==rhs.digits.length )
+                return 0;   // equals
+            if( i==this.digits.length )
+                return -1;  // rhs is larger
+            if( i==rhs.digits.length )
+                return 1;
+
+            int r = this.digits[i] - rhs.digits[i];
+            if(r!=0)    return r;
+        }
+    }
+}
diff --git a/istack-commons/test/src/main/java/com/sun/istack/test/VersionProcessor.java b/istack-commons/test/src/main/java/com/sun/istack/test/VersionProcessor.java
new file mode 100644
index 0000000..d08c06d
--- /dev/null
+++ b/istack-commons/test/src/main/java/com/sun/istack/test/VersionProcessor.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.test;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Represents a range of versions.
+ *
+ * @author
+ *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
+ */
+public final class VersionProcessor {
+    /**
+     * This test is only applicable to the RI of this version or later.
+     * can be null.
+     */
+    private final VersionNumber since;
+
+    /**
+     * This test is only applicable to the RI of this version or younger.
+     * can be null.
+     */
+    private final VersionNumber until;
+
+    /**
+     * This test shall be excluded from the RI of versions listed here.
+     */
+    private final Set<Object> excludeVersions;
+
+    /**
+     * Special version number constant to represent ALL in
+     * {@link #excludeVersions}.
+     */
+    private static final Object ALL_VERSION = new Object();
+
+    /**
+     * Creates a default {@link VersionProcessor} that accepts
+     * any version.
+     */
+    private VersionProcessor() {
+        since = null;
+        until = null;
+        excludeVersions = null;
+    }
+
+    public VersionProcessor( String sinceValue, String untilValue, String excludeFromValue ) {
+        if( sinceValue!=null && !sinceValue.trim().isEmpty())
+            since = new VersionNumber( sinceValue );
+        else
+            since = null;
+
+        if( untilValue!=null && !untilValue.trim().isEmpty())
+            until = new VersionNumber( untilValue );
+        else
+            until = null;
+
+        if( excludeFromValue!=null && !excludeFromValue.trim().isEmpty()) {
+            excludeVersions = new HashSet<>();
+            String v = excludeFromValue.trim();
+            if(v.equals("all")) {
+                excludeVersions.add(ALL_VERSION);
+            } else {
+                StringTokenizer tokens = new StringTokenizer( v );
+                while(tokens.hasMoreTokens())
+                    excludeVersions.add( new VersionNumber( tokens.nextToken() ) );
+            }
+        } else
+            excludeVersions = null;
+    }
+
+    public VersionProcessor( Document testSpecMeta ) {
+        this(testSpecMeta.getDocumentElement());
+    }
+
+    public VersionProcessor( Element e ) {
+        this(e.getAttribute("since"), e.getAttribute("until"), e.getAttribute("excludeFrom"));
+    }
+
+    /**
+     * Checks if the test is valid against the JAXB RI of
+     * the specified version.
+     * @param v version to check
+     * @return true if the test is valid
+     */
+    public boolean isApplicable(VersionNumber v) {
+        if( excludeVersions!=null ) {
+            if( excludeVersions.contains(ALL_VERSION)
+            ||  excludeVersions.contains(v) )
+                return false;
+        }
+
+        if(since!=null && since.isNewerThan(v))
+            return false;
+
+        return until == null || !v.isNewerThan(until);
+    }
+
+    /**
+     * Default {@link VersionProcessor} that accepts any version.
+     */
+    public static final VersionProcessor DEFAULT = new VersionProcessor();
+}
diff --git a/istack-commons/test/src/main/java/com/sun/istack/test/Which.java b/istack-commons/test/src/main/java/com/sun/istack/test/Which.java
new file mode 100644
index 0000000..0fe1525
--- /dev/null
+++ b/istack-commons/test/src/main/java/com/sun/istack/test/Which.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.test;
+
+import java.net.URL;
+
+/**
+ * Finds out where a class file is loaded from.
+ *
+ * @author
+ *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
+ */
+public class Which {
+
+    public static String which( Class<?> clazz ) {
+        return which( clazz.getName(), clazz.getClassLoader());
+    }
+
+    /**
+     * Search the specified classloader for the given classname.
+     *
+     * @param classname the fully qualified name of the class to search for
+     * @param loader the classloader to search
+     * @return the source location of the resource, or null if it wasn't found
+     */
+    public static String which(String classname, ClassLoader loader) {
+
+        String classnameAsResource = classname.replace('.', '/') + ".class";
+
+        if(loader == null) {
+            loader = ClassLoader.getSystemClassLoader();
+        }
+
+        URL it = loader.getResource(classnameAsResource);
+        if (it != null) {
+            return it.toString();
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/istack-commons/test/src/main/java/com/sun/istack/test/package-info.java b/istack-commons/test/src/main/java/com/sun/istack/test/package-info.java
new file mode 100644
index 0000000..b43349e
--- /dev/null
+++ b/istack-commons/test/src/main/java/com/sun/istack/test/package-info.java
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * Common test-related utility code for the istack components.
+ */
+package com.sun.istack.test;
diff --git a/istack-commons/test/src/main/java/module-info.java b/istack-commons/test/src/main/java/module-info.java
new file mode 100644
index 0000000..8874d01
--- /dev/null
+++ b/istack-commons/test/src/main/java/module-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * Common test-related utility code for the istack components.
+ */
+module com.sun.istack.test {
+    requires java.logging;
+    requires transitive java.xml;
+
+    exports com.sun.istack.test;
+}
diff --git a/istack-commons/tools/pom.xml b/istack-commons/tools/pom.xml
new file mode 100644
index 0000000..4775adb
--- /dev/null
+++ b/istack-commons/tools/pom.xml
@@ -0,0 +1,104 @@
+<!--
+
+    Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.sun.istack</groupId>
+        <artifactId>istack-commons</artifactId>
+        <version>4.2.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>istack-commons-tools</artifactId>
+
+    <name>istack common utility code tools</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <properties>
+        <argLine/>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>default-compile</id>
+                        <goals>
+                            <goal>compile</goal>
+                        </goals>
+                        <configuration>
+                            <compilerArgs>
+                                <arg>--add-reads</arg>
+                                <arg>com.sun.istack.tools=ALL-UNNAMED</arg>
+                            </compilerArgs>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>default-testCompile</id>
+                        <goals>
+                            <goal>testCompile</goal>
+                        </goals>
+                        <configuration>
+                            <compilerArgs>
+                                <arg>--add-reads</arg>
+                                <arg>com.sun.istack.tools=ALL-UNNAMED</arg>
+                            </compilerArgs>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <argLine>
+                        @{argLine} --add-opens java.base/java.net=com.sun.istack.tools
+                    </argLine>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <additionalJOptions>
+                        <additionalJOption>--add-reads</additionalJOption>
+                        <additionalJOption>com.sun.istack.tools=ALL-UNNAMED</additionalJOption>
+                    </additionalJOptions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/istack-commons/tools/src/main/java/com/sun/istack/tools/DefaultAuthenticator.java b/istack-commons/tools/src/main/java/com/sun/istack/tools/DefaultAuthenticator.java
new file mode 100644
index 0000000..6231b83
--- /dev/null
+++ b/istack-commons/tools/src/main/java/com/sun/istack/tools/DefaultAuthenticator.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.tools;
+
+import org.xml.sax.Locator;
+import org.xml.sax.helpers.LocatorImpl;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.Authenticator;
+import java.net.MalformedURLException;
+import java.net.PasswordAuthentication;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+/**
+ * @author Vivek Pandey
+ * @author Lukas Jungmann
+ */
+public class DefaultAuthenticator extends Authenticator {
+
+    private static final Logger LOGGER = Logger.getLogger(DefaultAuthenticator.class.getName());
+    private static DefaultAuthenticator instance;
+    private static Authenticator systemAuthenticator = getCurrentAuthenticator();
+    private String proxyUser;
+    private String proxyPasswd;
+    private final List<AuthInfo> authInfo = new ArrayList<>();
+    private static int counter = 0;
+
+    DefaultAuthenticator() {
+        //try undocumented but often used properties
+        if (System.getProperty("http.proxyUser") != null) {
+            proxyUser = System.getProperty("http.proxyUser");
+        } else {
+            proxyUser = System.getProperty("proxyUser");
+        }
+        if (System.getProperty("http.proxyPassword") != null) {
+            proxyPasswd = System.getProperty("http.proxyPassword");
+        } else {
+            proxyPasswd = System.getProperty("proxyPassword");
+        }
+    }
+
+    public static synchronized DefaultAuthenticator getAuthenticator() {
+        if (instance == null) {
+            instance = new DefaultAuthenticator();
+            Authenticator.setDefault(instance);
+        }
+        counter++;
+        return instance;
+    }
+
+    public static synchronized void reset() {
+        --counter;
+        if (instance != null && counter == 0) {
+            Authenticator.setDefault(systemAuthenticator);
+        }
+    }
+
+    @Override
+    protected PasswordAuthentication getPasswordAuthentication() {
+        //If user sets proxy user and passwd and the RequestType is from proxy server then create
+        // PasswordAuthentication using proxyUser and proxyPasswd;
+        if ((getRequestorType() == RequestorType.PROXY) && proxyUser != null && proxyPasswd != null) {
+            return new PasswordAuthentication(proxyUser, proxyPasswd.toCharArray());
+        }
+        for (AuthInfo auth : authInfo) {
+            if (auth.matchingHost(getRequestingURL())) {
+                return new PasswordAuthentication(auth.getUser(), auth.getPassword().toCharArray());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Proxy authorization string in form of username:password.
+     *
+     * @param proxyAuth Proxy authorization string
+     */
+    public void setProxyAuth(String proxyAuth) {
+        if (proxyAuth == null) {
+            this.proxyUser = null;
+            this.proxyPasswd = null;
+        } else {
+            int i = proxyAuth.indexOf(':');
+            if (i < 0) {
+                this.proxyUser = proxyAuth;
+                this.proxyPasswd = "";
+            } else if (i == 0) {
+                this.proxyUser = "";
+                this.proxyPasswd = proxyAuth.substring(1);
+            } else {
+                this.proxyUser = proxyAuth.substring(0, i);
+                this.proxyPasswd = proxyAuth.substring(i + 1);
+            }
+        }
+    }
+
+    public void setAuth(File f, Receiver l) {
+        Receiver listener = l == null ? new DefaultRImpl() : l;
+        BufferedReader in = null;
+        FileInputStream fi = null;
+        InputStreamReader is = null;
+        try {
+            String text;
+            LocatorImpl locator = new LocatorImpl();
+            locator.setSystemId(f.getAbsolutePath());
+            try {
+                fi = new FileInputStream(f);
+                is = new InputStreamReader(fi, StandardCharsets.UTF_8);
+                in = new BufferedReader(is);
+            } catch (FileNotFoundException e) {
+                listener.onError(e, locator);
+                return;
+            }
+            try {
+                int lineno = 1;
+                locator.setSystemId(f.getCanonicalPath());
+                while ((text = in.readLine()) != null) {
+                    locator.setLineNumber(lineno++);
+                    //ignore empty lines and treat those starting with '#' as comments
+                    if ("".equals(text.trim()) || text.startsWith("#")) {
+                        continue;
+                    }
+                    try {
+                        AuthInfo ai = parseLine(text);
+                        authInfo.add(ai);
+                    } catch (Exception e) {
+                        listener.onParsingError(text, locator);
+                    }
+                }
+            } catch (IOException e) {
+                listener.onError(e, locator);
+                LOGGER.log(Level.SEVERE, e.getMessage(), e);
+            }
+        } finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+                if (is != null) {
+                    is.close();
+                }
+                if (fi != null) {
+                    fi.close();
+                }
+            } catch (IOException ex) {
+                LOGGER.log(Level.SEVERE, null, ex);
+            }
+        }
+    }
+
+    private AuthInfo parseLine(String text) throws Exception {
+        URL url;
+        try {
+            url = new URL(text);
+        } catch (MalformedURLException mue) {
+            //possible cause of this can be that password contains
+            //character which has to be encoded in URL,
+            //such as '@', ')', '#' and few others
+            //so try to recreate the URL with encoded string
+            //between 2nd ':' and last '@'
+            int i = text.indexOf(':', text.indexOf(':') + 1) + 1;
+            int j = text.lastIndexOf('@');
+            String encodedUrl =
+                    text.substring(0, i)
+                    + URLEncoder.encode(text.substring(i, j), StandardCharsets.UTF_8)
+                    + text.substring(j);
+            url = new URL(encodedUrl);
+        }
+
+        String authinfo = url.getUserInfo();
+
+        if (authinfo != null) {
+            int i = authinfo.indexOf(':');
+
+            if (i >= 0) {
+                String user = authinfo.substring(0, i);
+                String password = authinfo.substring(i + 1);
+                return new AuthInfo(
+                        new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile()),
+                        user, URLDecoder.decode(password, StandardCharsets.UTF_8));
+            }
+        }
+        throw new Exception();
+    }
+
+    static Authenticator getCurrentAuthenticator() {
+        return Utils.getCurrentAuthenticator();
+    }
+
+    public interface Receiver {
+
+        void onParsingError(String line, Locator loc);
+
+        void onError(Exception e, Locator loc);
+    }
+
+    private static class DefaultRImpl implements Receiver {
+
+        @Override
+        public void onParsingError(String line, Locator loc) {
+            System.err.println(getLocationString(loc) + ": " + line);
+        }
+
+        @Override
+        public void onError(Exception e, Locator loc) {
+            System.err.println(getLocationString(loc) + ": " + e.getMessage());
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        }
+
+        private String getLocationString(Locator l) {
+            return "[" + l.getSystemId() + "#" + l.getLineNumber() + "]";
+        }
+    }
+
+    /**
+     * Represents authorization information needed by
+     * {@link DefaultAuthenticator} to authenticate access to remote resources.
+     *
+     * @author Vivek Pandey
+     * @author Lukas Jungmann
+     */
+    final static class AuthInfo {
+
+        private final String user;
+        private final String password;
+        private final Pattern urlPattern;
+
+        public AuthInfo(URL url, String user, String password) {
+            String u = url.toExternalForm().replaceFirst("\\?", "\\\\?");
+            this.urlPattern = Pattern.compile(u.replace("*", ".*"), Pattern.CASE_INSENSITIVE);
+            this.user = user;
+            this.password = password;
+        }
+
+        public String getUser() {
+            return user;
+        }
+
+        public String getPassword() {
+            return password;
+        }
+
+        /**
+         * Returns if the requesting host and port are associated with this
+         * {@link AuthInfo}
+         */
+        public boolean matchingHost(URL requestingURL) {
+            return urlPattern.matcher(requestingURL.toExternalForm()).matches();
+        }
+    }
+}
diff --git a/istack-commons/tools/src/main/java/com/sun/istack/tools/MaskingClassLoader.java b/istack-commons/tools/src/main/java/com/sun/istack/tools/MaskingClassLoader.java
new file mode 100644
index 0000000..d78c0cf
--- /dev/null
+++ b/istack-commons/tools/src/main/java/com/sun/istack/tools/MaskingClassLoader.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.tools;
+
+import java.util.Collection;
+
+/**
+ * {@link ClassLoader} that masks a specified set of classes
+ * from its parent class loader.
+ *
+ * <p>
+ * This code is used to create an isolated environment.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class MaskingClassLoader extends ClassLoader {
+
+    private final String[] masks;
+
+    public MaskingClassLoader(String... masks) {
+        this.masks = masks;
+    }
+
+    public MaskingClassLoader(Collection<String> masks) {
+        this(masks.toArray(new String[0]));
+    }
+
+    public MaskingClassLoader(ClassLoader parent, String... masks) {
+        super(parent);
+        this.masks = masks;
+    }
+
+    public MaskingClassLoader(ClassLoader parent, Collection<String> masks) {
+        this(parent, masks.toArray(new String[0]));
+    }
+
+    @Override
+    protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+        for (String mask : masks) {
+            if(name.startsWith(mask))
+                throw new ClassNotFoundException();
+        }
+
+        return super.loadClass(name, resolve);
+    }
+}
diff --git a/istack-commons/tools/src/main/java/com/sun/istack/tools/ParallelWorldClassLoader.java b/istack-commons/tools/src/main/java/com/sun/istack/tools/ParallelWorldClassLoader.java
new file mode 100644
index 0000000..aedadc8
--- /dev/null
+++ b/istack-commons/tools/src/main/java/com/sun/istack/tools/ParallelWorldClassLoader.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.tools;
+
+import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.URLConnection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Load classes/resources from a side folder, so that
+ * classes of the same package can live in a single jar file.
+ *
+ * <p>
+ * For example, with the following jar file:
+ * <pre>
+ *  /
+ *  +- foo
+ *     +- X.class
+ *  +- bar
+ *     +- X.class
+ * </pre>
+ * <p>
+ * {@link ParallelWorldClassLoader}("foo/") would load {@code X.class} from
+ * {@code /foo/X.class} (note that X is defined in the root package, not
+ * {@code foo.X}.
+ *
+ * <p>
+ * This can be combined with  {@link MaskingClassLoader} to mask classes which are loaded by the parent
+ * class loader so that the child class loader
+ * classes living in different folders are loaded
+ * before the parent class loader loads classes living the jar file publicly
+ * visible
+ * For example, with the following jar file:
+ * <pre>
+ *  /
+ *  +- foo
+ *     +- X.class
+ *  +- bar
+ *     +-foo
+ *        +- X.class
+ * </pre>
+ * <p>
+ * {@link ParallelWorldClassLoader}(MaskingClassLoader.class.getClassLoader())
+ * would load {@code foo.X.class}  from
+ * {@code /bar/foo.X.class} not the {@code foo.X.class}
+ * in the publicly visible place in the jar file, thus
+ * masking the parent classLoader from loading the class from {@code foo.X.class}
+ * (note that X is defined in the  package foo, not
+ * {@code bar.foo.X}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class ParallelWorldClassLoader extends ClassLoader implements Closeable {
+
+    /**
+     * Strings like "prefix/", "abc/", or "" to indicate
+     * classes should be loaded normally.
+     */
+    private final String prefix;
+    private final Set<JarFile> jars;
+
+    public ParallelWorldClassLoader(ClassLoader parent,String prefix) {
+        super(parent);
+        this.prefix = prefix;
+        jars = Collections.synchronizedSet(new HashSet<>());
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+
+        StringBuilder sb = new StringBuilder(name.length()+prefix.length()+6);
+        sb.append(prefix).append(name.replace('.','/')).append(".class");
+
+        URL u  = getParent().getResource(sb.toString());
+        if (u == null) {
+            throw new ClassNotFoundException(name);
+        }
+
+        InputStream is = null;
+        URLConnection con = null;
+
+        try {
+            con = u.openConnection();
+            is = con.getInputStream();
+        } catch (IOException ioe) {
+            throw new ClassNotFoundException(name);
+        }
+
+        if (is==null)
+            throw new ClassNotFoundException(name);
+
+        try {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            byte[] buf = new byte[1024];
+            int len;
+            while((len=is.read(buf))>=0)
+                baos.write(buf,0,len);
+
+            buf = baos.toByteArray();
+            int packIndex = name.lastIndexOf('.');
+            if (packIndex != -1) {
+                String pkgname = name.substring(0, packIndex);
+                // Check if package already loaded.
+                Package pkg = getDefinedPackage(pkgname);
+                if (pkg == null) {
+                    definePackage(pkgname, null, null, null, null, null, null, null);
+                }
+            }
+            return defineClass(name,buf,0,buf.length);
+        } catch (IOException e) {
+            throw new ClassNotFoundException(name,e);
+        } finally {
+            try {
+                if (con instanceof JarURLConnection) {
+                    jars.add(((JarURLConnection) con).getJarFile());
+                }
+            } catch (IOException ioe) {
+                //ignore
+            }
+            try {
+                is.close();
+            } catch (IOException ioe) {
+                //ignore
+            }
+        }
+    }
+
+    @Override
+    protected URL findResource(String name) {
+        URL u = getParent().getResource(prefix + name);
+        if (u != null) {
+            try {
+                jars.add(new JarFile(new File(toJarUrl(u).toURI())));
+            } catch (URISyntaxException | IOException ex) {
+                Logger.getLogger(ParallelWorldClassLoader.class.getName()).log(Level.WARNING, null, ex);
+            } catch (ClassNotFoundException ex) {
+                //ignore - not a jar
+            }
+        }
+        return u;
+    }
+
+    @Override
+    protected Enumeration<URL> findResources(String name) throws IOException {
+        Enumeration<URL> en = getParent().getResources(prefix + name);
+        while (en.hasMoreElements()) {
+            try {
+                jars.add(new JarFile(new File(toJarUrl(en.nextElement()).toURI())));
+            } catch (URISyntaxException | IOException ex) {
+                //should not happen
+                Logger.getLogger(ParallelWorldClassLoader.class.getName()).log(Level.WARNING, null, ex);
+            } catch (ClassNotFoundException ex) {
+                //ignore - not a jar
+            }
+        }
+        return en;
+    }
+
+    @Override
+    public synchronized void close() throws IOException {
+        for (JarFile jar : jars) {
+            jar.close();
+        }
+    }
+
+    /**
+     * Given the URL inside jar, returns the URL to the jar itself.
+     * @param res Resource in a jar
+     * @return URL to the conaining jar file
+     * @throws java.lang.ClassNotFoundException if res does not denote jar URL
+     * @throws java.net.MalformedURLException if computed URL is invalid
+     */
+    public static URL toJarUrl(URL res) throws ClassNotFoundException, MalformedURLException {
+        String url = res.toExternalForm();
+        if(!url.startsWith("jar:"))
+            throw new ClassNotFoundException("Loaded outside a jar "+url);
+        url = url.substring(4); // cut off jar:
+        url = url.substring(0,url.lastIndexOf('!'));    // cut off everything after '!'
+        url = url.replaceAll(" ", "%20"); // support white spaces in path
+        return new URL(url);
+    }
+}
diff --git a/istack-commons/tools/src/main/java/com/sun/istack/tools/ProtectedTask.java b/istack-commons/tools/src/main/java/com/sun/istack/tools/ProtectedTask.java
new file mode 100644
index 0000000..147ba37
--- /dev/null
+++ b/istack-commons/tools/src/main/java/com/sun/istack/tools/ProtectedTask.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package com.sun.istack.tools;
+
+import java.io.Closeable;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DynamicConfigurator;
+import org.apache.tools.ant.IntrospectionHelper;
+import org.apache.tools.ant.Task;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.apache.tools.ant.AntClassLoader;
+
+/**
+ * Executes a {@link Task} in a special class loader that allows us to control
+ * where to load particular APIs.
+ *
+ * @author Kohsuke Kawaguchi
+ * @author Bhakti Mehta
+ */
+public abstract class ProtectedTask extends Task implements DynamicConfigurator {
+
+    private final AntElement root = new AntElement("root");
+
+    public ProtectedTask() {
+        super();
+    }
+
+    @Override
+    public void setDynamicAttribute(String name, String value) throws BuildException {
+        root.setDynamicAttribute(name, value);
+    }
+
+    @Override
+    public Object createDynamicElement(String name) throws BuildException {
+        return root.createDynamicElement(name);
+    }
+
+    @Override
+    public void execute() throws BuildException {
+        //Leave XJC2 in the publicly visible place
+        // and then isolate XJC1 in a child class loader,
+        // then use a MaskingClassLoader
+        // so that the XJC2 classes in the parent class loader
+        //  won't interfere with loading XJC1 classes in a child class loader
+        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
+        try {
+            ClassLoader cl = createClassLoader();
+            @SuppressWarnings("unchecked")
+            Class<Task> driver = (Class<Task>) cl.loadClass(getCoreClassName());
+
+            Task t = driver.getDeclaredConstructor().newInstance();
+            t.setProject(getProject());
+            t.setTaskName(getTaskName());
+            root.configure(t);
+
+            Thread.currentThread().setContextClassLoader(cl);
+            try {
+                t.execute();
+            } finally {
+                driver = null;
+                t.setTaskName(null);
+                t.setProject(null);
+                t = null;
+            }
+        } catch (UnsupportedClassVersionError e) {
+            throw new BuildException("Requires Java SE 8 or later. Please download it from https://www.oracle.com/java/technologies/javase-download.html");
+        } catch (ReflectiveOperationException | IOException e) {
+            throw new BuildException(e);
+        } finally {
+            ClassLoader cl = Thread.currentThread().getContextClassLoader();
+            Thread.currentThread().setContextClassLoader(ccl);
+
+            //close/cleanup all classloaders but the one which loaded this class
+            while (cl != null && !ccl.equals(cl)) {
+                try {
+                    ((Closeable) cl).close();
+                } catch (IOException ex) {
+                    throw new BuildException(ex);
+                }
+                cl = getParentClassLoader(cl);
+            }
+            cl = null;
+        }
+    }
+
+    /**
+     * Returns the name of the class that extends {@link Task}.This class will
+     * be loaded int the protected classloader.
+     * @return Task class name
+     */
+    protected abstract String getCoreClassName();
+
+    /**
+     * Creates a protective class loader that will host the actual task.
+     * @return ClassLoader use d for task execution
+     * @throws java.lang.ClassNotFoundException if required APIs are not found
+     * @throws java.io.IOException if error happens
+     */
+    protected abstract ClassLoader createClassLoader() throws ClassNotFoundException, IOException;
+
+    private ClassLoader getParentClassLoader(final ClassLoader cl) {
+        //Calling getParent() on AntClassLoader doesn't return the - expected -
+        //actual parent classloader but always the SystemClassLoader.
+        if (cl instanceof AntClassLoader) {
+            //1.8 added getConfiguredParent() to get correct 'parent' classloader
+            ClassLoader loader = ((AntClassLoader) cl).getConfiguredParent();
+            // we may be called by Gradle, in such case do not close its classloader,
+            // so Gradle can handle it itself and return null here;
+            // in other cases return parent or null if not found
+            return loader == null ? null
+                    : loader.getClass().getName().startsWith("org.gradle.") ? null : loader;
+        }
+        return cl.getParent();
+    }
+
+    /**
+     * Captures the elements and attributes.
+     */
+    private class AntElement implements DynamicConfigurator {
+
+        private final String name;
+
+        private final Map<String,String> attributes = new HashMap<>();
+
+        private final List<AntElement> elements = new ArrayList<>();
+
+        public AntElement(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public void setDynamicAttribute(String name, String value) throws BuildException {
+            attributes.put(name, value);
+        }
+
+        @Override
+        public Object createDynamicElement(String name) throws BuildException {
+            AntElement e = new AntElement(name);
+            elements.add(e);
+            return e;
+        }
+
+        /**
+         * Copies the properties into the Ant task.
+         */
+        public void configure(Object antObject) {
+            IntrospectionHelper ih = IntrospectionHelper.getHelper(antObject.getClass());
+
+            // set attributes first
+            for (Entry<String, String> att : attributes.entrySet()) {
+                ih.setAttribute(getProject(), antObject, att.getKey(), att.getValue());
+            }
+
+            // then nested elements
+            for (AntElement e : elements) {
+                Object child = ih.getElementCreator(getProject(), "", antObject, e.name, null).create();
+                e.configure(child);
+                ih.storeElement(getProject(), antObject, child, e.name);
+            }
+        }
+    }
+}
diff --git a/istack-commons/tools/src/main/java/com/sun/istack/tools/Utils.java b/istack-commons/tools/src/main/java/com/sun/istack/tools/Utils.java
new file mode 100644
index 0000000..0265c90
--- /dev/null
+++ b/istack-commons/tools/src/main/java/com/sun/istack/tools/Utils.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2020, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.tools;
+
+import java.net.Authenticator;
+
+final class Utils {
+
+
+    private Utils() {}
+
+    static Authenticator getCurrentAuthenticator() {
+        return Authenticator.getDefault();
+    }
+}
diff --git a/istack-commons/tools/src/main/java/com/sun/istack/tools/package-info.java b/istack-commons/tools/src/main/java/com/sun/istack/tools/package-info.java
new file mode 100644
index 0000000..63fc6e3
--- /dev/null
+++ b/istack-commons/tools/src/main/java/com/sun/istack/tools/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * istack-commons tool time utilities.
+ *
+ * <p>
+ * This includes code that relies on APT, javac, etc.
+ */
+package com.sun.istack.tools;
diff --git a/istack-commons/tools/src/main/java/module-info.java b/istack-commons/tools/src/main/java/module-info.java
new file mode 100644
index 0000000..12efacb
--- /dev/null
+++ b/istack-commons/tools/src/main/java/module-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017, 2019 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * istack-commons tool time utilities.
+ */
+module com.sun.istack.tools {
+    requires java.logging;
+    requires transitive java.xml;
+
+    exports com.sun.istack.tools;
+}
diff --git a/istack-commons/tools/src/test/java/com/sun/istack/tools/DefaultAuthenticatorTest.java b/istack-commons/tools/src/test/java/com/sun/istack/tools/DefaultAuthenticatorTest.java
new file mode 100644
index 0000000..fb154b2
--- /dev/null
+++ b/istack-commons/tools/src/test/java/com/sun/istack/tools/DefaultAuthenticatorTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2005, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.tools;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.net.Authenticator;
+import java.net.MalformedURLException;
+import java.net.PasswordAuthentication;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import static org.testng.Assert.*;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+/**
+ * @author Rama Pulavarthi
+ * @author Lukas Jungmann
+ */
+public class DefaultAuthenticatorTest {
+
+    private static final Logger logger = Logger.getLogger(DefaultAuthenticatorTest.class.getName());
+
+    public DefaultAuthenticatorTest() {
+    }
+
+    private static class MyAuthenticator extends DefaultAuthenticator {
+
+        private String requestingURL;
+
+        @Override
+        protected URL getRequestingURL() {
+            try {
+                return new URL(requestingURL);
+            } catch (MalformedURLException e) {
+                logger.log(Level.SEVERE, null, e);
+            }
+            return null;
+        }
+
+        void setRequestingURL(String url) {
+            requestingURL = url;
+        }
+    }
+
+    @AfterMethod
+    public void after() {
+        clearTestAuthenticator();
+    }
+
+    @Test
+    public void testDefaultAuth() throws Exception {
+        URL url = getResourceAsUrl("com/sun/istack/tools/.auth");
+        MyAuthenticator ma = createTestAuthenticator();
+        ma.setRequestingURL("http://foo.com/myservice?wsdl");
+        assertNull(DefaultAuthenticator.getCurrentAuthenticator());
+        assertEquals(0, getCounter());
+        try {
+            DefaultAuthenticator da = DefaultAuthenticator.getAuthenticator();
+            assertEquals(ma, da);
+            assertEquals(1, getCounter());
+            da.setAuth(new File(url.toURI()), null);
+            PasswordAuthentication pa = da.getPasswordAuthentication();
+            assertTrue(pa != null && pa.getUserName().equals("duke") && Arrays.equals(pa.getPassword(), "test".toCharArray()));
+        } finally {
+            DefaultAuthenticator.reset();
+            assertNotEquals(ma, DefaultAuthenticator.getCurrentAuthenticator());
+            assertEquals(0, getCounter());
+        }
+    }
+
+    @Test
+    public void testGetDefaultAuth() {
+        Authenticator orig = DefaultAuthenticator.getCurrentAuthenticator();
+        try {
+            DefaultAuthenticator da = DefaultAuthenticator.getAuthenticator();
+            assertNotEquals(orig, da);
+            assertEquals(1, getCounter());
+            Authenticator auth = DefaultAuthenticator.getCurrentAuthenticator();
+            assertNotNull(auth);
+            assertEquals(da, auth);
+        } finally {
+            DefaultAuthenticator.reset();
+            assertEquals(orig, DefaultAuthenticator.getCurrentAuthenticator());
+            assertEquals(0, getCounter());
+        }
+    }
+
+    @Test
+    public void testJaxWs_1101() throws Exception {
+        URL url = getResourceAsUrl("com/sun/istack/tools/auth_test.resource");
+        MyAuthenticator ma = createTestAuthenticator();
+
+        try {
+            DefaultAuthenticator da = DefaultAuthenticator.getAuthenticator();
+            assertEquals(1, getCounter());
+            assertEquals(ma, da);
+            da.setAuth(new File(url.toURI()), null);
+
+            ma.setRequestingURL("http://server1.myserver.com/MyService/Service.svc?wsdl");
+            PasswordAuthentication pa = da.getPasswordAuthentication();
+            assertEquals("user", pa.getUserName());
+            assertEquals(")/_@B8M)gDw", new String(pa.getPassword()));
+
+            ma.setRequestingURL("http://server1.myserver.com/MyService/Service.svc?xsd=xsd0");
+            pa = da.getPasswordAuthentication();
+            assertEquals("user", pa.getUserName());
+            assertEquals(")/_@B8M)gDw", new String(pa.getPassword()));
+
+            ma.setRequestingURL("http://server1.myserver.com/MyService/Service.svc");
+            pa = da.getPasswordAuthentication();
+            assertEquals("user", pa.getUserName());
+            assertEquals(")/_@B8M)gDw", new String(pa.getPassword()));
+
+            ma.setRequestingURL("http://server1.myserver.com/encoded/MyService/Service.svc?wsdl");
+            pa = da.getPasswordAuthentication();
+            assertEquals("user2", pa.getUserName());
+            assertEquals(")/_@B8M)gDw", new String(pa.getPassword()));
+        } finally {
+            DefaultAuthenticator.reset();
+            assertEquals(0, getCounter());
+        }
+    }
+
+    private static URL getResourceAsUrl(String resourceName) throws RuntimeException {
+        URL input = Thread.currentThread().getContextClassLoader().getResource(resourceName);
+        if (input == null) {
+            throw new RuntimeException("Failed to find resource \"" + resourceName + "\"");
+        }
+        return input;
+    }
+
+    private MyAuthenticator createTestAuthenticator() {
+        Field f1 = null;
+        try {
+            f1 = DefaultAuthenticator.class.getDeclaredField("instance");
+            f1.setAccessible(true);
+            MyAuthenticator auth = new MyAuthenticator();
+            f1.set(null, auth);
+            return auth;
+        } catch (Exception ex) {
+            logger.log(Level.SEVERE, null, ex);
+        } finally {
+            if (f1 != null) {
+                f1.setAccessible(false);
+            }
+        }
+        return null;
+    }
+
+    private void clearTestAuthenticator() {
+        Field f1, f2 = f1 = null;
+        try {
+            f1 = DefaultAuthenticator.class.getDeclaredField("instance");
+            f1.setAccessible(true);
+            MyAuthenticator auth = new MyAuthenticator();
+            f1.set(null, null);
+            f2 = DefaultAuthenticator.class.getDeclaredField("counter");
+            f2.setAccessible(true);
+            f2.setInt(null, 0);
+        } catch (Exception ex) {
+            logger.log(Level.SEVERE, null, ex);
+        } finally {
+            if (f1 != null) {
+                f1.setAccessible(false);
+            }
+            if (f2 != null) {
+                f2.setAccessible(false);
+            }
+        }
+    }
+
+    private int getCounter() {
+        Field f = null;
+        try {
+            f = DefaultAuthenticator.class.getDeclaredField("counter");
+            f.setAccessible(true);
+            return f.getInt(null);
+        } catch (Exception ex) {
+            logger.log(Level.SEVERE, null, ex);
+        } finally {
+            if (f != null) {
+                f.setAccessible(false);
+            }
+        }
+        return -1;
+    }
+}
diff --git a/istack-commons/tools/src/test/java/com/sun/istack/tools/ParallelWorldClassLoaderTest.java b/istack-commons/tools/src/test/java/com/sun/istack/tools/ParallelWorldClassLoaderTest.java
new file mode 100644
index 0000000..f510849
--- /dev/null
+++ b/istack-commons/tools/src/test/java/com/sun/istack/tools/ParallelWorldClassLoaderTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.istack.tools;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import javax.xml.stream.XMLInputFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author lukas
+ */
+public class ParallelWorldClassLoaderTest {
+
+    private ClassLoader cl;
+    private MaskingClassLoader mcl;
+    private URLClassLoader ucl;
+    private ParallelWorldClassLoader pwcl;
+    private ClassLoader orig;
+
+    public ParallelWorldClassLoaderTest() {
+    }
+
+    @BeforeMethod
+    public void setUpMethod() throws Exception {
+        cl = ClassLoader.getSystemClassLoader();
+        mcl = new MaskingClassLoader(cl, "javax.xml.ws");
+        String dir = System.getProperty("surefire.test.class.path").split(File.pathSeparator)[0];
+        ucl = new URLClassLoader(new URL[] {new File(dir).toURI().toURL()}, mcl);
+        pwcl = new ParallelWorldClassLoader(ucl, "");
+        orig = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(pwcl);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDownMethod() {
+        Thread.currentThread().setContextClassLoader(orig);
+    }
+
+    /**
+     * Test of findClass method, of class ParallelWorldClassLoader.
+     */
+    @Test
+    public void testFindClass() {
+        System.out.println("findClass");
+        //XXX: why this fails ?
+//        Class c3 = pwcl.findClass("javax.xml.ws.Service");
+//        Assert.assertEquals(c3.getDeclaredMethods().length, 1);
+
+        Class<?> c1,c2;
+        try {
+            c1 = Class.forName("javax.xml.ws.Service", false, pwcl);
+            // jacoco adds method '$jacocoInit' so there can be at most two
+            Assert.assertTrue(c1.getDeclaredMethods().length < 3);
+        } catch (ClassNotFoundException cnfe) {
+            Assert.fail();
+        }
+        try {
+            c2 = Class.forName("javax.xml.ws.Service", false, Thread.currentThread().getContextClassLoader());
+            // jacoco adds method '$jacocoInit' so there can be at most two
+            Assert.assertTrue(c2.getDeclaredMethods().length < 3);
+        } catch (ClassNotFoundException cnfe) {
+            Assert.fail();
+        }
+    }
+
+    /**
+     * Test of findResource method, of class ParallelWorldClassLoader.
+     */
+    @Test
+    public void testFindResource() {
+        if (isJDK9()) return;
+        URL resource = pwcl.getResource("javax/xml/ws/Service.class");
+        URL object = pwcl.getResource("java/lang/Object.class");
+        String resJar = resource.getPath().substring(0, resource.getPath().indexOf("!"));
+        String rtJar = object.getPath().substring(0, object.getPath().indexOf("!"));
+        Assert.assertEquals(resJar, rtJar);
+    }
+
+    /**
+     * Test of findResources method, of class ParallelWorldClassLoader.
+     */
+    @Test
+    public void testFindResources() throws Exception {
+        if (isJDK9()) return;
+        Enumeration<URL> foundURLs = pwcl.getResources("javax/xml/ws/Service.class");
+        // TODO - this depends on jdk, maven cp, e.g.
+        ArrayList<URL> al = Collections.list(foundURLs);
+        int found = al.size();
+        if (!((found == 3) || (found == 4))) {
+            Assert.fail("Expected 3/4 elements. Verify the urls: \n" + al);
+        }
+    }
+
+    @Test
+    public void testJaxp() {
+        XMLInputFactory inFactory = XMLInputFactory.newInstance();
+        Assert.assertEquals(inFactory.getClass().getClassLoader(), ucl);
+    }
+
+    private static boolean isJDK9() {
+        return true;
+    }
+}
diff --git a/istack-commons/tools/src/test/java/javax/xml/ws/Service.java b/istack-commons/tools/src/test/java/javax/xml/ws/Service.java
new file mode 100644
index 0000000..32bb45d
--- /dev/null
+++ b/istack-commons/tools/src/test/java/javax/xml/ws/Service.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.xml.ws;
+
+/**
+ *
+ * @author lukas
+ */
+public final class Service {
+
+    public void test() {}
+}
diff --git a/istack-commons/tools/src/test/java/javax/xml/ws/XMLFactory.java b/istack-commons/tools/src/test/java/javax/xml/ws/XMLFactory.java
new file mode 100644
index 0000000..e88ee85
--- /dev/null
+++ b/istack-commons/tools/src/test/java/javax/xml/ws/XMLFactory.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.xml.ws;
+
+import java.io.InputStream;
+import java.io.Reader;
+import javax.xml.stream.EventFilter;
+import javax.xml.stream.StreamFilter;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLReporter;
+import javax.xml.stream.XMLResolver;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.util.XMLEventAllocator;
+import javax.xml.transform.Source;
+
+/**
+ *
+ * @author lukas
+ */
+public class XMLFactory extends XMLInputFactory {
+
+    public void test() {
+    }
+
+    @Override
+    public XMLStreamReader createXMLStreamReader(Reader reader) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLStreamReader createXMLStreamReader(Source source) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLStreamReader createXMLStreamReader(InputStream stream) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLStreamReader createXMLStreamReader(InputStream stream, String encoding) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLStreamReader createXMLStreamReader(String systemId, InputStream stream) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLStreamReader createXMLStreamReader(String systemId, Reader reader) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLEventReader createXMLEventReader(Reader reader) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLEventReader createXMLEventReader(String systemId, Reader reader) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLEventReader createXMLEventReader(XMLStreamReader reader) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLEventReader createXMLEventReader(Source source) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLEventReader createXMLEventReader(InputStream stream) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLEventReader createXMLEventReader(InputStream stream, String encoding) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLEventReader createXMLEventReader(String systemId, InputStream stream) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLStreamReader createFilteredReader(XMLStreamReader reader, StreamFilter filter) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLEventReader createFilteredReader(XMLEventReader reader, EventFilter filter) throws XMLStreamException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public XMLResolver getXMLResolver() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void setXMLResolver(XMLResolver resolver) {
+    }
+
+    @Override
+    public XMLReporter getXMLReporter() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void setXMLReporter(XMLReporter reporter) {
+    }
+
+    @Override
+    public void setProperty(String name, Object value) throws IllegalArgumentException {
+    }
+
+    @Override
+    public Object getProperty(String name) throws IllegalArgumentException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public boolean isPropertySupported(String name) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void setEventAllocator(XMLEventAllocator allocator) {
+    }
+
+    @Override
+    public XMLEventAllocator getEventAllocator() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+}
diff --git a/istack-commons/tools/src/test/resources/META-INF/services/javax.xml.stream.XMLInputFactory b/istack-commons/tools/src/test/resources/META-INF/services/javax.xml.stream.XMLInputFactory
new file mode 100644
index 0000000..f9a88b9
--- /dev/null
+++ b/istack-commons/tools/src/test/resources/META-INF/services/javax.xml.stream.XMLInputFactory
@@ -0,0 +1 @@
+javax.xml.ws.XMLFactory
\ No newline at end of file
diff --git a/istack-commons/tools/src/test/resources/com/sun/istack/tools/.auth b/istack-commons/tools/src/test/resources/com/sun/istack/tools/.auth
new file mode 100644
index 0000000..88b04e6
--- /dev/null
+++ b/istack-commons/tools/src/test/resources/com/sun/istack/tools/.auth
@@ -0,0 +1 @@
+http://duke:test@foo.com/myservice?wsdl
\ No newline at end of file
diff --git a/istack-commons/tools/src/test/resources/com/sun/istack/tools/auth_test.resource b/istack-commons/tools/src/test/resources/com/sun/istack/tools/auth_test.resource
new file mode 100644
index 0000000..2282fc2
--- /dev/null
+++ b/istack-commons/tools/src/test/resources/com/sun/istack/tools/auth_test.resource
@@ -0,0 +1,5 @@
+#plain password:
+http://user:)/_@B8M)gDw@server1.myserver.com/MyService/Service.svc*
+
+#encoded password:
+http://user2:%29%2F_%40B8M%29gDw@server1.myserver.com/encoded/MyService/Service.svc?WSDL