LCOV - code coverage report
Current view: top level - server/plugins - AbstractPreloadedPluginScanner.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 0 51 0.0 %
Date: 2022-11-19 15:00:39 Functions: 0 7 0.0 %

          Line data    Source code
       1             : // Copyright (C) 2014 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.server.plugins;
      16             : 
      17             : import static com.google.common.base.Preconditions.checkState;
      18             : import static java.nio.charset.StandardCharsets.UTF_8;
      19             : 
      20             : import com.google.common.collect.ImmutableMap;
      21             : import com.google.gerrit.extensions.annotations.Export;
      22             : import com.google.gerrit.server.plugins.Plugin.ApiType;
      23             : import com.google.inject.Module;
      24             : import com.google.inject.servlet.ServletModule;
      25             : import java.io.ByteArrayInputStream;
      26             : import java.io.IOException;
      27             : import java.lang.annotation.Annotation;
      28             : import java.lang.reflect.Modifier;
      29             : import java.util.HashSet;
      30             : import java.util.Map;
      31             : import java.util.Set;
      32             : import java.util.jar.Manifest;
      33             : 
      34             : /**
      35             :  * Base plugin scanner for a set of pre-loaded classes.
      36             :  *
      37             :  * <p>Utility base class for simplifying the development of Server plugin scanner based on a set of
      38             :  * externally pre-loaded classes.
      39             :  *
      40             :  * <p>Extending this class you can implement very easily a PluginContentScanner from a set of
      41             :  * pre-loaded Java Classes and an API Type. The convention used by this class is: - there is at most
      42             :  * one Guice module per Gerrit module type (SysModule, HttpModule, SshModule) - plugin is set to be
      43             :  * restartable in Gerrit Plugin MANIFEST - only Export and Listen annotated classes can be
      44             :  * self-discovered
      45             :  */
      46             : public abstract class AbstractPreloadedPluginScanner implements PluginContentScanner {
      47             :   protected final String pluginName;
      48             :   protected final String pluginVersion;
      49             :   protected final Set<Class<?>> preloadedClasses;
      50             :   protected final ApiType apiType;
      51             : 
      52             :   private Class<?> sshModuleClass;
      53             :   private Class<?> httpModuleClass;
      54             :   private Class<?> sysModuleClass;
      55             : 
      56             :   public AbstractPreloadedPluginScanner(
      57             :       String pluginName,
      58             :       String pluginVersion,
      59             :       Set<Class<?>> preloadedClasses,
      60           0 :       Plugin.ApiType apiType) {
      61           0 :     this.pluginName = pluginName;
      62           0 :     this.pluginVersion = pluginVersion;
      63           0 :     this.preloadedClasses = preloadedClasses;
      64           0 :     this.apiType = apiType;
      65           0 :   }
      66             : 
      67             :   @Override
      68             :   public Manifest getManifest() throws IOException {
      69           0 :     scanGuiceModules(preloadedClasses);
      70           0 :     StringBuilder manifestString =
      71             :         new StringBuilder(
      72             :             "PluginName: "
      73             :                 + pluginName
      74             :                 + "\n"
      75             :                 + "Implementation-Version: "
      76             :                 + pluginVersion
      77             :                 + "\n"
      78             :                 + "Gerrit-ReloadMode: restart\n"
      79             :                 + "Gerrit-ApiType: "
      80             :                 + apiType
      81             :                 + "\n");
      82           0 :     appendIfNotNull(manifestString, "Gerrit-SshModule: ", sshModuleClass);
      83           0 :     appendIfNotNull(manifestString, "Gerrit-HttpModule: ", httpModuleClass);
      84           0 :     appendIfNotNull(manifestString, "Gerrit-Module: ", sysModuleClass);
      85           0 :     return new Manifest(new ByteArrayInputStream(manifestString.toString().getBytes(UTF_8)));
      86             :   }
      87             : 
      88             :   @Override
      89             :   public Map<Class<? extends Annotation>, Iterable<ExtensionMetaData>> scan(
      90             :       String pluginName, Iterable<Class<? extends Annotation>> annotations)
      91             :       throws InvalidPluginException {
      92             :     ImmutableMap.Builder<Class<? extends Annotation>, Iterable<ExtensionMetaData>> result =
      93           0 :         ImmutableMap.builder();
      94             : 
      95           0 :     for (Class<? extends Annotation> annotation : annotations) {
      96           0 :       Set<ExtensionMetaData> classMetaDataSet = new HashSet<>();
      97           0 :       result.put(annotation, classMetaDataSet);
      98             : 
      99           0 :       for (Class<?> clazz : preloadedClasses) {
     100           0 :         if (!Modifier.isAbstract(clazz.getModifiers()) && clazz.getAnnotation(annotation) != null) {
     101           0 :           classMetaDataSet.add(
     102           0 :               new ExtensionMetaData(clazz.getName(), getExportAnnotationValue(clazz, annotation)));
     103             :         }
     104           0 :       }
     105           0 :     }
     106           0 :     return result.build();
     107             :   }
     108             : 
     109             :   private void appendIfNotNull(StringBuilder string, String header, Class<?> guiceModuleClass) {
     110           0 :     if (guiceModuleClass != null) {
     111           0 :       string.append(header);
     112           0 :       string.append(guiceModuleClass.getName());
     113           0 :       string.append("\n");
     114             :     }
     115           0 :   }
     116             : 
     117             :   private void scanGuiceModules(Set<Class<?>> classes) throws IOException {
     118             :     try {
     119           0 :       Class<?> sysModuleBaseClass = Module.class;
     120           0 :       Class<?> httpModuleBaseClass = ServletModule.class;
     121           0 :       Class<?> sshModuleBaseClass = Class.forName("com.google.gerrit.sshd.CommandModule");
     122           0 :       sshModuleClass = null;
     123           0 :       httpModuleClass = null;
     124           0 :       sysModuleClass = null;
     125             : 
     126           0 :       for (Class<?> clazz : classes) {
     127           0 :         if (clazz.isLocalClass()) {
     128           0 :           continue;
     129             :         }
     130             : 
     131           0 :         if (sshModuleBaseClass.isAssignableFrom(clazz)) {
     132           0 :           sshModuleClass = getUniqueGuiceModule(sshModuleBaseClass, sshModuleClass, clazz);
     133           0 :         } else if (httpModuleBaseClass.isAssignableFrom(clazz)) {
     134           0 :           httpModuleClass = getUniqueGuiceModule(httpModuleBaseClass, httpModuleClass, clazz);
     135           0 :         } else if (sysModuleBaseClass.isAssignableFrom(clazz)) {
     136           0 :           sysModuleClass = getUniqueGuiceModule(sysModuleBaseClass, sysModuleClass, clazz);
     137             :         }
     138           0 :       }
     139           0 :     } catch (ClassNotFoundException e) {
     140           0 :       throw new IOException("Cannot find base Gerrit classes for Guice Plugin Modules", e);
     141           0 :     }
     142           0 :   }
     143             : 
     144             :   private Class<?> getUniqueGuiceModule(
     145             :       Class<?> guiceModuleBaseClass,
     146             :       Class<?> existingGuiceModuleName,
     147             :       Class<?> newGuiceModuleClass) {
     148           0 :     checkState(
     149             :         existingGuiceModuleName == null,
     150             :         "Multiple %s implementations: %s, %s",
     151             :         guiceModuleBaseClass,
     152             :         existingGuiceModuleName,
     153             :         newGuiceModuleClass);
     154           0 :     return newGuiceModuleClass;
     155             :   }
     156             : 
     157             :   private String getExportAnnotationValue(
     158             :       Class<?> scriptClass, Class<? extends Annotation> annotation) {
     159           0 :     return annotation == Export.class ? scriptClass.getAnnotation(Export.class).value() : "";
     160             :   }
     161             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750