This is an automated email from the ASF dual-hosted git repository.

ggrzybek pushed a commit to branch karaf-4.2.x
in repository https://gitbox.apache.org/repos/asf/karaf.git


The following commit(s) were added to refs/heads/karaf-4.2.x by this push:
     new 7fc877f  [KARAF-7032] Provide a test for JTA API and change 
javax.transaction.* configuration in jre.properties and config.properties
     new 7a0092c  Merge pull request #1294 from grgrzybek/KARAF-7032-42x
7fc877f is described below

commit 7fc877f6789c987a4d65cc0201b4a58a41d122fb
Author: Grzegorz Grzybek <gr.grzy...@gmail.com>
AuthorDate: Thu Feb 11 10:05:52 2021 +0100

    [KARAF-7032] Provide a test for JTA API and change javax.transaction.* 
configuration in jre.properties and config.properties
---
 .../resources/etc/config.properties                |   9 +-
 .../resources/etc/jre.properties                   |  44 +++-
 .../karaf/instance/resources/etc/config.properties |   7 +-
 .../test/java/org/apache/karaf/itests/JtaTest.java | 277 +++++++++++++++++++++
 4 files changed, 331 insertions(+), 6 deletions(-)

diff --git 
a/assemblies/features/base/src/main/filtered-resources/resources/etc/config.properties
 
b/assemblies/features/base/src/main/filtered-resources/resources/etc/config.properties
index 4d9a7cf..6b418f2 100644
--- 
a/assemblies/features/base/src/main/filtered-resources/resources/etc/config.properties
+++ 
b/assemblies/features/base/src/main/filtered-resources/resources/etc/config.properties
@@ -169,12 +169,17 @@ eecap-1.8= osgi.ee; osgi.ee="OSGi/Minimum"; 
version:List<Version>="1.0,1.1,1.2",
  osgi.ee; osgi.ee="JavaSE/compact3"; version:List<Version>="1.8"
 
 #
-# javax.transaction is needed to avoid class loader constraint violation when 
using javax.sql
+# javax.transaction is needed ONLY for 
com.sun.corba.se.impl.javax.rmi.CORBA.Util.mapSystemException().
+# JDK8 and earlier provide only 3 exception classes in this package, so full 
JTA API bundles should always try the
+# bootdelegation first - even if they also package (and export) 
javax.transaction package
+#
+# boot delegation of javax.transaction.xa is needed to avoid class loader 
constraint violation when using javax.sql
+# and this package is always complete in all JDKs
 #
 org.osgi.framework.bootdelegation=\
       com.sun.*, \
       javax.transaction, \
-      javax.transaction.*, \
+      javax.transaction.xa, \
       javax.xml.crypto, \
       javax.xml.crypto.*, \
       jdk.nashorn.*, \
diff --git 
a/assemblies/features/base/src/main/filtered-resources/resources/etc/jre.properties
 
b/assemblies/features/base/src/main/filtered-resources/resources/etc/jre.properties
index 0f408ab..e99d6e4 100644
--- 
a/assemblies/features/base/src/main/filtered-resources/resources/etc/jre.properties
+++ 
b/assemblies/features/base/src/main/filtered-resources/resources/etc/jre.properties
@@ -340,6 +340,39 @@ jre-1.7= \
  org.xml.sax.helpers, \
  com.sun.nio.sctp
 
+#
+# A note about javax.transaction and javax.transaction.xa packages in JDK8 and 
JDK9+
+# - javax.transaction package is not provided at all in JDK9+ because of the 
removal of Corba
+# - javax.transaction package in JDK8 and earlier contains only 3 exception 
classes required to translate 3 Corba/OMG
+#   exception: org.omg.CORBA.TRANSACTION_REQUIRED, 
org.omg.CORBA.TRANSACTION_ROLLEDBACK, org.omg.CORBA.INVALID_TRANSACTION
+# - javax.transaction.xa package should always be provided by JDK itself (thus 
exported from system bundle and bootdelegated)
+#   because of javax.sql.XAConnection interface relying on 
javax.sql.xa.XAResource interface
+# - I decided to export javax.transaction.xa package with all the versions: 
1.1, 1.2 and 1.3 just to satisfy all potential
+#   import version ranges (and emphasize the fact that JavaEE doesn't version 
packages at all)
+# - javax.transaction package should be exported by JDK8 (but not JDK9+) with 
mandatory attribute ("partial" is an
+#   arbirtary name mentioned in 
"https://docs.osgi.org/specification/osgi.core/7.0.0/framework.module.html#framework.module.requirebundle";
+# - javax.transaction exported with "partial=true;mandatory:=partial" prevents 
system bundle to be a wire candidate for
+#   bundles with just "Import-Package: javax.transaction" - actual JTA API 
bundle is needed to provide all the classes
+#   from this package (like javax.transaction.UserTransaction)
+# - thus javax.transaction package is exported without a version - because 
each bundle with "Import-Package: javax.transaction"
+#   should always wire to full JTA API bundle. The fact that the JDK8 provided 
exception classes from this package
+#   are always loaded using boot class loader is an obvious, but internal 
consequence
+# - the full trick mentioned in "3.13.1 Require-Bundle" requires another 
bundle that exports javax.transaction package
+#   without mandatory attribute and that has Require-Bundle requirement to a 
bundle that exports the package with mandatory
+#   attribute - and that's what javax.transaction/javax.transaction-api/1.2 
does - it contains "Require-Bundle: system.bundle"
+# - Require-Bundle in JTA API bundle is not needed if javax.transaction is 
boot-delegated - because failure to search
+#   boot-delegated javax.* packages doesn't stop the class loading process - 
local content is checked
+# - jakarta.transaction/jakarta.transaction-api/1.3.x doesn't have (by 
mistake, see https://github.com/eclipse-ee4j/jta-api/issues/186)
+#   "Require-Bundle: system.bundle", but it still works thanks to 
boot-delegation
+# And last, but important thing - DBCP2 (see DBCP-571) has "Import-Package: 
javax.transaction.xa;partial=true;mandatory:=partial"
+# which is simply wrong (if anything, javax.transaction package should be 
imported this way, not javax.transaction.xa),
+# but to allow DBCP2 to be resolved on Karaf, special export package is added 
just for DBCP2:
+#     Export-Pacakge: 
javax.transaction.xa;partial=true;mandatory:=partial;version="1.1"
+# - mandatory "partial" attribute is added to javax.transaction export (JDK8) 
to prevent wiring to this package without
+#   full JTA API bundle
+# - mandatory "partial" attribute is added to javax.transaction.xa export (all 
JDKs) to satisfy DBCP2
+#
+
 jre-1.8= \
  javax.accessibility, \
  javax.activity, \
@@ -419,7 +452,11 @@ jre-1.8= \
  javax.swing.tree, \
  javax.swing.undo, \
  javax.tools, \
- javax.transaction; javax.transaction.xa; version="1.1"; partial=true; 
mandatory:=partial, \
+ javax.transaction;partial=true;mandatory:=partial, \
+ javax.transaction.xa;version="1.1";partial=true;mandatory:=partial, \
+ javax.transaction.xa;version="1.1", \
+ javax.transaction.xa;version="1.2", \
+ javax.transaction.xa;version="1.3", \
  javax.xml, \
  javax.xml.bind;version="2.2.8", \
  javax.xml.bind.annotation;version="2.2.8", \
@@ -612,7 +649,10 @@ jre-9= \
  javax.swing.tree, \
  javax.swing.undo, \
  javax.tools, \
- javax.transaction; javax.transaction.xa; version="1.1"; partial=true; 
mandatory:=partial, \
+ javax.transaction.xa;version="1.1";partial=true;mandatory:=partial, \
+ javax.transaction.xa;version="1.1", \
+ javax.transaction.xa;version="1.2", \
+ javax.transaction.xa;version="1.3", \
  javax.xml, \
  javax.xml.bind;version="2.3.0", \
  javax.xml.bind.annotation;version="2.3.0", \
diff --git 
a/instance/src/main/resources/org/apache/karaf/instance/resources/etc/config.properties
 
b/instance/src/main/resources/org/apache/karaf/instance/resources/etc/config.properties
index d50a4be..69313fd 100644
--- 
a/instance/src/main/resources/org/apache/karaf/instance/resources/etc/config.properties
+++ 
b/instance/src/main/resources/org/apache/karaf/instance/resources/etc/config.properties
@@ -173,12 +173,15 @@ eecap-1.8= osgi.ee; osgi.ee="OSGi/Minimum"; 
version:List<Version>="1.0,1.1,1.2",
  osgi.ee; osgi.ee="JavaSE/compact3"; version:List<Version>="1.8"
 
 #
-# javax.transaction is needed to avoid class loader constraint violation when 
using javax.sql
+# javax.transaction is needed ONLY for 
com.sun.corba.se.impl.javax.rmi.CORBA.Util.mapSystemException(). JDK8 and 
earlier
+# provide only 3 exception classes in this package, so full JTA bundles should 
always try first the bootdelegation
+# javax.transaction.xa is needed to avoid class loader constraint violation 
when using javax.sql and this package
+# is always complete in JDK8, earlier and older ones (including JPMS JDKs, 
a.k.a. "Jigsaw")
 #
 org.osgi.framework.bootdelegation = \
     com.sun.*, \
     javax.transaction, \
-    javax.transaction.*, \
+    javax.transaction.xa, \
     javax.xml.crypto, \
     javax.xml.crypto.*, \
     jdk.nashorn.*, \
diff --git a/itests/test/src/test/java/org/apache/karaf/itests/JtaTest.java 
b/itests/test/src/test/java/org/apache/karaf/itests/JtaTest.java
new file mode 100644
index 0000000..a8f0e3e
--- /dev/null
+++ b/itests/test/src/test/java/org/apache/karaf/itests/JtaTest.java
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.itests;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Properties;
+
+import aQute.lib.strings.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.framework.wiring.FrameworkWiring;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.OptionUtils.combine;
+import static 
org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerMethod.class)
+public class JtaTest extends BaseTest {
+
+    @Configuration
+    public Option[] config() {
+        File originalConfig = new 
File("../../assemblies/features/base/src/main/filtered-resources/resources/etc/config.properties");
+        Properties conf = new Properties();
+        try (FileReader fr = new FileReader(originalConfig)) {
+            conf.load(fr);
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+        String bd = conf.getProperty("org.osgi.framework.bootdelegation");
+        String[] packages = bd.split("\\s*,\\s*");
+        String[] filtered = Arrays.stream(packages).filter(p -> 
!p.contains("javax.transaction")).toArray(String[]::new);
+
+        // unfortunately this doesn't work. editConfigurationFilePut() for 
config.properties is overwritten by
+        // bootDelegation() options which always come last
+        // so I can't perform tests without boot delegation of 
javax.transaction packages
+        return combine(super.config(), 
editConfigurationFilePut("etc/config.properties", 
"org.osgi.framework.bootdelegation", Strings.join(", ", filtered)));
+    }
+
+    @Test
+    public void noSpecialFeatures() throws Exception {
+        ClassLoader cl = 
FrameworkUtil.getBundle(this.getClass()).adapt(BundleWiring.class).getClassLoader();
+
+        if (isJDK8OrEarlier()) {
+            // these classes should be boot delegated because they should be 
part of JDK8, all used ONLY
+            // in 
com.sun.corba.se.impl.javax.rmi.CORBA.Util.mapSystemException()
+            ensureLoadedFromSystem(cl, 
"javax.transaction.InvalidTransactionException");
+            ensureLoadedFromSystem(cl, 
"javax.transaction.TransactionRequiredException");
+            ensureLoadedFromSystem(cl, 
"javax.transaction.TransactionRolledbackException");
+        } else {
+            // JDK9+ doesn't provide javax.transaction package at all
+            ensureNotFound(cl, 
"javax.transaction.InvalidTransactionException");
+            ensureNotFound(cl, 
"javax.transaction.TransactionRequiredException");
+            ensureNotFound(cl, 
"javax.transaction.TransactionRolledbackException");
+        }
+
+        // whatever the JDK, these classes should be available
+        ensureLoadedFromSystem(cl, "javax.transaction.xa.XAException");
+        ensureLoadedFromSystem(cl, "javax.transaction.xa.XAResource");
+        ensureLoadedFromSystem(cl, "javax.transaction.xa.Xid");
+
+        // whatever the JDK, these classes should NOT be available
+        ensureNotFound(cl, "javax.transaction.UserTransaction");
+        ensureNotFound(cl, "javax.transaction.TransactionManager");
+    }
+
+    @Test
+    public void javaxTransaction1_2() throws Exception {
+        addFeaturesRepository("mvn:org.apache.karaf.features/enterprise/" + 
System.getProperty("karaf.version") + "/xml/features");
+        // this feature installs javax.transaction/javax.transaction-api/1.2 
with Require-Bundle: system.bundle
+        installAndAssertFeature("transaction-api");
+
+        ClassLoader myCl = 
FrameworkUtil.getBundle(this.getClass()).adapt(BundleWiring.class).getClassLoader();
+        ClassLoader jtaCl = 
FrameworkUtil.getBundle(myCl.loadClass("javax.transaction.UserTransaction")).adapt(BundleWiring.class).getClassLoader();
+
+        if (isJDK8OrEarlier()) {
+            // these classes should be boot delegated
+            ensureLoadedFromSystem(myCl, 
"javax.transaction.InvalidTransactionException");
+            ensureLoadedFromSystem(myCl, 
"javax.transaction.TransactionRequiredException");
+            ensureLoadedFromSystem(myCl, 
"javax.transaction.TransactionRolledbackException");
+        } else {
+            // these classes ARE boot delegated, but can't be found in JDK, so 
they're loaded from the API bundle
+            ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.InvalidTransactionException");
+            ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.TransactionRequiredException");
+            ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.TransactionRolledbackException");
+        }
+
+        // whatever the JDK, these classes should be available from system CL, 
even if javax.transaction-api/1.2
+        // exports javax.transaction.xa package
+        ensureLoadedFromSystem(myCl, "javax.transaction.xa.XAException");
+        ensureLoadedFromSystem(myCl, "javax.transaction.xa.XAResource");
+        ensureLoadedFromSystem(myCl, "javax.transaction.xa.Xid");
+        ensureLoadedFromSystem(jtaCl, "javax.transaction.xa.XAException");
+        ensureLoadedFromSystem(jtaCl, "javax.transaction.xa.XAResource");
+        ensureLoadedFromSystem(jtaCl, "javax.transaction.xa.Xid");
+
+        // these classes should be loaded from JTA API bundle
+        ensureLoadedFromCl(myCl, jtaCl, "javax.transaction.UserTransaction");
+        ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.TransactionManager");
+        ensureLoadedFromCl(jtaCl, jtaCl, "javax.transaction.UserTransaction");
+        ensureLoadedFromCl(jtaCl, jtaCl, 
"javax.transaction.TransactionManager");
+    }
+
+    @Test
+    public void javaxTransaction1_2AndDBCP2() throws Exception {
+        addFeaturesRepository("mvn:org.apache.karaf.features/enterprise/" + 
System.getProperty("karaf.version") + "/xml/features");
+        // this feature installs javax.transaction/javax.transaction-api/1.2 
with Require-Bundle: system.bundle
+        installAndAssertFeature("transaction-api");
+
+        Bundle pool2 = 
bundleContext.installBundle("mvn:org.apache.commons/commons-pool2/2.9.0");
+        // DBCP2 has:
+        //  - Import-Package: javax.transaction;version="1.1"
+        //  - Import-Package: 
javax.transaction.xa;version="1.1";partial=true;mandatory:=partial
+        // Karaf provides special Export-Package: 
javax.transaction.xa;version="1.1";partial=true;mandatory:=partial
+        // from system bundle just for DBCP2
+        // javax.transaction package is exported from system bundle (in JDK8) 
to prevent wiring this package
+        // requirement to system bundle - full JTA API is required and 
javax.transaction-api/1.2 does this
+        // using Require-Bundle: system.bundle
+        Bundle dbcp2 = 
bundleContext.installBundle("mvn:org.apache.commons/commons-dbcp2/2.8.0");
+        boolean resolved = 
bundleContext.getBundle(0).adapt(FrameworkWiring.class).resolveBundles(Collections.singletonList(dbcp2));
+        assertTrue(resolved);
+
+        ClassLoader myCl = 
FrameworkUtil.getBundle(this.getClass()).adapt(BundleWiring.class).getClassLoader();
+        ClassLoader dbcp2Cl = dbcp2.adapt(BundleWiring.class).getClassLoader();
+        ClassLoader jtaCl = 
FrameworkUtil.getBundle(myCl.loadClass("javax.transaction.UserTransaction")).adapt(BundleWiring.class).getClassLoader();
+
+        if (isJDK8OrEarlier()) {
+            // these classes should be boot delegated
+            ensureLoadedFromSystem(myCl, 
"javax.transaction.InvalidTransactionException");
+            ensureLoadedFromSystem(myCl, 
"javax.transaction.TransactionRequiredException");
+            ensureLoadedFromSystem(myCl, 
"javax.transaction.TransactionRolledbackException");
+        } else {
+            // these classes ARE boot delegated, but can't be found in JDK, so 
they're loaded from the API bundle
+            ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.InvalidTransactionException");
+            ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.TransactionRequiredException");
+            ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.TransactionRolledbackException");
+        }
+
+        // These classes should come from system - whether loaded from my, jta 
or dbcp2 CL, even if dbcp2 wires
+        // directly to system through Import-Package: 
javax.transaction.xa;partial=true;mandatory:=partial
+        // It works because:
+        //  - javax.transaction-api/1.2 has "Require-Bundle: system.bundle", 
which has priority over the fact that
+        //    javax.transaction.xa package is also exported from this bundle
+        //  - javax.transaction-api/1.3 has "Require-Bundle: system.bundle" 
and doesn't export javax.transaction.xa
+        //  - jakarta.transaction-api/1.3 doesn't have "Require-Bundle: 
system.bundle" and doesn't export javax.transaction.xa
+        // see:
+        // - https://github.com/ops4j/org.ops4j.pax.transx/issues/33
+        // - https://issues.apache.org/jira/browse/DBCP-571
+        ensureLoadedFromSystem(myCl, "javax.transaction.xa.Xid");
+        ensureLoadedFromSystem(jtaCl, "javax.transaction.xa.Xid");
+        ensureLoadedFromSystem(dbcp2Cl, "javax.transaction.xa.Xid");
+
+        // these classes should be loaded from JTA API bundle
+        ensureLoadedFromCl(myCl, jtaCl, "javax.transaction.UserTransaction");
+        ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.TransactionManager");
+        ensureLoadedFromCl(jtaCl, jtaCl, "javax.transaction.UserTransaction");
+        ensureLoadedFromCl(jtaCl, jtaCl, 
"javax.transaction.TransactionManager");
+        ensureLoadedFromCl(dbcp2Cl, jtaCl, 
"javax.transaction.UserTransaction");
+        ensureLoadedFromCl(dbcp2Cl, jtaCl, 
"javax.transaction.TransactionManager");
+    }
+
+    @Test
+    public void jakartaTransaction1_3AndDBCP2() throws Exception {
+        // this set of bundles matches Karaf's transaction-api feature, but 
uses jakarta.transaction-api/1.3 instead
+        // of javax.transaction-api/1.2
+        
bundleContext.installBundle("mvn:javax.interceptor/javax.interceptor-api/1.2");
+        
bundleContext.installBundle("mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.javax-inject/1_2");
+        bundleContext.installBundle("mvn:javax.el/javax.el-api/3.0.0");
+        bundleContext.installBundle("mvn:javax.enterprise/cdi-api/1.2");
+        // this bundle doesn't have Require-Bundle: system.bundle, but 
javax.transaction package (the 3 exception
+        // classes provided by JDK8) is still bootdelegated by Karaf
+        Bundle jta = 
bundleContext.installBundle("mvn:jakarta.transaction/jakarta.transaction-api/1.3.3");
+
+        Bundle pool2 = 
bundleContext.installBundle("mvn:org.apache.commons/commons-pool2/2.9.0");
+        Bundle dbcp2 = 
bundleContext.installBundle("mvn:org.apache.commons/commons-dbcp2/2.8.0");
+        // this won't resolve if system bundle doesn't export 
javax.transaction.xa package without mandatory "partial"
+        // attribute because jakarta.transaction-api/1.3.x exporting 
javax.transaction is needed to resolve dbcp2
+        boolean resolved = 
bundleContext.getBundle(0).adapt(FrameworkWiring.class).resolveBundles(Collections.singletonList(dbcp2));
+        assertTrue(resolved);
+
+        ClassLoader myCl = 
FrameworkUtil.getBundle(this.getClass()).adapt(BundleWiring.class).getClassLoader();
+        ClassLoader dbcp2Cl = dbcp2.adapt(BundleWiring.class).getClassLoader();
+        ClassLoader jtaCl = 
FrameworkUtil.getBundle(myCl.loadClass("javax.transaction.UserTransaction")).adapt(BundleWiring.class).getClassLoader();
+
+        if (isJDK8OrEarlier()) {
+            // these classes should be boot delegated
+            ensureLoadedFromSystem(myCl, 
"javax.transaction.InvalidTransactionException");
+            ensureLoadedFromSystem(myCl, 
"javax.transaction.TransactionRequiredException");
+            ensureLoadedFromSystem(myCl, 
"javax.transaction.TransactionRolledbackException");
+        } else {
+            // these classes ARE boot delegated, but can't be found in JDK, so 
they're loaded from the API bundle
+            ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.InvalidTransactionException");
+            ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.TransactionRequiredException");
+            ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.TransactionRolledbackException");
+        }
+
+        ensureLoadedFromSystem(jtaCl, "javax.transaction.xa.Xid");
+        ensureLoadedFromSystem(myCl, "javax.transaction.xa.Xid");
+        ensureLoadedFromSystem(dbcp2Cl, "javax.transaction.xa.Xid");
+
+        ensureLoadedFromCl(myCl, jtaCl, "javax.transaction.UserTransaction");
+        ensureLoadedFromCl(myCl, jtaCl, 
"javax.transaction.TransactionManager");
+        ensureLoadedFromCl(jtaCl, jtaCl, "javax.transaction.UserTransaction");
+        ensureLoadedFromCl(jtaCl, jtaCl, 
"javax.transaction.TransactionManager");
+        ensureLoadedFromCl(dbcp2Cl, jtaCl, 
"javax.transaction.UserTransaction");
+        ensureLoadedFromCl(dbcp2Cl, jtaCl, 
"javax.transaction.TransactionManager");
+    }
+
+    private void ensureLoadedFromSystem(ClassLoader cl, String className) {
+        try {
+            Class<?> c = cl.loadClass(className);
+            assertTrue(c != null && (c.getClassLoader() == null || 
c.getClassLoader().getClass().getName().contains("jdk.internal")));
+        } catch (ClassNotFoundException e) {
+            fail("Can't load " + className);
+        }
+    }
+
+    private void ensureLoadedFromCl(ClassLoader initiatingCl, ClassLoader 
loadingCl, String className) {
+        try {
+            Class<?> c = initiatingCl.loadClass(className);
+            assertTrue(c != null && c.getClassLoader() == loadingCl);
+        } catch (ClassNotFoundException e) {
+            fail("Can't load " + className);
+        }
+    }
+
+    private void ensureNotFound(ClassLoader cl, String className) {
+        try {
+            Class<?> c = cl.loadClass(className);
+            fail("Class " + className + " should not be available");
+        } catch (ClassNotFoundException ignored) {
+        }
+    }
+
+    private boolean isJDK8OrEarlier() {
+        String v = System.getProperty("java.specification.version");
+        try {
+            if (v.contains(".")) {
+                float f = Float.parseFloat(v);
+                return f < 1.9F;
+            } else {
+                int i = Integer.parseInt(v);
+                return i < 9;
+            }
+        } catch (NumberFormatException ignored) {
+            return true;
+        }
+    }
+
+}

Reply via email to