| // Copyright (C) 2012 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 com.google.common.base.Strings; |
| import com.google.gerrit.common.Nullable; |
| import com.google.gerrit.extensions.registration.RegistrationHandle; |
| import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle; |
| import com.google.gerrit.lifecycle.LifecycleManager; |
| import com.google.gerrit.server.PluginUser; |
| import com.google.inject.Injector; |
| import java.nio.file.Path; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.jar.Attributes; |
| import java.util.jar.Manifest; |
| import org.eclipse.jgit.internal.storage.file.FileSnapshot; |
| |
| public abstract class Plugin { |
| public enum ApiType { |
| EXTENSION, |
| PLUGIN, |
| JS |
| } |
| |
| /** Unique key that changes whenever a plugin reloads. */ |
| public static final class CacheKey { |
| private final String name; |
| |
| CacheKey(String name) { |
| this.name = name; |
| } |
| |
| @Override |
| public String toString() { |
| int id = System.identityHashCode(this); |
| return String.format("Plugin[%s@%x]", name, id); |
| } |
| } |
| |
| static ApiType getApiType(Manifest manifest) throws InvalidPluginException { |
| Attributes main = manifest.getMainAttributes(); |
| String v = main.getValue("Gerrit-ApiType"); |
| if (Strings.isNullOrEmpty(v) || ApiType.EXTENSION.name().equalsIgnoreCase(v)) { |
| return ApiType.EXTENSION; |
| } else if (ApiType.PLUGIN.name().equalsIgnoreCase(v)) { |
| return ApiType.PLUGIN; |
| } else if (ApiType.JS.name().equalsIgnoreCase(v)) { |
| return ApiType.JS; |
| } else { |
| throw new InvalidPluginException("Invalid Gerrit-ApiType: " + v); |
| } |
| } |
| |
| private final String name; |
| private final Path srcFile; |
| private final ApiType apiType; |
| private final boolean disabled; |
| private final CacheKey cacheKey; |
| private final PluginUser pluginUser; |
| private final FileSnapshot snapshot; |
| private CleanupHandle cleanupHandle; |
| |
| protected LifecycleManager manager; |
| |
| private List<ReloadableRegistrationHandle<?>> reloadableHandles; |
| |
| public Plugin( |
| String name, Path srcPath, PluginUser pluginUser, FileSnapshot snapshot, ApiType apiType) { |
| this.name = name; |
| this.srcFile = srcPath; |
| this.apiType = apiType; |
| this.snapshot = snapshot; |
| this.pluginUser = pluginUser; |
| this.cacheKey = new Plugin.CacheKey(name); |
| this.disabled = srcPath != null && srcPath.getFileName().toString().endsWith(".disabled"); |
| } |
| |
| public CleanupHandle getCleanupHandle() { |
| return cleanupHandle; |
| } |
| |
| public void setCleanupHandle(CleanupHandle cleanupHandle) { |
| this.cleanupHandle = cleanupHandle; |
| } |
| |
| PluginUser getPluginUser() { |
| return pluginUser; |
| } |
| |
| public Path getSrcFile() { |
| return srcFile; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| @Nullable |
| public abstract String getVersion(); |
| |
| public ApiType getApiType() { |
| return apiType; |
| } |
| |
| @Nullable |
| public String getApiVersion() { |
| return null; |
| } |
| |
| public Plugin.CacheKey getCacheKey() { |
| return cacheKey; |
| } |
| |
| public boolean isDisabled() { |
| return disabled; |
| } |
| |
| protected abstract void start(PluginGuiceEnvironment env) throws Exception; |
| |
| protected abstract void stop(PluginGuiceEnvironment env); |
| |
| public abstract PluginContentScanner getContentScanner(); |
| |
| public abstract Injector getSysInjector(); |
| |
| @Nullable |
| public abstract Injector getSshInjector(); |
| |
| @Nullable |
| public abstract Injector getHttpInjector(); |
| |
| public void add(RegistrationHandle handle) { |
| if (manager != null) { |
| if (handle instanceof ReloadableRegistrationHandle) { |
| if (reloadableHandles == null) { |
| reloadableHandles = new ArrayList<>(); |
| } |
| reloadableHandles.add((ReloadableRegistrationHandle<?>) handle); |
| } |
| manager.add(handle); |
| } |
| } |
| |
| List<ReloadableRegistrationHandle<?>> getReloadableHandles() { |
| if (reloadableHandles != null) { |
| return reloadableHandles; |
| } |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public String toString() { |
| return "Plugin [" + name + "]"; |
| } |
| |
| protected abstract boolean canReload(); |
| |
| boolean isModified(Path jar) { |
| return snapshot.isModified(jar.toFile()); |
| } |
| } |