INT-1201: add support for nested queries

This commit is contained in:
David Syer
2010-06-24 07:54:47 +00:00
parent 69d19fdf8c
commit 4ed5ae919b
9 changed files with 445 additions and 119 deletions

View File

@@ -46,22 +46,25 @@ public abstract class IntegrationNamespaceUtils {
static final String REF_ATTRIBUTE = "ref";
static final String METHOD_ATTRIBUTE = "method";
static final String ORDER = "order";
/**
* Configures the provided bean definition builder with a property
* value corresponding to the attribute whose name is provided if
* that attribute is defined in the given element.
* Configures the provided bean definition builder with a property value
* corresponding to the attribute whose name is provided if that attribute
* is defined in the given element.
*
* @param builder the bean definition builder to be configured
* @param element the XML element where the attribute should be defined
* @param attributeName the name of the attribute whose value will be
* used to populate the property
* @param propertyName the name of the property to be populated
* @param builder
* the bean definition builder to be configured
* @param element
* the XML element where the attribute should be defined
* @param attributeName
* the name of the attribute whose value will be used to populate
* the property
* @param propertyName
* the name of the property to be populated
*/
public static void setValueIfAttributeDefined(BeanDefinitionBuilder builder,
Element element, String attributeName, String propertyName) {
public static void setValueIfAttributeDefined(
BeanDefinitionBuilder builder, Element element,
String attributeName, String propertyName) {
String attributeValue = element.getAttribute(attributeName);
if (StringUtils.hasText(attributeValue)) {
builder.addPropertyValue(propertyName, attributeValue);
@@ -69,41 +72,50 @@ public abstract class IntegrationNamespaceUtils {
}
/**
* Configures the provided bean definition builder with a property
* value corresponding to the attribute whose name is provided if
* that attribute is defined in the given element.
* Configures the provided bean definition builder with a property value
* corresponding to the attribute whose name is provided if that attribute
* is defined in the given element.
*
* <p>The property name will be the camel-case equivalent of the lower
* case hyphen separated attribute (e.g. the "foo-bar" attribute would
* match the "fooBar" property).
* <p>
* The property name will be the camel-case equivalent of the lower case
* hyphen separated attribute (e.g. the "foo-bar" attribute would match the
* "fooBar" property).
*
* @see Conventions#attributeNameToPropertyName(String)
*
* @param builder the bean definition builder to be configured
* @param element - the XML element where the attribute should be defined
* @param attributeName - the name of the attribute whose value will be set
* on the property
* @param builder
* the bean definition builder to be configured
* @param element
* - the XML element where the attribute should be defined
* @param attributeName
* - the name of the attribute whose value will be set on the
* property
*/
public static void setValueIfAttributeDefined(BeanDefinitionBuilder builder,
Element element, String attributeName) {
setValueIfAttributeDefined(builder, element, attributeName,
Conventions.attributeNameToPropertyName(attributeName));
public static void setValueIfAttributeDefined(
BeanDefinitionBuilder builder, Element element, String attributeName) {
setValueIfAttributeDefined(builder, element, attributeName, Conventions
.attributeNameToPropertyName(attributeName));
}
/**
* Configures the provided bean definition builder with a property
* reference to a bean. The bean reference is identified by the value
* from the attribute whose name is provided if that attribute is
* defined in the given element.
* Configures the provided bean definition builder with a property reference
* to a bean. The bean reference is identified by the value from the
* attribute whose name is provided if that attribute is defined in the
* given element.
*
* @param builder the bean definition builder to be configured
* @param element the XML element where the attribute should be defined
* @param attributeName the name of the attribute whose value will be
* used as a bean reference to populate the property
* @param propertyName the name of the property to be populated
* @param builder
* the bean definition builder to be configured
* @param element
* the XML element where the attribute should be defined
* @param attributeName
* the name of the attribute whose value will be used as a bean
* reference to populate the property
* @param propertyName
* the name of the property to be populated
*/
public static void setReferenceIfAttributeDefined(BeanDefinitionBuilder builder,
Element element, String attributeName, String propertyName) {
public static void setReferenceIfAttributeDefined(
BeanDefinitionBuilder builder, Element element,
String attributeName, String propertyName) {
String attributeValue = element.getAttribute(attributeName);
if (StringUtils.hasText(attributeValue)) {
builder.addPropertyReference(propertyName, attributeValue);
@@ -111,34 +123,38 @@ public abstract class IntegrationNamespaceUtils {
}
/**
* Configures the provided bean definition builder with a property
* reference to a bean. The bean reference is identified by the value
* from the attribute whose name is provided if that attribute is
* defined in the given element.
* Configures the provided bean definition builder with a property reference
* to a bean. The bean reference is identified by the value from the
* attribute whose name is provided if that attribute is defined in the
* given element.
*
* <p>The property name will be the camel-case equivalent of the lower
* case hyphen separated attribute (e.g. the "foo-bar" attribute would
* match the "fooBar" property).
* <p>
* The property name will be the camel-case equivalent of the lower case
* hyphen separated attribute (e.g. the "foo-bar" attribute would match the
* "fooBar" property).
*
* @see Conventions#attributeNameToPropertyName(String)
*
* @param builder the bean definition builder to be configured
* @param element - the XML element where the attribute should be defined
* @param attributeName - the name of the attribute whose value will be
* used as a bean reference to populate the property
* @param builder
* the bean definition builder to be configured
* @param element
* - the XML element where the attribute should be defined
* @param attributeName
* - the name of the attribute whose value will be used as a bean
* reference to populate the property
*
* @see Conventions#attributeNameToPropertyName(String)
*/
public static void setReferenceIfAttributeDefined(BeanDefinitionBuilder builder,
Element element, String attributeName) {
public static void setReferenceIfAttributeDefined(
BeanDefinitionBuilder builder, Element element, String attributeName) {
setReferenceIfAttributeDefined(builder, element, attributeName,
Conventions.attributeNameToPropertyName(attributeName));
}
/**
* Provides a user friendly description of an element based on its node
* name and, if available, its "id" attribute value. This is useful for
* creating error messages from within bean definition parsers.
* Provides a user friendly description of an element based on its node name
* and, if available, its "id" attribute value. This is useful for creating
* error messages from within bean definition parsers.
*/
public static String createElementDescription(Element element) {
String elementId = "'" + element.getNodeName() + "'";
@@ -155,53 +171,106 @@ public abstract class IntegrationNamespaceUtils {
* attribute, this will create and register a PollerMetadata instance and
* then add it as a property reference of the target builder.
*
* @param pollerElement the "poller" element to parse
* @param targetBuilder the builder that expects the "trigger" property
* @param parserContext the parserContext for the target builder
* @param pollerElement
* the "poller" element to parse
* @param targetBuilder
* the builder that expects the "trigger" property
* @param parserContext
* the parserContext for the target builder
*/
public static void configurePollerMetadata(Element pollerElement, BeanDefinitionBuilder targetBuilder, ParserContext parserContext) {
public static void configurePollerMetadata(Element pollerElement,
BeanDefinitionBuilder targetBuilder, ParserContext parserContext) {
if (pollerElement.hasAttribute("ref")) {
if (pollerElement.getAttributes().getLength() != 1) {
parserContext.getReaderContext().error(
"A 'poller' element that provides a 'ref' must have no other attributes.", pollerElement);
parserContext
.getReaderContext()
.error(
"A 'poller' element that provides a 'ref' must have no other attributes.",
pollerElement);
}
if (pollerElement.getChildNodes().getLength() != 0) {
parserContext.getReaderContext().error(
"A 'poller' element that provides a 'ref' must have no child elements.", pollerElement);
parserContext
.getReaderContext()
.error(
"A 'poller' element that provides a 'ref' must have no child elements.",
pollerElement);
}
targetBuilder.addPropertyReference("pollerMetadata", pollerElement.getAttribute("ref"));
}
else {
BeanDefinition beanDefinition = parserContext.getDelegate().parseCustomElement(
pollerElement, targetBuilder.getBeanDefinition());
targetBuilder.addPropertyReference("pollerMetadata", pollerElement
.getAttribute("ref"));
} else {
BeanDefinition beanDefinition = parserContext.getDelegate()
.parseCustomElement(pollerElement,
targetBuilder.getBeanDefinition());
if (beanDefinition == null) {
parserContext.getReaderContext().error("BeanDefinition must not be null", pollerElement);
parserContext.getReaderContext().error(
"BeanDefinition must not be null", pollerElement);
}
targetBuilder.addPropertyValue("pollerMetadata", beanDefinition);
}
}
public static BeanComponentDefinition parseInnerHandlerDefinition(Element element, ParserContext parserContext){
// parses out inner bean definition for concrete implementation if defined
List<Element> childElements = DomUtils.getChildElementsByTagName(element, "bean");
/**
* Get a text value from a named attribute if it exists, otherwise check for
* a nested element of the same name. If both are specified it is an error,
* but if neither is specified, just returns null.
*
* @param element
* a DOM node
* @param name
* the name of the property (attribute or child element)
* @param parserContext
* the current context
* @return the text from the attribite or element or null
*/
public static String getTextFromAttributeOrNestedElement(Element element,
String name, ParserContext parserContext) {
String attr = element.getAttribute(name);
Element childElement = DomUtils.getChildElementByTagName(element, name);
if (StringUtils.hasText(attr) && childElement != null) {
parserContext.getReaderContext().error(
"Either an attribute or a child element can be specified for "
+ name + " but not both", element);
return null;
}
if (!StringUtils.hasText(attr) && childElement == null) {
return null;
}
return StringUtils.hasText(attr) ? attr : childElement.getTextContent();
}
public static BeanComponentDefinition parseInnerHandlerDefinition(
Element element, ParserContext parserContext) {
// parses out inner bean definition for concrete implementation if
// defined
List<Element> childElements = DomUtils.getChildElementsByTagName(
element, "bean");
BeanComponentDefinition innerComponentDefinition = null;
if (childElements != null && childElements.size() == 1){
if (childElements != null && childElements.size() == 1) {
Element beanElement = childElements.get(0);
BeanDefinitionParserDelegate delegate = parserContext.getDelegate();
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(beanElement);
bdHolder = delegate.decorateBeanDefinitionIfRequired(beanElement, bdHolder);
BeanDefinitionHolder bdHolder = delegate
.parseBeanDefinitionElement(beanElement);
bdHolder = delegate.decorateBeanDefinitionIfRequired(beanElement,
bdHolder);
BeanDefinition inDef = bdHolder.getBeanDefinition();
String beanName = BeanDefinitionReaderUtils.generateBeanName(inDef, parserContext.getRegistry());
innerComponentDefinition = new BeanComponentDefinition(inDef, beanName);
String beanName = BeanDefinitionReaderUtils.generateBeanName(inDef,
parserContext.getRegistry());
innerComponentDefinition = new BeanComponentDefinition(inDef,
beanName);
parserContext.registerBeanComponent(innerComponentDefinition);
}
String ref = element.getAttribute(REF_ATTRIBUTE);
Assert.isTrue(!(StringUtils.hasText(ref) && innerComponentDefinition != null), "Ambiguous definition. Inner bean " +
(innerComponentDefinition == null
? innerComponentDefinition
: innerComponentDefinition.getBeanDefinition().getBeanClassName()) + " declaration and \"ref\" " + ref +
" are not allowed together.");
Assert
.isTrue(
!(StringUtils.hasText(ref) && innerComponentDefinition != null),
"Ambiguous definition. Inner bean "
+ (innerComponentDefinition == null ? innerComponentDefinition
: innerComponentDefinition
.getBeanDefinition()
.getBeanClassName())
+ " declaration and \"ref\" " + ref
+ " are not allowed together.");
return innerComponentDefinition;
}