/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.config.spring.parsers.delegate;
import org.mule.runtime.config.spring.MuleHierarchicalBeanDefinitionParserDelegate;
import org.mule.runtime.config.spring.parsers.AbstractMuleBeanDefinitionParser;
import org.mule.runtime.config.spring.parsers.MuleDefinitionParser;
import org.mule.runtime.config.spring.parsers.MuleDefinitionParserConfiguration;
import org.mule.runtime.config.spring.parsers.PreProcessor;
import org.mule.runtime.config.spring.parsers.assembly.configuration.PropertyConfiguration;
import org.mule.runtime.core.util.StringUtils;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
* This allows a set of definition parsers to be used, one after another, to process the same element. This lets multiple beans be
* generated from a single element.
*
* <p>
* Since each bean typically needs a spearate name, this class guarantees that the name and id attributes are reset before each
* call. Delegates can then modify these on the element without worrying about interfering with other parsers.
* </p>
*
* <p>
* Typically, subclasses will add additional processing with {@link org.mule.runtime.config.spring.parsers.PreProcessor} and
* {@link org.mule.runtime.config.spring.parsers.PostProcessor} anonymous classes.
* </p>
*/
public abstract class AbstractSerialDelegatingDefinitionParser extends AbstractDelegatingDefinitionParser {
private int index = 0;
private boolean first;
private boolean doReset;
private String originalId;
private String originalName;
private Set handledExceptions = new HashSet();
public AbstractSerialDelegatingDefinitionParser() {
this(true); // by default, reset name
}
/**
* @param doReset Should the name be reset after called. This is typically true (it protects the parent from changes made by
* children) unless this is itself nested.
*/
public AbstractSerialDelegatingDefinitionParser(boolean doReset) {
this.doReset = doReset;
}
public AbstractBeanDefinition muleParse(Element element, ParserContext parserContext) {
if (index == 0 || index >= size()) {
first = true;
index = 0;
} else {
first = false;
}
AbstractBeanDefinition bean = null;
while (null == bean && index < size()) {
try {
MuleDefinitionParser parser = getDelegate(index);
bean = doSingleBean(index++, parser, element, parserContext);
} catch (RuntimeException e) {
if (isExceptionHandled(e)) {
bean = null;
} else {
throw e;
}
}
}
if (null != bean) {
if (index == size()) {
bean.removeAttribute(MuleHierarchicalBeanDefinitionParserDelegate.MULE_REPEAT_PARSE);
} else {
bean.setAttribute(MuleHierarchicalBeanDefinitionParserDelegate.MULE_REPEAT_PARSE, Boolean.TRUE);
}
}
return bean;
}
protected boolean isExceptionHandled(Exception e) {
return handledExceptions.contains(e.getClass());
}
protected AbstractBeanDefinition doSingleBean(int index, MuleDefinitionParser parser, Element element,
ParserContext parserContext) {
return parser.muleParse(element, parserContext);
}
protected MuleDefinitionParserConfiguration addDelegate(MuleDefinitionParser delegate) {
delegate.registerPreProcessor(new PreProcessor() {
public void preProcess(PropertyConfiguration config, Element element) {
if (first) {
originalId = element.getAttribute(AbstractMuleBeanDefinitionParser.ATTRIBUTE_ID);
originalName = element.getAttribute(AbstractMuleBeanDefinitionParser.ATTRIBUTE_NAME);
} else if (doReset) {
resetNameAndId(element);
}
}
});
return super.addDelegate(delegate);
}
protected void resetNameAndId(Element element) {
resetAttribute(element, AbstractMuleBeanDefinitionParser.ATTRIBUTE_ID, originalId);
resetAttribute(element, AbstractMuleBeanDefinitionParser.ATTRIBUTE_NAME, originalName);
}
protected void resetAttribute(Element element, String name, String value) {
if (StringUtils.isEmpty(value)) {
if (element.hasAttribute(name)) {
element.removeAttribute(name);
}
} else {
element.setAttribute(name, value);
}
}
protected void addHandledException(Class exception) {
handledExceptions.add(exception);
}
/**
* A utility class for selecting certain attributes. If the attributes are enabled, the default is set to block others; if
* specific attributes are disabled the default is set to allow others.
*
* @param delegate
* @param attributes
* @param enable
*/
public static void enableAttributes(MuleDefinitionParser delegate, String[] attributes, boolean enable) {
// if enabling specific attributes, block globally
delegate.setIgnoredDefault(enable);
Iterator names = Arrays.asList(attributes).iterator();
while (names.hasNext()) {
String name = (String) names.next();
if (enable) {
delegate.removeIgnored(name);
} else {
delegate.addIgnored(name);
}
}
}
public static void enableAttributes(MuleDefinitionParser delegate, String[][] attributes) {
for (int i = 0; i < attributes.length; ++i) {
enableAttributes(delegate, attributes[i], true);
}
}
public static void enableAttributes(MuleDefinitionParser delegate, String[] attributes) {
enableAttributes(delegate, attributes, true);
}
public static void enableAttribute(MuleDefinitionParser delegate, String attribute) {
enableAttributes(delegate, new String[] {attribute}, true);
}
public static void disableAttributes(MuleDefinitionParser delegate, String[][] attributes) {
for (int i = 0; i < attributes.length; ++i) {
enableAttributes(delegate, attributes[i], false);
}
}
public static void disableAttributes(MuleDefinitionParser delegate, String[] attributes) {
enableAttributes(delegate, attributes, false);
}
public static void disableAttribute(MuleDefinitionParser delegate, String attribute) {
enableAttributes(delegate, new String[] {attribute}, false);
}
}