
com.tobedevoured.command.ByYourCommandManager Maven / Gradle / Ivy
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
© 2015 - 2025 Weber Informatics LLC | Privacy Policy