summaryrefslogtreecommitdiffstats
path: root/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java')
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java348
1 files changed, 0 insertions, 348 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java
deleted file mode 100644
index 863ef3f197..0000000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright (C) 2014 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.server.plugins;
-
-import static com.google.common.base.MoreObjects.firstNonNull;
-import static com.google.common.collect.Iterables.transform;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.MultimapBuilder;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import org.eclipse.jgit.util.IO;
-import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.Attribute;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class JarScanner implements PluginContentScanner, AutoCloseable {
- private static final Logger log = LoggerFactory.getLogger(JarScanner.class);
- private static final int SKIP_ALL =
- ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES;
- private final JarFile jarFile;
-
- public JarScanner(Path src) throws IOException {
- this.jarFile = new JarFile(src.toFile());
- }
-
- @Override
- public Map<Class<? extends Annotation>, Iterable<ExtensionMetaData>> scan(
- String pluginName, Iterable<Class<? extends Annotation>> annotations)
- throws InvalidPluginException {
- Set<String> descriptors = new HashSet<>();
- ListMultimap<String, JarScanner.ClassData> rawMap =
- MultimapBuilder.hashKeys().arrayListValues().build();
- Map<Class<? extends Annotation>, String> classObjToClassDescr = new HashMap<>();
-
- for (Class<? extends Annotation> annotation : annotations) {
- String descriptor = Type.getType(annotation).getDescriptor();
- descriptors.add(descriptor);
- classObjToClassDescr.put(annotation, descriptor);
- }
-
- Enumeration<JarEntry> e = jarFile.entries();
- while (e.hasMoreElements()) {
- JarEntry entry = e.nextElement();
- if (skip(entry)) {
- continue;
- }
-
- ClassData def = new ClassData(descriptors);
- try {
- new ClassReader(read(jarFile, entry)).accept(def, SKIP_ALL);
- } catch (IOException err) {
- throw new InvalidPluginException("Cannot auto-register", err);
- } catch (RuntimeException err) {
- log.warn(
- "Plugin {} has invalid class file {} inside of {}",
- pluginName,
- entry.getName(),
- jarFile.getName(),
- err);
- continue;
- }
-
- if (!Strings.isNullOrEmpty(def.annotationName)) {
- if (def.isConcrete()) {
- rawMap.put(def.annotationName, def);
- } else {
- log.warn(
- "Plugin {} tries to @{}(\"{}\") abstract class {}",
- pluginName,
- def.annotationName,
- def.annotationValue,
- def.className);
- }
- }
- }
-
- ImmutableMap.Builder<Class<? extends Annotation>, Iterable<ExtensionMetaData>> result =
- ImmutableMap.builder();
-
- for (Class<? extends Annotation> annotoation : annotations) {
- String descr = classObjToClassDescr.get(annotoation);
- Collection<ClassData> discoverdData = rawMap.get(descr);
- Collection<ClassData> values = firstNonNull(discoverdData, Collections.<ClassData>emptySet());
-
- result.put(
- annotoation,
- transform(values, cd -> new ExtensionMetaData(cd.className, cd.annotationValue)));
- }
-
- return result.build();
- }
-
- public List<String> findSubClassesOf(Class<?> superClass) throws IOException {
- return findSubClassesOf(superClass.getName());
- }
-
- @Override
- public void close() throws IOException {
- jarFile.close();
- }
-
- private List<String> findSubClassesOf(String superClass) throws IOException {
- String name = superClass.replace('.', '/');
-
- List<String> classes = new ArrayList<>();
- Enumeration<JarEntry> e = jarFile.entries();
- while (e.hasMoreElements()) {
- JarEntry entry = e.nextElement();
- if (skip(entry)) {
- continue;
- }
-
- ClassData def = new ClassData(Collections.<String>emptySet());
- try {
- new ClassReader(read(jarFile, entry)).accept(def, SKIP_ALL);
- } catch (RuntimeException err) {
- log.warn("Jar {} has invalid class file {}", jarFile.getName(), entry.getName(), err);
- continue;
- }
-
- if (name.equals(def.superName)) {
- classes.addAll(findSubClassesOf(def.className));
- if (def.isConcrete()) {
- classes.add(def.className);
- }
- }
- }
-
- return classes;
- }
-
- private static boolean skip(JarEntry entry) {
- if (!entry.getName().endsWith(".class")) {
- return true; // Avoid non-class resources.
- }
- if (entry.getSize() <= 0) {
- return true; // Directories have 0 size.
- }
- if (entry.getSize() >= 1024 * 1024) {
- return true; // Do not scan huge class files.
- }
- return false;
- }
-
- private static byte[] read(JarFile jarFile, JarEntry entry) throws IOException {
- byte[] data = new byte[(int) entry.getSize()];
- try (InputStream in = jarFile.getInputStream(entry)) {
- IO.readFully(in, data, 0, data.length);
- }
- return data;
- }
-
- public static class ClassData extends ClassVisitor {
- int access;
- String className;
- String superName;
- String annotationName;
- String annotationValue;
- String[] interfaces;
- Collection<String> exports;
-
- private ClassData(Collection<String> exports) {
- super(Opcodes.ASM5);
- this.exports = exports;
- }
-
- boolean isConcrete() {
- return (access & Opcodes.ACC_ABSTRACT) == 0 && (access & Opcodes.ACC_INTERFACE) == 0;
- }
-
- @Override
- public void visit(
- int version,
- int access,
- String name,
- String signature,
- String superName,
- String[] interfaces) {
- this.className = Type.getObjectType(name).getClassName();
- this.access = access;
- this.superName = superName;
- }
-
- @Override
- public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- if (!visible) {
- return null;
- }
- Optional<String> found = exports.stream().filter(x -> x.equals(desc)).findAny();
- if (found.isPresent()) {
- annotationName = desc;
- return new AbstractAnnotationVisitor() {
- @Override
- public void visit(String name, Object value) {
- annotationValue = (String) value;
- }
- };
- }
- return null;
- }
-
- @Override
- public void visitSource(String arg0, String arg1) {}
-
- @Override
- public void visitOuterClass(String arg0, String arg1, String arg2) {}
-
- @Override
- public MethodVisitor visitMethod(
- int arg0, String arg1, String arg2, String arg3, String[] arg4) {
- return null;
- }
-
- @Override
- public void visitInnerClass(String arg0, String arg1, String arg2, int arg3) {}
-
- @Override
- public FieldVisitor visitField(int arg0, String arg1, String arg2, String arg3, Object arg4) {
- return null;
- }
-
- @Override
- public void visitEnd() {}
-
- @Override
- public void visitAttribute(Attribute arg0) {}
- }
-
- private abstract static class AbstractAnnotationVisitor extends AnnotationVisitor {
- AbstractAnnotationVisitor() {
- super(Opcodes.ASM5);
- }
-
- @Override
- public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
- return null;
- }
-
- @Override
- public AnnotationVisitor visitArray(String arg0) {
- return null;
- }
-
- @Override
- public void visitEnum(String arg0, String arg1, String arg2) {}
-
- @Override
- public void visitEnd() {}
- }
-
- @Override
- public Optional<PluginEntry> getEntry(String resourcePath) throws IOException {
- JarEntry jarEntry = jarFile.getJarEntry(resourcePath);
- if (jarEntry == null || jarEntry.getSize() == 0) {
- return Optional.empty();
- }
-
- return Optional.of(resourceOf(jarEntry));
- }
-
- @Override
- public Enumeration<PluginEntry> entries() {
- return Collections.enumeration(
- Lists.transform(
- Collections.list(jarFile.entries()),
- jarEntry -> {
- try {
- return resourceOf(jarEntry);
- } catch (IOException e) {
- throw new IllegalArgumentException(
- "Cannot convert jar entry " + jarEntry + " to a resource", e);
- }
- }));
- }
-
- @Override
- public InputStream getInputStream(PluginEntry entry) throws IOException {
- return jarFile.getInputStream(jarFile.getEntry(entry.getName()));
- }
-
- @Override
- public Manifest getManifest() throws IOException {
- return jarFile.getManifest();
- }
-
- private PluginEntry resourceOf(JarEntry jarEntry) throws IOException {
- return new PluginEntry(
- jarEntry.getName(),
- jarEntry.getTime(),
- Optional.of(jarEntry.getSize()),
- attributesOf(jarEntry));
- }
-
- private Map<Object, String> attributesOf(JarEntry jarEntry) throws IOException {
- Attributes attributes = jarEntry.getAttributes();
- if (attributes == null) {
- return Collections.emptyMap();
- }
- return Maps.transformEntries(
- attributes,
- new Maps.EntryTransformer<Object, Object, String>() {
- @Override
- public String transformEntry(Object key, Object value) {
- return (String) value;
- }
- });
- }
-}