/** * Assigns any existing properties to the node.<br> * It will call attributeDelegates before passing control to the factory that built the node. * * @param node the object returned by tne node factory * @param attributes the attributes for the node */ protected void handleNodeAttributes(Object node, Map attributes) { // first, short circuit if (node == null) { return; } for (Closure attrDelegate : getProxyBuilder().getAttributeDelegates()) { FactoryBuilderSupport builder = this; if (attrDelegate.getOwner() instanceof FactoryBuilderSupport) { builder = (FactoryBuilderSupport) attrDelegate.getOwner(); } else if (attrDelegate.getDelegate() instanceof FactoryBuilderSupport) { builder = (FactoryBuilderSupport) attrDelegate.getDelegate(); } attrDelegate.call(new Object[] {builder, node, attributes}); } if (getProxyBuilder() .getCurrentFactory() .onHandleNodeAttributes(getProxyBuilder().getChildBuilder(), node, attributes)) { getProxyBuilder().setNodeAttributes(node, attributes); } }
protected Object dispatchNodeCall(Object name, Object args) { Object node; Closure closure = null; List list = InvokerHelper.asList(args); final boolean needToPopContext; if (getProxyBuilder().getContexts().isEmpty()) { // should be called on first build method only getProxyBuilder().newContext(); needToPopContext = true; } else { needToPopContext = false; } try { Map namedArgs = Collections.EMPTY_MAP; // the arguments come in like [named_args?, args..., closure?] // so peel off a hashmap from the front, and a closure from the // end and presume that is what they meant, since there is // no way to distinguish node(a:b,c,d) {..} from // node([a:b],[c,d], {..}), i.e. the user can deliberately confuse // the builder and there is nothing we can really do to prevent // that if ((list.size() > 0) && (list.get(0) instanceof LinkedHashMap)) { namedArgs = (Map) list.get(0); list = list.subList(1, list.size()); } if ((list.size() > 0) && (list.get(list.size() - 1) instanceof Closure)) { closure = (Closure) list.get(list.size() - 1); list = list.subList(0, list.size() - 1); } Object arg; if (list.size() == 0) { arg = null; } else if (list.size() == 1) { arg = list.get(0); } else { arg = list; } node = getProxyBuilder().createNode(name, namedArgs, arg); Object current = getProxyBuilder().getCurrent(); if (current != null) { getProxyBuilder().setParent(current, node); } if (closure != null) { Factory parentFactory = getProxyBuilder().getCurrentFactory(); if (parentFactory.isLeaf()) { throw new RuntimeException("'" + name + "' doesn't support nesting."); } boolean processContent = true; if (parentFactory.isHandlesNodeChildren()) { processContent = parentFactory.onNodeChildren(this, node, closure); } if (processContent) { // push new node on stack String parentName = getProxyBuilder().getCurrentName(); Map parentContext = getProxyBuilder().getContext(); getProxyBuilder().newContext(); try { getProxyBuilder().getContext().put(OWNER, closure.getOwner()); getProxyBuilder().getContext().put(CURRENT_NODE, node); getProxyBuilder().getContext().put(PARENT_FACTORY, parentFactory); getProxyBuilder().getContext().put(PARENT_NODE, current); getProxyBuilder().getContext().put(PARENT_CONTEXT, parentContext); getProxyBuilder().getContext().put(PARENT_NAME, parentName); getProxyBuilder().getContext().put(PARENT_BUILDER, parentContext.get(CURRENT_BUILDER)); getProxyBuilder().getContext().put(CURRENT_BUILDER, parentContext.get(CHILD_BUILDER)); // lets register the builder as the delegate getProxyBuilder().setClosureDelegate(closure, node); closure.call(); } finally { getProxyBuilder().popContext(); } } } getProxyBuilder().nodeCompleted(current, node); node = getProxyBuilder().postNodeCompletion(current, node); } finally { if (needToPopContext) { // pop the first context getProxyBuilder().popContext(); } } return node; }