Merge "Add a BeanParseListener interface to DynamicOptions."

This commit is contained in:
Martin Fick
2017-04-11 19:23:11 +00:00
committed by Gerrit Code Review
3 changed files with 74 additions and 17 deletions

View File

@@ -63,7 +63,10 @@ class ParameterParser {
T param, ListMultimap<String, String> in, HttpServletRequest req, HttpServletResponse res) T param, ListMultimap<String, String> in, HttpServletRequest req, HttpServletResponse res)
throws IOException { throws IOException {
CmdLineParser clp = parserFactory.create(param); CmdLineParser clp = parserFactory.create(param);
DynamicOptions.parse(dynamicBeans, clp, param); DynamicOptions pluginOptions = new DynamicOptions(param, dynamicBeans);
pluginOptions.parseDynamicBeans(clp);
pluginOptions.setDynamicBeans();
pluginOptions.onBeanParseStart();
try { try {
clp.parseOptionMap(in); clp.parseOptionMap(in);
} catch (CmdLineException | NumberFormatException e) { } catch (CmdLineException | NumberFormatException e) {
@@ -84,6 +87,7 @@ class ParameterParser {
replyBinaryResult(req, res, BinaryResult.create(msg.toString()).setContentType("text/plain")); replyBinaryResult(req, res, BinaryResult.create(msg.toString()).setContentType("text/plain"));
return false; return false;
} }
pluginOptions.onBeanParseEnd();
return true; return true;
} }

View File

@@ -17,7 +17,11 @@ package com.google.gerrit.server;
import com.google.gerrit.extensions.registration.DynamicMap; import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.util.cli.CmdLineParser; import com.google.gerrit.util.cli.CmdLineParser;
import com.google.inject.Provider; 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 { public class DynamicOptions {
/** /**
* To provide additional options, bind a DynamicBean. For example: * To provide additional options, bind a DynamicBean. For example:
@@ -43,6 +47,16 @@ public class DynamicOptions {
*/ */
public interface DynamicBean {} 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 * 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) * DynamicBean it provided. To do so, the existing class should implement BeanReceiver (a setter)
@@ -66,32 +80,67 @@ public class DynamicOptions {
void setDynamicBean(String plugin, DynamicBean dynamicBean); 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 * Internal: For Gerrit to include options from DynamicBeans, setup a DynamicMap and instantiate
* example: * this class so the following methods can be called if desired:
* *
* <pre> * <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 { * pluginOptions.onBeanParseEnd();
* final CmdLineParser clp = newCmdLineParser(options);
* DynamicOptions.parse(dynamicBeans, clp, options);
* ...
* }
* </pre> * </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()) { for (String plugin : dynamicBeans.plugins()) {
Provider<DynamicBean> provider = Provider<DynamicBean> provider =
dynamicBeans.byPlugin(plugin).get(bean.getClass().getCanonicalName()); dynamicBeans.byPlugin(plugin).get(bean.getClass().getCanonicalName());
if (provider != null) { if (provider != null) {
DynamicBean dynamicBean = provider.get(); beansByPlugin.put(plugin, provider.get());
clp.parseWithPrefix(plugin, dynamicBean); }
if (bean instanceof BeanReceiver) { }
((BeanReceiver) bean).setDynamicBean(plugin, dynamicBean); }
}
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);
} }
} }
} }

View File

@@ -197,7 +197,10 @@ public abstract class BaseCommand implements Command {
*/ */
protected void parseCommandLine(Object options) throws UnloggedFailure { protected void parseCommandLine(Object options) throws UnloggedFailure {
final CmdLineParser clp = newCmdLineParser(options); final CmdLineParser clp = newCmdLineParser(options);
DynamicOptions.parse(dynamicBeans, clp, options); DynamicOptions pluginOptions = new DynamicOptions(options, dynamicBeans);
pluginOptions.parseDynamicBeans(clp);
pluginOptions.setDynamicBeans();
pluginOptions.onBeanParseStart();
try { try {
clp.parseArgument(argv); clp.parseArgument(argv);
} catch (IllegalArgumentException | CmdLineException err) { } catch (IllegalArgumentException | CmdLineException err) {
@@ -212,6 +215,7 @@ public abstract class BaseCommand implements Command {
msg.write(usage()); msg.write(usage());
throw new UnloggedFailure(1, msg.toString()); throw new UnloggedFailure(1, msg.toString());
} }
pluginOptions.onBeanParseEnd();
} }
protected String usage() { protected String usage() {