Allow SSH commands to be registered dynamically
A new top level command can be added to the DispatchCommandProvider that has the annotation @CommandName(Commands.ROOT). Once registered it can be removed later by calling remove() on the supplied handle. Change-Id: I8e60aa0f19e16ca3f21926b03f0be46537b5ef7a
This commit is contained in:
committed by
gerrit code review
parent
cb0ca18ab1
commit
b4992582d6
@@ -0,0 +1,21 @@
|
||||
// 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.guice;
|
||||
|
||||
/** Handle for registered information. */
|
||||
public interface RegistrationHandle {
|
||||
/** Delete this registration. */
|
||||
public void remove();
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package com.google.gerrit.sshd;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.server.guice.RegistrationHandle;
|
||||
import com.google.inject.Binding;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
@@ -23,11 +25,8 @@ import com.google.inject.TypeLiteral;
|
||||
import org.apache.sshd.server.Command;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* Creates DispatchCommand using commands registered by {@link CommandModule}.
|
||||
@@ -42,7 +41,7 @@ public class DispatchCommandProvider implements Provider<DispatchCommand> {
|
||||
private final String dispatcherName;
|
||||
private final CommandName parent;
|
||||
|
||||
private volatile Map<String, Provider<Command>> map;
|
||||
private volatile ConcurrentMap<String, Provider<Command>> map;
|
||||
|
||||
public DispatchCommandProvider(final CommandName cn) {
|
||||
this(Commands.nameOf(cn), cn);
|
||||
@@ -59,7 +58,21 @@ public class DispatchCommandProvider implements Provider<DispatchCommand> {
|
||||
return factory.create(dispatcherName, getMap());
|
||||
}
|
||||
|
||||
private Map<String, Provider<Command>> getMap() {
|
||||
public RegistrationHandle register(final CommandName name,
|
||||
final Provider<Command> cmd) {
|
||||
final ConcurrentMap<String, Provider<Command>> m = getMap();
|
||||
if (m.putIfAbsent(name.value(), cmd) != null) {
|
||||
throw new IllegalArgumentException(name.value() + " exists");
|
||||
}
|
||||
return new RegistrationHandle() {
|
||||
@Override
|
||||
public void remove() {
|
||||
m.remove(name.value(), cmd);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ConcurrentMap<String, Provider<Command>> getMap() {
|
||||
if (map == null) {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
@@ -71,10 +84,8 @@ public class DispatchCommandProvider implements Provider<DispatchCommand> {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Provider<Command>> createMap() {
|
||||
final Map<String, Provider<Command>> m =
|
||||
new TreeMap<String, Provider<Command>>();
|
||||
|
||||
private ConcurrentMap<String, Provider<Command>> createMap() {
|
||||
ConcurrentMap<String, Provider<Command>> m = Maps.newConcurrentMap();
|
||||
for (final Binding<?> b : allCommands()) {
|
||||
final Annotation annotation = b.getKey().getAnnotation();
|
||||
if (annotation instanceof CommandName) {
|
||||
@@ -84,9 +95,7 @@ public class DispatchCommandProvider implements Provider<DispatchCommand> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(
|
||||
new LinkedHashMap<String, Provider<Command>>(m));
|
||||
return m;
|
||||
}
|
||||
|
||||
private static final TypeLiteral<Command> type =
|
||||
|
||||
Reference in New Issue
Block a user