From 1d83b9a0954dbe76625e689a40d6047839354ee1 Mon Sep 17 00:00:00 2001 From: Jose Date: Mon, 23 Dec 2024 11:22:57 +0100 Subject: [PATCH] Fix android IceSSL testing - #3288 --- .../com/zeroc/Ice/InitializationData.java | 10 +++++++ .../main/java/com/zeroc/Ice/Properties.java | 2 +- .../java/com/zeroc/Ice/SSL/SSLEngine.java | 11 ++++++-- .../src/main/java/com/zeroc/Ice/Util.java | 20 +++++++++++-- .../testcontroller/ControllerActivity.java | 2 +- .../zeroc/testcontroller/ControllerApp.java | 28 +++++++++---------- java/test/src/main/java/test/TestHelper.java | 11 ++++++++ scripts/Util.py | 1 - 8 files changed, 62 insertions(+), 23 deletions(-) diff --git a/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/InitializationData.java b/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/InitializationData.java index ff8a0effcf2..987ca0e149f 100644 --- a/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/InitializationData.java +++ b/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/InitializationData.java @@ -76,4 +76,14 @@ public InitializationData clone() { * the SSLEngineFactory. */ public SSLEngineFactory clientSSLEngineFactory; + + /** + * A user-supplied function used to loads resources (e.g., key stores, trust stores) given a + * resource identifier or path. If this field is non-null, the provided function is used to load + * resources. Otherwise, the default loader (using the classpath and file system) is used. + * + *

If the function itself returns {@code null} when attempting to load a particular resource, + * this class will automatically fall back to the default resource loader. + */ + public java.util.function.Function resourceLoader; } diff --git a/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/Properties.java b/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/Properties.java index 00002ce2c3b..b3a6f8e6299 100644 --- a/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/Properties.java +++ b/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/Properties.java @@ -553,7 +553,7 @@ public void load(String file) { } else { java.io.PushbackInputStream is = null; try { - java.io.InputStream f = Util.openResource(getClass().getClassLoader(), file); + java.io.InputStream f = Util.openResource(null, getClass().getClassLoader(), file); if (f == null) { throw new FileException("failed to open '" + file + "'"); } diff --git a/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/SSL/SSLEngine.java b/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/SSL/SSLEngine.java index 806144c9575..9bf84ba1e0d 100644 --- a/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/SSL/SSLEngine.java +++ b/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/SSL/SSLEngine.java @@ -476,6 +476,11 @@ void trustManagerFailure(boolean incoming, CertificateException ex) } private java.io.InputStream openResource(String path) throws java.io.IOException { + java.io.InputStream stream; + + com.zeroc.Ice.InitializationData initData = + _communicator.getInstance().initializationData(); + boolean isAbsolute = false; try { new java.net.URL(path); @@ -485,8 +490,9 @@ private java.io.InputStream openResource(String path) throws java.io.IOException isAbsolute = f.isAbsolute(); } - java.io.InputStream stream = - com.zeroc.Ice.Util.openResource(getClass().getClassLoader(), path); + stream = + com.zeroc.Ice.Util.openResource( + initData.resourceLoader, getClass().getClassLoader(), path); // // If the first attempt fails and IceSSL.DefaultDir is defined and the original @@ -497,6 +503,7 @@ private java.io.InputStream openResource(String path) throws java.io.IOException if (stream == null && !_defaultDir.isEmpty() && !isAbsolute) { stream = com.zeroc.Ice.Util.openResource( + initData.resourceLoader, getClass().getClassLoader(), _defaultDir + java.io.File.separator + path); } diff --git a/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/Util.java b/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/Util.java index 2c8e193a295..bc9af5b2174 100644 --- a/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/Util.java +++ b/java/src/com.zeroc.ice/src/main/java/com/zeroc/Ice/Util.java @@ -569,14 +569,28 @@ public static ProtocolPluginFacade getProtocolPluginFacade(Communicator communic } /** - * Given a path name, first try to open it as a class path resource (the path is treated as + * Given a path name, first try to open it using the provided resource loader. If the resource + * loader is null or if it returns null try as a class path resource (the path is treated as * absolute). If that fails, fall back to the file system. Returns null if the file does not * exist and raises IOException if an error occurs. * * @hidden Public because it's used by SSL. */ - public static java.io.InputStream openResource(ClassLoader cl, String path) + public static java.io.InputStream openResource( + java.util.function.Function resourceLoader, + ClassLoader cl, + String path) throws java.io.IOException { + + java.io.InputStream stream = null; + // Try the resource loader first if one is provided. + if (resourceLoader != null) { + stream = resourceLoader.apply(path); + if (stream != null) { + return stream; + } + } + // // Calling getResourceAsStream on the class loader means all paths are absolute, // whereas calling it on the class means all paths are relative to the class @@ -584,7 +598,6 @@ public static java.io.InputStream openResource(ClassLoader cl, String path) // // getResourceAsStream returns null if the resource can't be found. // - java.io.InputStream stream = null; try { stream = cl.getResourceAsStream(path); } catch (IllegalArgumentException ex) { @@ -598,6 +611,7 @@ public static java.io.InputStream openResource(ClassLoader cl, String path) // java.io.InputStream in = Util.openResource(cl, "c:\\foo.txt"); // } + if (stream == null) { try { java.io.File f = new java.io.File(path); diff --git a/java/test/android/controller/src/main/java/com/zeroc/testcontroller/ControllerActivity.java b/java/test/android/controller/src/main/java/com/zeroc/testcontroller/ControllerActivity.java index 825b8dae4ec..78192357aab 100644 --- a/java/test/android/controller/src/main/java/com/zeroc/testcontroller/ControllerActivity.java +++ b/java/test/android/controller/src/main/java/com/zeroc/testcontroller/ControllerActivity.java @@ -131,7 +131,7 @@ public void onNothingSelected(AdapterView arg0) // Start the controller in a background thread. Starting the controller creates the ObjectAdapter which makes // IO calls. Android doesn't allow making IO calls from the main thread. - Executor executor = Executors.newSingleThreadExecutor(); + ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(() -> { try { app.startController(this, bluetooth); diff --git a/java/test/android/controller/src/main/java/com/zeroc/testcontroller/ControllerApp.java b/java/test/android/controller/src/main/java/com/zeroc/testcontroller/ControllerApp.java index 7d0f4d0986b..634eb560886 100644 --- a/java/test/android/controller/src/main/java/com/zeroc/testcontroller/ControllerApp.java +++ b/java/test/android/controller/src/main/java/com/zeroc/testcontroller/ControllerApp.java @@ -281,21 +281,19 @@ public ControllerHelperI(TestSuiteBundle bundle, String[] args) { _args = args; } - public void communicatorInitialized(Communicator communicator) { - com.zeroc.Ice.Properties properties = communicator.getProperties(); - if (properties - .getIceProperty("Ice.Plugin.IceSSL") - .equals("com.zeroc.IceSSL.PluginFactory")) { - com.zeroc.Ice.SSL.Plugin plugin = - (com.zeroc.Ice.SSL.Plugin) - communicator.getPluginManager().getPlugin("IceSSL"); - String keystore = communicator.getProperties().getIceProperty("IceSSL.Keystore"); - properties.setProperty("IceSSL.Keystore", ""); - int resource = keystore.equals("client.bks") ? R.raw.client : R.raw.server; - java.io.InputStream certs = getResources().openRawResource(resource); - plugin.setKeystoreStream(certs); - plugin.setTruststoreStream(certs); - communicator.getPluginManager().initializePlugins(); + public void communicatorInitialized(Communicator communicator) {} + + public java.io.InputStream loadResource(String path) { + switch (path) { + case "server.bks" -> { + return getResources().openRawResource(R.raw.server); + } + case "client.bks" -> { + return getResources().openRawResource(R.raw.client); + } + default -> { + return null; + } } } diff --git a/java/test/src/main/java/test/TestHelper.java b/java/test/src/main/java/test/TestHelper.java index bd1feaace0c..1ed282a45d8 100644 --- a/java/test/src/main/java/test/TestHelper.java +++ b/java/test/src/main/java/test/TestHelper.java @@ -16,6 +16,8 @@ public static void test(boolean b) { public interface ControllerHelper { void communicatorInitialized(Communicator c); + java.io.InputStream loadResource(String name); + void serverReady(); } @@ -127,6 +129,15 @@ public Communicator initialize(InitializationData initData) { initData.classLoader = _classLoader; } + if (isAndroid()) { + initData.resourceLoader = + (String path) -> { + return _controllerHelper != null + ? _controllerHelper.loadResource(path) + : null; + }; + } + Communicator communicator = Util.initialize(initData); if (_communicator == null) { _communicator = communicator; diff --git a/scripts/Util.py b/scripts/Util.py index 2b3b30c9707..c2ec6f0ed04 100644 --- a/scripts/Util.py +++ b/scripts/Util.py @@ -3780,7 +3780,6 @@ def getSSLProps(self, process, current): { "IceSSL.KeystoreType": "BKS", "IceSSL.TruststoreType": "BKS", - "Ice.InitPlugins": "0", "IceSSL.Keystore": "server.bks" if isinstance(process, Server) else "client.bks",