Merge "Add a BeanParseListener interface to DynamicOptions."
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java
index 3e1913d..6dec9a4 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java
@@ -63,7 +63,10 @@
T param, ListMultimap<String, String> in, HttpServletRequest req, HttpServletResponse res)
throws IOException {
CmdLineParser clp = parserFactory.create(param);
- DynamicOptions.parse(dynamicBeans, clp, param);
+ DynamicOptions pluginOptions = new DynamicOptions(param, dynamicBeans);
+ pluginOptions.parseDynamicBeans(clp);
+ pluginOptions.setDynamicBeans();
+ pluginOptions.onBeanParseStart();
try {
clp.parseOptionMap(in);
} catch (CmdLineException | NumberFormatException e) {
@@ -84,6 +87,7 @@
replyBinaryResult(req, res, BinaryResult.create(msg.toString()).setContentType("text/plain"));
return false;
}
+ pluginOptions.onBeanParseEnd();
return true;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/DynamicOptions.java b/gerrit-server/src/main/java/com/google/gerrit/server/DynamicOptions.java
index 6584301..51ad282 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/DynamicOptions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/DynamicOptions.java
@@ -17,7 +17,11 @@
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.util.cli.CmdLineParser;
import com.google.inject.Provider;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+/** Helper class to define and parse options from plugins on ssh and RestAPI commands. */
public class DynamicOptions {
/**
* To provide additional options, bind a DynamicBean. For example:
@@ -44,6 +48,16 @@
public interface DynamicBean {}
/**
+ * Implement this if your DynamicBean needs an opportunity to act on the Bean directly before or
+ * after argument parsing.
+ */
+ public interface BeanParseListener extends DynamicBean {
+ void onBeanParseStart(String plugin, Object bean);
+
+ void onBeanParseEnd(String plugin, Object bean);
+ }
+
+ /**
* The entity which provided additional options may need a way to receive a reference to the
* DynamicBean it provided. To do so, the existing class should implement BeanReceiver (a setter)
* and then provide some way for the plugin to request its DynamicBean (a getter.) For example:
@@ -66,32 +80,67 @@
void setDynamicBean(String plugin, DynamicBean dynamicBean);
}
+ Object bean;
+ Map<String, DynamicBean> beansByPlugin;
+
/**
- * To include options from DynamicBeans, setup a DynamicMap and call this parse method. For
- * example:
+ * Internal: For Gerrit to include options from DynamicBeans, setup a DynamicMap and instantiate
+ * this class so the following methods can be called if desired:
*
* <pre>
- * DynamicMap.mapOf(binder(), DynamicOptions.DynamicBean.class);
+ * DynamicOptions pluginOptions = new DynamicOptions(bean, dynamicBeans);
+ * pluginOptions.parseDynamicBeans(clp);
+ * pluginOptions.setDynamicBeans();
+ * pluginOptions.onBeanParseStart();
*
- * ...
+ * // parse arguments here: clp.parseArgument(argv);
*
- * protected void parseCommandLine(Object options) throws UnloggedFailure {
- * final CmdLineParser clp = newCmdLineParser(options);
- * DynamicOptions.parse(dynamicBeans, clp, options);
- * ...
- * }
+ * pluginOptions.onBeanParseEnd();
* </pre>
*/
- public static void parse(DynamicMap<DynamicBean> dynamicBeans, CmdLineParser clp, Object bean) {
+ public DynamicOptions(Object bean, DynamicMap<DynamicBean> dynamicBeans) {
+ this.bean = bean;
+ beansByPlugin = new HashMap<String, DynamicBean>();
for (String plugin : dynamicBeans.plugins()) {
Provider<DynamicBean> provider =
dynamicBeans.byPlugin(plugin).get(bean.getClass().getCanonicalName());
if (provider != null) {
- DynamicBean dynamicBean = provider.get();
- clp.parseWithPrefix(plugin, dynamicBean);
- if (bean instanceof BeanReceiver) {
- ((BeanReceiver) bean).setDynamicBean(plugin, dynamicBean);
- }
+ beansByPlugin.put(plugin, provider.get());
+ }
+ }
+ }
+
+ public void parseDynamicBeans(CmdLineParser clp) {
+ for (Entry<String, DynamicBean> e : beansByPlugin.entrySet()) {
+ clp.parseWithPrefix(e.getKey(), e.getValue());
+ }
+ }
+
+ public void setDynamicBeans() {
+ if (bean instanceof BeanReceiver) {
+ BeanReceiver receiver = (BeanReceiver) bean;
+ for (Entry<String, DynamicBean> e : beansByPlugin.entrySet()) {
+ receiver.setDynamicBean(e.getKey(), e.getValue());
+ }
+ }
+ }
+
+ public void onBeanParseStart() {
+ for (Entry<String, DynamicBean> e : beansByPlugin.entrySet()) {
+ DynamicBean instance = e.getValue();
+ if (instance instanceof BeanParseListener) {
+ BeanParseListener listener = (BeanParseListener) instance;
+ listener.onBeanParseStart(e.getKey(), bean);
+ }
+ }
+ }
+
+ public void onBeanParseEnd() {
+ for (Entry<String, DynamicBean> e : beansByPlugin.entrySet()) {
+ DynamicBean instance = e.getValue();
+ if (instance instanceof BeanParseListener) {
+ BeanParseListener listener = (BeanParseListener) instance;
+ listener.onBeanParseEnd(e.getKey(), bean);
}
}
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
index b828a58..8f4cfad 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
@@ -197,7 +197,10 @@
*/
protected void parseCommandLine(Object options) throws UnloggedFailure {
final CmdLineParser clp = newCmdLineParser(options);
- DynamicOptions.parse(dynamicBeans, clp, options);
+ DynamicOptions pluginOptions = new DynamicOptions(options, dynamicBeans);
+ pluginOptions.parseDynamicBeans(clp);
+ pluginOptions.setDynamicBeans();
+ pluginOptions.onBeanParseStart();
try {
clp.parseArgument(argv);
} catch (IllegalArgumentException | CmdLineException err) {
@@ -212,6 +215,7 @@
msg.write(usage());
throw new UnloggedFailure(1, msg.toString());
}
+ pluginOptions.onBeanParseEnd();
}
protected String usage() {