blob: 238066b507f9357eb59dc6ef3f34c8ed922ded13 [file] [log] [blame]
// 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());
}
}