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

ardovm pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit 45c5a00162811bd03b87fcb4fe9996782f2b59ec
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Fri Jul 3 09:16:41 2026 +0200

    Skip invalid entries
    
    Detect malformed URLs, log them and and skip them.
    
    The per-entry handling is factored into a shared Tools.addClassPathURL
    helper used by both ClassMap variants, with ToolsTest covering the
    accepted and skipped schemes (subsequent JUnit test under
    connectivity/qa/complex/sdbc).
    
    Assisted-By: Claude Opus 4.8 <[email protected]>
---
 .../main/java/com/sun/star/comp/sdbc/ClassMap.java |   9 +-
 .../main/java/com/sun/star/comp/sdbc/Tools.java    |  67 +++++++++++
 .../sun/star/comp/sdbc/classloading/ClassMap.java  |  11 +-
 main/connectivity/qa/complex/sdbc/ToolsTest.java   | 134 +++++++++++++++++++++
 main/connectivity/qa/complex/sdbc/makefile.mk      |  58 +++++++++
 5 files changed, 269 insertions(+), 10 deletions(-)

diff --git 
a/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/ClassMap.java
 
b/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/ClassMap.java
index 6bdd506af2..fc7b93d698 100644
--- 
a/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/ClassMap.java
+++ 
b/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/ClassMap.java
@@ -21,7 +21,6 @@
 package com.sun.star.comp.sdbc;
 
 import java.lang.ref.WeakReference;
-import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
@@ -86,7 +85,7 @@ public class ClassMap {
     private final LinkedList<ClassMapEntry> map = new LinkedList<>();
 
     public synchronized ClassLoaderAndClass loadClass(XComponentContext 
context, String classPath, String className)
-            throws MalformedURLException, ClassNotFoundException {
+            throws ClassNotFoundException {
 
         ClassLoader classLoader = null;
         Class<?> classObject = null;
@@ -130,7 +129,7 @@ public class ClassMap {
         return new ClassLoaderAndClass(classLoader, classObject);
     }
 
-    private static List<URL> translateToUrls(XComponentContext context, String 
classPath) throws MalformedURLException {
+    private static List<URL> translateToUrls(XComponentContext context, String 
classPath) {
         StringTokenizer tokenizer = new StringTokenizer(classPath, " ", false);
         ArrayList<URL> urls = new ArrayList<>();
         while (tokenizer.hasMoreTokens()) {
@@ -159,8 +158,8 @@ public class ClassMap {
                 CompHelper.disposeComponent(expUrl);
                 CompHelper.disposeComponent(macroExpander);
             }
-            URL javaURL = new URL(url);
-            urls.add(javaURL);
+            // Add local entries to classpath
+            Tools.addClassPathURL(urls, url);
         }
         return urls;
     }
diff --git 
a/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/Tools.java
 
b/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/Tools.java
index 49cb07cb0f..9725949b32 100644
--- 
a/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/Tools.java
+++ 
b/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/Tools.java
@@ -20,6 +20,16 @@
  *************************************************************/
 package com.sun.star.comp.sdbc;
 
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
 import 
org.apache.openoffice.comp.sdbc.dbtools.comphelper.ResourceBasedEventLogger;
 import org.apache.openoffice.comp.sdbc.dbtools.util.StandardSQLState;
 
@@ -34,6 +44,17 @@ import com.sun.star.uno.AnyConverter;
 public class Tools {
     private static final int MAX_EXCEPTION_NESTING = 8;
 
+    private static final Logger LOGGER = 
Logger.getLogger(Tools.class.getName());
+
+    /**
+     * URL schemes that resolve to the local filesystem or the running JVM 
image.
+     *
+     * <p>jvmaccess/source/classpath.cxx enforces the same allow-list in C++ 
for
+     * the UNO bootstrap class path; keep the two in sync.</p>
+     */
+    private static final Set<String> LOCAL_PROTOCOLS =
+            Collections.unmodifiableSet(new HashSet<>(Arrays.asList("file", 
"jrt", "jmod")));
+
     public static SQLException toUnoException(Object source, Throwable 
throwable) {
         return toUnoException(source, throwable, 0);
     }
@@ -128,4 +149,50 @@ public class Tools {
         }
         return ret;
     }
+
+    /**
+     * Appends a class path entry to the list of URLs used to build a class 
loader.
+     *
+     * <p>Only local entries or a jar: wrapping a local entry are added.
+     * A malformed or non-local entry is logged and skipped.</p>
+     *
+     * @param urls the list of class path URLs to append to
+     * @param url  the class path entry to parse and validate
+     */
+    public static void addClassPathURL(Collection<URL> urls, String url) {
+        URL javaURL;
+        String protocol;
+        try {
+            javaURL = new URL(url);
+            protocol = getEffectiveProtocol(javaURL);
+        } catch (MalformedURLException e) {
+            LOGGER.log(Level.WARNING, e, () -> "Skipping malformed class path 
entry: " + url);
+            return;
+        }
+        if (LOCAL_PROTOCOLS.contains(protocol)) {
+            LOGGER.fine(() -> "Adding class path entry: " + url);
+            urls.add(javaURL);
+        } else {
+            LOGGER.warning(() -> "Skipping non-local class path entry: " + 
url);
+        }
+    }
+
+    /**
+     * Returns the scheme that actually locates the resource.
+     *
+     * <p>Since {@code jar:} only wraps another URL, the scheme of that 
wrapped URL is returned.
+     * For any other URL its own scheme is returned.</p>
+     *
+     * @param url the class path URL to inspect
+     * @return the effective URL scheme
+     * @throws MalformedURLException if the wrapped jar: URL cannot be parsed
+     */
+    private static String getEffectiveProtocol(URL url) throws 
MalformedURLException {
+        if (!"jar".equals(url.getProtocol())) {
+            return url.getProtocol();
+        }
+        String path = url.getPath();
+        int separator = path.lastIndexOf("!/");
+        return new URL(separator == -1 ? path : path.substring(0, 
separator)).getProtocol();
+    }
 }
diff --git 
a/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/classloading/ClassMap.java
 
b/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/classloading/ClassMap.java
index b8a03af528..13bf139a93 100644
--- 
a/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/classloading/ClassMap.java
+++ 
b/main/connectivity/java/sdbc_jdbc/src/main/java/com/sun/star/comp/sdbc/classloading/ClassMap.java
@@ -21,7 +21,6 @@
 package com.sun.star.comp.sdbc.classloading;
 
 import java.lang.ref.WeakReference;
-import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
@@ -32,6 +31,8 @@ import java.util.StringTokenizer;
 
 import org.apache.openoffice.comp.sdbc.dbtools.comphelper.CompHelper;
 
+import com.sun.star.comp.sdbc.Tools;
+
 import com.sun.star.lang.IllegalArgumentException;
 import com.sun.star.uno.RuntimeException;
 import com.sun.star.uno.UnoRuntime;
@@ -69,7 +70,7 @@ public class ClassMap {
     private final LinkedList<ClassMapEntry> map = new LinkedList<>();
 
     public synchronized ClassLoaderAndClass loadClass(XComponentContext 
context, String classPath, String className)
-            throws MalformedURLException, ClassNotFoundException {
+            throws ClassNotFoundException {
 
         ClassLoader classLoader = null;
         Class<?> classObject = null;
@@ -113,7 +114,7 @@ public class ClassMap {
         return new ClassLoaderAndClass(classLoader, classObject);
     }
 
-    private static List<URL> translateToUrls(XComponentContext context, String 
classPath) throws MalformedURLException {
+    private static List<URL> translateToUrls(XComponentContext context, String 
classPath) {
         StringTokenizer tokenizer = new StringTokenizer(classPath, " ", false);
         ArrayList<URL> urls = new ArrayList<>();
         while (tokenizer.hasMoreTokens()) {
@@ -142,8 +143,8 @@ public class ClassMap {
                 CompHelper.disposeComponent(expUrl);
                 CompHelper.disposeComponent(macroExpander);
             }
-            URL javaURL = new URL(url);
-            urls.add(javaURL);
+            // Add local entries to classpath
+            Tools.addClassPathURL(urls, url);
         }
         return urls;
     }
diff --git a/main/connectivity/qa/complex/sdbc/ToolsTest.java 
b/main/connectivity/qa/complex/sdbc/ToolsTest.java
new file mode 100644
index 0000000000..3e5d1a9f85
--- /dev/null
+++ b/main/connectivity/qa/complex/sdbc/ToolsTest.java
@@ -0,0 +1,134 @@
+/**************************************************************
+ *
+ * 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 complex.sdbc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assume;
+import org.junit.Test;
+
+import com.sun.star.comp.sdbc.Tools;
+
+/**
+ * Tests for the {@link Tools} helper class.
+ */
+public final class ToolsTest {
+
+    /** Runs each entry through addClassPathURL and returns what was accepted. 
*/
+    private static List<URL> collect(String... entries) {
+        List<URL> urls = new ArrayList<URL>();
+        for (String entry : entries) {
+            Tools.addClassPathURL(urls, entry);
+        }
+        return urls;
+    }
+
+    /** True if the running JRE has a URL stream handler for the given scheme. 
*/
+    private static boolean schemeSupported(String scheme) {
+        try {
+            new URL(scheme + ":/probe");
+            return true;
+        } catch (MalformedURLException e) {
+            return false;
+        }
+    }
+
+    @Test
+    public void testAddClassPathURLAddsLocalFileEntry() {
+        List<URL> urls = collect("file:/opt/a.jar");
+        assertEquals(1, urls.size());
+        assertEquals("file", urls.get(0).getProtocol());
+    }
+
+    @Test
+    public void testAddClassPathURLAddsJarWrappedLocalFile() {
+        assertEquals(1, collect("jar:file:/opt/a.jar!/").size());
+    }
+
+    @Test
+    public void testAddClassPathURLTreatsJarInnerSchemeCaseInsensitively() {
+        // URL.getPath() does not normalize the wrapped URL.
+        assertEquals(1, collect("jar:FILE:/opt/a.jar!/").size());
+    }
+
+    @Test
+    public void testAddClassPathURLSkipsRemoteEntries() {
+        assertTrue(collect(
+                "http://host/a.jar";,
+                "https://host/b.jar";,
+                "ftp://host/c.jar";).isEmpty());
+    }
+
+    @Test
+    public void testAddClassPathURLSkipsJarWrappedRemoteEntry() {
+        assertTrue(collect("jar:http://host/a.jar!/";).isEmpty());
+    }
+
+    @Test
+    public void testAddClassPathURLSkipsMalformedEntry() {
+        assertTrue(collect("::not-a-url::").isEmpty());
+    }
+
+    @Test
+    public void testAddClassPathURLSkipsUnknownScheme() {
+        // A scheme with no registered URL handler cannot be constructed, so 
the
+        // entry is treated as malformed and skipped.
+        assertTrue(collect(
+                "wibble:/opt/a.jar",
+                "classpath:/opt/b.jar",
+                "foo://host/c.jar").isEmpty());
+    }
+
+    @Test
+    public void testAddClassPathURLSkipsJarWrappedUnknownScheme() {
+        assertTrue(collect("jar:wibble:/opt/a.jar!/").isEmpty());
+    }
+
+    @Test
+    public void testAddClassPathURLKeepsOnlyLocalEntriesInOrder() {
+        List<URL> urls = collect(
+                "http://host/a.jar";,
+                "file:/opt/b.jar",
+                "jar:http://host/c.jar!/";,
+                "file:/opt/d.jar");
+        assertEquals(2, urls.size());
+        assertEquals("/opt/b.jar", urls.get(0).getPath());
+        assertEquals("/opt/d.jar", urls.get(1).getPath());
+    }
+
+    @Test
+    public void testAddClassPathURLAddsJrtSchemeWhenSupported() {
+        Assume.assumeTrue(schemeSupported("jrt"));
+        assertEquals(1, collect("jrt:/java.base/module-info.class").size());
+    }
+
+    @Test
+    public void testAddClassPathURLAddsJmodSchemeWhenSupported() {
+        Assume.assumeTrue(schemeSupported("jmod"));
+        assertEquals(1, collect("jmod:/x").size());
+    }
+}
diff --git a/main/connectivity/qa/complex/sdbc/makefile.mk 
b/main/connectivity/qa/complex/sdbc/makefile.mk
new file mode 100644
index 0000000000..64c1d0cffa
--- /dev/null
+++ b/main/connectivity/qa/complex/sdbc/makefile.mk
@@ -0,0 +1,58 @@
+#**************************************************************
+#
+#  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.
+#
+#**************************************************************
+
+
+.IF "$(OOO_SUBSEQUENT_TESTS)" == ""
+nothing .PHONY:
+.ELSE
+
+PRJ = ..$/..$/..
+PRJNAME = connectivity
+TARGET  = SdbcToolsTest
+
+.IF "$(OOO_JUNIT_JAR)" != ""
+PACKAGE = complex$/sdbc
+
+# here store only Files which contain a @Test
+JAVATESTFILES = \
+    ToolsTest.java
+
+# put here all other files
+JAVAFILES = $(JAVATESTFILES)
+
+# The class under test lives in sdbc_jdbc.jar; dbtools.jar supplies the two
+# helper types Tools references (ResourceBasedEventLogger, StandardSQLState),
+# so that com.sun.star.comp.sdbc.Tools can be loaded and verified.
+JARFILES = ridl.jar unoil.jar jurt.jar juh.jar java_uno.jar dbtools.jar 
sdbc_jdbc.jar
+EXTRAJARFILES = $(OOO_JUNIT_JAR)
+
+# Sample how to debug
+# JAVAIFLAGS+=-Xdebug  
-Xrunjdwp:transport=dt_socket,server=y,address=9003,suspend=y
+
+.END
+
+.INCLUDE: settings.mk
+.INCLUDE: target.mk
+.INCLUDE: installationtest.mk
+
+ALLTAR : javatest
+
+.END

Reply via email to