connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/JavaSQLConnection.java | 3 connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/classloading/ClassLoaderAndClass.java | 46 +++ connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/classloading/ClassMap.java | 150 ++++++++++ 3 files changed, 198 insertions(+), 1 deletion(-)
New commits: commit 40424188a15d5253b23ff5a7f96a472ffa899534 Author: Damjan Jovanovic <dam...@apache.org> AuthorDate: Mon Dec 3 17:03:12 2018 +0000 Commit: Damjan Jovanovic <dam...@apache.org> CommitDate: Mon Dec 3 17:03:12 2018 +0000 Refactor classloading in the postgresql driver. Patch by: me diff --git a/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/JavaSQLConnection.java b/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/JavaSQLConnection.java index f4fb4298ae6f..7535cb6f67b1 100644 --- a/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/JavaSQLConnection.java +++ b/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/JavaSQLConnection.java @@ -20,6 +20,7 @@ *************************************************************/ package com.sun.star.comp.sdbc; +import com.sun.star.comp.sdbc.classloading.ClassMap; import java.util.Iterator; import java.util.Properties; @@ -31,7 +32,7 @@ import org.apache.openoffice.comp.sdbc.dbtools.util.StandardSQLState; import com.sun.star.beans.NamedValue; import com.sun.star.beans.PropertyValue; -import com.sun.star.comp.sdbc.ClassMap.ClassLoaderAndClass; +import com.sun.star.comp.sdbc.classloading.ClassLoaderAndClass; import com.sun.star.comp.sdbc.ConnectionLog.ObjectType; import com.sun.star.container.XNameAccess; import com.sun.star.lang.IllegalArgumentException; diff --git a/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/classloading/ClassLoaderAndClass.java b/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/classloading/ClassLoaderAndClass.java new file mode 100644 index 000000000000..c3946c8c5bd9 --- /dev/null +++ b/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/classloading/ClassLoaderAndClass.java @@ -0,0 +1,46 @@ +/************************************************************** + * + * 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 com.sun.star.comp.sdbc.classloading; + +/** + * + * @author dacha + */ +public class ClassLoaderAndClass { + + private final ClassLoader classLoader; + private final Class<?> classObject; + + public ClassLoaderAndClass(ClassLoader classLoader, Class<?> classObject) { + this.classLoader = classLoader; + this.classObject = classObject; + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + public Class<?> getClassObject() { + return classObject; + } + +} diff --git a/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/classloading/ClassMap.java b/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/classloading/ClassMap.java new file mode 100644 index 000000000000..b8a03af52858 --- /dev/null +++ b/connectivity/java/sdbc_jdbc/src/com/sun/star/comp/sdbc/classloading/ClassMap.java @@ -0,0 +1,150 @@ +/************************************************************** + * + * 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 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; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.openoffice.comp.sdbc.dbtools.comphelper.CompHelper; + +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.uno.RuntimeException; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import com.sun.star.uri.UriReferenceFactory; +import com.sun.star.uri.XUriReferenceFactory; +import com.sun.star.uri.XVndSunStarExpandUrlReference; +import com.sun.star.util.XMacroExpander; + +/** + * A map from pairs of (classPath, name) to pairs of weak Java + * references to (ClassLoader, Class) is maintained, so that a class is only + * loaded once. + * + * It may happen that the weak reference to the ClassLoader becomes null while + * the reference to the Class remains non-null (in case the Class was actually + * loaded by some parent of the ClassLoader), in which case the ClassLoader is + * resurrected (which cannot cause any classes to be loaded multiple times, as + * the ClassLoader is no longer reachable, so no classes it has ever loaded are + * still reachable). + * + * Similarly, it may happen that the weak reference to the Class becomes null + * while the reference to the ClassLoader remains non-null, in which case the + * Class is simply re-loaded. + */ +public class ClassMap { + + private static class ClassMapEntry { + String classPath; + String className; + WeakReference<ClassLoader> classLoader; + WeakReference<Class<?>> classObject; + } + + private final LinkedList<ClassMapEntry> map = new LinkedList<>(); + + public synchronized ClassLoaderAndClass loadClass(XComponentContext context, String classPath, String className) + throws MalformedURLException, ClassNotFoundException { + + ClassLoader classLoader = null; + Class<?> classObject = null; + // Prune dangling weak references from the list while searching for a match, + // so that the list cannot grow unbounded: + ClassMapEntry matchingEntry = null; + for (Iterator<ClassMapEntry> it = map.iterator(); it.hasNext();) { + ClassMapEntry entry = it.next(); + classLoader = entry.classLoader.get(); + classObject = entry.classObject.get(); + if (classLoader == null && classObject == null) { + it.remove(); + } else if (entry.classPath.equals(classPath) && entry.className.equals(className)) { + matchingEntry = entry; + break; + } + } + if (classLoader == null || classObject == null) { + if (matchingEntry == null) { + // Push a new ClassMapEntry (which can potentially fail) before + // loading the class, so that it never happens that a class is + // loaded but not added to the map (which could have effects on the + // JVM that are not easily undone). If the pushed ClassMapEntry is + // not used after all (return false, etc.) it will be pruned on next + // call because its classLoader/classObject are null: + matchingEntry = new ClassMapEntry(); + matchingEntry.classPath = classPath; + matchingEntry.className = className; + map.addFirst(matchingEntry); + } + if (classLoader == null) { + List<URL> urls = translateToUrls(context, classPath); + classLoader = new URLClassLoader(urls.toArray(new URL[0])); + } + if (classObject == null) { + classObject = classLoader.loadClass(className); + } + matchingEntry.classLoader = new WeakReference<ClassLoader>(classLoader); + matchingEntry.classObject = new WeakReference<Class<?>>(classObject); + } + return new ClassLoaderAndClass(classLoader, classObject); + } + + private static List<URL> translateToUrls(XComponentContext context, String classPath) throws MalformedURLException { + StringTokenizer tokenizer = new StringTokenizer(classPath, " ", false); + ArrayList<URL> urls = new ArrayList<>(); + while (tokenizer.hasMoreTokens()) { + String url = tokenizer.nextToken(); + XUriReferenceFactory uriReferenceFactory = null; + XVndSunStarExpandUrlReference expUrl = null; + XMacroExpander macroExpander = null; + try { + uriReferenceFactory = UriReferenceFactory.create(context); + expUrl = UnoRuntime.queryInterface( + XVndSunStarExpandUrlReference.class, uriReferenceFactory.parse(url)); + if (expUrl != null) { + macroExpander = UnoRuntime.queryInterface( + XMacroExpander.class, + context.getValueByName("/singletons/com.sun.star.util.theMacroExpander")); + try { + url = expUrl.expand(macroExpander); + } catch (IllegalArgumentException illegalArgumentException) { + throw new RuntimeException( + "com.sun.star.lang.IllegalArgumentException: " + illegalArgumentException.getMessage(), + illegalArgumentException); + } + } + } finally { + CompHelper.disposeComponent(uriReferenceFactory); + CompHelper.disposeComponent(expUrl); + CompHelper.disposeComponent(macroExpander); + } + URL javaURL = new URL(url); + urls.add(javaURL); + } + return urls; + } +} _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits