com.yammer.dropwizard.cli.ConfiguredCommand Maven / Gradle / Ivy
package com.yammer.dropwizard.cli;
import com.yammer.dropwizard.AbstractService;
import com.yammer.dropwizard.config.Configuration;
import com.yammer.dropwizard.config.ConfigurationException;
import com.yammer.dropwizard.config.ConfigurationFactory;
import com.yammer.dropwizard.config.LoggingFactory;
import com.yammer.dropwizard.validation.Validator;
import org.apache.commons.cli.CommandLine;
import java.io.File;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* A command whose first parameter is the location of a YAML configuration file. That file is parsed
*
* @param the {@link Configuration} subclass which is loaded from the configuration file
* @see Configuration
*/
public abstract class ConfiguredCommand extends Command {
/**
* Creates a new {@link ConfiguredCommand} with the given name and configuration.
*
* @param name the command's name
* @param description a description of the command
*/
protected ConfiguredCommand(String name,
String description) {
super(name, description);
}
@SuppressWarnings("unchecked")
protected Class getConfigurationClass() {
Type t = getClass();
while (t instanceof Class>) {
t = ((Class>) t).getGenericSuperclass();
}
/* This is not guaranteed to work for all cases with convoluted piping
* of type parameters: but it can at least resolve straight-forward
* extension with single type parameter (as per [Issue-89]).
* And when it fails to do that, will indicate with specific exception.
*/
if (t instanceof ParameterizedType) {
// should typically have one of type parameters (first one) that matches:
for (Type param : ((ParameterizedType) t).getActualTypeArguments()) {
if (param instanceof Class>) {
Class> cls = (Class>) param;
if (Configuration.class.isAssignableFrom(cls)) {
return (Class) cls;
}
}
}
}
throw new IllegalStateException("Can not figure out Configuration type parameterization for "+getClass().getName());
}
/**
* Returns the usage syntax, minus the configuration file param.
*
* @return the command's usage syntax
*/
protected String getConfiguredSyntax() {
return null;
}
@Override
protected final String getSyntax() {
final StringBuilder syntax = new StringBuilder("");
final String configured = getConfiguredSyntax();
if ((configured != null) && !configured.isEmpty()) {
syntax.append(' ').append(configured);
}
return syntax.toString();
}
@Override
@SuppressWarnings("unchecked")
protected final void run(AbstractService> service,
CommandLine params) throws Exception {
final ConfigurationFactory factory = ConfigurationFactory.forClass(getConfigurationClass(),
new Validator(),
service.getJacksonModules());
final String[] args = params.getArgs();
if (args.length >= 1) {
params.getArgList().remove(0);
try {
final T configuration = factory.build(new File(args[0]));
new LoggingFactory(configuration.getLoggingConfiguration(), service.getName()).configure();
run((AbstractService) service, configuration, params);
} catch (ConfigurationException e) {
printHelp(e.getMessage(), service.getClass());
}
} else {
printHelp(service.getClass());
System.exit(-1);
}
}
/**
* Runs the command with the given {@link AbstractService} and {@link Configuration}.
*
* @param service the service to which the command belongs
* @param configuration the configuration object
* @param params any additional command-line parameters
* @throws Exception if something goes wrong
*/
protected abstract void run(AbstractService service,
T configuration,
CommandLine params) throws Exception;
}