com.tobedevoured.command.ByYourCommandManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core Show documentation
Show all versions of core Show documentation
Make Java do your bidding by turning any code into an executable
The newest version!
package com.tobedevoured.command;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.beanutils.ConstructorUtils;
import org.modeshape.common.text.Inflector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.tobedevoured.command.annotation.ByYourCommand;
import com.tobedevoured.command.annotation.ByYourCommandGroup;
import com.tobedevoured.command.annotation.Command;
import com.tobedevoured.command.annotation.CommandParam;
import com.tobedevoured.command.annotation.CommandParams;
/**
* Manages the creation and execution of commands.
*
* @author Michael Guymon
*/
public class ByYourCommandManager {
private static Logger logger = LoggerFactory.getLogger(ByYourCommandManager.class);
private final static String[] EMPTY_STRING_ARRAY = new String[] { "" };
// Commands and their Dependencies
Map commands;
// Class and the Plan to execute them
private Map plans;
// Groups and their Commands
private Map> groups;
// Description of every command
private Set commandsDesc;
private Inflector inflector;
private DependencyResolvable dependencyResolver;
/**
* Construct new instance
*/
public ByYourCommandManager() {
inflector = new Inflector();
plans = new HashMap();
commands = new HashMap();
commandsDesc = new TreeSet();
groups = new HashMap>();
// Create default dep manager
dependencyResolver = buildDependencyResolver();
dependencyResolver.setManager(this);
}
public DependencyResolvable buildDependencyResolver() {
return new DefaultDependencyResolver();
}
/**
* Create a default Plan
*
* @return {@link Plan}
*/
public Plan createObjectPlan() {
return new Plan();
}
/**
* Scans a List of packages for @ByYourCommand annotated Classes
*
* @param packages List
* @throws CommandException fails scan for commands
*/
public void scanForCommands( List packages ) throws CommandException {
for( String _package: packages ) {
scanForCommands( _package );
}
}
/**
* Scan a package for classes annotated with @ByYourCommand and register them.
*
* @param _package String
* @throws CommandException fails to scan for commands
*/
public void scanForCommands( String _package ) throws CommandException {
Set> execCommands = null;
try {
execCommands = new ClassScanner().findAnnotatedClasses( _package, ByYourCommand.class);
} catch (IOException e) {
throw new CommandException(e);
}
logger.debug( "Scanned {} and found {}", _package, execCommands );
for ( Class clazz : execCommands ) {
logger.debug( "Parsing class: {}", clazz );
ByYourCommand execCommand = (ByYourCommand)clazz.getAnnotation( ByYourCommand.class );
// Create ExecCommandDependency for annotated class
CommandDependency execCommandDependency = newCommandDependency(clazz);
execCommandDependency.setTarget( clazz );
// Plan on how to exec the target
Plan plan = createObjectPlan();
plan.setTarget( clazz );
// Determine the name that will be used
String target = null;
if ( execCommand.name().length() > 0 ) {
target = execCommand.name();
} else {
target = inflector.underscore( clazz.getSimpleName() );
}
plan.setTargetName( target );
// Determine the group that will be used
String group = null;
if ( execCommand.group().length() > 0 ) {
group = execCommand.group();
} else {
group = clazz.getPackage().getName();
group = group.substring( group.lastIndexOf(".") + 1 );
group = inflector.underscore( group );
}
plan.setTargetGroup( group );
// Create root notation of group:target
String notation = new StringBuilder( group ).append(":").append( target ).toString();
// If default method is set in the annotation
if ( execCommand.defaultCommand().length() > 0 ) {
Method[] methods = null;
try {
methods = clazz.getMethods();
} catch ( Error e ) {
logger.warn( "Failed to load methods for {}, skipping", clazz.getName(), e );
continue;
}
// Find the method set as the default
String command = execCommand.defaultCommand();
for( Method method : methods ) {
// Found the method, now set it as the default
if ( method.getName().equals( command ) ) {
CommandMethod defaultMethod = new CommandMethod( inflector.underscore( command ), method.getName() );
defaultMethod.setExit( execCommand.defaultExit() );
plan.setDefaultCommand( defaultMethod );
commands.put( notation, execCommandDependency );
}
}
// Default method not found, toss exception
if ( plan.getDefaultCommand() == null ) {
throw new CommandException( "Default method " + command + " not found for " + clazz );
}
}
// Find methods annotated with @Command
for( Method method : clazz.getMethods() ) {
Command exec = (Command)method.getAnnotation( Command.class );
if ( exec != null ) {
// Determine name for @Command
String command = null;
if ( exec.name().length() > 0 ) {
command = exec.name();
} else {
command = inflector.underscore( method.getName() );
}
// Create CommandMethod for @Command
CommandMethod commandMethod = new CommandMethod( command, method.getName() );
commandMethod.setExit( exec.exit() );
commandMethod.setLogResult( exec.logResult() );
CommandParam[] commandParams = null;
CommandParams params = method.getAnnotation( CommandParams.class );
if ( params != null ) {
commandParams = params.value();
} else {
CommandParam param = method.getAnnotation( CommandParam.class );
if ( param != null ) {
commandParams = new CommandParam[] { param };
}
}
// Set params if set by @Command
if ( commandParams != null && commandParams.length > 0) {
logger.debug( "CommandParams: {}", commandParams );
for ( CommandParam commandParam : commandParams ) {
if ( commandParam.defaultValues().length > 0 ) {
commandMethod.addParam( commandParam.name(), commandParam.type(), commandParam.defaultValues() );
} else {
commandMethod.addParam( commandParam.name(), commandParam.type() );
}
}
}
// Add the CommandMethod to the Plan for this class
plan.addCommand( commandMethod );
// Create full notation of group:name:command
String commandNotation = new StringBuilder(notation).append(":").append(command).toString();
commands.put(commandNotation, execCommandDependency );
logger.debug( "Registering command {} {}", commandNotation, execCommandDependency );
}
}
// Add the Plan for the Class into the Map registry
plans.put( clazz, plan );
// Add the plan description into the commandsDesc helper
commandsDesc.addAll( plan.commandsDesc() );
// If the class is *not* excluded from group execution, add to group execution
ByYourCommandGroup execGroup = clazz.getPackage().getAnnotation( ByYourCommandGroup.class );
if ( execGroup != null ) {
List excludes = Arrays.asList( execGroup.excludes() );
if ( !excludes.contains( target ) ) {
Set groupCommands = groups.get( group );
if ( groupCommands == null ) {
groupCommands = new HashSet();
}
groupCommands.add( notation );
groups.put( group, groupCommands );
logger.debug( "Registering to group {}", group );
} else {
logger.debug( "Excluded from group {}", group );
}
}
}
}
protected CommandDependency newCommandDependency(Class clazz) {
return new CommandDependency();
}
/**
* Execute a command using the String notation group:target:command
*
* @param commandNotation String
* @return {@link CommandMethod}
* @throws CommandException fails to exec
*/
public CommandMethod exec( String commandNotation ) throws CommandException {
return exec(commandNotation, null );
}
/**
* Execute a command using the String notation group:target:command with
* a List of params
*
* @param commandNotation String
* @param params List
* @return {@link CommandMethod}
* @throws CommandException fails to exec
*/
public CommandMethod exec(String commandNotation, List