package net.sourceforge.javautil.groovy.builder.standard;
import java.util.LinkedHashMap;
import java.util.Map;
import net.sourceforge.javautil.groovy.builder.GroovyBuilderInterceptor;
import groovy.lang.Closure;
import groovy.lang.MetaMethod;
import groovy.lang.MissingMethodException;
/**
* This is the standard implementation of the builder interceptor to work with the standard builder and standard stack.
* If the meta method is not null it will be invoked. Otherwise it will accept the standard max three arguments (value, map and closure)
* and call the appropriate methods on the @link StandardBuilder.
*
* @author elponderador
*
*/
public class StandardInterceptor<B extends StandardBuilder, S extends StandardStack> implements GroovyBuilderInterceptor<B, S> {
public Object handleInvokedMethod(InterceptorContext<B, S> ctx) {
MetaMethod method = ctx.getMetaMethod();
B builder = ctx.getBuilder();
S stack = ctx.getStack();
Object[] args = ctx.getArgs();
String name = ctx.getMethodName();
if (method != null) return method.invoke(builder, args);
Object value = null;
Map<Object, Object> parameters = null;
Closure closure = null;
switch (args.length) {
case 0: break;
case 1: case 2: case 3:
for (int i=0; i<args.length; i++) {
if (args[i] instanceof Map && parameters == null) parameters = (Map) args[i];
else if (args[i] instanceof Closure && closure == null) closure = (Closure) args[i];
else if (value == null) value = args[i];
else throw new IllegalArgumentException("Could not understand node argument: " + args[i] + " for node " + name);
}
break;
default:
throw new MissingMethodException(name, builder.getClass(), args);
}
return this.handleNode(builder, stack, name, builder.startNode(name, value, parameters), parameters, closure);
}
public Object handleNode(B builder, S stack, String name, Object node, Map<Object, Object> attributes, Closure tree) {
Object current = stack.getCurrent();
try {
if (stack.isFirstNodeStarting()) builder.startBuilding();
builder.getEventPropagator().nodeStarted(builder, current, node);
stack.push(node);
builder.setParent(node, current);
if (current != null) builder.getEventPropagator().nodeChild(builder, node, current);
if (tree != null) builder.invoke(tree);
builder.finishNode(node);
builder.getEventPropagator().nodeFinished(builder, current, node);
return stack.pop();
} finally {
if (stack.isFirstNodeClosing()) {
builder.stopBuilding();
builder.cleanupStack();
}
}
}
}