Line data Source code
1 : // Copyright (C) 2012 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 com.google.common.base.Strings; 18 : import com.google.gerrit.common.Nullable; 19 : import com.google.gerrit.extensions.registration.RegistrationHandle; 20 : import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle; 21 : import com.google.gerrit.lifecycle.LifecycleManager; 22 : import com.google.gerrit.server.PluginUser; 23 : import com.google.inject.Injector; 24 : import java.nio.file.Path; 25 : import java.util.ArrayList; 26 : import java.util.Collections; 27 : import java.util.List; 28 : import java.util.jar.Attributes; 29 : import java.util.jar.Manifest; 30 : import org.eclipse.jgit.internal.storage.file.FileSnapshot; 31 : 32 : public abstract class Plugin { 33 14 : public enum ApiType { 34 14 : EXTENSION, 35 14 : PLUGIN, 36 14 : JS 37 : } 38 : 39 : /** Unique key that changes whenever a plugin reloads. */ 40 : public static final class CacheKey { 41 : private final String name; 42 : 43 14 : CacheKey(String name) { 44 14 : this.name = name; 45 14 : } 46 : 47 : @Override 48 : public String toString() { 49 0 : int id = System.identityHashCode(this); 50 0 : return String.format("Plugin[%s@%x]", name, id); 51 : } 52 : } 53 : 54 : static ApiType getApiType(Manifest manifest) throws InvalidPluginException { 55 1 : Attributes main = manifest.getMainAttributes(); 56 1 : String v = main.getValue("Gerrit-ApiType"); 57 1 : if (Strings.isNullOrEmpty(v) || ApiType.EXTENSION.name().equalsIgnoreCase(v)) { 58 1 : return ApiType.EXTENSION; 59 0 : } else if (ApiType.PLUGIN.name().equalsIgnoreCase(v)) { 60 0 : return ApiType.PLUGIN; 61 0 : } else if (ApiType.JS.name().equalsIgnoreCase(v)) { 62 0 : return ApiType.JS; 63 : } else { 64 0 : throw new InvalidPluginException("Invalid Gerrit-ApiType: " + v); 65 : } 66 : } 67 : 68 : private final String name; 69 : private final Path srcFile; 70 : private final ApiType apiType; 71 : private final boolean disabled; 72 : private final CacheKey cacheKey; 73 : private final PluginUser pluginUser; 74 : private final FileSnapshot snapshot; 75 : private CleanupHandle cleanupHandle; 76 : 77 : protected LifecycleManager manager; 78 : 79 : private List<ReloadableRegistrationHandle<?>> reloadableHandles; 80 : 81 : public Plugin( 82 14 : String name, Path srcPath, PluginUser pluginUser, FileSnapshot snapshot, ApiType apiType) { 83 14 : this.name = name; 84 14 : this.srcFile = srcPath; 85 14 : this.apiType = apiType; 86 14 : this.snapshot = snapshot; 87 14 : this.pluginUser = pluginUser; 88 14 : this.cacheKey = new Plugin.CacheKey(name); 89 14 : this.disabled = srcPath != null && srcPath.getFileName().toString().endsWith(".disabled"); 90 14 : } 91 : 92 : public CleanupHandle getCleanupHandle() { 93 3 : return cleanupHandle; 94 : } 95 : 96 : public void setCleanupHandle(CleanupHandle cleanupHandle) { 97 1 : this.cleanupHandle = cleanupHandle; 98 1 : } 99 : 100 : PluginUser getPluginUser() { 101 14 : return pluginUser; 102 : } 103 : 104 : public Path getSrcFile() { 105 11 : return srcFile; 106 : } 107 : 108 : public String getName() { 109 14 : return name; 110 : } 111 : 112 : @Nullable 113 : public abstract String getVersion(); 114 : 115 : public ApiType getApiType() { 116 13 : return apiType; 117 : } 118 : 119 : @Nullable 120 : public String getApiVersion() { 121 3 : return null; 122 : } 123 : 124 : public Plugin.CacheKey getCacheKey() { 125 1 : return cacheKey; 126 : } 127 : 128 : public boolean isDisabled() { 129 3 : return disabled; 130 : } 131 : 132 : protected abstract void start(PluginGuiceEnvironment env) throws Exception; 133 : 134 : protected abstract void stop(PluginGuiceEnvironment env); 135 : 136 : public abstract PluginContentScanner getContentScanner(); 137 : 138 : public abstract Injector getSysInjector(); 139 : 140 : @Nullable 141 : public abstract Injector getSshInjector(); 142 : 143 : @Nullable 144 : public abstract Injector getHttpInjector(); 145 : 146 : public void add(RegistrationHandle handle) { 147 3 : if (manager != null) { 148 3 : if (handle instanceof ReloadableRegistrationHandle) { 149 3 : if (reloadableHandles == null) { 150 3 : reloadableHandles = new ArrayList<>(); 151 : } 152 3 : reloadableHandles.add((ReloadableRegistrationHandle<?>) handle); 153 : } 154 3 : manager.add(handle); 155 : } 156 3 : } 157 : 158 : List<ReloadableRegistrationHandle<?>> getReloadableHandles() { 159 1 : if (reloadableHandles != null) { 160 1 : return reloadableHandles; 161 : } 162 0 : return Collections.emptyList(); 163 : } 164 : 165 : @Override 166 : public String toString() { 167 0 : return "Plugin [" + name + "]"; 168 : } 169 : 170 : protected abstract boolean canReload(); 171 : 172 : boolean isModified(Path jar) { 173 0 : return snapshot.isModified(jar.toFile()); 174 : } 175 : }