package org.apache.ode.spi.di;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Qualifier;
import javax.xml.namespace.QName;
import org.apache.ode.spi.di.CommandAnnotationScanner.CommandModel;
import org.apache.ode.spi.di.OperationAnnotationScanner.BaseModel;
import org.apache.ode.spi.di.OperationAnnotationScanner.OperationModel;
import org.apache.ode.spi.work.Command;
import org.apache.ode.spi.work.Command.CommandSet;
import org.apache.ode.spi.work.Command.CommandSetRef;
import org.apache.ode.spi.work.ExecutionUnit.InBuffer;
import org.apache.ode.spi.work.ExecutionUnit.OutBuffer;
import org.apache.ode.spi.work.Operation;
import org.apache.ode.spi.work.Operation.I;
import org.apache.ode.spi.work.Operation.IO;
import org.apache.ode.spi.work.Operation.IOP;
import org.apache.ode.spi.work.Operation.IP;
import org.apache.ode.spi.work.Operation.O;
import org.apache.ode.spi.work.Operation.OP;
public class CommandAnnotationScanner implements AnnotationScanner<Map<QName, CommandModel>> {
protected static final Logger log = Logger.getLogger(CommandAnnotationScanner.class.getName());
protected ConcurrentHashMap<Class<?>, Class<?>> commandSetRefs = new ConcurrentHashMap<>();
public Map<QName, CommandModel> scan(Class<?> clazz) {
log.fine(String.format("scanned class %s\n", clazz));
if (clazz.isAnnotationPresent(CommandSetRef.class)) {
CommandSetRef cmdSetRef = clazz.getAnnotation(CommandSetRef.class);
if (cmdSetRef.value().length == 0) {
return null;
}
Map<QName, CommandModel> commands = new HashMap<>();
for (Class<?> cmdClazz : cmdSetRef.value()) {
if (!cmdClazz.isAnnotationPresent(CommandSet.class)) {
log.severe(String.format("Class %s is referenced from %s as a CommandSet but it is missing the annotation\n", cmdClazz, clazz));
continue;
}
Class<?> exists = commandSetRefs.putIfAbsent(cmdClazz, clazz);
if (exists != null) {
log.fine(String.format("Class %s is referenced from %s as a CommandSet but it has already been processed from reference in %s, skipping\n", cmdClazz, clazz,
commandSetRefs.get(exists)));
continue;
}
if (!Modifier.isInterface(cmdClazz.getModifiers())) {
log.severe(String.format("Class %s is a CommandSet but is not an interface\n", cmdClazz, clazz));
continue;
}
CommandSet cmdSet = cmdClazz.getAnnotation(CommandSet.class);
for (Method m : cmdClazz.getMethods()) {
if (m.isAnnotationPresent(Command.class)) {
Command cmd = m.getAnnotation(Command.class);
String commandNamespace = cmd.namespace();
if (commandNamespace.length() == 0) {
commandNamespace = cmdSet.namespace();
}
if (commandNamespace.length() == 0) {
log.severe(String.format("Unable to determine command namespace for Class %s method %s, skipping", cmdClazz.getName(), m.getName()));
continue;
}
String commandName = cmd.name();
if (commandName.length() == 0) {
commandName = m.getName();
}
QName commandQName = new QName(commandNamespace, commandName);
CommandModel cm = new CommandModel(commandQName);
if (OperationAnnotationScanner.inspect(cmdClazz, false, m, cm)) {
commands.put(commandQName, cm);
}
}
}
}
return commands;
} else {
return null;
}
}
@Qualifier
@Retention(RUNTIME)
@Target(FIELD)
public @interface Commands {
}
public static class CommandModel extends BaseModel {
private final QName commandName;
public CommandModel(QName commandName) {
this.commandName = commandName;
}
public QName commandName() {
return commandName;
}
}
}