INTEXT-12 - Add XQuery support
For reference: https://jira.springsource.org/browse/INTEXT-12
This commit is contained in:
committed by
Gunnar Hillert
parent
e353bf49f5
commit
0180a51729
@@ -8,6 +8,7 @@ The Spring Integration Extensions project provides extension modules for [Spring
|
||||
* [SMB][] Support
|
||||
* [Print][] Support
|
||||
* [Atmosphere][] Support ([Websockets][])
|
||||
* [XQuery][] Support
|
||||
|
||||
## Getting support
|
||||
|
||||
@@ -123,4 +124,5 @@ The Spring Integration Extensions Framework is released under version 2.0 of the
|
||||
[SMB]: http://en.wikipedia.org/wiki/Server_Message_Block
|
||||
[Print]: http://docs.oracle.com/javase/6/docs/technotes/guides/jps/index.html
|
||||
[Atmosphere]: https://github.com/Atmosphere/atmosphere
|
||||
[Websockets]: http://www.html5rocks.com/en/tutorials/websockets/basics/
|
||||
[Websockets]: http://www.html5rocks.com/en/tutorials/websockets/basics/
|
||||
[XQuery]: http://en.wikipedia.org/wiki/XQuery
|
||||
170
spring-integration-xquery/README.md
Normal file
170
spring-integration-xquery/README.md
Normal file
@@ -0,0 +1,170 @@
|
||||
Spring Integration XQuery Support
|
||||
=================================
|
||||
|
||||
# Overview
|
||||
|
||||
**XQuery** is a query and functional programming language that is used to query over a collection of XML data. XQuery is a super-set of **XPath 2.0**. Therefore, if you are looking for *XPath 2.0* functionality, you may consider using the provided components as well. For more information on *XQuery*, please see:
|
||||
|
||||
* http://en.wikipedia.org/wiki/XQuery
|
||||
* http://en.wikipedia.org/wiki/XPath_2.0
|
||||
|
||||
The **XQuery API for Java** ([JSR225][]) is a specification for providing a common *XQuery API* to the Java programming language. The API can be used for *XML databases* as well as pure *XQuery processors*. For more information, please see:
|
||||
|
||||
* http://en.wikipedia.org/wiki/XQuery_API_for_Java
|
||||
* http://xqj.net/
|
||||
* http://xqj.net/javadoc/
|
||||
|
||||
Various products and libraries provide *XQuery* support. Below is a selection of available choices:
|
||||
|
||||
## XML Databases
|
||||
|
||||
* **BaseX** (BSD License) - http://basex.org/
|
||||
* **eXist** (GNU LGPL) - http://www.exist-db.org/
|
||||
* **MarkLogic** (Commercial License, Free Option) - http://developer.marklogic.com/express
|
||||
* **Sedna** (Apache License, Version 2.0) - http://www.sedna.org/
|
||||
|
||||
## XQuery Processors
|
||||
|
||||
* **Zorba** (Apache License, Version 2.0) - http://www.zorba-xquery.com/
|
||||
* **SAXON** (Mozilla Public License) - http://saxon.sourceforge.net/
|
||||
|
||||
*Zorba* is written in C++ but provides a Java API ([JSR225][]). *SAXON*, being a pure Java implementation, can be used as a normal Java library. Of all the available XQuery supporting options, *SAXON* is probably the the most widely used choice for Java developers.
|
||||
|
||||
# Provided Spring Integration Components
|
||||
|
||||
Currently, the *Spring Integration XQuery Module* provides the following components:
|
||||
|
||||
* XQuery Router
|
||||
* XQuery Transformer
|
||||
|
||||
## Java Implementation
|
||||
|
||||
The class *o.s.i.xquery.core.XQueryExecutor* is the backbone for all *XQuery* related operations within this Spring Integration module. Its corresponding test class is *o.s.i.xquery.core.AbstractXQueryExecutorTests* with the subclasses:
|
||||
|
||||
* *o.s.i.xquery.core.SaxonXQueryExecutorTests*
|
||||
* *o.s.i.xquery.core.SednaXQueryExecutorTests*
|
||||
|
||||
Each of these sub-classes instantiates the *XQueryExecutor* with the corresponding implementations of the *javax.xml.xquery.[XQDataSource][]* interface. The *XQueryExecutor* provides a setter for specifying the [XQDataSource][] to use. If not explicitly specified, it will default to use *Saxon*, if available on the classpath.
|
||||
|
||||
The XQuery Executor is tested using Saxon and Sedna. Furthermore, we provide the [Spring Integration XQuery Samples][] that additionally also cover *BaseX*. *BaseX* is not included in the actual Spring Integration module, as it conflicts with the *Saxon* jars. Both, the *Sedna* and the *BaseX* XML database need to be started and the datasource needs to connect to them. This is even true, if the XML being queried is not present in the database (as we typically provide it with the payload of the Spring Integration *Message*).
|
||||
|
||||
See the class comments of *o.s.i.xquery.core.SednaXQueryExecutorTests* for instructions on starting the *Sedna* server and executing the tests using *Sedna*'s implementation. Additional information can also be found at:
|
||||
|
||||
* http://xqj.net/
|
||||
|
||||
Of course, much more detailed information is also available on the respective product websites.
|
||||
|
||||
## XML Namespace Support
|
||||
|
||||
The Spring Integration XQuery components also provide XML Namespace support in order to simplify their configuration.
|
||||
|
||||
### Routers
|
||||
|
||||
#### With **xquery** sub element
|
||||
|
||||
<int-xquery:xquery-router id="xqueryRouterOne" input-channel="xpathRouterOne">
|
||||
<int-xquery:xquery>
|
||||
<![CDATA[
|
||||
declare variable $name as xs:string external;
|
||||
declare variable $class as xs:int external;
|
||||
for $student in /mappings/students/student,
|
||||
$subject in /mappings/subjects/subject
|
||||
where $student/@id = $subject/students/studentId
|
||||
and $student/name = $name
|
||||
and $student/class = $class
|
||||
return $subject/name/text()
|
||||
]]>
|
||||
</int-xquery:xquery>
|
||||
<int-xquery:xquery-parameter name="name" expression="headers['name']"/>
|
||||
<int-xquery:xquery-parameter name="class" value="1"/>
|
||||
</int-xquery:xquery-router>
|
||||
|
||||
The configuration is pretty simple. The XQuery in this example is specified using the *xquery* sub-element. The query once executed will yield the names of the output channels. XQueries can have *named parameters* specified. In this case we have two named parameters: **name** and **class**.
|
||||
|
||||
The value or the expression to find the value for these named parameters is specified using the *xquery-parameter* sub-element. This sub-element provides two possible ways to provide parameters. In the first parameter, the value of the **name** parameter is deduced using a SpEL expression. For the second parameter named **class**, a statically defined value is used.
|
||||
|
||||
#### With **xquery** attribute
|
||||
|
||||
<int-xquery:xquery-router id="xqueryRouterTwo"
|
||||
input-channel="xpathRouterOne"
|
||||
xquery="'Hello World'"
|
||||
converter="converter"
|
||||
xq-datasource="xqDs">
|
||||
<int-xquery:xquery-parameter name="name" ref="name"/>
|
||||
</int-xquery:xquery-router>
|
||||
|
||||
The above config now specifies the *xquery* attribute to specify the query. It additionally has the *converter* and the *xq-datasource* attributes. The *converter* holds a reference to the bean which implements the `org.springframework.integration.xml.DefaultXmlPayloadConverter` interface. By default it uses `org.springframework.integration.xml.DefaultXmlPayloadConverter` Please note that this interface and the implementation is from **spring-integration-xml** project. The *xq-datasource* attribute holds a reference to a bean that implements the `javax.xml.xquery.XQDataSource` interface. By default it will use `net.sf.saxon.xqj.SaxonXQDataSource` implementation.
|
||||
|
||||
#### With **xquery-file-resource** attribute
|
||||
|
||||
<int-xquery:xquery-router id="xqueryRouterFour"
|
||||
input-channel="xpathRouterOne"
|
||||
xquery-file-resource="org/springframework/integration/xquery/XQuery.xq"
|
||||
converter="converter"
|
||||
xq-datasource="xqDs">
|
||||
<int-xquery:xquery-parameter name="name" expression="headers['name']"/>
|
||||
<int-xquery:xquery-parameter name="class" value="1"/>
|
||||
</int-xquery:xquery-router>
|
||||
|
||||
Instead of the nested *xquery* element or the *xquery* attribute, we provide the path to the resource that contains the xquery, typically a *.xq* file.
|
||||
|
||||
Similar to the routers in the core module, the xquery routers accept the mapping subelement to provide an additional level of indirection and mapping from the obtained value(s) from xquery execution to the output channels. Thus, you can have the following subelement in the xquery router definition
|
||||
|
||||
<int:mapping value="val1" channel="channelA" />
|
||||
<int:mapping value="val2" channel="channelB" />
|
||||
|
||||
### Transformers
|
||||
|
||||
Similar to routers, transformers too support accepting the xquery as a child sub element, attribute or an attribute with the resource path to the *.xq* file. Since the definitions and meaning of the common attributes are similar to that of the router, we will not be explaining them again unless we have some attribute specific to transformers.
|
||||
|
||||
#### With **xquery** subelement
|
||||
|
||||
<int-xquery:xquery-transformer id="xqueryTransformerOne"
|
||||
input-channel="xqueryTransformerInOne"
|
||||
output-channel="output">
|
||||
<int-xquery:xquery>
|
||||
<![CDATA[
|
||||
declare variable $name as xs:string external;
|
||||
declare variable $class as xs:int external;
|
||||
for $student in /mappings/students/student,
|
||||
$subject in /mappings/subjects/subject
|
||||
where $student/@id = $subject/students/studentId
|
||||
and $student/name = $name
|
||||
and $student/class = $class
|
||||
return $subject/name/text()
|
||||
]]>
|
||||
</int-xquery:xquery>
|
||||
<int-xquery:xquery-parameter name="name" expression="headers['name']"/>
|
||||
<int-xquery:xquery-parameter name="class" value="1"/>
|
||||
</int-xquery:xquery-transformer>
|
||||
|
||||
#### With **xquery** attribute
|
||||
|
||||
<int-xquery:xquery-transformer id="xqueryTransformerTwo"
|
||||
input-channel="xqueryTransformerOutTwo"
|
||||
output-channel="output"
|
||||
xquery="'Hello World'"
|
||||
converter="converter"
|
||||
xq-datasource="xqDs"
|
||||
format-output="true">
|
||||
</int-xquery:xquery-transformer>
|
||||
|
||||
An additional attibute *format-output* is mentioned, the value could be *true* or *false*. It informs the transformer to format the output xml generated after transformation.
|
||||
|
||||
#### With **xquery-file** attribute.
|
||||
|
||||
<int-xquery:xquery-transformer id="xqueryTransformerThree"
|
||||
input-channel="xqueryTransformerIPThree"
|
||||
output-channel="output"
|
||||
xquery-file-resource="classpath:org/springframework/integration/xquery/XQueryTransform.xq"
|
||||
converter="converter"
|
||||
xq-datasource="xqDs">
|
||||
</int-xquery:xquery-transformer>
|
||||
|
||||
###Credits
|
||||
We would like to thank **Ganesh Shetty** for his suggestion of inclusion of *XQuery* support in *Spring Integration*, giving the initial requirements and use cases for this module. We look forward for more support from the community for evaluating the libraries and provide their feedback.
|
||||
|
||||
[JSR225]: http://jcp.org/aboutJava/communityprocess/final/jsr225/index.html
|
||||
[xqj.net]: http://xqj.net/
|
||||
[XQDataSource]: http://xqj.net/javadoc/javax/xml/xquery/XQDataSource.html
|
||||
[Spring Integration XQuery Samples]: https://github.com/SpringSource/spring-integration-samples/tree/master/basic/xquery
|
||||
109
spring-integration-xquery/pom.xml
Normal file
109
spring-integration-xquery/pom.xml
Normal file
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-xquery</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<prerequisites>
|
||||
<maven>2.2.1</maven>
|
||||
</prerequisites>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*Tests.java</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>**/*Abstract*.java</exclude>
|
||||
</excludes>
|
||||
<excludes>
|
||||
<exclude>**/SednaXQueryExecutorTests.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>springsource-libs-milestone</id>
|
||||
<name>Spring Framework Maven Milestone Repository</name>
|
||||
<url>https://repo.springsource.org/libs-milestone</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-core</artifactId>
|
||||
<version>2.2.0.M3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-xml</artifactId>
|
||||
<version>2.2.0.M3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-test</artifactId>
|
||||
<version>2.2.0.M3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.xml.xquery</groupId>
|
||||
<artifactId>xqj-api</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.sf.saxon</groupId>
|
||||
<artifactId>Saxon-HE</artifactId>
|
||||
<version>9.4</version>
|
||||
<scope>optional</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.xqj.sedna</groupId>
|
||||
<artifactId>sedna-xqj</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>optional</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.xqj2</groupId>
|
||||
<artifactId>xqj2</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<scope>optional</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit-dep</artifactId>
|
||||
<version>4.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.config.xml;
|
||||
|
||||
import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler;
|
||||
|
||||
/**
|
||||
* The namespace handler for the "int-xquery" namespace
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class IntegrationXQueryNamespaceHandler extends
|
||||
AbstractIntegrationNamespaceHandler {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.NamespaceHandler#init()
|
||||
*/
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("xquery-router", new XQueryRouterParser());
|
||||
registerBeanDefinitionParser("xquery-transformer", new XQueryTransformerParser());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.config.xml;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.xquery.core.XQueryExecutor;
|
||||
import org.springframework.integration.xquery.support.XQueryParameter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* The common utility class for the XQuery components that will be performing the
|
||||
* common operations used in the parsers like, creating the XQueryExecutor instance
|
||||
* etc.
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryParserUtils {
|
||||
|
||||
/**
|
||||
* Create the instance of the {@link XQueryExecutor}
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
public static final AbstractBeanDefinition getXQueryExecutor(Element element) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(XQueryExecutor.class);
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "converter");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "xq-datasource","xQDataSource");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "format-output");
|
||||
NodeList list = element.getElementsByTagNameNS(element.getNamespaceURI(), "xquery");
|
||||
Attr xQueryAttribute = element.getAttributeNode("xquery");
|
||||
Attr xQueryResource = element.getAttributeNode("xquery-file-resource");
|
||||
|
||||
Assert.isTrue(!(xQueryAttribute != null && xQueryResource != null),
|
||||
"Only one of xquery or xquery-file-resource may be specified");
|
||||
|
||||
Assert.isTrue(!(xQueryAttribute != null && list != null && list.getLength() > 0),
|
||||
"At most one of the xquery attribute " +
|
||||
"or the xquery child element should to be provided");
|
||||
|
||||
Assert.isTrue(!(xQueryResource != null && list != null && list.getLength() > 0),
|
||||
"At most one of the xquery-file-resource attribute " +
|
||||
"or the xquery child element should to be provided");
|
||||
|
||||
Assert.isTrue(xQueryResource != null || xQueryAttribute != null || (list != null && list.getLength() > 0),
|
||||
"At least one of xquery, xquery-file-resource attributes or the xquery child element needs to be provided");
|
||||
|
||||
if(xQueryResource != null) {
|
||||
//resource specified
|
||||
String textContent = xQueryResource.getTextContent();
|
||||
Assert.isTrue(StringUtils.hasText(textContent),"Non empty, non null resource path should be provided");
|
||||
Resource resource;
|
||||
if(textContent.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) {
|
||||
resource = new ClassPathResource(textContent.substring(ResourceUtils.CLASSPATH_URL_PREFIX.length()));
|
||||
}
|
||||
else if(textContent.startsWith(ResourceUtils.FILE_URL_PREFIX)) {
|
||||
resource = new FileSystemResource(textContent.substring(ResourceUtils.FILE_URL_PREFIX.length()));
|
||||
}
|
||||
else {
|
||||
//assuming its a classpath resource
|
||||
resource = new ClassPathResource(textContent);
|
||||
}
|
||||
builder.addPropertyValue("xQueryFileResource", resource);
|
||||
}
|
||||
else {
|
||||
//child element or attribute defined
|
||||
String textContent;
|
||||
if(xQueryAttribute == null) {
|
||||
//child might be element specified
|
||||
Assert.isTrue(list != null && list.getLength() == 1,"Maximum one xquery child node may be specified");
|
||||
textContent = list.item(0).getTextContent();
|
||||
}
|
||||
else {
|
||||
//xquery specified in the attribute
|
||||
textContent = xQueryAttribute.getTextContent();
|
||||
}
|
||||
if(StringUtils.hasText(textContent)) {
|
||||
builder.addPropertyValue("xQuery", textContent.trim());
|
||||
}
|
||||
}
|
||||
|
||||
//lets get the parameter nodes
|
||||
NodeList parameters = element.getElementsByTagNameNS(element.getNamespaceURI(), "xquery-parameter");
|
||||
if(parameters != null && parameters.getLength() > 0) {
|
||||
ManagedList<AbstractBeanDefinition> params = new ManagedList<AbstractBeanDefinition>();
|
||||
for(int i = 0;i < parameters.getLength();i++) {
|
||||
Node node = parameters.item(i);
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
Assert.isTrue(attrs.getLength() > 1,
|
||||
"One of ref, value or expression should be present with the name attribute");
|
||||
Attr nameAttr = (Attr)attrs.getNamedItem("name");
|
||||
|
||||
//TODO No check for the mutually exclusivity of these attributes, needed?
|
||||
|
||||
//create a new XQueryParameter instance
|
||||
BeanDefinitionBuilder paramBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(XQueryParameter.class);
|
||||
paramBuilder.addConstructorArgValue(nameAttr.getTextContent());
|
||||
Attr attr;
|
||||
//add the value if present
|
||||
if(attrs.getNamedItem("value") != null) {
|
||||
attr = (Attr)attrs.getNamedItem("value");
|
||||
paramBuilder.addPropertyValue("parameterValue",attr.getTextContent());
|
||||
}
|
||||
else if(attrs.getNamedItem("ref") != null) {
|
||||
attr = (Attr)attrs.getNamedItem("ref");
|
||||
paramBuilder.addPropertyReference("parameterValue", attr.getTextContent());
|
||||
}
|
||||
else if(attrs.getNamedItem("expression") != null) {
|
||||
attr = (Attr)attrs.getNamedItem("expression");
|
||||
paramBuilder.addPropertyValue("expression", attr.getTextContent());
|
||||
}
|
||||
params.add(paramBuilder.getBeanDefinition());
|
||||
}
|
||||
builder.addPropertyValue("xQueryParameters", params);
|
||||
}
|
||||
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.config.xml;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractRouterParser;
|
||||
import org.springframework.integration.xquery.router.XQueryRouter;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* The parser for the XQuery router
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryRouterParser extends AbstractRouterParser {
|
||||
|
||||
@Override
|
||||
protected BeanDefinition doParseRouter(Element element,
|
||||
ParserContext parserContext) {
|
||||
BeanDefinitionBuilder routerBuilder = BeanDefinitionBuilder.genericBeanDefinition(XQueryRouter.class);
|
||||
AbstractBeanDefinition executor = XQueryParserUtils.getXQueryExecutor(element);
|
||||
routerBuilder.addPropertyValue("executor", executor);
|
||||
return routerBuilder.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.config.xml;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractTransformerParser;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The parser for the XQuery transformer component
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryTransformerParser extends AbstractTransformerParser {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.integration.config.xml.AbstractTransformerParser#getTransformerClassName()
|
||||
*/
|
||||
@Override
|
||||
protected String getTransformerClassName() {
|
||||
return "org.springframework.integration.xquery.transformer.XQueryTransformer";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.integration.config.xml.AbstractTransformerParser#parseTransformer(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
|
||||
*/
|
||||
@Override
|
||||
protected void parseTransformer(Element element,
|
||||
ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
AbstractBeanDefinition executor = XQueryParserUtils.getXQueryExecutor(element);
|
||||
builder.addPropertyValue("executor", executor);
|
||||
//Add the result type and the result class attributes
|
||||
String resultType = element.getAttribute("result-type");
|
||||
boolean hasResultType = StringUtils.hasText(resultType);
|
||||
String xqueryResultMapper = element.getAttribute("xquery-result-mapper");
|
||||
boolean hasResultMapper = StringUtils.hasText(xqueryResultMapper);
|
||||
Assert.isTrue(!(hasResultType && hasResultMapper),
|
||||
"Only one of result-type or xquery-result-mapper may be specified");
|
||||
if(hasResultType) {
|
||||
Class<?> type = null;
|
||||
if("string".equalsIgnoreCase(resultType)) {
|
||||
type = String.class;
|
||||
}
|
||||
else if("boolean".equalsIgnoreCase(resultType)) {
|
||||
type = Boolean.class;
|
||||
}
|
||||
else if("number".equalsIgnoreCase(resultType)) {
|
||||
type = Number.class;
|
||||
}
|
||||
else if("node".equalsIgnoreCase(resultType)) {
|
||||
type = Node.class;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
type = Class.forName(resultType);
|
||||
} catch (ClassNotFoundException e) {
|
||||
new IllegalArgumentException("Class " + resultType + " specified in result-type not found, " +
|
||||
"have you provided the fully qualified name?",e);
|
||||
}
|
||||
}
|
||||
builder.addPropertyValue("resultType", type);
|
||||
}
|
||||
else if(hasResultMapper) {
|
||||
builder.addPropertyReference("resultMapper", xqueryResultMapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.xquery.XQConnection;
|
||||
import javax.xml.xquery.XQConstants;
|
||||
import javax.xml.xquery.XQDataSource;
|
||||
import javax.xml.xquery.XQException;
|
||||
import javax.xml.xquery.XQPreparedExpression;
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.xml.DefaultXmlPayloadConverter;
|
||||
import org.springframework.integration.xml.XmlPayloadConverter;
|
||||
import org.springframework.integration.xquery.support.AbstractXQueryResultMapper;
|
||||
import org.springframework.integration.xquery.support.BooleanResultMapper;
|
||||
import org.springframework.integration.xquery.support.NodeResultMapper;
|
||||
import org.springframework.integration.xquery.support.NumberResultMapper;
|
||||
import org.springframework.integration.xquery.support.StringResultMapper;
|
||||
import org.springframework.integration.xquery.support.XQueryParameter;
|
||||
import org.springframework.integration.xquery.support.XQueryResultMapper;
|
||||
import org.springframework.integration.xquery.support.XQueryUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The common logic for performing the common xquery operations would reside in this
|
||||
* implementation.
|
||||
* The class would be instantiated with the xquery to be executed and the parameters
|
||||
* that would be used. It would return the result of the execution with the
|
||||
* {@link Message} instance passed to one of its execute methods.
|
||||
* Currently doesn't support advanced mapping techniques of mapping the resulting Node(s)
|
||||
* to a custom object type
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryExecutor implements InitializingBean,BeanClassLoaderAware {
|
||||
|
||||
|
||||
private static final String SAXON_XQ_DATASOURCE_CLASS = "net.sf.saxon.xqj.SaxonXQDataSource";
|
||||
|
||||
private final Log logger = LogFactory.getLog(XQueryExecutor.class);
|
||||
|
||||
/**
|
||||
* The payload converter
|
||||
*/
|
||||
private XmlPayloadConverter converter = new DefaultXmlPayloadConverter();
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private volatile Map resultMappers;
|
||||
|
||||
private volatile boolean formatOutput;
|
||||
|
||||
/**
|
||||
* The xQuery that this Executor will execute
|
||||
*/
|
||||
private String xQuery;
|
||||
|
||||
private XQDataSource xqDataSource;
|
||||
|
||||
private Map<String, XQueryParameter> xQueryParameterMap;
|
||||
|
||||
//maintained internally and used for setting the values
|
||||
private List<String> xQueryParameters;
|
||||
|
||||
//The resource to the XQuery's .xq file
|
||||
private Resource xQueryFileResource;
|
||||
|
||||
private String userName;
|
||||
|
||||
private String password;
|
||||
|
||||
private ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
//TODO: Can we have a static xml resource which will be used always to execute the
|
||||
//given XQuery as against the one sent in the payload. The default is to use the one in the
|
||||
//payload unless one for static xml is provided
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if(resultMappers == null) {
|
||||
resultMappers = new HashMap<Class<?>,XQueryResultMapper<?>>();
|
||||
}
|
||||
addDefaultMappers();
|
||||
|
||||
if(xqDataSource == null) {
|
||||
xqDataSource = discoverXQDataSource();//default
|
||||
}
|
||||
if(xQuery == null) {
|
||||
//perhaps resource specified
|
||||
Assert.notNull(xQueryFileResource, "One of XQuery or the XQuery resource is mandatory");
|
||||
xQuery = XQueryUtils.readXQueryFromResource(xQueryFileResource);
|
||||
}
|
||||
|
||||
try {
|
||||
XQConnection conn = getConnection();
|
||||
XQPreparedExpression expression = conn.prepareExpression(xQuery);
|
||||
QName[] extParameters = expression.getAllExternalVariables();
|
||||
if(extParameters != null && extParameters.length > 0) {
|
||||
xQueryParameters = new ArrayList<String>();
|
||||
for(QName qName:extParameters) {
|
||||
xQueryParameters.add(qName.getLocalPart());
|
||||
}
|
||||
}
|
||||
expression.close();
|
||||
conn.close();
|
||||
} catch (XQException e) {
|
||||
throw new MessagingException("Caught Exception while opening a connection to the datasource", e);
|
||||
}
|
||||
|
||||
if(xQueryParameters != null) {
|
||||
if (xQueryParameterMap == null) {
|
||||
throw new MessagingException("Expecting " + xQueryParameters.size() + " parameters in the xquery, " +
|
||||
"but none provided to the router");
|
||||
}
|
||||
|
||||
//now check if all the parameter needed are present in the map
|
||||
List<String> missingParameters = new ArrayList<String>();
|
||||
for(String xQueryParameter:xQueryParameters) {
|
||||
if(!xQueryParameterMap.containsKey(xQueryParameter)) {
|
||||
missingParameters.add(xQueryParameter);
|
||||
}
|
||||
}
|
||||
|
||||
if(missingParameters.size() > 0) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("[").append("$").append(missingParameters.get(0));
|
||||
if(missingParameters.size() > 1) {
|
||||
for(int i = 1;i < missingParameters.size();i++) {
|
||||
builder.append(", ").append("$").append(missingParameters.get(i));
|
||||
}
|
||||
}
|
||||
builder.append("]");
|
||||
throw new MessagingException("Missing parameter(s) " + builder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
Assert.notNull(classLoader, "Non null class loader instance expected");
|
||||
this.classLoader = classLoader;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The method that finds an implementation in the classpath for some well known
|
||||
* providers. This will kick into action only if an {@link XQDataSource} is not
|
||||
* explicitly provided by the user by invoking {@link XQueryExecutor#setXQDataSource(XQDataSource)}
|
||||
* The method currently looks for Saxon's implementation only
|
||||
*
|
||||
* @return the instantiated {@link XQDataSource}
|
||||
*/
|
||||
private XQDataSource discoverXQDataSource() {
|
||||
Object xqDataSource = null;
|
||||
try {
|
||||
if(ClassUtils.isPresent(SAXON_XQ_DATASOURCE_CLASS, classLoader)) {
|
||||
xqDataSource = Class.forName(SAXON_XQ_DATASOURCE_CLASS).newInstance();
|
||||
}
|
||||
//For now its just Saxon we will discover, we can add other implementations here later
|
||||
} catch (Exception e) {
|
||||
throw new MessagingException("Unable to discover/instantiate an XQDataSource, " +
|
||||
"see nested exception for details", e);
|
||||
}
|
||||
Assert.notNull(xqDataSource, "No XQDataSource provided nor any known implementation discovered in the classpath");
|
||||
logger.info("Using \"" + xqDataSource.getClass() + "\" as the XQDataSource implementation");
|
||||
return (XQDataSource)xqDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the connection, uses userName and password if one is set
|
||||
* @return
|
||||
* @throws XQException
|
||||
*/
|
||||
private XQConnection getConnection() throws XQException {
|
||||
XQConnection conn;
|
||||
if(StringUtils.hasText(userName)) {
|
||||
conn = xqDataSource.getConnection(userName,password);
|
||||
}
|
||||
else {
|
||||
conn = xqDataSource.getConnection();
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* There are some default mappers defined, those will be added if the user has not provided
|
||||
* some implementations for them
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addDefaultMappers() {
|
||||
if(!resultMappers.containsKey(String.class)) {
|
||||
StringResultMapper mapper = new StringResultMapper();
|
||||
mapper.setFormatOutput(formatOutput);
|
||||
resultMappers.put(String.class, mapper);
|
||||
}
|
||||
|
||||
if(!resultMappers.containsKey(Boolean.class)) {
|
||||
BooleanResultMapper mapper = new BooleanResultMapper();
|
||||
mapper.setFormatOutput(formatOutput);
|
||||
resultMappers.put(Boolean.class, mapper);
|
||||
}
|
||||
|
||||
if(!resultMappers.containsKey(Number.class)) {
|
||||
NumberResultMapper mapper = new NumberResultMapper();
|
||||
mapper.setFormatOutput(formatOutput);
|
||||
resultMappers.put(Number.class, mapper);
|
||||
}
|
||||
|
||||
if(!resultMappers.containsKey(Node.class)) {
|
||||
NodeResultMapper mapper = new NodeResultMapper();
|
||||
mapper.setFormatOutput(formatOutput);
|
||||
resultMappers.put(Node.class, mapper);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the XQuery for result and produce the result as a {@link List} of {@link String}
|
||||
* @param message the source message that would be used to derive the values of the parameters
|
||||
*
|
||||
* @return The {@link List} of results
|
||||
*/
|
||||
public List<String> executeForString(Message<?> message) {
|
||||
return execute(message,String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the XQuery for result and produce the result as a {@link List} of {@link Boolean}
|
||||
* @param message the source message that would be used to derive the values of the parameters
|
||||
*
|
||||
* @return The {@link List} of results
|
||||
*/
|
||||
public List<Boolean> executeForBoolean(Message<?> message) {
|
||||
return execute(message,Boolean.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the XQuery for result and produce the result as a {@link List} of {@link Number}
|
||||
* @param message the source message that would be used to derive the values of the parameters
|
||||
*
|
||||
* @return The {@link List} of results
|
||||
*/
|
||||
public List<Number> executeForNumber(Message<?> message) {
|
||||
return execute(message,Number.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the XQuery for result and produce the result as a {@link List} of {@link Node}
|
||||
* @param message the source message that would be used to derive the values of the parameters
|
||||
*
|
||||
* @return The {@link List} of results
|
||||
*/
|
||||
public List<Node> executeForNode(Message<?> message) {
|
||||
return execute(message,Node.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given XQuery and returns a {@link List} of the provided type
|
||||
* @param <T>
|
||||
* @param message
|
||||
* @param returnType
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked"})
|
||||
public <T> List<T> execute(Message<?> message,Class<T> returnType) {
|
||||
Assert.notNull(message,"Non null message expected");
|
||||
Assert.notNull(returnType,"Non null type expected");
|
||||
Assert.isTrue(resultMappers.containsKey(returnType),"No Result mapper found for the type " + returnType.getName());
|
||||
return execute(message, (XQueryResultMapper<T>)resultMappers.get(returnType));
|
||||
}
|
||||
|
||||
/**
|
||||
* The method that executes the actual XQuery and uses the provided mapper
|
||||
* to get the result that is returned.
|
||||
* @param <T>
|
||||
* @param message
|
||||
* @param mapper
|
||||
* @return
|
||||
*/
|
||||
public <T> List<T> execute(Message<?> message,XQueryResultMapper<T> mapper) {
|
||||
Node node = converter.convertToNode(message.getPayload());
|
||||
|
||||
if(node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
XQConnection connection = null;
|
||||
XQPreparedExpression expression = null;
|
||||
try {
|
||||
connection = getConnection();
|
||||
expression = connection.prepareExpression(xQuery);
|
||||
expression.bindNode(XQConstants.CONTEXT_ITEM, node, null);
|
||||
|
||||
//bind the parameter values
|
||||
if(xQueryParameters != null && xQueryParameters.size() > 0) {
|
||||
//bind them one by one
|
||||
for(String parameter:xQueryParameters) {
|
||||
XQueryParameter xQueryParam = xQueryParameterMap.get(parameter);
|
||||
//TODO: Check what possible values can be supported to be set here
|
||||
//Accordingly do we need to set the third parameter for XQItemType
|
||||
expression.bindObject(new QName(xQueryParam.getParameterName()),
|
||||
xQueryParam.evaluate(message), null);
|
||||
}
|
||||
}
|
||||
|
||||
XQResultSequence result = expression.executeQuery();
|
||||
return mapper.mapResults(result);
|
||||
|
||||
} catch (XQException e) {
|
||||
throw new MessagingException("Caught Exception while opening a connection to the datasource", e);
|
||||
} finally {
|
||||
try {
|
||||
if(expression != null) {
|
||||
expression.close();
|
||||
}
|
||||
if(connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
} catch (XQException e) {
|
||||
logger.error("Caught Exception while closing the XQ expression.connection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all the result mappers to be used by this executor.
|
||||
* @param <T>
|
||||
* @param mappers
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public <T> void setResultMappers(Map<Class<T>, XQueryResultMapper<T>> mappers) {
|
||||
Assert.notNull(mappers);
|
||||
this.resultMappers = new HashMap<Class<T>, XQueryResultMapper<T>>(mappers);
|
||||
//not iterate through them and set the format
|
||||
for(Object mapper:resultMappers.values()) {
|
||||
if(mapper instanceof AbstractXQueryResultMapper) {
|
||||
((AbstractXQueryResultMapper)mapper).setFormatOutput(formatOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*Set the {@link XmlPayloadConverter} that would be used to convert the payload
|
||||
* into the XML {@link Node}
|
||||
*
|
||||
* @param converter
|
||||
*/
|
||||
public void setConverter(XmlPayloadConverter converter) {
|
||||
Assert.notNull(converter, "Provide a non null instance of XmlPayloadConverter");
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* The XQuery string that would be evaluated to determine the channel names
|
||||
* @param xQuery
|
||||
*/
|
||||
public void setXQuery(String xQuery) {
|
||||
Assert.isTrue(xQueryFileResource == null, "Only one of XQuery resource file or XQuery may be specified");
|
||||
Assert.notNull(xQuery, "Provide a non null XQuery");
|
||||
this.xQuery = xQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the XQuery's .xq file as the resource. The contents of this file will be read as xQuery
|
||||
*
|
||||
* @param xQueryFileResource
|
||||
*/
|
||||
public void setXQueryFileResource(Resource xQueryFileResource) {
|
||||
Assert.isTrue(xQuery == null,"Only one of XQuery resource file or XQuery may be specified");
|
||||
this.xQueryFileResource = xQueryFileResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link XQDataSource}
|
||||
* @param xqDataSource
|
||||
*/
|
||||
public void setXQDataSource(XQDataSource xqDataSource) {
|
||||
Assert.notNull(xqDataSource, "Provide a non null instance of the XQDatasource");
|
||||
this.xqDataSource = xqDataSource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parameter map where the parameter name is the key and the
|
||||
* {@link XQueryParameter} instance is the value
|
||||
*
|
||||
* @param xQueryParameterMap
|
||||
*/
|
||||
public void setXQueryParameterMap(
|
||||
Map<String, XQueryParameter> xQueryParameterMap) {
|
||||
this.xQueryParameterMap = xQueryParameterMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a {@link XQueryParameter} to the map
|
||||
* @param param
|
||||
*/
|
||||
public void addXQueryParameter(XQueryParameter param) {
|
||||
if(xQueryParameterMap == null) {
|
||||
xQueryParameterMap = new HashMap<String, XQueryParameter>();
|
||||
}
|
||||
xQueryParameterMap.put(param.getParameterName(), param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that would be used to set the parameters in the parameter
|
||||
* map. Any non conflicting parameters would be retained
|
||||
* @param params
|
||||
*/
|
||||
public void setXQueryParameters(List<XQueryParameter> params) {
|
||||
if(params != null && params.size() > 0) {
|
||||
if(xQueryParameterMap == null)
|
||||
xQueryParameterMap = new HashMap<String, XQueryParameter>();
|
||||
for(XQueryParameter param:params) {
|
||||
xQueryParameterMap.put(param.getParameterName(), param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the output result is an xml, the value of this parameter will determine
|
||||
* if the output xml is to be formatted or not. By default, the output will
|
||||
* not be formatted
|
||||
*
|
||||
* @param formatOutput
|
||||
*/
|
||||
public void setFormatOutput(boolean formatOutput) {
|
||||
this.formatOutput = formatOutput;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//TODO: Support date, dateTime data types
|
||||
|
||||
|
||||
/**
|
||||
* Sets the user name to be used while obtaining the connection.
|
||||
*
|
||||
*/
|
||||
public void setUserName(String userName) {
|
||||
Assert.hasText(userName, "Null or empty string provided as user name");
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password to be used for obtaining the connection
|
||||
* The value if ignored if the userName is null
|
||||
*
|
||||
* @param password
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
Assert.notNull(password, "Null password provided");
|
||||
//Can password be empty string?
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.router;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.router.AbstractMappingMessageRouter;
|
||||
import org.springframework.integration.xquery.core.XQueryExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The message router that will evaluate the provided XQuery on the xml to determine the channel(s)
|
||||
* to which the message will be routed
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryRouter extends AbstractMappingMessageRouter {
|
||||
|
||||
private XQueryExecutor executor;
|
||||
|
||||
private Class<?> resultType;
|
||||
|
||||
@Override
|
||||
public void onInit() {
|
||||
super.onInit();
|
||||
Assert.notNull(executor,"No XQueryExecutor instance provided");
|
||||
if(resultType == null) {
|
||||
resultType = String.class;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.integration.router.AbstractMappingMessageRouter#getChannelKeys(org.springframework.integration.Message)
|
||||
*/
|
||||
@Override
|
||||
protected List<Object> getChannelKeys(Message<?> message) {
|
||||
List<Object> channelKeys = null;
|
||||
//Accept the key types in this class and then execute the appropriate method
|
||||
channelKeys = new ArrayList<Object>(executor.execute(message, resultType));
|
||||
return channelKeys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return "int-xml:xquery-router";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the executor to be used for executing the XQueries
|
||||
* @param executor
|
||||
*/
|
||||
public void setExecutor(XQueryExecutor executor) {
|
||||
Assert.notNull(executor,"Provide a non null implementation of the executor");
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the type of the object that would returned in the {@link List} returned
|
||||
* from getChannelKeys method. If non specified, {@link String} is assumed.
|
||||
* @param resultType
|
||||
*/
|
||||
public void setResultType(Class<?> resultType) {
|
||||
this.resultType = resultType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.support;
|
||||
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_BOOLEAN;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_DECIMAL;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_DOUBLE;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_FLOAT;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_INT;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_INTEGER;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_LONG;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_NEGATIVE_INTEGER;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_NONNEGATIVE_INTEGER;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_NONPOSITIVE_INTEGER;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_POSITIVE_INTEGER;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_SHORT;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_STRING;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_UNSIGNED_INT;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_UNSIGNED_LONG;
|
||||
import static javax.xml.xquery.XQItemType.XQBASETYPE_UNSIGNED_SHORT;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_ATTRIBUTE;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_COMMENT;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_DOCUMENT;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_DOCUMENT_ELEMENT;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_DOCUMENT_SCHEMA_ELEMENT;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_ELEMENT;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_NODE;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_PI;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_SCHEMA_ATTRIBUTE;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_SCHEMA_ELEMENT;
|
||||
import static javax.xml.xquery.XQItemType.XQITEMKIND_TEXT;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.TransformerFactoryConfigurationError;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.xquery.XQException;
|
||||
import javax.xml.xquery.XQItemType;
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
import org.springframework.integration.xquery.support.XQueryResultMapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The absract base class for {@link XQueryResultMapper} implementations
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractXQueryResultMapper<T> implements XQueryResultMapper<T> {
|
||||
|
||||
protected volatile boolean formatOutput;
|
||||
/**
|
||||
* The getBaseType method throws an exception if the item kind is of some specific types
|
||||
* This method will be used to check if the getBaseType method can be invoked or not
|
||||
* on the given element
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
protected boolean shouldSkipBaseType(XQItemType type) {
|
||||
return isNodeType(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* The method checks if the given type is a numeric field and returns an appropriate implementation
|
||||
* of the {@link Number}
|
||||
*
|
||||
* @param type
|
||||
* @param result
|
||||
* @return the appropriate {@link Number} implementation or null if cannot be converted to number
|
||||
*/
|
||||
protected Number convertToNumber(XQItemType type,XQResultSequence result) throws XQException {
|
||||
boolean skipBaseTypes = shouldSkipBaseType(type);
|
||||
Number value = null;
|
||||
if(!skipBaseTypes) {
|
||||
int baseType = type.getBaseType();
|
||||
if(baseType == XQBASETYPE_DOUBLE) {
|
||||
value = Double.valueOf(result.getDouble());
|
||||
|
||||
}
|
||||
else if(baseType == XQBASETYPE_FLOAT) {
|
||||
value = Float.valueOf(result.getFloat());
|
||||
}
|
||||
else if(baseType == XQBASETYPE_DECIMAL) {
|
||||
value = Double.valueOf(result.getAtomicValue());
|
||||
//TODO: Should DECIMAL be BigDecimal?
|
||||
}
|
||||
|
||||
else if(baseType == XQBASETYPE_INT
|
||||
|| baseType == XQBASETYPE_NEGATIVE_INTEGER
|
||||
|| baseType == XQBASETYPE_POSITIVE_INTEGER
|
||||
|| baseType == XQBASETYPE_NONNEGATIVE_INTEGER
|
||||
|| baseType == XQBASETYPE_NONPOSITIVE_INTEGER
|
||||
|| baseType == XQBASETYPE_UNSIGNED_INT) {
|
||||
value = Integer.valueOf(result.getInt());
|
||||
}
|
||||
else if(baseType == XQBASETYPE_INTEGER) {
|
||||
value = BigInteger.valueOf(result.getInt());
|
||||
}
|
||||
else if(baseType == XQBASETYPE_LONG
|
||||
|| baseType == XQBASETYPE_UNSIGNED_LONG) {
|
||||
value = Long.valueOf(result.getLong());
|
||||
}
|
||||
else if(baseType == XQBASETYPE_SHORT
|
||||
|| baseType == XQBASETYPE_UNSIGNED_SHORT) {
|
||||
value = Short.valueOf(result.getShort());
|
||||
}
|
||||
else if(baseType == XQBASETYPE_STRING) {
|
||||
String strValue = result.getAtomicValue();
|
||||
value = convertStringToNumber(strValue);
|
||||
}
|
||||
}
|
||||
else if(XQITEMKIND_TEXT == type.getItemKind()) {
|
||||
String textContent = result.getNode().getTextContent();
|
||||
value = convertStringToNumber(textContent);
|
||||
}
|
||||
else if(XQITEMKIND_ATTRIBUTE == type.getItemKind()) {
|
||||
String textContent = ((Attr)result.getNode()).getValue();
|
||||
value = convertStringToNumber(textContent);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**Helper method that will be used to convert a String value to Number
|
||||
* @param value
|
||||
* @param strValue
|
||||
* @return
|
||||
*/
|
||||
private Number convertStringToNumber(String strValue) {
|
||||
Number value = null;
|
||||
try {
|
||||
if(StringUtils.hasText(strValue)) {
|
||||
if(strValue.indexOf(".") > 0) {
|
||||
value = Double.valueOf(strValue);
|
||||
}
|
||||
else {
|
||||
value = Long.valueOf(strValue);
|
||||
}
|
||||
}
|
||||
} catch(NumberFormatException ne) {
|
||||
value = null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the given text content as String if the type is a string base type
|
||||
* @param type
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
protected String convertToString(XQItemType type,XQResultSequence result) throws XQException {
|
||||
boolean skipBaseTypes = shouldSkipBaseType(type);
|
||||
String value = null;
|
||||
if(!skipBaseTypes) {
|
||||
int baseType = type.getBaseType();
|
||||
if(baseType == XQBASETYPE_STRING) {
|
||||
value = result.getAtomicValue();
|
||||
}
|
||||
}
|
||||
else if(XQITEMKIND_TEXT == type.getItemKind()) {
|
||||
value = result.getNode().getTextContent();
|
||||
}
|
||||
else if(XQITEMKIND_ATTRIBUTE == type.getItemKind()) {
|
||||
value = ((Attr)result.getNode()).getValue();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the data type of the string and converts to boolean if applicable.
|
||||
* The types have to be either boolean or string. For a string value,
|
||||
* the returned value is same as Boolean.valueOf(strValue)
|
||||
*
|
||||
* @param type
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
protected Boolean convertToBoolean(XQItemType type,XQResultSequence result) throws XQException {
|
||||
boolean skipBaseTypes = shouldSkipBaseType(type);
|
||||
Boolean value = null;
|
||||
if(!skipBaseTypes) {
|
||||
if(type.getBaseType() == XQBASETYPE_BOOLEAN) {
|
||||
value = Boolean.valueOf(result.getBoolean());
|
||||
}
|
||||
else if(type.getBaseType() == XQBASETYPE_STRING) {
|
||||
value = Boolean.valueOf(result.getAtomicValue());
|
||||
}
|
||||
}
|
||||
else if(XQITEMKIND_TEXT == type.getItemKind()) {
|
||||
String textContent = result.getNode().getTextContent();
|
||||
value = Boolean.valueOf(textContent);
|
||||
}
|
||||
else if(XQITEMKIND_ATTRIBUTE == type.getItemKind()) {
|
||||
String textContent = ((Attr)result.getNode()).getValue();
|
||||
value = Boolean.valueOf(textContent);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given type if for a valid node type
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
protected boolean isNodeType(XQItemType type) {
|
||||
int itemKind = type.getItemKind();
|
||||
return (
|
||||
itemKind == XQITEMKIND_ATTRIBUTE
|
||||
||
|
||||
itemKind == XQITEMKIND_COMMENT
|
||||
||
|
||||
itemKind == XQITEMKIND_DOCUMENT
|
||||
||
|
||||
itemKind == XQITEMKIND_DOCUMENT_ELEMENT
|
||||
||
|
||||
itemKind == XQITEMKIND_DOCUMENT_SCHEMA_ELEMENT
|
||||
||
|
||||
itemKind == XQITEMKIND_ELEMENT
|
||||
||
|
||||
itemKind == XQITEMKIND_NODE
|
||||
||
|
||||
itemKind == XQITEMKIND_PI
|
||||
||
|
||||
itemKind == XQITEMKIND_SCHEMA_ATTRIBUTE
|
||||
||
|
||||
itemKind == XQITEMKIND_SCHEMA_ELEMENT
|
||||
||
|
||||
itemKind == XQITEMKIND_TEXT
|
||||
);
|
||||
}
|
||||
|
||||
/**Transforms the given {@link Node} to a String
|
||||
* @param n
|
||||
* @return
|
||||
* @throws TransformerConfigurationException
|
||||
* @throws TransformerFactoryConfigurationError
|
||||
* @throws TransformerException
|
||||
*/
|
||||
protected String transformNodeToString(Node n)
|
||||
throws TransformerConfigurationException,
|
||||
TransformerFactoryConfigurationError, TransformerException {
|
||||
String value;
|
||||
StringWriter writer = new StringWriter();
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
if(formatOutput)
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.transform( new DOMSource(n), new StreamResult(writer));
|
||||
value = writer.toString();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the output result is an xml, the value of this parameter will determine
|
||||
* if the output xml is to be formatted or not. By default, the output will
|
||||
* not be formatted
|
||||
*
|
||||
* @param formatOutput
|
||||
*/
|
||||
public void setFormatOutput(boolean formatOutput) {
|
||||
this.formatOutput = formatOutput;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.xquery.XQItemType;
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The Result mapper implementation that maps the {@link XQResultSequence} to {@link Boolean}
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class BooleanResultMapper extends AbstractXQueryResultMapper<Boolean> {
|
||||
|
||||
public List<Boolean> mapResults(XQResultSequence result) {
|
||||
List<Boolean> results = new ArrayList<Boolean>();
|
||||
try {
|
||||
//check for boolean or string type and convert it accordingly, if a node then get it's text
|
||||
//content and convert to boolean
|
||||
while(result.next()) {
|
||||
XQItemType type = result.getItemType();
|
||||
Boolean value = convertToBoolean(type, result);
|
||||
if(value == null) {
|
||||
if(isNodeType(type)) {
|
||||
Node n = result.getNode();
|
||||
value = Boolean.valueOf(transformNodeToString(n));
|
||||
}
|
||||
}
|
||||
results.add(value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new MessagingException("Caught Exception while mapping the result sequence to string",e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.xquery.XQItemType;
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The Result mapper implementation that maps the {@link XQResultSequence} to {@link Node}
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class NodeResultMapper extends AbstractXQueryResultMapper<Node> {
|
||||
|
||||
public List<Node> mapResults(XQResultSequence result) {
|
||||
List<Node> results = new ArrayList<Node>();
|
||||
try {
|
||||
while(result.next()) {
|
||||
XQItemType type = result.getItemType();
|
||||
if(isNodeType(type)) {
|
||||
Node n = result.getNode();
|
||||
results.add(n);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new MessagingException("Caught Exception while mapping the result sequence to string",e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.xquery.XQItemType;
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The Result mapper implementation that maps the {@link XQResultSequence} to {@link Number}
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class NumberResultMapper extends AbstractXQueryResultMapper<Number> {
|
||||
|
||||
public List<Number> mapResults(XQResultSequence result) {
|
||||
List<Number> results = new ArrayList<Number>();
|
||||
try {
|
||||
while(result.next()) {
|
||||
|
||||
XQItemType type = result.getItemType();
|
||||
Number value = convertToNumber(type, result);
|
||||
if(value == null) {
|
||||
if(isNodeType(type)) {
|
||||
Node n = result.getNode();
|
||||
String strValue = transformNodeToString(n);
|
||||
if(StringUtils.hasText(strValue)) {
|
||||
if(strValue.indexOf(".") > 0) {
|
||||
value = Double.valueOf(strValue);
|
||||
}
|
||||
else {
|
||||
value = Long.valueOf(strValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
results.add(value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new MessagingException("Caught Exception while mapping the result sequence to string",e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.xquery.XQItemType;
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The Result mapper implementation that maps the {@link XQResultSequence} to {@link String}
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class StringResultMapper extends AbstractXQueryResultMapper<String> {
|
||||
|
||||
public List<String> mapResults(XQResultSequence result) {
|
||||
List<String> results = new ArrayList<String>();
|
||||
try {
|
||||
while(result.next()) {
|
||||
XQItemType type = result.getItemType();
|
||||
String value = convertToString(type, result);
|
||||
if(value == null) {
|
||||
Number number = convertToNumber(type, result);
|
||||
if(number == null) {
|
||||
Boolean boolValue = convertToBoolean(type, result);
|
||||
if(boolValue == null) {
|
||||
if(isNodeType(type)) {
|
||||
Node n = result.getNode();
|
||||
value = transformNodeToString(n);
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = boolValue.toString();
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = number.toString();
|
||||
}
|
||||
}
|
||||
results.add(value);
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new MessagingException("Caught Exception while mapping the result sequence to string",e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.support;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The class that represents the XQuery parameter provided. It is also responsible
|
||||
* for the evaluation and returning the corresponding value against the given {@link Message}
|
||||
* instance
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryParameter {
|
||||
|
||||
private final String parameterName;
|
||||
private volatile Object parameterValue;
|
||||
private volatile String expression;
|
||||
private volatile boolean isValueSet;
|
||||
//Will be used only when an expression is set
|
||||
private volatile ExpressionEvaluatingMessageProcessor<Object> messageProcessor;
|
||||
|
||||
/**
|
||||
* The default no argument constructor
|
||||
*/
|
||||
public XQueryParameter(String parameterName) {
|
||||
Assert.hasText(parameterName, "Non null non empty String value expected for parameter name");
|
||||
this.parameterName = parameterName;
|
||||
}
|
||||
/**
|
||||
* The constructor that takes the parameter name and a static parameter value
|
||||
*
|
||||
* @param parameterName
|
||||
* @param parameterValue
|
||||
*/
|
||||
public XQueryParameter(String parameterName, Object parameterValue) {
|
||||
this(parameterName);
|
||||
Assert.notNull(parameterValue, "Parameter value provided is null");
|
||||
this.parameterValue = parameterValue;
|
||||
isValueSet = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor that takes the parameter name and the expression that would
|
||||
* be evaluated to get the value of the parameter
|
||||
* @param parameterName
|
||||
* @param expression
|
||||
*/
|
||||
public XQueryParameter(String parameterName, String expression) {
|
||||
this(parameterName);
|
||||
Assert.isTrue(StringUtils.hasText(expression), "Non null non empty String value expected for expression");
|
||||
setExpression(expression);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the parameter name of this instance
|
||||
* @return
|
||||
*/
|
||||
public String getParameterName() {
|
||||
return parameterName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parameter value, this is mutually exclusive with the expression
|
||||
* @param parameterValue
|
||||
*/
|
||||
public void setParameterValue(Object parameterValue) {
|
||||
Assert.isTrue(!StringUtils.hasText(expression), "The parameter value and expression are mutually " +
|
||||
"exclusive, parameter expression already set");
|
||||
Assert.notNull(parameterValue, "Null parameter value provided");
|
||||
this.parameterValue = parameterValue;
|
||||
isValueSet = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the expression that would be evaluated to get the parameter value
|
||||
* @param expression
|
||||
*/
|
||||
public void setExpression(String expression) {
|
||||
Assert.isTrue(parameterValue == null, "The parameter value and expression are mutually exclusive" +
|
||||
", parameter value already set");
|
||||
Assert.isTrue(!StringUtils.hasText(this.expression), "Expression string is already set once, cannot reset it");
|
||||
Assert.hasText(expression, "Please provide a non null, non empty expression string");
|
||||
this.expression = expression;
|
||||
isValueSet = false;
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expr = parser.parseExpression(expression);
|
||||
messageProcessor = new ExpressionEvaluatingMessageProcessor<Object>(expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given message against the provided expression if one is set
|
||||
* else, returns the static value provided. If none of the static value or
|
||||
* expression are provided. The value returned is null.
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public Object evaluate(Message<?> message) {
|
||||
if(isValueSet) {
|
||||
return parameterValue;
|
||||
}
|
||||
else {
|
||||
if(messageProcessor != null) {
|
||||
return messageProcessor.processMessage(message);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
/**
|
||||
* The strategy interface that will be used to map the {@link XQResultSequence}
|
||||
* returned by XQuery execution to a List of the specified type
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public interface XQueryResultMapper<T> {
|
||||
|
||||
/**
|
||||
* Maps the results from the {@link XQResultSequence} to a {@link List} of a specific type
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
List<T> mapResults(XQResultSequence result);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.support;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The common utility class that is used to perform all common operations
|
||||
* amongst XQuery modules. To contain all common operations that would be used
|
||||
* by the router, transformer etc along with all the parsers for these components
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryUtils {
|
||||
|
||||
/**
|
||||
* Reads the XQuery string from the resource file specified
|
||||
*
|
||||
* @param resource the {@link Resource} instance of the file that contains the XQuery
|
||||
* currently only classpath and file resources are supported
|
||||
*
|
||||
* @return the XQuery string from the resource specified
|
||||
*/
|
||||
public static String readXQueryFromResource(Resource resource) {
|
||||
Assert.notNull(resource, "null resource provided");
|
||||
Assert.isTrue(resource.exists(), "Provided XQuery resource does not exist");
|
||||
Assert.isTrue(resource.isReadable(), "Provided XQuery resource is not readable");
|
||||
try {
|
||||
URL url = resource.getURL();
|
||||
InputStream inStream = url.openStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
|
||||
String line = reader.readLine();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
while(line != null) {
|
||||
builder.append(line).append("\n");
|
||||
line = reader.readLine();
|
||||
}
|
||||
String xQuery = builder.toString();
|
||||
reader.close();
|
||||
return xQuery;
|
||||
} catch (IOException e) {
|
||||
throw new MessagingException("Error while reading the xQuery resource", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.transformer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.transformer.AbstractTransformer;
|
||||
import org.springframework.integration.xquery.core.XQueryExecutor;
|
||||
import org.springframework.integration.xquery.support.XQueryResultMapper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
|
||||
/**
|
||||
* Transform the incoming message payload to the type specified in the {@link #resultType}
|
||||
* attribute. Currently {@link #resultType} supports only the following values out of the box
|
||||
*
|
||||
* 1. {@link String}
|
||||
* 2. {@link Boolean}
|
||||
* 3. {@link Number}
|
||||
* 4. {@link Node}
|
||||
*
|
||||
* For any other custom conversion, provide an instance of {@link XQueryResultMapper} in the
|
||||
* {@link #resultMapper} attribute. The {@link #resultMapper} and {@link #resultType} attribute
|
||||
* values are mutually exclusive to each other. If none of the above two attributes are
|
||||
* provided then the value of the {@link #resultType} defaults to {@link String}.
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class XQueryTransformer extends AbstractTransformer {
|
||||
|
||||
private XQueryExecutor executor;
|
||||
|
||||
private Class<?> resultType;
|
||||
|
||||
private XQueryResultMapper resultMapper;
|
||||
|
||||
@Override
|
||||
public void onInit() {
|
||||
Assert.notNull(executor,"No XQueryExecutor instance provided");
|
||||
if(resultMapper == null && resultType == null) {
|
||||
resultType = String.class;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.integration.transformer.AbstractTransformer#doTransform(org.springframework.integration.Message)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Object doTransform(Message<?> message) throws Exception {
|
||||
Object transformed;
|
||||
List<Object> queryResult;
|
||||
if(resultType != null) {
|
||||
queryResult = (List<Object>) executor.execute(message, resultType);
|
||||
}
|
||||
else {
|
||||
queryResult = executor.execute(message, resultMapper);
|
||||
}
|
||||
|
||||
if(queryResult != null && queryResult.size() == 1) {
|
||||
transformed = queryResult.get(0);
|
||||
}
|
||||
else {
|
||||
transformed = queryResult;
|
||||
}
|
||||
|
||||
return transformed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the XQuery executor instance to be used by the {@link XQueryTransformer}
|
||||
* @param executor
|
||||
*/
|
||||
public void setExecutor(XQueryExecutor executor) {
|
||||
Assert.notNull(executor,"Provide a non null XQueryExecutor instance");
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Type of the result, if none specified and if a {@link XQueryResultMapper} instance is
|
||||
* not provided, String is assumed by default.
|
||||
* The permitted value of the class is one of the
|
||||
* String.class, Boolean.class, Number.class or Node.class. For any other type of class
|
||||
* Provide an instance of {@link XQueryResultMapper}
|
||||
*
|
||||
* @param resultType
|
||||
*/
|
||||
public void setResultType(Class<?> resultType) {
|
||||
Assert.notNull(resultType,"Provide a non null value for the result type");
|
||||
Assert.isTrue(resultMapper == null,"Only one of the result mapper of the resultType can be set");
|
||||
Assert.isTrue(String.class == resultType || Boolean.class == resultType
|
||||
|| Number.class == resultType || Node.class == resultType,
|
||||
"Valid values for the result type class is String, Boolean, Number or Node, " +
|
||||
"for any other type, provide a custom implementation of XQueryResultMapper");
|
||||
this.resultType = resultType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ResultMapper to be used for mapping the result of the XQuery Object to
|
||||
* an appropriate object.
|
||||
* @param resultMapper
|
||||
*/
|
||||
public void setResultMapper(XQueryResultMapper resultMapper) {
|
||||
Assert.notNull(resultMapper,"Provide a non null value for the result mapper");
|
||||
Assert.isTrue(resultType == null,"Only one of the result mapper of the resultType can be set");
|
||||
this.resultMapper = resultMapper;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
http\://www.springframework.org/schema/integration/xquery=org.springframework.integration.xquery.config.xml.IntegrationXQueryNamespaceHandler
|
||||
@@ -0,0 +1,2 @@
|
||||
http\://www.springframework.org/schema/integration/xquery/spring-integration-xquery-2.2.xsd=org/springframework/integration/xquery/config/spring-integration-xquery-2.2.xsd
|
||||
http\://www.springframework.org/schema/integration/xquery/spring-integration-xquery.xsd=org/springframework/integration/xquery/config/spring-integration-xquery-2.2.xsd
|
||||
@@ -0,0 +1,318 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/integration/xquery"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
targetNamespace="http://www.springframework.org/schema/integration/xquery"
|
||||
elementFormDefault="qualified" attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans" />
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool" />
|
||||
<xsd:import namespace="http://www.springframework.org/schema/integration"
|
||||
schemaLocation="http://www.springframework.org/schema/integration/spring-integration-2.2.xsd" />
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines the configuration elements for Spring
|
||||
Integration's Xquery support.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:complexType name="inputOutputEndpoint">
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="integration:poller" minOccurs="0"
|
||||
maxOccurs="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:string" />
|
||||
<xsd:attribute name="input-channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type
|
||||
type="org.springframework.integration.MessageChannel" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="output-channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type
|
||||
type="org.springframework.integration.MessageChannel" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:attributeGroup name="xquery-executor-common-attributes">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The common attributes that would be used for all
|
||||
the xquery components
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="xq-datasource" type="xsd:string"
|
||||
use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The reference to the XQDataSource that will be
|
||||
provided by the user to
|
||||
execute the provided XQuery. If none is
|
||||
provided, then the default
|
||||
implementation will be used.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="xquery-file-resource" type="xsd:string"
|
||||
use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The classpath or the file system resource path to
|
||||
the file containing
|
||||
the
|
||||
xquery, typically .xq file. This attribute is
|
||||
mutually exclusive with the
|
||||
xquery attribute and the xquery
|
||||
subelement
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="xquery" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The String representing the XQuery that needs to
|
||||
be executed. Either
|
||||
this attribute or the xquery sub element needs
|
||||
to be provided.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="converter" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify the Converter to use when converting
|
||||
payloads prior to evaluation.
|
||||
The DefaultXmlPayloadConverter is used
|
||||
if this reference is not
|
||||
provided, and it
|
||||
should be sufficient in
|
||||
most cases since it can convert from Node,
|
||||
Document, Source,
|
||||
File,
|
||||
and String typed payloads. If you need to extend beyond the
|
||||
capabilities of
|
||||
that default implementation, then an upstream
|
||||
Transformer is probably a
|
||||
better option
|
||||
than providing a reference to
|
||||
a custom implementation of this strategy
|
||||
here.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type
|
||||
type="org.springframework.integration.xml.XmlPayloadConverter" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
|
||||
|
||||
<xsd:complexType name="XQueryParameterType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The subelement of the xquery based component that
|
||||
will be used to
|
||||
specify the
|
||||
parameters for the xquery
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The mandatory attribute that will be used to
|
||||
specify the name of the
|
||||
XQuery parameter
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="value" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The attribute that will be used to specify the
|
||||
static value to be used
|
||||
for the named
|
||||
parameter.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="ref" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
This attribute, mutually exclusive with value and
|
||||
expression that is
|
||||
used to specify
|
||||
reference to some other bean in
|
||||
the application context.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expression" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The attribute mutually exclusive with ref and
|
||||
value attribute, this
|
||||
will be
|
||||
used to provide the expression that
|
||||
would be evaluated on the incoming
|
||||
message
|
||||
to derive the value of the
|
||||
header.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="xquery" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The element that will be the sub element of all
|
||||
the XQuery components.
|
||||
It will be used to provide the XQuery string
|
||||
to these XQuery
|
||||
components.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="xquery-parameter" type="XQueryParameterType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
One or more xquery-parameter elements will be used
|
||||
to specify the
|
||||
names and one of the three attributes used to derive
|
||||
the
|
||||
value of the parameter
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="mapping" type="integration:mappingValueChannelType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
If the values returned by the XQuery Expression
|
||||
do not represent the channel names themselves, additional
|
||||
mappings can be specified using the "mapping" sub-element.
|
||||
|
||||
For example if the '/request/responders' expression
|
||||
results in two values: 'responderA' and 'responderB',
|
||||
but you don't want to couple the responder names
|
||||
to channel names you may provide additional mappings
|
||||
such as:
|
||||
|
||||
<int-xml:mapping value="responderA" channel="channelA"/>
|
||||
<int-xml:mapping value="responderB" channel="channelB"/>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="XQueryRouterType">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="integration:abstractRouterType">
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="integration:poller" minOccurs="0"
|
||||
maxOccurs="1" />
|
||||
<xsd:element ref="xquery" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element ref="xquery-parameter" minOccurs="0"
|
||||
maxOccurs="unbounded" />
|
||||
<xsd:element ref="mapping" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="integration:topLevelRouterAttributeGroup" />
|
||||
<xsd:attributeGroup ref="xquery-executor-common-attributes" />
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="XQueryTransformerType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The type definition for the XQuery router
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="inputOutputEndpoint">
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="xquery" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element ref="xquery-parameter" minOccurs="0"
|
||||
maxOccurs="unbounded" />
|
||||
<xsd:element ref="mapping" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="xquery-executor-common-attributes" />
|
||||
<xsd:attribute name="format-output" type="xsd:boolean"
|
||||
default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
This attribute, only valid for a transformer is
|
||||
used to configure the
|
||||
property that instructs the component to
|
||||
format the output xml if
|
||||
one is produced by the transformer after
|
||||
XQuery transformation. By default
|
||||
the output is not formatted.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="result-type" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The expected type of the result after
|
||||
transformation of the
|
||||
input payload. The value is the fully
|
||||
qualified name of the class
|
||||
The default value assumed in
|
||||
java.lang.String.
|
||||
If a class is provided using this attribute
|
||||
which is other than
|
||||
java.lang.String, java.lang.Number,
|
||||
java.lang.Boolean or
|
||||
org.w3c.dom.Node,
|
||||
then you need to have a
|
||||
mapper registered using the mapping child
|
||||
element.
|
||||
If a
|
||||
transformation to any other type is needed and you
|
||||
dont want to
|
||||
provide
|
||||
the mapping child element, then provide a
|
||||
reference to the
|
||||
xquery-result-mapper attribute.
|
||||
This attribute is
|
||||
mutually
|
||||
exclusive to the xquery-result-mapper attribute.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="xquery-result-mapper" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
This attribute allows the user to provide
|
||||
mapper instance that would be
|
||||
used to map the result of the XQuery
|
||||
executed to a desired target type of the transformer.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="xquery-router" type="XQueryRouterType" />
|
||||
<xsd:element name="xquery-transformer" type="XQueryTransformerType" />
|
||||
|
||||
</xsd:schema>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 579 B |
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
|
||||
import org.springframework.integration.xml.XmlPayloadConverter;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The Dummy Xml payload converter class that would be used for parser tests
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class DummyXmlPayloadConverter implements XmlPayloadConverter {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.integration.xml.XmlPayloadConverter#convertToDocument(java.lang.Object)
|
||||
*/
|
||||
public Document convertToDocument(Object object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.integration.xml.XmlPayloadConverter#convertToNode(java.lang.Object)
|
||||
*/
|
||||
public Node convertToNode(Object object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.integration.xml.XmlPayloadConverter#convertToSource(java.lang.Object)
|
||||
*/
|
||||
public Source convertToSource(Object object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.config.xml;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.xquery.XQDataSource;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import net.sf.saxon.xqj.SaxonXQDataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.integration.endpoint.EventDrivenConsumer;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.xml.XmlPayloadConverter;
|
||||
import org.springframework.integration.xquery.DummyXmlPayloadConverter;
|
||||
import org.springframework.integration.xquery.router.XQueryRouter;
|
||||
import org.springframework.integration.xquery.support.XQueryParameter;
|
||||
|
||||
|
||||
/**
|
||||
* The test case for the XQuery router parser
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryRouterParserTests {
|
||||
|
||||
private ClassPathXmlApplicationContext ctx;
|
||||
private EventDrivenConsumer consumer;
|
||||
|
||||
|
||||
@Test
|
||||
public void routerOne() {
|
||||
setUp("xqueryRouterOne");
|
||||
XQueryRouter router = TestUtils.getPropertyValue(consumer, "handler", XQueryRouter.class);
|
||||
Assert.assertNotNull(TestUtils.getPropertyValue(router, "executor.xQuery", String.class));
|
||||
Assert.assertEquals(SaxonXQDataSource.class,
|
||||
TestUtils.getPropertyValue(router, "executor.xqDataSource", XQDataSource.class).getClass());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, XQueryParameter> params =
|
||||
TestUtils.getPropertyValue(router, "executor.xQueryParameterMap",Map.class);
|
||||
Assert.assertEquals(2, params.size());
|
||||
Assert.assertTrue(params.containsKey("name"));
|
||||
Assert.assertTrue(params.containsKey("class"));
|
||||
XQueryParameter param = params.get("name");
|
||||
Assert.assertEquals("name", param.getParameterName());
|
||||
Assert.assertEquals("headers['name']",
|
||||
TestUtils.getPropertyValue(param, "messageProcessor.expression.expression",String.class));
|
||||
|
||||
destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void routerTwo() {
|
||||
setUp("xqueryRouterTwo");
|
||||
XQueryRouter router = TestUtils.getPropertyValue(consumer, "handler", XQueryRouter.class);
|
||||
Assert.assertNotNull(TestUtils.getPropertyValue(router, "executor.xQuery", String.class));
|
||||
Assert.assertEquals(DummyXQDataSource.class,
|
||||
TestUtils.getPropertyValue(router, "executor.xqDataSource", XQDataSource.class).getClass());
|
||||
Assert.assertEquals(DummyXmlPayloadConverter.class,
|
||||
TestUtils.getPropertyValue(router,"executor.converter",XmlPayloadConverter.class).getClass());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, XQueryParameter> params =
|
||||
TestUtils.getPropertyValue(router, "executor.xQueryParameterMap",Map.class);
|
||||
Assert.assertEquals(1, params.size());
|
||||
Assert.assertTrue(params.containsKey("name"));
|
||||
XQueryParameter param = params.get("name");
|
||||
Assert.assertEquals("name", param.getParameterName());
|
||||
Assert.assertEquals("name",
|
||||
TestUtils.getPropertyValue(param, "parameterValue",String.class));
|
||||
destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void routerThree() {
|
||||
setUp("xqueryRouterThree");
|
||||
XQueryRouter router = TestUtils.getPropertyValue(consumer, "handler", XQueryRouter.class);
|
||||
Assert.assertNotNull(TestUtils.getPropertyValue(router, "executor.xQuery", String.class));
|
||||
Assert.assertEquals(ClassPathResource.class, TestUtils.getPropertyValue(router, "executor.xQueryFileResource",Resource.class).getClass());
|
||||
destroy();
|
||||
}
|
||||
|
||||
private void setUp(String beanName) {
|
||||
ctx = new ClassPathXmlApplicationContext("XQueryRouterParserTests-context.xml",XQueryRouterParserTests.class);
|
||||
consumer = ctx.getBean(beanName, EventDrivenConsumer.class);
|
||||
}
|
||||
|
||||
|
||||
public void destroy() {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
public static class DummyXQDataSource extends SaxonXQDataSource {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.config.xml;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.xquery.XQDataSource;
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import net.sf.saxon.xqj.SaxonXQDataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.integration.endpoint.EventDrivenConsumer;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.transformer.Transformer;
|
||||
import org.springframework.integration.xml.XmlPayloadConverter;
|
||||
import org.springframework.integration.xquery.DummyXmlPayloadConverter;
|
||||
import org.springframework.integration.xquery.support.XQueryParameter;
|
||||
import org.springframework.integration.xquery.support.XQueryResultMapper;
|
||||
import org.springframework.integration.xquery.transformer.XQueryTransformer;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* The test class for XQuery Transformer parser
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class XQueryTransformerParserTests {
|
||||
|
||||
private ClassPathXmlApplicationContext ctx;
|
||||
private EventDrivenConsumer consumer;
|
||||
|
||||
@Test
|
||||
public void transformerOne() {
|
||||
setUp("xqueryTransformerOne");
|
||||
Transformer transformer = TestUtils.getPropertyValue(consumer, "handler.transformer", Transformer.class);
|
||||
Assert.assertEquals(XQueryTransformer.class, transformer.getClass());
|
||||
Assert.assertEquals(String.class, TestUtils.getPropertyValue(transformer, "resultType", Class.class));
|
||||
Assert.assertNotNull(TestUtils.getPropertyValue(transformer, "executor.xQuery", String.class));
|
||||
Assert.assertEquals(SaxonXQDataSource.class,
|
||||
TestUtils.getPropertyValue(transformer, "executor.xqDataSource", XQDataSource.class).getClass());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, XQueryParameter> params =
|
||||
TestUtils.getPropertyValue(transformer, "executor.xQueryParameterMap",Map.class);
|
||||
Assert.assertEquals(2, params.size());
|
||||
Assert.assertTrue(params.containsKey("name"));
|
||||
Assert.assertTrue(params.containsKey("class"));
|
||||
XQueryParameter param = params.get("name");
|
||||
Assert.assertEquals("name", param.getParameterName());
|
||||
Assert.assertEquals("headers['name']",
|
||||
TestUtils.getPropertyValue(param, "messageProcessor.expression.expression",String.class));
|
||||
|
||||
destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transformerTwo() {
|
||||
setUp("xqueryTransformerTwo");
|
||||
XQueryTransformer transformer = TestUtils.getPropertyValue(consumer, "handler.transformer", XQueryTransformer.class);
|
||||
Assert.assertNotNull(TestUtils.getPropertyValue(transformer, "executor.xQuery", String.class));
|
||||
Assert.assertEquals(DummyXQDataSource.class,
|
||||
TestUtils.getPropertyValue(transformer, "executor.xqDataSource", XQDataSource.class).getClass());
|
||||
Assert.assertEquals(DummyXmlPayloadConverter.class,
|
||||
TestUtils.getPropertyValue(transformer,"executor.converter",XmlPayloadConverter.class).getClass());
|
||||
Assert.assertEquals(true, TestUtils.getPropertyValue(transformer, "executor.formatOutput",Boolean.class).booleanValue());
|
||||
destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transformerThree() {
|
||||
setUp("xqueryTransformerThree");
|
||||
XQueryTransformer transformer = TestUtils.getPropertyValue(consumer, "handler.transformer", XQueryTransformer.class);
|
||||
Assert.assertNotNull(TestUtils.getPropertyValue(transformer, "executor.xQuery", String.class));
|
||||
Assert.assertEquals(ClassPathResource.class, TestUtils.getPropertyValue(transformer, "executor.xQueryFileResource",Resource.class).getClass());
|
||||
destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void booleanTypeResult() {
|
||||
setUp("booleanResultTypeTransformer");
|
||||
XQueryTransformer transformer = TestUtils.getPropertyValue(consumer, "handler.transformer", XQueryTransformer.class);
|
||||
Assert.assertEquals(Boolean.class, TestUtils.getPropertyValue(transformer, "resultType", Class.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringTypeResult() {
|
||||
setUp("stringResultTypeTransformer");
|
||||
XQueryTransformer transformer = TestUtils.getPropertyValue(consumer, "handler.transformer", XQueryTransformer.class);
|
||||
Assert.assertEquals(String.class, TestUtils.getPropertyValue(transformer, "resultType", Class.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resultMapperProvided() {
|
||||
setUp("customXQueryResultMapper");
|
||||
XQueryTransformer transformer = TestUtils.getPropertyValue(consumer, "handler.transformer", XQueryTransformer.class);
|
||||
Assert.assertEquals(DummyXQueryResultMapper.class, TestUtils.getPropertyValue(transformer, "resultMapper", XQueryResultMapper.class).getClass());
|
||||
}
|
||||
|
||||
|
||||
private void setUp(String beanName) {
|
||||
ctx = new ClassPathXmlApplicationContext("XQueryTransformerParserTests-context.xml",XQueryTransformerParserTests.class);
|
||||
consumer = ctx.getBean(beanName, EventDrivenConsumer.class);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
public static class DummyXQDataSource extends SaxonXQDataSource {
|
||||
|
||||
}
|
||||
|
||||
public static class DummyXQueryResultMapper implements XQueryResultMapper<String> {
|
||||
|
||||
public List<String> mapResults(XQResultSequence result) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.core;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.xquery.XQDataSource;
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.xquery.support.AbstractXQueryResultMapper;
|
||||
import org.springframework.integration.xquery.support.BooleanResultMapper;
|
||||
import org.springframework.integration.xquery.support.NodeResultMapper;
|
||||
import org.springframework.integration.xquery.support.NumberResultMapper;
|
||||
import org.springframework.integration.xquery.support.StringResultMapper;
|
||||
import org.springframework.integration.xquery.support.XQueryParameter;
|
||||
import org.springframework.integration.xquery.support.XQueryResultMapper;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The base test class for the XQueryExecutor tests
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractXQueryExecutorTests {
|
||||
|
||||
|
||||
private final static String EXT_VARIABLE_XQUERY =
|
||||
"declare variable $name as xs:string external;" +
|
||||
"declare variable $class as xs:int external;" +
|
||||
" for $student in /mappings/students/student," +
|
||||
" $subject in /mappings/subjects/subject " +
|
||||
"where $student/@id = $subject/students/studentId " +
|
||||
"and $student/name = $name " +
|
||||
"and $student/class = $class " +
|
||||
"return $subject/name/text()";
|
||||
|
||||
private final String xmlString = "<person active=\"true\">" +
|
||||
"<name>Mike</name>" +
|
||||
"<age>29</age>" +
|
||||
"</person>";
|
||||
|
||||
|
||||
/**
|
||||
* Test if default created result mappers are appropriately instantiated
|
||||
*/
|
||||
@Test
|
||||
public void initializeDefaultMappers() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("'Hello World'");
|
||||
executor.afterPropertiesSet();
|
||||
@SuppressWarnings("rawtypes")
|
||||
Map executorMap = TestUtils.getPropertyValue(executor, "resultMappers", Map.class);
|
||||
Assert.assertNotNull(executorMap);
|
||||
Assert.assertEquals(4, executorMap.size());
|
||||
Assert.assertEquals(StringResultMapper.class, executorMap.get(String.class).getClass());
|
||||
Assert.assertEquals(BooleanResultMapper.class, executorMap.get(Boolean.class).getClass());
|
||||
Assert.assertEquals(NumberResultMapper.class, executorMap.get(Number.class).getClass());
|
||||
Assert.assertEquals(NodeResultMapper.class, executorMap.get(Node.class).getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests of the registered mappers take priority over the defaults
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Test
|
||||
public void registerCustomMappers() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("'Hello'");
|
||||
Map map = new HashMap();
|
||||
map.put(MyCustomClass.class, new XQueryResultMapper<MyCustomClass>() {
|
||||
public List<MyCustomClass> mapResults(XQResultSequence result) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
});
|
||||
map.put(Node.class, new CustomNodeMapper());
|
||||
executor.setResultMappers(map);
|
||||
executor.afterPropertiesSet();
|
||||
Map executorMap = TestUtils.getPropertyValue(executor, "resultMappers", Map.class);
|
||||
Assert.assertNotNull(executorMap);
|
||||
Assert.assertEquals(5, executorMap.size());
|
||||
Assert.assertEquals(StringResultMapper.class, executorMap.get(String.class).getClass());
|
||||
Assert.assertEquals(BooleanResultMapper.class, executorMap.get(Boolean.class).getClass());
|
||||
Assert.assertEquals(NumberResultMapper.class, executorMap.get(Number.class).getClass());
|
||||
Assert.assertEquals(CustomNodeMapper.class, executorMap.get(Node.class).getClass());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tries to execute the result passing an unmapped class
|
||||
*/
|
||||
@Test
|
||||
public void executeForUnknownClassType() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("'Hello World'");
|
||||
executor.afterPropertiesSet();
|
||||
try {
|
||||
executor.execute(MessageBuilder.withPayload("").build(), MyCustomClass.class);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("No Result mapper found for the type org.springframework.integration.xquery.core.AbstractXQueryExecutorTests$MyCustomClass",
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
protected abstract XQueryExecutor getExecutor();
|
||||
|
||||
/**
|
||||
* Test with null message
|
||||
*/
|
||||
@Test
|
||||
public void withNullMessage() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("'Hello World'");
|
||||
executor.afterPropertiesSet();
|
||||
try {
|
||||
executor.execute(null, String.class);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Non null message expected", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeWithStringForNonLeaf() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery(".//person");
|
||||
executor.afterPropertiesSet();
|
||||
List<String> names = executor.executeForString(MessageBuilder.withPayload(xmlString).build());
|
||||
Assert.assertNotNull(names);
|
||||
Assert.assertEquals(1, names.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void executeWithBooleanForNonLeaf() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("//person");
|
||||
executor.afterPropertiesSet();
|
||||
List<Boolean> names = executor.executeForBoolean(MessageBuilder.withPayload(xmlString).build());
|
||||
Assert.assertNotNull(names);
|
||||
Assert.assertEquals(1, names.size());
|
||||
Assert.assertTrue(names.contains(Boolean.FALSE));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void executeWithNumberForNonLeaf() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("//person");
|
||||
executor.afterPropertiesSet();
|
||||
@SuppressWarnings("unused")
|
||||
List<Number> names;
|
||||
try {
|
||||
names = executor.executeForNumber(MessageBuilder.withPayload(xmlString).build());
|
||||
} catch (MessagingException e) {
|
||||
Assert.assertEquals(NumberFormatException.class,e.getCause().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test case to execute the XQuery and return a {@link List} of {@link String}
|
||||
*/
|
||||
@Test
|
||||
public void executeWithString() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery(".//person/name/text()");
|
||||
executor.afterPropertiesSet();
|
||||
List<String> names = executor.executeForString(MessageBuilder.withPayload(xmlString).build());
|
||||
Assert.assertNotNull(names);
|
||||
Assert.assertEquals(1, names.size());
|
||||
Assert.assertTrue(names.contains("Mike"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test case to execute the XQuery and return a {@link List} of {@link Boolean}
|
||||
*/
|
||||
@Test
|
||||
public void executeWithBoolean() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("//person/@active");
|
||||
executor.afterPropertiesSet();
|
||||
List<Boolean> names = executor.executeForBoolean(MessageBuilder.withPayload(xmlString).build());
|
||||
Assert.assertNotNull(names);
|
||||
Assert.assertEquals(1, names.size());
|
||||
Assert.assertTrue(names.contains(Boolean.TRUE));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test case to execute the XQuery and return a {@link List} of {@link Number}
|
||||
*/
|
||||
@Test
|
||||
public void executeWithNumber() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("//person/age/text()");
|
||||
executor.afterPropertiesSet();
|
||||
List<Number> names = executor.executeForNumber(MessageBuilder.withPayload(xmlString).build());
|
||||
Assert.assertNotNull(names);
|
||||
Assert.assertEquals(1, names.size());
|
||||
Assert.assertTrue(names.contains(Long.valueOf(29)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test case to execute the XQuery and return a {@link List} of {@link Node}
|
||||
*/
|
||||
@Test
|
||||
public void executeWithNode() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("//person");
|
||||
executor.afterPropertiesSet();
|
||||
List<Node> names = executor.executeForNode(MessageBuilder.withPayload(xmlString).build());
|
||||
Assert.assertNotNull(names);
|
||||
Assert.assertEquals(1, names.size());
|
||||
Assert.assertEquals("person",names.get(0).getLocalName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test with null message
|
||||
*/
|
||||
@Test
|
||||
public void withNullType() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("'Hello World'");
|
||||
executor.afterPropertiesSet();
|
||||
try {
|
||||
executor.execute(MessageBuilder.withPayload("").build(),(Class<?>) null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Non null type expected", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the case where the router has no parameters but the query expects parameters
|
||||
*/
|
||||
@Test
|
||||
public void noParametersProvided() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery(EXT_VARIABLE_XQUERY);
|
||||
try {
|
||||
executor.afterPropertiesSet();
|
||||
} catch (MessagingException e) {
|
||||
Assert.assertEquals("Expecting 2 parameters in the xquery, but none provided to the router", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the case where parameters are provided, but some or all of the parameters are missing
|
||||
*/
|
||||
@Test
|
||||
public void fewParametersProvided() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery(EXT_VARIABLE_XQUERY);
|
||||
executor.addXQueryParameter(new XQueryParameter("class",Integer.valueOf(3)));
|
||||
try {
|
||||
executor.afterPropertiesSet();
|
||||
} catch (MessagingException e) {
|
||||
Assert.assertEquals("Missing parameter(s) [$name]", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets null XQuery, should get an exception
|
||||
*/
|
||||
@Test
|
||||
public void setNullXQuery() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
try {
|
||||
executor.setXQuery(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Provide a non null XQuery", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the XQuery file resource and then the xquery
|
||||
*/
|
||||
@Test
|
||||
public void setResourceAndXQuery() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
Resource res = new ClassPathResource("/org/springframework/integration/xquery/XQuery.xq");
|
||||
Assert.assertTrue(res.exists());
|
||||
executor.setXQueryFileResource(res);
|
||||
try {
|
||||
executor.setXQuery("'Hello World'");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Only one of XQuery resource file or XQuery may be specified", e.getMessage());
|
||||
}
|
||||
Assert.assertNull(TestUtils.getPropertyValue(executor, "xQuery"));
|
||||
executor.addXQueryParameter(new XQueryParameter("name", "headers['studentName']"));
|
||||
executor.addXQueryParameter(new XQueryParameter("class", Integer.valueOf(1)));
|
||||
executor.afterPropertiesSet();
|
||||
Assert.assertNotNull(TestUtils.getPropertyValue(executor, "xQuery",String.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the router without setting the xquery
|
||||
*/
|
||||
@Test
|
||||
public void withoutXQuery() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
try {
|
||||
executor.afterPropertiesSet();
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("One of XQuery or the XQuery resource is mandatory", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*Sets the XQuery and then the resource
|
||||
*/
|
||||
@Test
|
||||
public void setXQueryAndResource() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
Resource res = new ClassPathResource("org/springframework/integration/xquery/XQuery.xq");
|
||||
Assert.assertTrue(res.exists());
|
||||
executor.setXQuery("'Hello World'");
|
||||
try {
|
||||
executor.setXQueryFileResource(res);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Only one of XQuery resource file or XQuery may be specified", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*Sets a null {@link XQDataSource} instance
|
||||
*/
|
||||
@Test
|
||||
public void setNullXQataSource() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
try {
|
||||
executor.setXQDataSource(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Provide a non null instance of the XQDatasource", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests the router with valid xml payload. The values returned will be the
|
||||
* text content of the node, if the node is a text or attribute type
|
||||
*/
|
||||
@Test
|
||||
public void withValidPayload() {
|
||||
withValidPayloadInternal(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the router with valid xml payload. The values returned will be the
|
||||
* {@link Node}, irrespective of the type of the node
|
||||
*/
|
||||
@Test
|
||||
public void withValidPayload2() {
|
||||
withValidPayloadInternal(false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void withValidPayloadInternal(boolean extractNodeText) {
|
||||
File file = new File("./src/test/resources/org/springframework/integration/xquery/SubjectMapping.xml");
|
||||
Message<File> message = MessageBuilder.withPayload(file)
|
||||
.setHeader("studentName", "Jughead")
|
||||
.build();
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery(EXT_VARIABLE_XQUERY);
|
||||
executor.addXQueryParameter(new XQueryParameter("name", "headers['studentName']"));
|
||||
executor.addXQueryParameter(new XQueryParameter("class", Integer.valueOf(1)));
|
||||
executor.afterPropertiesSet();
|
||||
List<Object> subjects;
|
||||
if(extractNodeText) {
|
||||
subjects = new ArrayList<Object>(executor.executeForString(message));
|
||||
}
|
||||
else {
|
||||
subjects = new ArrayList<Object>(executor.executeForNode(message));
|
||||
}
|
||||
Assert.assertNotNull(subjects);
|
||||
Assert.assertEquals(2, subjects.size());
|
||||
if(extractNodeText) {
|
||||
Assert.assertEquals(String.class, subjects.get(0).getClass());
|
||||
Assert.assertTrue(subjects.contains("Cooking"));
|
||||
Assert.assertTrue(subjects.contains("Math"));
|
||||
}
|
||||
else {
|
||||
Assert.assertTrue(Node.class.isAssignableFrom(subjects.get(0).getClass()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests with a query that will generate a numeric value and we get the result as {@link Number}
|
||||
*/
|
||||
@Test
|
||||
public void withNumericExpression() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("2 + 2");
|
||||
executor.afterPropertiesSet();
|
||||
List<Number> result = executor.executeForNumber(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.get(0).intValue() == 4);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*Tests a query that will generate a decimal value and we get the result as a {@link Number}
|
||||
*/
|
||||
@Test
|
||||
public void withDecimalExpression() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("2.0 + 2.1");
|
||||
executor.afterPropertiesSet();
|
||||
List<Number> result = executor.executeForNumber(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains(Double.valueOf(4.1)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the XQuery that gives a boolean value and get the value as a Boolean
|
||||
*/
|
||||
@Test
|
||||
public void withBooleanResult() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("1 = 1");
|
||||
executor.afterPropertiesSet();
|
||||
List<Boolean> result = executor.executeForBoolean(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains(Boolean.TRUE));
|
||||
}
|
||||
|
||||
/**
|
||||
*The XQuery gives a string value and we want the result to be a string value
|
||||
*/
|
||||
@Test
|
||||
public void getTextString() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("'Hello World'");
|
||||
executor.afterPropertiesSet();
|
||||
List<String> result = executor.executeForString(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains("Hello World"));
|
||||
}
|
||||
|
||||
/**
|
||||
*The XQuery gives a boolean value and we want the result to be a string value
|
||||
*/
|
||||
@Test
|
||||
public void getBooleanAsTextString() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("1 = 2");
|
||||
executor.afterPropertiesSet();
|
||||
List<String> result = executor.executeForString(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains("false"));
|
||||
}
|
||||
|
||||
/**
|
||||
*The XQuery gives a text value in the node and we want the result to be a string value
|
||||
*/
|
||||
@Test
|
||||
public void getTextNodeAsString() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("//test/text()");
|
||||
executor.afterPropertiesSet();
|
||||
List<String> result = executor.executeForString(MessageBuilder.withPayload("<test>Some Value</test>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains("Some Value"));
|
||||
}
|
||||
|
||||
/**
|
||||
*The XQuery gives a text value in the node and we want the result to be a Boolean
|
||||
*/
|
||||
@Test
|
||||
public void getTextNodeAsBoolean() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("//test/text()");
|
||||
executor.afterPropertiesSet();
|
||||
List<Boolean> result = executor.executeForBoolean(MessageBuilder.withPayload("<test>Some Value</test>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains(Boolean.FALSE));
|
||||
}
|
||||
|
||||
/**
|
||||
*The XQuery gives a text value in the node and we want the result to be a Long
|
||||
*/
|
||||
@Test
|
||||
public void getTextNodeAsLong() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("//number/text()");
|
||||
executor.afterPropertiesSet();
|
||||
List<Number> result = executor.executeForNumber(MessageBuilder.withPayload("<number>1</number>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains(Long.valueOf(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
*The XQuery gives a text value in the node and we want the result to be a Long
|
||||
*/
|
||||
@Test
|
||||
public void getTextNodeAsDouble() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("//number/text()");
|
||||
executor.afterPropertiesSet();
|
||||
List<Number> result = executor.executeForNumber(MessageBuilder.withPayload("<number>1.1</number>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains(Double.valueOf(1.1)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tests by using a String that is a non decimal number and we get the value as a {@link Number}
|
||||
*/
|
||||
@Test
|
||||
public void withNonDecimalStringExpression() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setResultMappers(Collections.singletonMap(Number.class,
|
||||
(XQueryResultMapper<Number>)new NumberResultMapper()));
|
||||
executor.setXQuery("'4'");
|
||||
executor.afterPropertiesSet();
|
||||
List<Number> result = executor.executeForNumber(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains(Long.valueOf(4)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests by using a String that is a decimal number and we get the value as a {@link Number}
|
||||
*/
|
||||
@Test
|
||||
public void withDecimalStringExpression() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setResultMappers(Collections.singletonMap(Number.class,
|
||||
(XQueryResultMapper<Number>)new NumberResultMapper()));
|
||||
executor.setXQuery("'4.1'");
|
||||
executor.afterPropertiesSet();
|
||||
List<Number> result = executor.executeForNumber(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains(Double.valueOf(4.1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests by getting the Integer value and getting the result as {@link String}
|
||||
*/
|
||||
@Test
|
||||
public void getIntegerAsString() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("4");
|
||||
executor.afterPropertiesSet();
|
||||
List<String> result = executor.executeForString(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains("4"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Uses a decimal value and gets the result as {@link String}
|
||||
*/
|
||||
@Test
|
||||
public void getDecimalAsString() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setXQuery("4.1");
|
||||
executor.afterPropertiesSet();
|
||||
List<String> result = executor.executeForString(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains("4.1"));
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void getCurrentDate() {
|
||||
// XQueryExecutor executor = new XQueryExecutor();
|
||||
// executor.setXQuery("current-date()");
|
||||
// executor.afterPropertiesSet();
|
||||
// executor.executeForString(MessageBuilder.withPayload("<test/>").build());
|
||||
// }
|
||||
|
||||
|
||||
@Test
|
||||
public void withStringExpression2() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setResultMappers(Collections.singletonMap(Number.class,
|
||||
(XQueryResultMapper<Number>)new NumberResultMapper()));
|
||||
executor.setXQuery("/person/age/text()");
|
||||
executor.afterPropertiesSet();
|
||||
List<Number> result = executor.executeForNumber(MessageBuilder.withPayload(xmlString).build());
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains(Long.valueOf(29)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withFormatingFlag() {
|
||||
XQueryExecutor executor = getExecutor();
|
||||
executor.setFormatOutput(true);
|
||||
executor.setXQuery("'Hello World'");
|
||||
executor.afterPropertiesSet();
|
||||
//should not fail
|
||||
executor.executeForString(MessageBuilder.withPayload("<dummy/>").build());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Class<Object>, XQueryResultMapper<Object>> mappers = TestUtils.getPropertyValue(executor, "resultMappers", Map.class);
|
||||
for(Object val:mappers.values()) {
|
||||
if(val instanceof AbstractXQueryResultMapper) {
|
||||
Assert.assertEquals(true,
|
||||
TestUtils.getPropertyValue(val, "formatOutput", Boolean.class).booleanValue());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class MyCustomClass {}
|
||||
private class CustomNodeMapper implements XQueryResultMapper<Node> {
|
||||
public List<Node> mapResults(XQResultSequence result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.xquery.core;
|
||||
|
||||
|
||||
/**
|
||||
* The test class that uses the saxon's implementation in {@link XQueryExecutor}
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class SaxonXQueryExecutorTests extends AbstractXQueryExecutorTests {
|
||||
|
||||
|
||||
@Override
|
||||
protected XQueryExecutor getExecutor() {
|
||||
//use the default one that uses Saxon's implementation
|
||||
XQueryExecutor executor = new XQueryExecutor();
|
||||
return executor;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.core;
|
||||
|
||||
import javax.xml.xquery.XQDataSource;
|
||||
import javax.xml.xquery.XQException;
|
||||
|
||||
import net.xqj.sedna.SednaXQDataSource;
|
||||
|
||||
/**
|
||||
* The Test class that uses {@link SednaXQDataSource} in {@link XQueryExecutor}
|
||||
*
|
||||
* This test is intentionally excluded from being executed by surefire as it will
|
||||
* fail if the Sedna database is not up and running
|
||||
*
|
||||
* To run this test we need to have the Sedna XML Database up and running.
|
||||
* Visit {@link http://xqj.net/sedna/} for more details about Sedna.
|
||||
*
|
||||
* Once the Sedna xml database is downloaded and extracted the you will find
|
||||
* various executables in the bin directory, do the following to start it and create
|
||||
* a new database called 'test'
|
||||
*
|
||||
* 1. Start the governer by executing se_gov
|
||||
* 2. Create a new database called 'test' by executing se_cdb test
|
||||
* 3. Start the newly created database by running se_sm test. If the database was already
|
||||
* created, you can skip the step 2 and execute this step directly.
|
||||
*
|
||||
* Once the database is up and running, you can execute the below test case.
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class SednaXQueryExecutorTests extends AbstractXQueryExecutorTests {
|
||||
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Gets an instance of SednaXQDataSource for the tests.
|
||||
*
|
||||
*/
|
||||
protected XQueryExecutor getExecutor() {
|
||||
XQueryExecutor executor = new XQueryExecutor();
|
||||
XQDataSource ds;
|
||||
try {
|
||||
ds = new SednaXQDataSource();
|
||||
ds.setProperty("serverName", "localhost");
|
||||
ds.setProperty("databaseName", "test");
|
||||
} catch (XQException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
executor.setXQDataSource(ds);
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.router;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.xquery.core.XQueryExecutor;
|
||||
|
||||
|
||||
/**
|
||||
* The Test class for the XQuery router
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryRouterTests {
|
||||
|
||||
private static final String STUDENT_XML = "<students>" +
|
||||
"<student>" +
|
||||
"<name>Name1</name>" +
|
||||
"<age>21</age>" +
|
||||
"</student>" +
|
||||
"<student>" +
|
||||
"<name>Name2</name>" +
|
||||
"<age>22</age>" +
|
||||
"</student>" +
|
||||
"</students>";
|
||||
|
||||
/**
|
||||
* Tests the executor without seting the XQueryExecutor's instance
|
||||
*/
|
||||
@Test
|
||||
public void withoutExecutor() {
|
||||
XQueryRouter router = new XQueryRouter();
|
||||
try {
|
||||
router.afterPropertiesSet();
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("No XQueryExecutor instance provided", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tries setting the executor instance of the {@link XQueryRouter} to null.
|
||||
*/
|
||||
@Test
|
||||
public void setNullExecutor() {
|
||||
XQueryRouter router = new XQueryRouter();
|
||||
try {
|
||||
router.setExecutor(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Provide a non null implementation of the executor", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the channel keys for the given XQuery expression
|
||||
*/
|
||||
@Test
|
||||
public void getChannelKeys() {
|
||||
XQueryRouter router = new XQueryRouter();
|
||||
router.setExecutor(getExecutor("//test/text()"));
|
||||
router.afterPropertiesSet();
|
||||
List<Object> keys=
|
||||
router.getChannelKeys(MessageBuilder.withPayload("<test>Test</test>").build());
|
||||
Assert.assertNotNull(keys);
|
||||
Assert.assertEquals(1, keys.size());
|
||||
Assert.assertTrue(keys.contains("Test"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultResultType() {
|
||||
XQueryRouter router = new XQueryRouter();
|
||||
router.setExecutor(getExecutor("'Hello'"));
|
||||
router.afterPropertiesSet();
|
||||
Assert.assertEquals(String.class,
|
||||
TestUtils.getPropertyValue(router, "resultType", Class.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getChannelKeysAsStrings() {
|
||||
XQueryRouter router = new XQueryRouter();
|
||||
router.setExecutor(getExecutor("/students/student/name/text()"));
|
||||
router.afterPropertiesSet();
|
||||
List<Object> keys = router.getChannelKeys(MessageBuilder.withPayload(STUDENT_XML).build());
|
||||
Assert.assertEquals(2, keys.size());
|
||||
Assert.assertTrue(keys.contains("Name1"));
|
||||
Assert.assertTrue(keys.contains("Name2"));
|
||||
}
|
||||
|
||||
/**
|
||||
* The method demonstrates the conversion of a Numeric type to a String with get
|
||||
* channel keys method.
|
||||
*/
|
||||
@Test
|
||||
public void getChannelKeysAsStrings2() {
|
||||
XQueryRouter router = new XQueryRouter();
|
||||
router.setExecutor(getExecutor("/students/student/age/text()"));
|
||||
router.afterPropertiesSet();
|
||||
List<Object> keys = router.getChannelKeys(MessageBuilder.withPayload(STUDENT_XML).build());
|
||||
Assert.assertEquals(2, keys.size());
|
||||
Assert.assertTrue(keys.contains("21"));
|
||||
Assert.assertTrue(keys.contains("22"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private XQueryExecutor getExecutor(String xQuery) {
|
||||
XQueryExecutor executor = new XQueryExecutor();
|
||||
executor.setXQuery(xQuery);
|
||||
executor.afterPropertiesSet();
|
||||
return executor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
|
||||
/**
|
||||
* The test class for {@link XQueryParameter} class
|
||||
*
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryParameterTests {
|
||||
|
||||
/**
|
||||
* Sets a null parameter name, should throw an exception
|
||||
*/
|
||||
@Test
|
||||
public void setNullParameterName() {
|
||||
try {
|
||||
@SuppressWarnings("unused")
|
||||
XQueryParameter param = new XQueryParameter(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Non null non empty String value expected for parameter name", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a null parameter name, should throw an exception
|
||||
*/
|
||||
@Test
|
||||
public void setEmptyParameterName() {
|
||||
try {
|
||||
@SuppressWarnings("unused")
|
||||
XQueryParameter param = new XQueryParameter("");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Non null non empty String value expected for parameter name", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the valid parameter name
|
||||
*/
|
||||
@Test
|
||||
public void setValidParameterName() {
|
||||
XQueryParameter param = new XQueryParameter("testName");
|
||||
Assert.assertEquals("testName", param.getParameterName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets both the expression then the parameter value, should throw an exception
|
||||
*/
|
||||
@Test
|
||||
public void setParameterExpressionThenValue() {
|
||||
XQueryParameter param = new XQueryParameter("testParameter");
|
||||
param.setExpression("headers['someHeader']");
|
||||
try {
|
||||
param.setParameterValue("Some Value");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("The parameter value and expression are mutually " +
|
||||
"exclusive, parameter expression already set", e.getMessage());
|
||||
}
|
||||
Assert.assertEquals(false, TestUtils.getPropertyValue(param,"isValueSet", Boolean.class).booleanValue());
|
||||
Assert.assertEquals("headers['someHeader']",
|
||||
TestUtils.getPropertyValue(param, "messageProcessor.expression.expression",String.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets both the value then the parameter expression, should throw an exception
|
||||
*/
|
||||
@Test
|
||||
public void setParameterValueThenExpression() {
|
||||
XQueryParameter param = new XQueryParameter("testParameter");
|
||||
param.setParameterValue("Some Value");
|
||||
try {
|
||||
param.setExpression("headers['someHeader']");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("The parameter value and expression are mutually exclusive" +
|
||||
", parameter value already set", e.getMessage());
|
||||
}
|
||||
Assert.assertEquals(true, TestUtils.getPropertyValue(param,"isValueSet", Boolean.class).booleanValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameter name and its value from the constructor
|
||||
*/
|
||||
@Test
|
||||
public void setParameterValueInConstructor() {
|
||||
XQueryParameter param = new XQueryParameter("testName", (Object)"testValue");
|
||||
Assert.assertEquals(true, TestUtils.getPropertyValue(param, "isValueSet",Boolean.class).booleanValue());
|
||||
Assert.assertEquals("testName", param.getParameterName());
|
||||
Assert.assertEquals("testValue", TestUtils.getPropertyValue(param, "parameterValue", String.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameter value from the constructor
|
||||
*/
|
||||
@Test
|
||||
public void setParameterExpressionInConstructor() {
|
||||
XQueryParameter param = new XQueryParameter("testName", "headers['someHeader']");
|
||||
Assert.assertEquals(false, TestUtils.getPropertyValue(param, "isValueSet",Boolean.class).booleanValue());
|
||||
Assert.assertEquals("testName", param.getParameterName());
|
||||
Assert.assertEquals("headers['someHeader']", TestUtils.getPropertyValue(param, "expression", String.class));
|
||||
Assert.assertEquals("headers['someHeader']",
|
||||
TestUtils.getPropertyValue(param, "messageProcessor.expression.expression",String.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expression string twice, should throw an exception
|
||||
*/
|
||||
@Test
|
||||
public void setExpressionTwice() {
|
||||
XQueryParameter param = new XQueryParameter("paramName");
|
||||
param.setExpression("headers['headerValue']");
|
||||
try {
|
||||
param.setExpression("headers['headerV']");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Expression string is already set once, cannot reset it", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the parameter to get the static value set
|
||||
*/
|
||||
@Test
|
||||
public void executeForStaticValue() {
|
||||
XQueryParameter param = new XQueryParameter("paramName", Integer.valueOf(10));
|
||||
Object value = param.evaluate(null);
|
||||
Assert.assertEquals(value, Integer.valueOf(10));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an expression to get the return values
|
||||
*/
|
||||
@Test
|
||||
public void executeExpressionValue() {
|
||||
XQueryParameter param = new XQueryParameter("paramName","headers['numbers'].?[#this > 5]");
|
||||
List<Integer> numbers = Arrays.asList(1,3,4,2,5,6,7);
|
||||
Message<String> message = MessageBuilder.withPayload("")
|
||||
.setHeader("numbers", numbers)
|
||||
.build();
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Integer> coll = (Collection<Integer>)param.evaluate(message);
|
||||
Assert.assertEquals(2, coll.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.xquery.transformer;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.xquery.core.XQueryExecutor;
|
||||
import org.springframework.integration.xquery.support.XQueryResultMapper;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* The Test class for the {@link XQueryTransformer} class
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class XQueryTransformerTests {
|
||||
|
||||
@Test
|
||||
public void withNoExecutor() {
|
||||
try {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.afterPropertiesSet();
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("No XQueryExecutor instance provided", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void withNullExecutor() {
|
||||
try {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setExecutor(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Provide a non null XQueryExecutor instance", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withNoMapperAndResultType() {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setExecutor(getExecutor("//hello"));
|
||||
transformer.afterPropertiesSet();
|
||||
Assert.assertEquals(String.class, TestUtils.getPropertyValue(transformer, "resultType",Class.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withStringResultType() {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setExecutor(getExecutor("//hello"));
|
||||
transformer.setResultType(String.class);
|
||||
transformer.afterPropertiesSet();
|
||||
Assert.assertEquals(String.class, TestUtils.getPropertyValue(transformer, "resultType",Class.class));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void withNumberResultType() {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setExecutor(getExecutor("//hello"));
|
||||
transformer.setResultType(Number.class);
|
||||
transformer.afterPropertiesSet();
|
||||
Assert.assertEquals(Number.class, TestUtils.getPropertyValue(transformer, "resultType",Class.class));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void withBooleanResultType() {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setExecutor(getExecutor("//hello"));
|
||||
transformer.setResultType(Boolean.class);
|
||||
transformer.afterPropertiesSet();
|
||||
Assert.assertEquals(Boolean.class, TestUtils.getPropertyValue(transformer, "resultType",Class.class));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void withNodeResultType() {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setExecutor(getExecutor("//hello"));
|
||||
transformer.setResultType(Node.class);
|
||||
transformer.afterPropertiesSet();
|
||||
Assert.assertEquals(Node.class, TestUtils.getPropertyValue(transformer, "resultType",Class.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withUnknownResultType() {
|
||||
try {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setExecutor(getExecutor("//hello"));
|
||||
transformer.setResultType(getClass());
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Valid values for the result type class is String, Boolean, Number or Node, " +
|
||||
"for any other type, provide a custom implementation of XQueryResultMapper", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setFirstTypeThenMapper() {
|
||||
try {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setResultType(String.class);
|
||||
transformer.setResultMapper(new DummyXQueryResultMapper());
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Only one of the result mapper of the resultType can be set", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setFirstMapperThenType() {
|
||||
try {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setResultMapper(new DummyXQueryResultMapper());
|
||||
transformer.setResultType(String.class);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Only one of the result mapper of the resultType can be set", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNullMapper() {
|
||||
try {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setResultMapper(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Provide a non null value for the result mapper", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNullType() {
|
||||
try {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setResultType(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("Provide a non null value for the result type", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeForString() {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setExecutor(getExecutor("'Hello World!'"));
|
||||
transformer.afterPropertiesSet();
|
||||
try {
|
||||
Object result = transformer.doTransform(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals("Hello World!", result);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.assertTrue(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeForInteger() {
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
transformer.setExecutor(getExecutor("10 + 12"));
|
||||
transformer.setResultType(Number.class);
|
||||
transformer.afterPropertiesSet();
|
||||
try {
|
||||
Object result = transformer.doTransform(MessageBuilder.withPayload("<test/>").build());
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(BigInteger.valueOf(22), result);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.assertTrue(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void personTransformer() {
|
||||
String inputXml = "<employees>" +
|
||||
"<employee id=\"1\" name=\"Emp1\" dept=\"Dep1\"/>" +
|
||||
"<employee id=\"2\" name=\"Emp2\" dept=\"Dep2\"/>" +
|
||||
"</employees>";
|
||||
|
||||
XQueryTransformer transformer = new XQueryTransformer();
|
||||
XQueryExecutor executor = new XQueryExecutor();
|
||||
executor.setXQueryFileResource(
|
||||
new ClassPathResource("org/springframework/integration/xquery/XQueryTransform.xq"));
|
||||
executor.setFormatOutput(true);
|
||||
executor.afterPropertiesSet();
|
||||
transformer.setExecutor(executor);
|
||||
transformer.afterPropertiesSet();
|
||||
try {
|
||||
Object transformed = transformer.doTransform(MessageBuilder.withPayload(inputXml).build());
|
||||
Assert.assertNotNull(transformed);
|
||||
System.out.println(transformed);
|
||||
} catch (Exception e) {
|
||||
Assert.assertTrue("Caught Exception while transformation, " + e.getMessage(),false);
|
||||
}
|
||||
}
|
||||
|
||||
private class DummyXQueryResultMapper implements XQueryResultMapper<Integer> {
|
||||
|
||||
public List<Integer> mapResults(XQResultSequence result) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TODO: Refactor, Can have a common superclass for all XQuery components
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private XQueryExecutor getExecutor(String xQuery) {
|
||||
XQueryExecutor executor = new XQueryExecutor();
|
||||
executor.setXQuery(xQuery);
|
||||
executor.afterPropertiesSet();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<mappings>
|
||||
<students>
|
||||
<student id="1">
|
||||
<name>Jughead</name>
|
||||
<class>1</class>
|
||||
</student>
|
||||
<student id="2">
|
||||
<name>Archie</name>
|
||||
<class>1</class>
|
||||
</student>
|
||||
<student id="3">
|
||||
<name>Reggie</name>
|
||||
<class>1</class>
|
||||
</student>
|
||||
<student id="4">
|
||||
<name>Moose</name>
|
||||
<class>1</class>
|
||||
</student>
|
||||
<student id="5">
|
||||
<name>Betty</name>
|
||||
<class>1</class>
|
||||
</student>
|
||||
<student id="6">
|
||||
<name>Veronica</name>
|
||||
<class>1</class>
|
||||
</student>
|
||||
</students>
|
||||
<subjects>
|
||||
<subject>
|
||||
<name>Math</name>
|
||||
<students>
|
||||
<studentId>1</studentId>
|
||||
<studentId>2</studentId>
|
||||
<studentId>5</studentId>
|
||||
</students>
|
||||
</subject>
|
||||
<subject>
|
||||
<name>Physics</name>
|
||||
<students>
|
||||
<studentId>2</studentId>
|
||||
<studentId>5</studentId>
|
||||
<studentId>6</studentId>
|
||||
</students>
|
||||
</subject>
|
||||
<subject>
|
||||
<name>Chemistry</name>
|
||||
<students>
|
||||
<studentId>3</studentId>
|
||||
<studentId>4</studentId>
|
||||
<studentId>6</studentId>
|
||||
</students>
|
||||
</subject>
|
||||
<subject>
|
||||
<name>Cooking</name>
|
||||
<students>
|
||||
<studentId>1</studentId>
|
||||
<studentId>5</studentId>
|
||||
</students>
|
||||
</subject>
|
||||
</subjects>
|
||||
</mappings>
|
||||
@@ -0,0 +1,8 @@
|
||||
declare variable $name as xs:string external;
|
||||
declare variable $class as xs:int external;
|
||||
for $student in /mappings/students/student,
|
||||
$subject in /mappings/subjects/subject
|
||||
where $student/@id = $subject/students/studentId
|
||||
and $student/name = $name
|
||||
and $student/class = $class
|
||||
return $subject/name/text()
|
||||
@@ -0,0 +1,11 @@
|
||||
<employees>
|
||||
{
|
||||
for $emp in /employees/employee
|
||||
return
|
||||
<employee>
|
||||
<id>{string($emp/@id)}</id>
|
||||
<name>{string($emp/@name)}</name>
|
||||
<department>{string($emp/@name)}</department>
|
||||
</employee>
|
||||
}
|
||||
</employees>
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-xquery="http://www.springframework.org/schema/integration/xquery"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/xquery http://www.springframework.org/schema/integration/xquery/spring-integration-xquery.xsd">
|
||||
|
||||
<int-xquery:xquery-router id="xqueryRouterOne" input-channel="xpathRouterOne">
|
||||
<int-xquery:xquery>
|
||||
<![CDATA[
|
||||
declare variable $name as xs:string external;
|
||||
declare variable $class as xs:int external;
|
||||
for $student in /mappings/students/student,
|
||||
$subject in /mappings/subjects/subject
|
||||
where $student/@id = $subject/students/studentId
|
||||
and $student/name = $name
|
||||
and $student/class = $class
|
||||
return $subject/name/text()
|
||||
]]>
|
||||
</int-xquery:xquery>
|
||||
<int-xquery:xquery-parameter name="name" expression="headers['name']"/>
|
||||
<int-xquery:xquery-parameter name="class" value="1"/>
|
||||
</int-xquery:xquery-router>
|
||||
|
||||
<int-xquery:xquery-router id="xqueryRouterTwo"
|
||||
input-channel="xpathRouterOne"
|
||||
xquery="'Hello World'"
|
||||
converter="converter"
|
||||
xq-datasource="xqDs">
|
||||
<int-xquery:xquery-parameter name="name" ref="name"/>
|
||||
</int-xquery:xquery-router>
|
||||
|
||||
<int-xquery:xquery-router id="xqueryRouterThree"
|
||||
input-channel="xpathRouterOne"
|
||||
xquery-file-resource="classpath:org/springframework/integration/xquery/XQuery.xq"
|
||||
converter="converter"
|
||||
xq-datasource="xqDs">
|
||||
<int-xquery:xquery-parameter name="name" expression="headers['name']"/>
|
||||
<int-xquery:xquery-parameter name="class" value="1"/>
|
||||
</int-xquery:xquery-router>
|
||||
|
||||
|
||||
|
||||
<int-xquery:xquery-router id="xqueryRouterFour"
|
||||
input-channel="xpathRouterOne"
|
||||
xquery-file-resource="org/springframework/integration/xquery/XQuery.xq"
|
||||
converter="converter"
|
||||
xq-datasource="xqDs">
|
||||
<int-xquery:xquery-parameter name="name" expression="headers['name']"/>
|
||||
<int-xquery:xquery-parameter name="class" value="1"/>
|
||||
</int-xquery:xquery-router>
|
||||
|
||||
<bean id="converter" class="org.springframework.integration.xquery.DummyXmlPayloadConverter"/>
|
||||
|
||||
<bean id="xqDs" class="org.springframework.integration.xquery.config.xml.XQueryRouterParserTests.DummyXQDataSource"/>
|
||||
|
||||
<bean id="name" class="java.lang.String">
|
||||
<constructor-arg index="0" value="name"/>
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-xquery="http://www.springframework.org/schema/integration/xquery"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/xquery http://www.springframework.org/schema/integration/xquery/spring-integration-xquery.xsd">
|
||||
|
||||
<int:channel id="output"/>
|
||||
|
||||
<int-xquery:xquery-transformer id="xqueryTransformerOne"
|
||||
input-channel="xqueryTransformerInOne"
|
||||
output-channel="output">
|
||||
<int-xquery:xquery>
|
||||
<![CDATA[
|
||||
declare variable $name as xs:string external;
|
||||
declare variable $class as xs:int external;
|
||||
for $student in /mappings/students/student,
|
||||
$subject in /mappings/subjects/subject
|
||||
where $student/@id = $subject/students/studentId
|
||||
and $student/name = $name
|
||||
and $student/class = $class
|
||||
return $subject/name/text()
|
||||
]]>
|
||||
</int-xquery:xquery>
|
||||
<int-xquery:xquery-parameter name="name" expression="headers['name']"/>
|
||||
<int-xquery:xquery-parameter name="class" value="1"/>
|
||||
</int-xquery:xquery-transformer>
|
||||
|
||||
<int-xquery:xquery-transformer id="xqueryTransformerTwo"
|
||||
input-channel="xqueryTransformerOutTwo"
|
||||
output-channel="output"
|
||||
xquery="'Hello World'"
|
||||
converter="converter"
|
||||
xq-datasource="xqDs"
|
||||
format-output="true">
|
||||
</int-xquery:xquery-transformer>
|
||||
|
||||
<int-xquery:xquery-transformer id="xqueryTransformerThree"
|
||||
input-channel="xqueryTransformerIPThree"
|
||||
output-channel="output"
|
||||
xquery-file-resource="classpath:org/springframework/integration/xquery/XQueryTransform.xq"
|
||||
converter="converter"
|
||||
xq-datasource="xqDs">
|
||||
</int-xquery:xquery-transformer>
|
||||
|
||||
<int-xquery:xquery-transformer id="booleanResultTypeTransformer"
|
||||
input-channel="booleanResultTypeTransformerIP"
|
||||
output-channel="output"
|
||||
result-type="java.lang.Boolean"
|
||||
xquery-file-resource="classpath:org/springframework/integration/xquery/XQueryTransform.xq"
|
||||
xq-datasource="xqDs"/>
|
||||
|
||||
<int-xquery:xquery-transformer id="stringResultTypeTransformer"
|
||||
input-channel="stringResultTypeTransformerIP"
|
||||
output-channel="output"
|
||||
result-type="string"
|
||||
xquery-file-resource="classpath:org/springframework/integration/xquery/XQueryTransform.xq"
|
||||
xq-datasource="xqDs"/>
|
||||
|
||||
<int-xquery:xquery-transformer id="customXQueryResultMapper"
|
||||
input-channel="stringResultTypeTransformerIP"
|
||||
output-channel="output"
|
||||
xquery-result-mapper="xqueryResultMapper"
|
||||
xquery-file-resource="classpath:org/springframework/integration/xquery/XQueryTransform.xq"
|
||||
xq-datasource="xqDs"/>
|
||||
|
||||
<bean id="converter" class="org.springframework.integration.xquery.DummyXmlPayloadConverter"/>
|
||||
|
||||
<bean id="xqDs" class="org.springframework.integration.xquery.config.xml.XQueryTransformerParserTests.DummyXQDataSource"/>
|
||||
|
||||
<bean id="xqueryResultMapper" class="org.springframework.integration.xquery.config.xml.XQueryTransformerParserTests.DummyXQueryResultMapper"/>
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user