Merge changes I93022cb7,I4b32d082
* changes:
Rearrange code to avoid dependency on GerritClassLoader internally.
Revert "Revert "Use custom gerrit class loader to avoid usage of reflection""
diff --git a/java/com/google/gerrit/common/BUILD b/java/com/google/gerrit/common/BUILD
index 1099919..8f930bb 100644
--- a/java/com/google/gerrit/common/BUILD
+++ b/java/com/google/gerrit/common/BUILD
@@ -23,6 +23,7 @@
":annotations",
"//java/com/google/gerrit/entities",
"//java/com/google/gerrit/extensions:api",
+ "//java/com/google/gerrit/launcher",
"//java/com/google/gerrit/prettify:server",
"//lib:guava",
"//lib:jgit",
diff --git a/java/com/google/gerrit/common/IoUtil.java b/java/com/google/gerrit/common/IoUtil.java
index 09a8993..e51a6e5 100644
--- a/java/com/google/gerrit/common/IoUtil.java
+++ b/java/com/google/gerrit/common/IoUtil.java
@@ -14,20 +14,9 @@
package com.google.gerrit.common;
-import com.google.common.collect.Sets;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
public final class IoUtil {
public static void copyWithThread(InputStream src, OutputStream dst) {
@@ -64,50 +53,5 @@
}.start();
}
- public static void loadJARs(Collection<Path> jars) {
- if (jars.isEmpty()) {
- return;
- }
-
- ClassLoader cl = IoUtil.class.getClassLoader();
- if (!(cl instanceof URLClassLoader)) {
- throw noAddURL("Not loaded by URLClassLoader", null);
- }
-
- @SuppressWarnings("resource") // Leave open so classes can be loaded.
- URLClassLoader urlClassLoader = (URLClassLoader) cl;
-
- Method addURL;
- try {
- addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
- addURL.setAccessible(true);
- } catch (SecurityException | NoSuchMethodException e) {
- throw noAddURL("Method addURL not available", e);
- }
-
- Set<URL> have = Sets.newHashSet(Arrays.asList(urlClassLoader.getURLs()));
- for (Path path : jars) {
- try {
- URL url = path.toUri().toURL();
- if (have.add(url)) {
- addURL.invoke(cl, url);
- }
- } catch (MalformedURLException | IllegalArgumentException | IllegalAccessException e) {
- throw noAddURL("addURL " + path + " failed", e);
- } catch (InvocationTargetException e) {
- throw noAddURL("addURL " + path + " failed", e.getCause());
- }
- }
- }
-
- public static void loadJARs(Path jar) {
- loadJARs(Collections.singleton(jar));
- }
-
- private static UnsupportedOperationException noAddURL(String m, Throwable why) {
- String prefix = "Cannot extend classpath: ";
- return new UnsupportedOperationException(prefix + m, why);
- }
-
private IoUtil() {}
}
diff --git a/java/com/google/gerrit/common/JarUtil.java b/java/com/google/gerrit/common/JarUtil.java
new file mode 100644
index 0000000..b88a7ab
--- /dev/null
+++ b/java/com/google/gerrit/common/JarUtil.java
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed 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.google.gerrit.common;
+
+import com.google.common.collect.Sets;
+import com.google.gerrit.launcher.GerritLauncher.GerritClassLoader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+/** Provides util methods for dynamic loading jars */
+public final class JarUtil {
+ public static void loadJars(Collection<Path> jars) {
+ if (jars.isEmpty()) {
+ return;
+ }
+
+ ClassLoader cl = JarUtil.class.getClassLoader();
+ if (!(cl instanceof GerritClassLoader)) {
+ throw noAddURL("Not loaded by GerritClassLoader", null);
+ }
+
+ @SuppressWarnings("resource") // Leave open so classes can be loaded.
+ GerritClassLoader gerritClassLoader = (GerritClassLoader) cl;
+
+ Set<URL> have = Sets.newHashSet(Arrays.asList(gerritClassLoader.getURLs()));
+ for (Path path : jars) {
+ try {
+ URL url = path.toUri().toURL();
+ if (have.add(url)) {
+ gerritClassLoader.addURL(url);
+ }
+ } catch (MalformedURLException | IllegalArgumentException e) {
+ throw noAddURL("addURL " + path + " failed", e);
+ }
+ }
+ }
+
+ public static void loadJars(Path jar) {
+ loadJars(Collections.singleton(jar));
+ }
+
+ private static UnsupportedOperationException noAddURL(String m, Throwable why) {
+ String prefix = "Cannot extend classpath: ";
+ return new UnsupportedOperationException(prefix + m, why);
+ }
+
+ private JarUtil() {}
+}
diff --git a/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java b/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java
index fa9b139..95df5be 100644
--- a/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java
+++ b/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java
@@ -35,7 +35,7 @@
public static void loadSiteLib(Path libdir) {
try {
List<Path> jars = listJars(libdir);
- IoUtil.loadJARs(jars);
+ JarUtil.loadJars(jars);
logger.atFine().log("Loaded site libraries: %s", lazy(() -> jarList(jars)));
} catch (IOException e) {
logger.atSevere().withCause(e).log("Error scanning lib directory %s", libdir);
diff --git a/java/com/google/gerrit/httpd/raw/SiteStaticDirectoryServlet.java b/java/com/google/gerrit/httpd/raw/SiteStaticDirectoryServlet.java
index 594415a..bdc4f65 100644
--- a/java/com/google/gerrit/httpd/raw/SiteStaticDirectoryServlet.java
+++ b/java/com/google/gerrit/httpd/raw/SiteStaticDirectoryServlet.java
@@ -35,7 +35,7 @@
SiteStaticDirectoryServlet(
SitePaths site,
@GerritServerConfig Config cfg,
- @Named(StaticModule.CACHE) Cache<Path, Resource> cache) {
+ @Named(StaticModuleConstants.CACHE) Cache<Path, Resource> cache) {
super(cache, cfg.getBoolean("site", "refreshHeaderFooter", true));
Path p;
try {
diff --git a/java/com/google/gerrit/httpd/raw/StaticModule.java b/java/com/google/gerrit/httpd/raw/StaticModule.java
index 8319d9d..3c8287f 100644
--- a/java/com/google/gerrit/httpd/raw/StaticModule.java
+++ b/java/com/google/gerrit/httpd/raw/StaticModule.java
@@ -14,6 +14,8 @@
package com.google.gerrit.httpd.raw;
+import static com.google.gerrit.httpd.raw.StaticModuleConstants.CACHE;
+import static com.google.gerrit.httpd.raw.StaticModuleConstants.POLYGERRIT_INDEX_PATHS;
import static java.nio.file.Files.exists;
import static java.nio.file.Files.isReadable;
@@ -60,28 +62,6 @@
public class StaticModule extends ServletModule {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- public static final String CACHE = "static_content";
-
- /**
- * Paths at which we should serve the main PolyGerrit application {@code index.html}.
- *
- * <p>Supports {@code "/*"} as a trailing wildcard.
- */
- public static final ImmutableList<String> POLYGERRIT_INDEX_PATHS =
- ImmutableList.of(
- "/",
- "/c/*",
- "/id/*",
- "/p/*",
- "/q/*",
- "/x/*",
- "/admin/*",
- "/dashboard/*",
- "/profile/*",
- "/groups/self",
- "/settings/*",
- "/Documentation/q/*");
-
/**
* Paths that should be treated as static assets when serving PolyGerrit.
*
diff --git a/java/com/google/gerrit/httpd/raw/StaticModuleConstants.java b/java/com/google/gerrit/httpd/raw/StaticModuleConstants.java
new file mode 100644
index 0000000..23cffa1
--- /dev/null
+++ b/java/com/google/gerrit/httpd/raw/StaticModuleConstants.java
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed 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.google.gerrit.httpd.raw;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Various constants related to {@link StaticModule}
+ *
+ * <p>Methods of the {@link StaticModule} are not used internally in google, so moving public
+ * constants into the {@link StaticModuleConstants} allows to exclude {@link StaticModule} from the
+ * google-hosted gerrit hosts.
+ */
+public final class StaticModuleConstants {
+ public static final String CACHE = "static_content";
+
+ /**
+ * Paths at which we should serve the main PolyGerrit application {@code index.html}.
+ *
+ * <p>Supports {@code "/*"} as a trailing wildcard.
+ */
+ public static final ImmutableList<String> POLYGERRIT_INDEX_PATHS =
+ ImmutableList.of(
+ "/",
+ "/c/*",
+ "/id/*",
+ "/p/*",
+ "/q/*",
+ "/x/*",
+ "/admin/*",
+ "/dashboard/*",
+ "/profile/*",
+ "/groups/self",
+ "/settings/*",
+ "/Documentation/q/*");
+
+ private StaticModuleConstants() {};
+}
diff --git a/java/com/google/gerrit/launcher/GerritLauncher.java b/java/com/google/gerrit/launcher/GerritLauncher.java
index 8783593..07a071a 100644
--- a/java/com/google/gerrit/launcher/GerritLauncher.java
+++ b/java/com/google/gerrit/launcher/GerritLauncher.java
@@ -60,6 +60,33 @@
private static final String PKG = "com.google.gerrit.pgm";
public static final String NOT_ARCHIVED = "NOT_ARCHIVED";
+ // Classloader that allows to add additional jars to the classpath.
+ public static class GerritClassLoader extends URLClassLoader {
+ static {
+ ClassLoader.registerAsParallelCapable();
+ }
+
+ /**
+ * Constructs a new URLClassLoader for the given URLs.
+ *
+ * @param urls the URLs from which to load classes and resources
+ * @param parent the parent class loader for delegation
+ */
+ GerritClassLoader(URL[] urls, ClassLoader parent) {
+ super(urls, parent);
+ }
+
+ /**
+ * Appends the additional URL to the list of URLs to search for classes and resources.
+ *
+ * @param url the URL to be added to the search path of URLs
+ */
+ @Override
+ public void addURL(URL url) {
+ super.addURL(url);
+ }
+ }
+
private static ClassLoader daemonClassLoader;
public static void main(String[] argv) throws Exception {
@@ -308,7 +335,7 @@
if (!extapi.isEmpty()) {
parent = URLClassLoader.newInstance(extapi.toArray(new URL[extapi.size()]), parent);
}
- return URLClassLoader.newInstance(jars.values().toArray(new URL[jars.size()]), parent);
+ return new GerritClassLoader(jars.values().toArray(new URL[jars.size()]), parent);
}
private static void extractJar(ZipFile zf, ZipEntry ze, NavigableMap<String, URL> jars)
diff --git a/java/com/google/gerrit/pgm/SwitchSecureStore.java b/java/com/google/gerrit/pgm/SwitchSecureStore.java
index 6dec2d8..063fcdb 100644
--- a/java/com/google/gerrit/pgm/SwitchSecureStore.java
+++ b/java/com/google/gerrit/pgm/SwitchSecureStore.java
@@ -18,7 +18,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.common.IoUtil;
+import com.google.gerrit.common.JarUtil;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.SiteLibraryLoaderUtil;
import com.google.gerrit.pgm.util.SiteProgram;
@@ -79,7 +79,7 @@
return -1;
}
- IoUtil.loadJARs(newSecureStorePath);
+ JarUtil.loadJars(newSecureStorePath);
SiteLibraryLoaderUtil.loadSiteLib(sitePaths.lib_dir);
logger.atInfo().log(
diff --git a/java/com/google/gerrit/pgm/init/BaseInit.java b/java/com/google/gerrit/pgm/init/BaseInit.java
index b59b924..abaefb2 100644
--- a/java/com/google/gerrit/pgm/init/BaseInit.java
+++ b/java/com/google/gerrit/pgm/init/BaseInit.java
@@ -21,7 +21,7 @@
import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Die;
-import com.google.gerrit.common.IoUtil;
+import com.google.gerrit.common.JarUtil;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.index.IndexType;
@@ -331,7 +331,7 @@
"%s has more that one implementation of %s interface",
secureStore, SecureStore.class.getName()));
}
- IoUtil.loadJARs(secureStoreLib);
+ JarUtil.loadJars(secureStoreLib);
return new SecureStoreInitData(secureStoreLib, secureStores.get(0));
} catch (IOException e) {
throw new InvalidSecureStoreException(String.format("%s is not a valid jar", secureStore), e);