| // 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()); | |
| } | |
| } |