Export ServerInformation to extensions and plugins

Plugins can take this value by injection and learn the current
server state during their own LifecycleListener. This enables a
plugin to determine if it is loading as part of server startup, or
because it was dynamically installed or reloaded by an administrator.

Change-Id: Iac57e039ed9f9f3ecaf2f384c5a3c6a66223f5e1
This commit is contained in:
Shawn O. Pearce
2012-05-11 15:44:47 -07:00
parent 521380a28d
commit d7f89fb05f
6 changed files with 111 additions and 11 deletions

View File

@@ -0,0 +1,42 @@
// 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.extensions.systemstatus;
/** Exports current server information to an extension. */
public interface ServerInformation {
/** Current state of the server. */
public enum State {
/**
* The server is starting up, and network connections are not yet being
* accepted. Plugins or extensions starting during this time are starting
* for the first time in this process.
*/
STARTUP,
/**
* The server is running and handling requests. Plugins starting during this
* state may be reloading, or being installed into a running system.
*/
RUNNING,
/**
* The server is attempting a graceful halt of operations and will exit (or
* be killed by the operating system) soon.
*/
SHUTDOWN;
}
State getState();
}

View File

@@ -19,6 +19,7 @@ import com.google.common.collect.Lists;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.registration.RegistrationHandle;
import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle;
import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.gerrit.lifecycle.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.inject.AbstractModule;
@@ -165,16 +166,24 @@ public class Plugin {
}
private Injector newRootInjector(PluginGuiceEnvironment env) {
return Guice.createInjector(
env.getSysModule(),
new AbstractModule() {
@Override
protected void configure() {
bind(String.class)
.annotatedWith(PluginName.class)
.toInstance(name);
}
});
List<Module> modules = Lists.newArrayListWithCapacity(4);
modules.add(env.getSysModule());
final ServerInformation srvInfo = env.getServerInformation();
modules.add(new AbstractModule() {
@Override
protected void configure() {
bind(ServerInformation.class).toInstance(srvInfo);
}
});
modules.add(new AbstractModule() {
@Override
protected void configure() {
bind(String.class)
.annotatedWith(PluginName.class)
.toInstance(name);
}
});
return Guice.createInjector(modules);
}
public void stop() {

View File

@@ -24,6 +24,7 @@ import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.registration.PrivateInternals_DynamicMapImpl;
import com.google.gerrit.extensions.registration.RegistrationHandle;
import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle;
import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.gerrit.lifecycle.LifecycleListener;
import com.google.inject.AbstractModule;
import com.google.inject.Binding;
@@ -56,6 +57,7 @@ import javax.inject.Inject;
@Singleton
public class PluginGuiceEnvironment {
private final Injector sysInjector;
private final ServerInformation srvInfo;
private final CopyConfigModule copyConfigModule;
private final List<StartPluginListener> onStart;
private final List<ReloadPluginListener> onReload;
@@ -76,8 +78,12 @@ public class PluginGuiceEnvironment {
private Map<TypeLiteral<?>, DynamicMap<?>> httpMaps;
@Inject
PluginGuiceEnvironment(Injector sysInjector, CopyConfigModule ccm) {
PluginGuiceEnvironment(
Injector sysInjector,
ServerInformation srvInfo,
CopyConfigModule ccm) {
this.sysInjector = sysInjector;
this.srvInfo = srvInfo;
this.copyConfigModule = ccm;
onStart = new CopyOnWriteArrayList<StartPluginListener>();
@@ -90,6 +96,10 @@ public class PluginGuiceEnvironment {
sysMaps = dynamicMapsOf(sysInjector);
}
ServerInformation getServerInformation() {
return srvInfo;
}
boolean hasDynamicSet(TypeLiteral<?> type) {
return sysSets.containsKey(type)
|| (sshSets != null && sshSets.containsKey(type))

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.server.plugins;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.gerrit.lifecycle.LifecycleListener;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -59,6 +60,7 @@ public class PluginLoader implements LifecycleListener {
private final File pluginsDir;
private final File tmpDir;
private final PluginGuiceEnvironment env;
private final ServerInformationImpl srvInfoImpl;
private final ConcurrentMap<String, Plugin> running;
private final Map<String, FileSnapshot> broken;
private final ReferenceQueue<ClassLoader> cleanupQueue;
@@ -68,10 +70,12 @@ public class PluginLoader implements LifecycleListener {
@Inject
public PluginLoader(SitePaths sitePaths,
PluginGuiceEnvironment pe,
ServerInformationImpl sii,
@GerritServerConfig Config cfg) {
pluginsDir = sitePaths.plugins_dir;
tmpDir = sitePaths.tmp_dir;
env = pe;
srvInfoImpl = sii;
running = Maps.newConcurrentMap();
broken = Maps.newHashMap();
cleanupQueue = new ReferenceQueue<ClassLoader>();
@@ -184,7 +188,9 @@ public class PluginLoader implements LifecycleListener {
@Override
public synchronized void start() {
log.info("Loading plugins from " + pluginsDir.getAbsolutePath());
srvInfoImpl.state = ServerInformation.State.STARTUP;
rescan(false);
srvInfoImpl.state = ServerInformation.State.RUNNING;
if (scanner != null) {
scanner.start();
}
@@ -195,6 +201,7 @@ public class PluginLoader implements LifecycleListener {
if (scanner != null) {
scanner.end();
}
srvInfoImpl.state = ServerInformation.State.SHUTDOWN;
synchronized (this) {
boolean clean = !running.isEmpty();
for (Plugin p : running.values()) {

View File

@@ -14,11 +14,15 @@
package com.google.gerrit.server.plugins;
import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.gerrit.lifecycle.LifecycleModule;
public class PluginModule extends LifecycleModule {
@Override
protected void configure() {
bind(ServerInformationImpl.class);
bind(ServerInformation.class).to(ServerInformationImpl.class);
bind(PluginGuiceEnvironment.class);
bind(PluginLoader.class);
bind(CopyConfigModule.class);

View File

@@ -0,0 +1,28 @@
// 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.gerrit.extensions.systemstatus.ServerInformation;
import com.google.inject.Singleton;
@Singleton
class ServerInformationImpl implements ServerInformation {
volatile State state = State.STARTUP;
@Override
public State getState() {
return state;
}
}