INT-1983 - Add JPA Adapter

For reference see: https://jira.springsource.org/browse/INT-1983

* INT-2435 - Add the ability to automatically resolve the entity-class from the payload as fallback
* Add <transactional/> support for **Jpa Outbound Gateway** and **Jpa Outbound Channel Adapter**
* Merging Documentation from: https://github.com/amolnayak311/spring-integration/blob/INT-2440/src/reference/docbook/jpa.xml
* Provide JPA Tests against Hibernate, EclipseLink and OpenJPA
* Improve Documentation
* Remove trailing white-space, convert white-space to tabs, remove @transactional from DefaultJpaOperations
* INT-2440 Adding the documentation for the JPA adapters

INT-1983 - Code Review based Fixes
* Fix indentation in XML Schema
* Remove *transactional* sub-element definition from JPA Inbound Channel Adapter in XML Schema
* Fix enumeration *gatewayType*

INT-1983 - Based on Code Review

* Remove '/** {@inheritDoc} */' from DefaultJpaOperations
* Remove JavaDoc parameters that don't contains details
* Cleanup *JpaUtils*
* Remove "transaction-manager-ref" from *spring-integration-jpa-2.2.xsd*
* Cleanup *spring-integration-jpa-2.2.xsd*
* Provide documentation to *EclipseLinkJpaOperationsTests* on how to run tests in IDE
* Provide documentation to *OpenJpaJpaOperationsTests* on how to run tests in IDE
* Refactor JPA Reference Doc Chapter (work in progress)

INT-1983 - Code Review: provide better JavaDoc
This commit is contained in:
Amol Nayak
2012-02-16 22:27:00 +05:30
committed by Oleg Zhurakousky
parent 6c2f3d8dd0
commit 16f48a12e6
82 changed files with 7762 additions and 0 deletions

View File

@@ -74,6 +74,8 @@ subprojects { subproject ->
// and http://www.gradle.org/docs/current/dsl/org.gradle.api.artifacts.ConfigurationContainer.html
configurations {
jacoco //Configuration Group used by Sonar to provide Code Coverage using JaCoCo
javaAgentSpringInstrument //Configuration Group used by the JPA Adapter during test execution
javaAgentOpenJpa //Configuration Group used by the JPA Adapter during test execution
}
// dependencies that are common across all java projects
@@ -491,6 +493,51 @@ project('spring-integration-jmx') {
}
}
project('spring-integration-jpa') {
description = 'Spring Integration JPA Support'
dependencies {
compile project(":spring-integration-core")
compile "org.springframework:spring-aop:$springVersion"
compile "org.springframework:spring-orm:$springVersion"
compile "org.springframework:spring-tx:$springVersion"
compile "org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.0.Final"
testCompile project(":spring-integration-test")
testCompile "com.h2database:h2:1.3.166"
testCompile "hsqldb:hsqldb:1.8.0.10"
testCompile "org.apache.derby:derby:10.5.3.0_1"
testCompile "org.aspectj:aspectjrt:$aspectjVersion"
testCompile "org.aspectj:aspectjweaver:$aspectjVersion"
testCompile "org.hibernate:hibernate-entitymanager:4.0.1.Final"
testCompile "org.eclipse.persistence:org.eclipse.persistence.jpa:2.3.2"
testCompile "org.apache.openjpa:openjpa:2.2.0"
javaAgentSpringInstrument "org.springframework:spring-instrument:$springVersion"
javaAgentOpenJpa "org.apache.openjpa:openjpa:2.2.0"
}
bundlor {
bundleSymbolicName = 'org.springframework.integration.jpa'
importTemplate += [
'org.springframework.integration.*;version="[2.1.0, 2.1.1)"',
'org.springframework.*;version="[3.0.5, 4.0.0)"',
'org.apache.commons.logging;version="[1.1.1, 2.0.0)"',
'org.aopalliance.*;version="[1.0.0, 2.0.0)"',
'javax.persistence.*;version="[1.0.0, 2.0.0)"',
'javax.sql.*;version="0"',
'org.w3c.dom.*;version="0"'
]
}
test.doFirst {
String jvmArgsSpringIntrument = "-javaagent:${configurations.javaAgentSpringInstrument.asPath}"
String jvmArgsOpenJpa = "-javaagent:${configurations.javaAgentOpenJpa.files.iterator().next()}"
jvmArgs jvmArgsSpringIntrument , jvmArgsOpenJpa
}
}
project('spring-integration-mail') {
description = 'Spring Integration Mail Support'
dependencies {

View File

@@ -13,6 +13,7 @@ include 'spring-integration-ip'
include 'spring-integration-jdbc'
include 'spring-integration-jms'
include 'spring-integration-jmx'
include 'spring-integration-jpa'
include 'spring-integration-mail'
include 'spring-integration-mongodb'
include 'spring-integration-redis'

View File

@@ -0,0 +1,61 @@
/*
* 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.jpa.config.xml;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jpa.inbound.JpaPollingChannelAdapter;
import org.w3c.dom.Element;
/**
* The JPA Inbound Channel adapter parser
*
* @author Amol Nayak
* @since 2.2
*
*
*/
public class JpaInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser{
protected BeanMetadataElement parseSource(Element element,
ParserContext parserContext) {
final BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getJpaExecutorBuilder(element, parserContext);
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "delete-after-poll");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "delete-per-row");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "expect-single-result");
final BeanDefinition jpaExecutorBuilderBeanDefinition = jpaExecutorBuilder.getBeanDefinition();
final String jpaExecutorBeanName = BeanDefinitionReaderUtils.generateBeanName(jpaExecutorBuilderBeanDefinition, parserContext.getRegistry());
parserContext.registerBeanComponent(new BeanComponentDefinition(jpaExecutorBuilderBeanDefinition, jpaExecutorBeanName));
final BeanDefinitionBuilder jpaPollingChannelAdapterBuilder = BeanDefinitionBuilder
.genericBeanDefinition(JpaPollingChannelAdapter.class);
jpaPollingChannelAdapterBuilder.addConstructorArgReference(jpaExecutorBeanName);
return jpaPollingChannelAdapterBuilder.getBeanDefinition();
}
}

View File

@@ -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.jpa.config.xml;
import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler;
/**
* The namespace handler for the JPA namespace
*
* @author Amol Nayak
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaNamespaceHandler extends AbstractIntegrationNamespaceHandler {
/* (non-Javadoc)
* @see org.springframework.beans.factory.xml.NamespaceHandler#init()
*/
public void init() {
this.registerBeanDefinitionParser("inbound-channel-adapter", new JpaInboundChannelAdapterParser());
this.registerBeanDefinitionParser("outbound-channel-adapter", new JpaOutboundChannelAdapterParser());
this.registerBeanDefinitionParser("outbound-gateway", new JpaOutboundGatewayParser());
}
}

View File

@@ -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.jpa.config.xml;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jpa.outbound.JpaOutboundGatewayFactoryBean;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* The parser for JPA outbound channel adapter
*
* @author Amol Nayak
* @author Gunnar Hillert
*
* @since 2.2
*
*/
public class JpaOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
@Override
protected boolean shouldGenerateId() {
return false;
}
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
final BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getJpaExecutorBuilder(element, parserContext);
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "persist-mode");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "parameter-source-factory");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "use-payload-as-parameter-source");
final BeanDefinition jpaExecutorBuilderBeanDefinition = jpaExecutorBuilder.getBeanDefinition();
final String jpaExecutorBeanName = BeanDefinitionReaderUtils.generateBeanName(jpaExecutorBuilderBeanDefinition, parserContext.getRegistry());
parserContext.registerBeanComponent(new BeanComponentDefinition(jpaExecutorBuilderBeanDefinition, jpaExecutorBeanName));
final BeanDefinitionBuilder jpaOutboundChannelAdapterBuilder = BeanDefinitionBuilder.genericBeanDefinition(JpaOutboundGatewayFactoryBean.class);
jpaOutboundChannelAdapterBuilder.addConstructorArgReference(jpaExecutorBeanName);
jpaOutboundChannelAdapterBuilder.addPropertyValue("producesReply", Boolean.FALSE);
final Element transactionalElement = DomUtils.getChildElementByTagName(element, "transactional");
if(transactionalElement != null) {
BeanDefinition txAdviceDefinition = JpaParserUtils.configureTransactionAttributes(transactionalElement);
ManagedList<BeanDefinition> adviceChain = new ManagedList<BeanDefinition>();
adviceChain.add(txAdviceDefinition);
jpaOutboundChannelAdapterBuilder.addPropertyValue("adviceChain", adviceChain);
}
return jpaOutboundChannelAdapterBuilder.getBeanDefinition();
}
}

View File

@@ -0,0 +1,99 @@
/*
* 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.jpa.config.xml;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jpa.outbound.JpaOutboundGatewayFactoryBean;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* The Parser for JPA Outbound Gateway, the MessageHandler implementation is same as the
* outbound chanel adapter and hence we extend the class and setting the few additional
* attributes that we wish to in the MessageSource
*
* @author Amol Nayak
* @author Gunnar Hillert
*
* @since 2.2
*
*/
public class JpaOutboundGatewayParser extends AbstractConsumerEndpointParser {
protected boolean shouldGenerateId() {
return false;
}
protected boolean shouldGenerateIdAsFallback() {
return true;
}
protected BeanDefinitionBuilder parseHandler(Element gatewayElement, ParserContext parserContext) {
final BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getJpaExecutorBuilder(gatewayElement, parserContext);
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "persist-mode");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "parameter-source-factory");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "use-payload-as-parameter-source");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "delete-after-poll");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "delete-per-row");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "expect-single-result");
final BeanDefinition jpaExecutorBuilderBeanDefinition = jpaExecutorBuilder.getBeanDefinition();
final String jpaExecutorBeanName = BeanDefinitionReaderUtils.generateBeanName(jpaExecutorBuilderBeanDefinition, parserContext.getRegistry());
parserContext.registerBeanComponent(new BeanComponentDefinition(jpaExecutorBuilderBeanDefinition, jpaExecutorBeanName));
final BeanDefinitionBuilder jpaOutboundGatewayBuilder = BeanDefinitionBuilder
.genericBeanDefinition(JpaOutboundGatewayFactoryBean.class);
jpaOutboundGatewayBuilder.addConstructorArgReference(jpaExecutorBeanName);
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaOutboundGatewayBuilder, gatewayElement, "gateway-type");
final String replyChannel = gatewayElement.getAttribute("reply-channel");
if (StringUtils.hasText(replyChannel)) {
jpaOutboundGatewayBuilder.addPropertyReference("outputChannel", replyChannel);
}
final Element transactionalElement = DomUtils.getChildElementByTagName(gatewayElement, "transactional");
if(transactionalElement != null) {
BeanDefinition txAdviceDefinition = JpaParserUtils.configureTransactionAttributes(transactionalElement);
ManagedList<BeanDefinition> adviceChain = new ManagedList<BeanDefinition>();
adviceChain.add(txAdviceDefinition);
jpaOutboundGatewayBuilder.addPropertyValue("adviceChain", adviceChain);
}
return jpaOutboundGatewayBuilder;
}
protected String getInputChannelAttributeName() {
return "request-channel";
}
}

View File

@@ -0,0 +1,206 @@
/*
* 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.jpa.config.xml;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.endpoint.AbstractPollingEndpoint;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.jpa.support.JpaParameter;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* The common method for generating the BeanDefinition for the common MessageHandler
* is implemented in this class
*
* @author Amol Nayak
* @author Gunnar Hillert
*
* @since 2.2
*
*/
public final class JpaParserUtils {
private static final Log logger = LogFactory.getLog(JpaParserUtils.class);
/** Prevent instantiation. */
private JpaParserUtils() {
throw new AssertionError();
}
/**
* Create a new {@link BeanDefinitionBuilder} for the class {@link JpaExecutor}.
* Initialize the wrapped {@link JpaExecutor} with common properties.
*
* @param element Must not be Null
* @param parserContext Must not be Null
* @return The BeanDefinitionBuilder for the JpaExecutor
*/
public static BeanDefinitionBuilder getJpaExecutorBuilder(final Element element,
final ParserContext parserContext) {
Assert.notNull(element, "The provided element must not be Null.");
Assert.notNull(parserContext, "The provided parserContext must not be Null.");
final Object source = parserContext.extractSource(element);
final BeanDefinitionBuilder jpaExecutorBuilder = BeanDefinitionBuilder.genericBeanDefinition(JpaExecutor.class);
int attributeCount = 0;
final String entityManagerRef = element.getAttribute("entity-manager");
final String entityManagerFactoryRef = element.getAttribute("entity-manager-factory");
final String jpaOperationsRef = element.getAttribute("jpa-operations");
if (StringUtils.hasText(jpaOperationsRef)) {
attributeCount++;
jpaExecutorBuilder.addConstructorArgReference(jpaOperationsRef);
}
if (StringUtils.hasText(entityManagerRef)) {
if (attributeCount > 0) {
parserContext.getReaderContext().error("Exactly only one of the attributes 'entity-manager' or " +
"'entity-manager-factory' or 'jpa-operations' must be be set.", source);
}
attributeCount++;
jpaExecutorBuilder.addConstructorArgReference(entityManagerRef);
}
if (StringUtils.hasText(entityManagerFactoryRef)) {
if (attributeCount > 0) {
parserContext.getReaderContext().error("Exactly only one of the attributes 'entity-manager' or " +
"'entity-manager-factory' or 'jpa-operations' must be be set.", source);
}
attributeCount++;
jpaExecutorBuilder.addConstructorArgReference(entityManagerFactoryRef);
}
if (attributeCount == 0) {
parserContext.getReaderContext().error("Exactly one of the attributes 'entity-manager' or " +
"'entity-manager-factory' or 'jpa-operations' must be be set.", source);
}
final ManagedList<BeanDefinition> jpaParameterList = JpaParserUtils.getJpaParameterBeanDefinitions(element, parserContext);
if (!jpaParameterList.isEmpty()) {
jpaExecutorBuilder.addPropertyValue("jpaParameters", jpaParameterList);
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "entity-class");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "jpa-query");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "native-query");
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "named-query");
return jpaExecutorBuilder;
}
/**
* @param jpaComponent
* @param parserContext
*/
public static ManagedList<BeanDefinition> getJpaParameterBeanDefinitions(
Element jpaComponent, ParserContext parserContext) {
final ManagedList<BeanDefinition> parameterList = new ManagedList<BeanDefinition>();
final List<Element> parameterChildElements = DomUtils
.getChildElementsByTagName(jpaComponent, "parameter");
for (Element childElement : parameterChildElements) {
final BeanDefinitionBuilder parameterBuilder = BeanDefinitionBuilder.genericBeanDefinition(JpaParameter.class);
String name = childElement.getAttribute("name");
String expression = childElement.getAttribute("expression");
String value = childElement.getAttribute("value");
String type = childElement.getAttribute("type");
if (StringUtils.hasText(name)) {
parameterBuilder.addPropertyValue("name", name);
}
if (StringUtils.hasText(expression)) {
parameterBuilder.addPropertyValue("expression", expression);
}
if (StringUtils.hasText(value)) {
if (!StringUtils.hasText(type)) {
if (logger.isInfoEnabled()) {
logger.info(String
.format("Type attribute not set for parameter '%s'. Defaulting to "
+ "'java.lang.String'.", value));
}
parameterBuilder.addPropertyValue("value",
new TypedStringValue(value, String.class));
} else {
parameterBuilder.addPropertyValue("value",
new TypedStringValue(value, type));
}
}
parameterList.add(parameterBuilder.getBeanDefinition());
}
return parameterList;
}
/**
* Parse a "transactional" element and configure a TransactionInterceptor with "transactionManager"
* and other "transactionDefinition" properties. This advisor will be applied on the Polling Task proxy
* (see {@link AbstractPollingEndpoint}).
*
* FIXME Copied from {@link org.springframework.integration.config.xml.PollerParser} - should be refactored.
*/
public static BeanDefinition configureTransactionAttributes(Element txElement) {
BeanDefinitionBuilder txDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(DefaultTransactionAttribute.class);
txDefinitionBuilder.addPropertyValue("propagationBehaviorName", "PROPAGATION_" + txElement.getAttribute("propagation"));
txDefinitionBuilder.addPropertyValue("isolationLevelName", "ISOLATION_" + txElement.getAttribute("isolation"));
txDefinitionBuilder.addPropertyValue("timeout", txElement.getAttribute("timeout"));
txDefinitionBuilder.addPropertyValue("readOnly", txElement.getAttribute("read-only"));
BeanDefinitionBuilder attributeSourceBuilder = BeanDefinitionBuilder.genericBeanDefinition(MatchAlwaysTransactionAttributeSource.class);
attributeSourceBuilder.addPropertyValue("transactionAttribute", txDefinitionBuilder.getBeanDefinition());
BeanDefinitionBuilder txInterceptorBuilder = BeanDefinitionBuilder.genericBeanDefinition(TransactionInterceptor.class);
txInterceptorBuilder.addPropertyReference("transactionManager", txElement.getAttribute("transaction-manager"));
txInterceptorBuilder.addPropertyValue("transactionAttributeSource", attributeSourceBuilder.getBeanDefinition());
return txInterceptorBuilder.getBeanDefinition();
}
}

View File

@@ -0,0 +1,4 @@
/**
* Provides parser classes to provide Xml namespace support for the Jpa components.
*/
package org.springframework.integration.jpa.config.xml;

View File

@@ -0,0 +1,68 @@
/*
* 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.jpa.core;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.orm.jpa.SharedEntityManagerCreator;
import org.springframework.util.Assert;
/**
*
* @author Gunnar Hillert
*
* @since 2.2
*
*/
abstract class AbstractJpaOperations implements JpaOperations, InitializingBean {
protected EntityManager entityManager;
private EntityManagerFactory entityManagerFactory;
public void setEntityManager(EntityManager entityManager) {
Assert.notNull(entityManager, "The provided entitymanager must not be null.");
this.entityManager = entityManager;
}
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
Assert.notNull(entityManagerFactory, "The provided entitymanagerFactory must not be null.");
this.entityManagerFactory = entityManagerFactory;
}
public final void afterPropertiesSet() {
this.onInit();
}
/**
* Subclasses may implement this for initialization logic.
*/
protected void onInit() {
if (this.entityManager == null && this.entityManagerFactory != null) {
this.entityManager = SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory);
}
Assert.notNull(entityManager, "The entitymanager is null. Please set " +
"either the entityManager or the entityManagerFactory.");
}
}

View File

@@ -0,0 +1,230 @@
/*
* 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.jpa.core;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.persistence.Parameter;
import javax.persistence.Query;
import org.springframework.integration.jpa.support.JpaUtils;
import org.springframework.integration.jpa.support.parametersource.ParameterSource;
import org.springframework.integration.jpa.support.parametersource.PositionSupportingParameterSource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Class similar to JPA template limited to the operations required for the JPA adapters/gateway
* not using JpaTemplate as the class is deprecated since Spring 3.1
*
* @author Amol Nayak
* @author Gunnar Hillert
*
* @since 2.2
*
*/
public class DefaultJpaOperations extends AbstractJpaOperations {
public void delete(Object entity) {
Assert.notNull(entity, "The entity must not be null!");
entityManager.remove(entity);
}
public void deleteInBatch(Iterable<?> entities) {
Assert.notNull(entities, "entities must not be null.");
Iterator<?> iterator = entities.iterator();
if (!iterator.hasNext()) {
return;
}
Class<?> entityClass = null;
for (Object object : entities) {
if (entityClass == null) {
entityClass = object.getClass();
} else {
if (entityClass != object.getClass()) {
throw new IllegalArgumentException("entities must be of the same type.");
}
}
}
final String entityName = JpaUtils.getEntityName(entityManager, entityClass);
final String queryString = JpaUtils.getQueryString(JpaUtils.DELETE_ALL_QUERY_STRING, entityName);
JpaUtils.applyAndBind(queryString, entities, entityManager)
.executeUpdate();
}
public int executeUpdate(String updateQuery, ParameterSource source) {
Query query = entityManager.createQuery(updateQuery);
setParametersIfRequired(updateQuery, source, query);
return query.executeUpdate();
}
public int executeUpdateWithNamedQuery(String updateQuery, ParameterSource source) {
Query query = entityManager.createNamedQuery(updateQuery);
setParametersIfRequired(updateQuery, source, query);
return query.executeUpdate();
}
public int executeUpdateWithNativeQuery(String updateQuery, ParameterSource source) {
Query query = entityManager.createNativeQuery(updateQuery);
setParametersIfRequired(updateQuery, source, query);
return query.executeUpdate();
}
public <T> T find(Class<T> entityType, Object id) {
return entityManager.find(entityType, id);
}
private Query getQuery(String queryString, ParameterSource source) {
Query query = entityManager.createQuery(queryString);
setParametersIfRequired(queryString, source, query);
return query;
}
public List<?> getResultListForClass(Class<?> entityClass, int maxNumberOfResults) {
final String entityName = JpaUtils.getEntityName(entityManager, entityClass);
final Query query = entityManager.createQuery("select x from " + entityName + " x", entityClass);
if(maxNumberOfResults > 0) {
query.setMaxResults(maxNumberOfResults);
}
return query.getResultList();
}
public List<?> getResultListForNamedQuery(String selectNamedQuery,
ParameterSource parameterSource, int maxNumberOfResults) {
final Query query = entityManager.createNamedQuery(selectNamedQuery);
setParametersIfRequired(selectNamedQuery, parameterSource, query);
if(maxNumberOfResults > 0) {
query.setMaxResults(maxNumberOfResults);
}
return query.getResultList();
}
public List<?> getResultListForNativeQuery(String selectQuery, Class<?> entityClass,
ParameterSource parameterSource, int maxNumberOfResults) {
final Query query;
if (entityClass == null) {
query = entityManager.createNativeQuery(selectQuery);
} else {
query = entityManager.createNativeQuery(selectQuery, entityClass);
}
setParametersIfRequired(selectQuery, parameterSource, query);
if(maxNumberOfResults > 0) {
query.setMaxResults(maxNumberOfResults);
}
return query.getResultList();
}
public List<?> getResultListForQuery(String query, ParameterSource source) {
return getResultListForQuery(query,source, 0);
}
public List<?> getResultListForQuery(String queryString, ParameterSource source,
int maxNumberOfResults) {
Query query = getQuery(queryString,source);
if(maxNumberOfResults > 0) {
query.setMaxResults(maxNumberOfResults);
}
return query.getResultList();
}
public Object getSingleResultForQuery(String queryString, ParameterSource source) {
Query query = getQuery(queryString,source);
return query.getSingleResult();
}
public Object merge(Object entity) {
return entityManager.merge(entity);
}
public void persist(Object entity) {
entityManager.persist(entity);
}
/**
* Given a JPQL query, this method gets all parameters defined in this query and
* use the {@link JPAQLParameterSource} to find their values and set them
*
*/
private void setParametersIfRequired(String queryString,
ParameterSource source, Query query) {
Set<Parameter<?>> parameters = query.getParameters();
if(parameters != null && !parameters.isEmpty()) {
if(source != null) {
for(Parameter<?> param:parameters) {
String paramName = param.getName();
Integer position = param.getPosition();
final Object paramValue;
if (position != null) {
if (source instanceof PositionSupportingParameterSource) {
paramValue = ((PositionSupportingParameterSource) source).getValueByPosition(position - 1);
query.setParameter(position, paramValue);
} else {
throw new JpaOperationFailedException("Positional Parameters are only support "
+ "for PositionSupportingParameterSources.")
.withOffendingJPAQl(queryString);
}
} else {
if(StringUtils.hasText(paramName)) {
paramValue = source.getValue(paramName);
query.setParameter(paramName, paramValue);
} else {
throw new JpaOperationFailedException(
"This parameter does not contain a parameter name. " +
"Additionally it is not a postitional parameter, neither.")
.withOffendingJPAQl(queryString);
}
}
}
} else {
throw new IllegalArgumentException("Query has parameters but no parameter source provided");
}
}
}
}

View File

@@ -0,0 +1,453 @@
/*
* 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.jpa.core;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.jpa.support.JpaParameter;
import org.springframework.integration.jpa.support.PersistMode;
import org.springframework.integration.jpa.support.parametersource.BeanPropertyParameterSourceFactory;
import org.springframework.integration.jpa.support.parametersource.ExpressionEvaluatingParameterSourceFactory;
import org.springframework.integration.jpa.support.parametersource.ParameterSource;
import org.springframework.integration.jpa.support.parametersource.ParameterSourceFactory;
import org.springframework.util.Assert;
/**
* Executes Jpa Operations that produce payload objects from the result of the provided:
*
* <ul>
* <li>entityClass</li>
* <li>JpQl Select Query</li>
* <li>Sql Native Query</li>
* <li>JpQl Named Query</li>
* <li>Sql Native Named Query</li>
* </ul>
*
* When objects are being retrieved, it also possibly to:
*
* <ul>
* <li>delete the retrieved object</li>
* </ul>
*
* If neither entityClass nor any other query is specified then the entity-class
* is "guessed" from the {@link Message} payload.
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaExecutor implements InitializingBean {
private volatile JpaOperations jpaOperations;
private volatile List<JpaParameter> jpaParameters;
private volatile Class<?> entityClass;
private volatile String jpaQuery;
private volatile String nativeQuery;
private volatile String namedQuery;
/** 0 means all possible objects shall be retrieved. */
private volatile int maxNumberOfResults = 0;
private volatile PersistMode persistMode = PersistMode.MERGE;
private volatile ParameterSourceFactory parameterSourceFactory = null;
private volatile ParameterSource parameterSource;
private volatile boolean deleteAfterPoll = false;
private volatile boolean deletePerRow = false;
private volatile boolean expectSingleResult = false;
/**
* Indicates that whether only the payload of the passed in {@link Message}
* will be used as a source of parameters. The is 'true' by default because as a
* default a {@link BeanPropertyJpaParameterSourceFactory} implementation is
* used for the sqlParameterSourceFactory property.
*/
private volatile Boolean usePayloadAsParameterSource = null;
//~~~~Constructors~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Constructor taking an {@link EntityManagerFactory} from which the
* {@link EntityManager} can be obtained.
*
* @param entityManagerFactory Must not be null.
*/
public JpaExecutor(EntityManagerFactory entityManagerFactory) {
Assert.notNull(entityManagerFactory, "entityManagerFactory must not be null.");
DefaultJpaOperations defaultJpaOperations = new DefaultJpaOperations();
defaultJpaOperations.setEntityManagerFactory(entityManagerFactory);
defaultJpaOperations.afterPropertiesSet();
this.jpaOperations = defaultJpaOperations;
}
/**
* Constructor taking an {@link EntityManager} directly.
*
* @param entityManager Must not be null.
*/
public JpaExecutor(EntityManager entityManager) {
Assert.notNull(entityManager, "entityManager must not be null.");
DefaultJpaOperations defaultJpaOperations = new DefaultJpaOperations();
defaultJpaOperations.setEntityManager(entityManager);
defaultJpaOperations.afterPropertiesSet();
this.jpaOperations = defaultJpaOperations;
}
/**
* If custom behavior is required a custom implementation of {@link JpaOperations}
* can be passed in. The implementations themselves typically provide access
* to the {@link EntityManager}.
*
* See also {@link DefaultJpaOperations} and {@link AbstractJpaOperations}.
*
* @param jpaOperations Must not be null.
*/
public JpaExecutor(JpaOperations jpaOperations) {
Assert.notNull(jpaOperations, "jpaOperations must not be null.");
this.jpaOperations = jpaOperations;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
*
* Verifies and sets the parameters. E.g. initializes the to be used
* {@link ParameterSourceFactory}.
*
*/
public void afterPropertiesSet() {
if (this.jpaParameters != null ) {
if (this.parameterSourceFactory == null) {
ExpressionEvaluatingParameterSourceFactory expressionSourceFactory =
new ExpressionEvaluatingParameterSourceFactory();
expressionSourceFactory.setParameters(jpaParameters);
this.parameterSourceFactory = expressionSourceFactory;
} else {
if (!(this.parameterSourceFactory instanceof ExpressionEvaluatingParameterSourceFactory)) {
throw new IllegalStateException("You are providing 'JpaParameters'. "
+ "Was expecting the the provided jpaParameterSourceFactory "
+ "to be an instance of 'ExpressionEvaluatingJpaParameterSourceFactory', "
+ "however the provided one is of type '" + this.parameterSourceFactory.getClass().getName() + "'");
}
}
if (this.usePayloadAsParameterSource == null) {
this.usePayloadAsParameterSource = false;
}
} else {
if (this.parameterSourceFactory == null) {
this.parameterSourceFactory = new BeanPropertyParameterSourceFactory();
}
if (this.usePayloadAsParameterSource == null) {
this.usePayloadAsParameterSource = true;
}
}
}
/**
* Executes the actual Jpa Operation. Call this method, if you need access to
* process return values. This methods return a Map that contains either
* the number of affected entities or the affected entity itself.
*
* Keep in mind that the number of entities effected by the operation may
* not necessarily correlate with the number of rows effected in the database.
*
* @param message
* @return Either the number of affected entities when using a JPAQL query. When using a merge/persist the updated/inserted itself is returned.
*/
public Object executeOutboundJpaOperation(final Message<?> message) {
final Object result;
if (this.jpaQuery != null) {
result = this.jpaOperations.executeUpdate(this.jpaQuery, parameterSourceFactory.createParameterSource(message));
} else if (this.nativeQuery != null) {
result = this.jpaOperations.executeUpdateWithNativeQuery(this.nativeQuery, parameterSourceFactory.createParameterSource(message));
} else if (this.namedQuery != null) {
result = this.jpaOperations.executeUpdateWithNamedQuery(this.namedQuery, parameterSourceFactory.createParameterSource(message));
} else {
if (PersistMode.PERSIST.equals(this.persistMode)) {
this.jpaOperations.persist(message.getPayload());
result = message.getPayload();
} else if (PersistMode.MERGE.equals(this.persistMode)) {
final Object mergedEntity = this.jpaOperations.merge(message.getPayload());
result = mergedEntity;
} else if (PersistMode.DELETE.equals(this.persistMode)) {
this.jpaOperations.delete(message.getPayload());
result = message.getPayload();
} else {
throw new IllegalStateException(String.format("Unsupported PersistMode: '%s'", this.persistMode.name()));
}
}
return result;
}
/**
* Execute a (typically retrieving) JPA operation. The <i>requestMessage</i>
* can be used to provide additional query parameters using
* {@link JpaExecutor#parameterSourceFactorymeterSourceFactory}. If the
* <i>requestMessage</i> parameter is null then
* {@link JpaExecutor#parameterSource} is being used for providing query parameters.
*
* @param requestMessage May be null.
* @return The payload object, which may be null.
*/
@SuppressWarnings("unchecked")
public Object poll(final Message<?> requestMessage) {
final Object payload;
final List<?> result;
if (requestMessage == null) {
result = doPoll(this.parameterSource);
} else {
result = doPoll(this.parameterSourceFactory.createParameterSource(requestMessage));
}
if (result.isEmpty()) {
payload = null;
} else {
if (this.expectSingleResult) {
if (result.size() == 1) {
payload = result.iterator().next();
} else {
throw new MessageHandlingException(requestMessage,
"The Jpa operation returned more than "
+ "1 result object but expectSingleResult was 'true'.");
}
} else {
payload = result;
}
}
if (payload != null && this.deleteAfterPoll) {
if (payload instanceof Iterable) {
if (this.deletePerRow) {
for (Object entity : (Iterable<?>) payload) {
this.jpaOperations.delete(entity);
}
} else {
this.jpaOperations.deleteInBatch((Iterable<Object>) payload);
}
} else {
this.jpaOperations.delete(payload);
}
}
return payload;
}
/**
* Execute the JPA operation. Delegates to {@link JpaExecutor#poll(Message)}.
*/
public Object poll() {
return poll(null);
}
protected List<?> doPoll(ParameterSource jpaQLParameterSource) {
List<?> payload = null;
if (this.jpaQuery != null) {
payload = jpaOperations.getResultListForQuery(this.jpaQuery, jpaQLParameterSource, maxNumberOfResults);
} else if (this.nativeQuery != null) {
payload = jpaOperations.getResultListForNativeQuery(this.nativeQuery, this.entityClass, jpaQLParameterSource, maxNumberOfResults);
} else if (this.namedQuery != null) {
payload = jpaOperations.getResultListForNamedQuery(this.namedQuery, jpaQLParameterSource, maxNumberOfResults);
} else if (this.entityClass != null) {
payload = jpaOperations.getResultListForClass(this.entityClass, maxNumberOfResults);
} else {
throw new IllegalStateException("For the polling operation, one of "
+ "the following properties must be specified: "
+ "query, namedQuery or entityClass.");
}
return payload;
}
//~~~~Setters~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Sets the class type which is being used to poll the database or to also
* update the persistence store.
*
* @param entityClass Must not be null.
*/
public void setEntityClass(Class<?> entityClass) {
Assert.notNull(entityClass, "entityClass must not be null.");
this.entityClass = entityClass;
}
/**
* @param jpaQuery The provided JPA query must neither be null nor empty.
*/
public void setJpaQuery(String jpaQuery) {
if (this.nativeQuery != null || this.namedQuery != null) {
throw new IllegalArgumentException("You can define only one of the " +
"properties 'jpaQuery', 'nativeQuery', 'namedQuery'");
}
Assert.hasText(jpaQuery, "jpaQuery must neither be null nor empty.");
this.jpaQuery = jpaQuery;
}
/**
* You can also use native Sql queries to poll data from the database. If set
* this property will allow you to use native SQL. Optionally you can also set
* the entityClass property at the same time. If specified the entityClass will
* be used as the result class for the native query.
*
* @param nativeQuery The provided SQL query must neither be null nor empty.
*/
public void setNativeQuery(String nativeQuery) {
if (this.jpaQuery != null || this.namedQuery != null) {
throw new IllegalArgumentException("You can define only one of the " +
"properties 'jpaQuery', 'nativeQuery', 'namedQuery'");
}
Assert.hasText(nativeQuery, "nativeQuery must neither be null nor empty.");
this.nativeQuery = nativeQuery;
}
/**
* A named query can either refer to a named JPQL based query or a native SQL
* query.
*
* @param namedQuery Must neither be null nor empty
*/
public void setNamedQuery(String namedQuery) {
if (this.jpaQuery != null || this.nativeQuery != null) {
throw new IllegalArgumentException("You can define only one of the " +
"properties 'jpaQuery', 'nativeQuery', 'namedQuery'");
}
Assert.hasText(namedQuery, "namedQuery must neither be null nor empty.");
this.namedQuery = namedQuery;
}
public void setPersistMode(PersistMode persistMode) {
this.persistMode = persistMode;
}
public void setJpaParameters(List<JpaParameter> jpaParameters) {
this.jpaParameters = jpaParameters;
}
public void setUsePayloadAsParameterSource(Boolean usePayloadAsParameterSource) {
this.usePayloadAsParameterSource = usePayloadAsParameterSource;
}
/**
* If not set, this property default to 'true', which means that deletion
* occur on a per object basis.
*
* If set to 'false' the elements of the payload are deleted as a batch
* operation. Be aware that this exhibit issues in regards to cascaded deletes. //TODO further information needed
*
* @param deletePerRow Defaults to 'true'.
*/
public void setDeletePerRow(boolean deletePerRow) {
this.deletePerRow = deletePerRow;
}
/**
* If set to 'true', the retrieved objects are deleted from the database upon
* being polled. May not work in all situations, e.g. for Native SQL Queries.
*
* @param deleteAfterPoll Defaults to 'false'.
*/
public void setDeleteAfterPoll(boolean deleteAfterPoll) {
this.deleteAfterPoll = deleteAfterPoll;
}
/**
*
* @param maxNumberOfResults Must not be negative.
*/
public void setMaxRows(int maxNumberOfResults) {
Assert.isTrue(maxNumberOfResults >= 0, "maxRows must not be negative.");
this.maxNumberOfResults = maxNumberOfResults;
}
/**
*
* @param parameterSourceFactory
*/
public void setParameterSourceFactory(
ParameterSourceFactory parameterSourceFactory) {
Assert.notNull(parameterSourceFactory, "parameterSourceFactory must not be null.");
this.parameterSourceFactory = parameterSourceFactory;
}
/**
*
* @param parameterSource
*/
public void setParameterSource(ParameterSource parameterSource) {
Assert.notNull(parameterSource, "parameterSource must not be null.");
this.parameterSource = parameterSource;
}
public void setExpectSingleResult(boolean expectSingleResult) {
this.expectSingleResult = expectSingleResult;
}
}

View File

@@ -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.jpa.core;
/**
* An Exception that would be thrown if any of the Operations from {@link JpaOperations} fails
*
* @author Amol Nayak
* @since 2.2
*
*/
public class JpaOperationFailedException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
private String offendingJPAQl;
public JpaOperationFailedException() {
super();
}
public JpaOperationFailedException(String message, Throwable cause) {
super(message, cause);
}
public JpaOperationFailedException(String message) {
super(message);
}
public JpaOperationFailedException(Throwable cause) {
super(cause);
}
/**
* If execution of a JPA QL fails, we can set that query using this convenience method.
* @param offendingJPAQl
* @return JpaOperationFailedException
*/
public JpaOperationFailedException withOffendingJPAQl(String offendingJPAQl) {
setOffendingJPAQl(offendingJPAQl);
return this;
}
public String getOffendingJPAQl() {
return offendingJPAQl;
}
public void setOffendingJPAQl(String offendingJPAQl) {
this.offendingJPAQl = offendingJPAQl;
}
}

View File

@@ -0,0 +1,155 @@
/*
* 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.jpa.core;
import java.util.List;
import org.springframework.integration.jpa.support.parametersource.ParameterSource;
/**
* The Interface containing all the JpaOperations those will be executed by
* the Jpa Spring Integration components.
*
* @author Amol Nayak
* @author Gunnar Hillert
* @since 2.2
*
*/
public interface JpaOperations {
/**
*
* @param entity
*/
void delete(Object entity);
/**
*
* @param entities
*/
void deleteInBatch(Iterable<?> entities);
/**
* Executes the given update statement and uses the given parameter source to
* set the required query parameters.
*
* @param updateQuery Must Not be empty.
* @param source Must Not be null.
* @return The number of entities updated
*/
int executeUpdate(String updateQuery, ParameterSource source);
/**
*
* @param updateQuery
* @param source
* @return The number of entities updated
*/
int executeUpdateWithNamedQuery(String updateQuery, ParameterSource source);
/**
*
* @param updateQuery
* @param source
* @return The number of entities updated
*/
int executeUpdateWithNativeQuery(String updateQuery, ParameterSource source);
/**
* Find an Entity of given type with the given primary key type.
*
* @param <T>
* @param entityType
* @param id
* @return The entity if it exist, null is returned otherwise
*/
<T> T find(Class<T> entityType, Object id);
/**
*
* @param entityClass
* @param maxNumberOfReturnedObjects
* @return List of found entities
*/
List<?> getResultListForClass(Class<?> entityClass,
int maxNumberOfReturnedObjects);
/**
*
* @param selectNamedQuery
* @param jpaQLParameterSource
* @param maxNumberOfResults
* @return List of found entities
*/
List<?> getResultListForNamedQuery(String selectNamedQuery, ParameterSource jpaQLParameterSource,
int maxNumberOfResults);
/**
*
* @param selectQuery
* @param entityClass
* @param jpaQLParameterSource
* @param maxNumberOfResults
* @return List of found entities
*/
List<?> getResultListForNativeQuery(String selectQuery,
Class<?> entityClass, ParameterSource jpaQLParameterSource, int maxNumberOfResults);
/**
* Executes the provided query to return a list of results
* @param query
* @param source the Parameter source for this query to be executed, if none then set as null
* @return List of found entities
*/
List<?> getResultListForQuery(String query, ParameterSource source);
/**
* Executes the provided query to return a list of results.
*
* @param query Must not be null or empty
* @param maxNumberOfResults Must be a non-negative value
* @param source the Parameter source for this query to be executed, if none then set null
* @return List of found entities
*/
List<?> getResultListForQuery(String query, ParameterSource source, int maxNumberOfResults);
/**
* Executes the provided query to return a single element
*
* @param query Must not be empty
* @param source the Parameter source for this query to be executed, if none then set as null
* @return Will always return a result. If no object was found in the database an exception is raised.
*/
Object getSingleResultForQuery(String query, ParameterSource source);
/**
* The entity to be merged with the entity manager
*
* @param entity Must not be null.
* @return The merged managed instance of the entity.
*/
Object merge(Object entity);
/**
* Persists the entity
* @param entity Must not be null
*
*/
void persist(Object entity);
}

View File

@@ -0,0 +1,4 @@
/**
* Provides core classes of the JPA module.
*/
package org.springframework.integration.jpa.core;

View File

@@ -0,0 +1,97 @@
/*
* 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.jpa.inbound;
import org.springframework.integration.Message;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
/**
* Polling message source that produces messages from the result of the provided:
*
* <ul>
* <li>entityClass</li>
* <li>JpQl Select Query</li>
* <li>Sql Native Query</li>
* <li>JpQl Named Query</li>
* <li>Sql Native Named Query</li>
* </ul>
*
* After the objects have been polled, it also possibly to either:
*
* executes an update after the select possibly to updated the state of selected records
*
* <ul>
* <li>executes an update (per retrieved object or for the entire payload)</li>
* <li>delete the retrieved object</li>
* </ul>
*
* @author Amol Nayak
* @author Gunnar Hillert
*
* @since 2.2
*
*/
public class JpaPollingChannelAdapter extends IntegrationObjectSupport implements MessageSource<Object>{
private final JpaExecutor jpaExecutor;
/**
* Constructor taking a {@link JpaExecutor} that provide all required JPA
* functionality.
*
* @param jpaExecutor Must not be null.
*/
public JpaPollingChannelAdapter(JpaExecutor jpaExecutor) {
super();
Assert.notNull(jpaExecutor, "jpaExecutor must not be null.");
this.jpaExecutor = jpaExecutor;
}
/**
* Check for mandatory attributes
*/
@Override
protected void onInit() throws Exception {
super.onInit();
}
/**
* Uses {@link JpaExecutor#poll()} to executes the JPA operation.
*
* If {@link JpaExecutor#poll()} returns null, this method will return
* <code>null</code>. Otherwise, a new {@link Message} is constructed and returned.
*/
public Message<Object> receive() {
final Object payload = jpaExecutor.poll();
if (payload == null) {
return null;
}
return MessageBuilder.withPayload(payload).build();
}
@Override
public String getComponentType(){
return "jpa:inbound-channel-adapter";
}
}

View File

@@ -0,0 +1,4 @@
/**
* Provides inbound Spring Integration Jpa components.
*/
package org.springframework.integration.jpa.inbound;

View File

@@ -0,0 +1,117 @@
/*
* 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.jpa.outbound;
import org.springframework.integration.Message;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.jpa.support.OutboundGatewayType;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
/**
* The Jpa Outbound Gateway will allow you to make outbound operations to either:
*
* <ul>
* <li>submit (insert, delete) data to a database using JPA</li>
* <li>retrieve (select) data from a database</li>
* </ul>
*
* Depending on the selected {@link OutboundGatewayType}, the outbound gateway
* will use either the {@link JpaExecutor}'s poll method or its
* executeOutboundJpaOperation method.
*
* In order to initialize the adapter, you must provide a {@link JpaExecutor} as
* constructor.
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaOutboundGateway extends AbstractReplyProducingMessageHandler {
private final JpaExecutor jpaExecutor;
private OutboundGatewayType gatewayType = OutboundGatewayType.UPDATING;
private boolean producesReply = true; //false for outbound-channel-adapter, true for outbound-gateway
/**
* Constructor taking an {@link JpaExecutor} that wraps all JPA Operations.
*
* @param jpaExecutor Must not be null
*
*/
public JpaOutboundGateway(JpaExecutor jpaExecutor) {
Assert.notNull(jpaExecutor, "jpaExecutor must not be null.");
this.jpaExecutor = jpaExecutor;
}
/**
*
*/
@Override
protected void onInit() {
super.onInit();
}
@Override
protected Object handleRequestMessage(Message<?> requestMessage) {
final Object result;
if (OutboundGatewayType.RETRIEVING.equals(this.gatewayType)) {
result = this.jpaExecutor.poll(requestMessage);
} else if (OutboundGatewayType.UPDATING.equals(this.gatewayType)) {
result = this.jpaExecutor.executeOutboundJpaOperation(requestMessage);
} else {
throw new IllegalArgumentException(String.format("GatewayType '%s' is not supported.", this.gatewayType));
}
if (result == null || !producesReply) {
return null;
}
return MessageBuilder.withPayload(result).copyHeaders(requestMessage.getHeaders()).build();
}
/**
*
* @param gatewayType
*/
public void setGatewayType(OutboundGatewayType gatewayType) {
Assert.notNull(gatewayType, "gatewayType must not be null.");
this.gatewayType = gatewayType;
}
/**
* If set to 'false', this component will act as an Outbound Channel Adapter.
* If not explicitly set this property will default to 'true'.
*
* @param producesReply Defaults to 'true'.
*
*/
public void setProducesReply(boolean producesReply) {
this.producesReply = producesReply;
}
}

View File

@@ -0,0 +1,116 @@
/*
* 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.jpa.outbound;
import java.util.List;
import org.aopalliance.aop.Advice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.jpa.support.OutboundGatewayType;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
/**
* The {@link JpaOutboundGatewayFactoryBean} creates instances of the
* {@link JpaOutboundGateway}. Optionally this {@link FactoryBean} will add Aop
* Advices (e.g. {@link TransactionInterceptor} to the {@link JpaOutboundGateway}
* instance.
*
* @author Amol Nayak
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaOutboundGatewayFactoryBean extends AbstractFactoryBean<MessageHandler> {
private final JpaExecutor jpaExecutor;
private OutboundGatewayType gatewayType = OutboundGatewayType.UPDATING;
private volatile List<Advice> adviceChain;
private volatile ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private boolean producesReply = true;
private MessageChannel outputChannel;
private int order;
/**
* Constructor taking an {@link JpaExecutor} that wraps all JPA Operations.
*
* @param jpaExecutor Must not be null
*
*/
public JpaOutboundGatewayFactoryBean(JpaExecutor jpaExecutor) {
Assert.notNull(jpaExecutor, "jpaExecutor must not be null.");
this.jpaExecutor = jpaExecutor;
}
public void setGatewayType(OutboundGatewayType gatewayType) {
this.gatewayType = gatewayType;
}
@Override
public Class<?> getObjectType() {
return MessageHandler.class;
}
@Override
protected MessageHandler createInstance() {
JpaOutboundGateway jpaOutboundGateway = new JpaOutboundGateway(jpaExecutor);
jpaOutboundGateway.setGatewayType(this.gatewayType);
jpaOutboundGateway.setProducesReply(this.producesReply);
jpaOutboundGateway.setOutputChannel(this.outputChannel);
jpaOutboundGateway.setOrder(this.order);
if (!CollectionUtils.isEmpty(this.adviceChain)) {
ProxyFactory proxyFactory = new ProxyFactory(jpaOutboundGateway);
if (!CollectionUtils.isEmpty(adviceChain)) {
for (Advice advice : adviceChain) {
proxyFactory.addAdvice(advice);
}
}
return (MessageHandler) proxyFactory.getProxy(this.beanClassLoader);
}
return jpaOutboundGateway;
}
public void setAdviceChain(List<Advice> adviceChain) {
this.adviceChain = adviceChain;
}
public void setProducesReply(boolean producesReply) {
this.producesReply = producesReply;
}
public void setOutputChannel(MessageChannel outputChannel) {
this.outputChannel = outputChannel;
}
public void setOrder(int order) {
this.order = order;
}
}

View File

@@ -0,0 +1,4 @@
/**
* Provides Spring Integration components for doing outbound operations.
*/
package org.springframework.integration.jpa.outbound;

View File

@@ -0,0 +1,4 @@
/**
* Root package of the JPA Module.
*/
package org.springframework.integration.jpa;

View File

@@ -0,0 +1,102 @@
/*
* 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.jpa.support;
import org.springframework.util.Assert;
/**
* Abstraction of Jpa parameters allowing to provide static parameters
* and SpEl Expression based parameters.
*
* TODO Should we combine ProcedureParameter class and this class?
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaParameter {
private String name;
private Object value;
private String expression;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Object getValue() {
return this.value;
}
public void setValue(Object value) {
this.value = value;
}
public String getExpression() {
return this.expression;
}
public void setExpression(String expression) {
this.expression = expression;
}
/**
* Instantiates a new Jpa Parameter.
*
* @param name Name of the JPA parameter, must not be null or empty
* @param value If null, the expression property must be set
* @param expression If null, the value property must be set
*/
public JpaParameter(String name, Object value, String expression) {
super();
Assert.hasText(name, "'name' must not be empty.");
this.name = name;
this.value = value;
this.expression = expression;
}
/**
* Instantiates a new Jpa Parameter without a name. This is useful for specifying
* positional Jpa parameters.
*
* @param value If null, the expression property must be set
* @param expression If null, the value property must be set
*/
public JpaParameter(Object value, String expression) {
super();
this.value = value;
this.expression = expression;
}
/**
* Default constructor.
*/
public JpaParameter() {
super();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("JpaParameter [name=").append(this.name)
.append(", value=").append(this.value)
.append(", expression=").append(this.expression)
.append("]");
return builder.toString();
}
}

View File

@@ -0,0 +1,153 @@
/*
* 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.jpa.support;
import static java.util.regex.Pattern.CASE_INSENSITIVE;
import static java.util.regex.Pattern.compile;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.springframework.util.Assert;
/**
* This Utility contains a sub-set of utility methods from the Spring Data JPA Project.
* As the Spring Integration JPA adapter uses only these utility methods, they
* were copied into this class in order to prevent having to declare a dependency
* on Spring Data JPA.
*
*
* @author Oliver Gierke
* @author Gunnar Hillert
*
* @since 2.2
*
*/
public final class JpaUtils {
public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
private static final Pattern ALIAS_MATCH;
private static final String IDENTIFIER = "[\\p{Alnum}._$]+";
private static final String IDENTIFIER_GROUP = String.format("(%s)", IDENTIFIER);
static {
StringBuilder builder = new StringBuilder();
builder.append("(?<=from)"); // from as starting delimiter
builder.append("(?: )+"); // at least one space separating
builder.append(IDENTIFIER_GROUP); // Entity name, can be qualified (any
builder.append("(?: as)*"); // exclude possible "as" keyword
builder.append("(?: )+"); // at least one space separating
builder.append("(\\w*)"); // the actual alias
ALIAS_MATCH = compile(builder.toString(), CASE_INSENSITIVE);
builder = new StringBuilder();
builder.append("(select\\s+((distinct )?.+?)\\s+)?(from\\s+");
builder.append(IDENTIFIER);
builder.append("(?:\\s+as)?\\s+)");
builder.append(IDENTIFIER_GROUP);
builder.append("(.*)");
}
/**
* Private constructor to prevent instantiation.
*/
private JpaUtils() {
}
/**
* Resolves the alias for the entity to be retrieved from the given JPA query.
*
*/
public static String detectAlias(String query) {
Matcher matcher = ALIAS_MATCH.matcher(query);
return matcher.find() ? matcher.group(2) : null;
}
/**
* Creates a where-clause referencing the given entities and appends it to the given query string. Binds the given
* entities to the query.
*
*/
public static <T> Query applyAndBind(String queryString, Iterable<T> entities, EntityManager entityManager) {
Assert.notNull(queryString);
Assert.notNull(entities);
Assert.notNull(entityManager);
Iterator<T> iterator = entities.iterator();
if (!iterator.hasNext()) {
return entityManager.createQuery(queryString);
}
String alias = detectAlias(queryString);
StringBuilder builder = new StringBuilder(queryString);
builder.append(" where");
int i = 0;
while (iterator.hasNext()) {
iterator.next();
builder.append(String.format(" %s = ?%d", alias, ++i));
if (iterator.hasNext()) {
builder.append(" or");
}
}
Query query = entityManager.createQuery(builder.toString());
iterator = entities.iterator();
i = 0;
while (iterator.hasNext()) {
query.setParameter(++i, iterator.next());
}
return query;
}
/**
* Returns the query string for the given class name.
*/
public static String getQueryString(String template, String entityName) {
Assert.hasText(entityName, "Entity name must not be null or empty!");
return String.format(template, entityName);
}
public static String getEntityName(EntityManager em, Class<?> entityClass) {
return em.getMetamodel().entity(entityClass).getName();
}
}

View File

@@ -0,0 +1,27 @@
/*
* 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.jpa.support;
/**
* Indicates the mode of operation for the outbound Jpa Gateway.
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public enum OutboundGatewayType {
UPDATING, RETRIEVING
}

View File

@@ -0,0 +1,27 @@
/*
* 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.jpa.support;
/**
* Indicates how entities shall be persisted to the underlying persistence store.
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public enum PersistMode {
PERSIST, MERGE, DELETE
}

View File

@@ -0,0 +1,4 @@
/**
* Provides various support classes used across Spring Integration Jpa Components.
*/
package org.springframework.integration.jpa.support;

View File

@@ -0,0 +1,81 @@
/*
* 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.jpa.support.parametersource;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.NotReadablePropertyException;
import org.springframework.beans.PropertyAccessor;
import org.springframework.beans.PropertyAccessorFactory;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class BeanPropertyParameterSource implements ParameterSource {
private final BeanWrapper beanWrapper;
private String[] propertyNames;
/**
* Create a new BeanPropertySqlParameterSource for the given bean.
* @param object the bean instance to wrap
*/
public BeanPropertyParameterSource(Object object) {
this.beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(object);
}
public boolean hasValue(String paramName) {
return this.beanWrapper.isReadableProperty(paramName);
}
public Object getValue(String paramName) {
try {
return this.beanWrapper.getPropertyValue(paramName);
}
catch (NotReadablePropertyException ex) {
throw new IllegalArgumentException(ex.getMessage());
}
}
/**
* Provide access to the property names of the wrapped bean.
* Uses support provided in the {@link PropertyAccessor} interface.
* @return an array containing all the known property names
*/
public String[] getReadablePropertyNames() {
if (this.propertyNames == null) {
final List<String> names = new ArrayList<String>();
PropertyDescriptor[] props = this.beanWrapper.getPropertyDescriptors();
for (PropertyDescriptor pd : props) {
if (this.beanWrapper.isReadableProperty(pd.getName())) {
names.add(pd.getName());
}
}
this.propertyNames = names.toArray(new String[names.size()]);
}
return this.propertyNames;
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.jpa.support.parametersource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class BeanPropertyParameterSourceFactory implements ParameterSourceFactory {
private volatile Map<String, Object> staticParameters;
public BeanPropertyParameterSourceFactory() {
this.staticParameters = Collections.unmodifiableMap(new HashMap<String, Object>());
}
/**
* If the input is a List or a Map, the output is a map parameter source, and in that case some static parameters
* can be added (default is empty). If the input is not a List or a Map then this value is ignored.
*
* @param staticParameters the static parameters to set
*/
public void setStaticParameters(Map<String, Object> staticParameters) {
this.staticParameters = staticParameters;
}
public ParameterSource createParameterSource(Object input) {
ParameterSource toReturn = new StaticBeanPropertyParameterSource(input, staticParameters);
return toReturn;
}
private static class StaticBeanPropertyParameterSource implements
ParameterSource {
private final BeanPropertyParameterSource input;
private final Map<String, Object> staticParameters;
public StaticBeanPropertyParameterSource(Object input, Map<String, Object> staticParameters) {
this.input = new BeanPropertyParameterSource(input);
this.staticParameters = staticParameters;
}
public Object getValue(String paramName) {
return staticParameters.containsKey(paramName) ? staticParameters.get(paramName) : input
.getValue(paramName);
}
public boolean hasValue(String paramName) {
return staticParameters.containsKey(paramName) || input.hasValue(paramName);
}
}
}

View File

@@ -0,0 +1,110 @@
package org.springframework.integration.jpa.support.parametersource;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.expression.ExpressionException;
import org.springframework.integration.jpa.support.JpaParameter;
import org.springframework.integration.jpa.support.parametersource.ExpressionEvaluatingParameterSourceFactory.ParameterExpressionEvaluator;
import org.springframework.util.Assert;
class ExpressionEvaluatingParameterSource implements PositionSupportingParameterSource {
private static final Log logger = LogFactory.getLog(ExpressionEvaluatingParameterSource.class);
private static final Object ERROR = new Object();
private final Object input;
private volatile Map<String, Object> values = new HashMap<String, Object>();
private final Map<String, String> parameterExpressions;
private final List<JpaParameter> parameters;
private final ParameterExpressionEvaluator expressionEvaluator;
ExpressionEvaluatingParameterSource(Object input, List<JpaParameter> parameters, ParameterExpressionEvaluator expressionEvaluator) {
this.input = input;
this.expressionEvaluator = expressionEvaluator;
this.parameters = parameters;
this.parameterExpressions = ExpressionEvaluatingParameterSourceFactory.convertExpressions(parameters);
this.values.putAll(ExpressionEvaluatingParameterSourceFactory.convertStaticParameters(parameters));
}
public Object getValueByPosition(int position) {
Assert.isTrue(position >= 0, "The position must be be non-negative.");
if (position <= parameters.size()) {
final JpaParameter parameter = parameters.get(position);
if (parameter.getValue() != null) {
return parameter.getValue();
}
if (parameter.getExpression() != null) {
String expression = parameter.getExpression();
if (input instanceof Collection<?>) {
expression = "#root.![" + expression + "]";
}
final Object value = this.expressionEvaluator.evaluateExpression(expression, input);
//FIXME values.put(paramName, value);
if (logger.isDebugEnabled()) {
logger.debug("Resolved expression " + expression + " to " + value);
}
return value;
}
}
return null;
}
public Object getValue(String paramName) {
if (values.containsKey(paramName)) {
return values.get(paramName);
}
String expression = paramName;
if (parameterExpressions.containsKey(expression)) {
expression = parameterExpressions.get(expression);
}
if (input instanceof Collection<?>) {
expression = "#root.![" + expression + "]";
}
final Object value = this.expressionEvaluator.evaluateExpression(expression, input);
values.put(paramName, value);
if (logger.isDebugEnabled()) {
logger.debug("Resolved expression " + expression + " to " + value);
}
return value;
}
public boolean hasValue(String paramName) {
try {
final Object value = getValue(paramName);
if (value == ERROR) {
return false;
}
}
catch (ExpressionException e) {
if (logger.isDebugEnabled()) {
logger.debug("Could not evaluate expression", e);
}
values.put(paramName, ERROR);
return false;
}
return true;
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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.jpa.support.parametersource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.integration.jpa.support.JpaParameter;
import org.springframework.integration.util.AbstractExpressionEvaluator;
import org.springframework.util.Assert;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class ExpressionEvaluatingParameterSourceFactory implements ParameterSourceFactory {
private volatile List<JpaParameter> parameters;
private ParameterExpressionEvaluator expressionEvaluator = new ParameterExpressionEvaluator();
public ExpressionEvaluatingParameterSourceFactory() {
this.parameters = Collections.unmodifiableList(new ArrayList<JpaParameter>());
}
/**
* Define the (optional) parameter values.
*
* @param parameters the parameters to be set
*/
public void setParameters(List<JpaParameter> parameters) {
Assert.notEmpty(parameters, "parameters must not be null or empty.");
for (JpaParameter parameter : parameters) {
Assert.notNull(parameter, "The provided list (parameters) cannot contain null values.");
}
this.parameters = parameters;
expressionEvaluator.getEvaluationContext().setVariable("staticParameters", convertStaticParameters(parameters));
}
public PositionSupportingParameterSource createParameterSource(final Object input) {
return new ExpressionEvaluatingParameterSource(input, this.parameters, expressionEvaluator);
}
/**
* Utility method that converts a Collection of {@link JpaParameter} to
* a Map containing only expression parameters.
*
* @param jpaParameters Must not be null.
* @return Map containing only the Expression bound parameters. Will never be null.
*/
public static Map<String, String> convertExpressions(Collection<JpaParameter> jpaParameters) {
Assert.notNull(jpaParameters, "The Collection of jpaParameters must not be null.");
for (JpaParameter parameter : jpaParameters) {
Assert.notNull(parameter, "'jpaParameters' must not contain null values.");
}
final Map<String, String> staticParameters = new HashMap<String, String>();
for (JpaParameter parameter : jpaParameters) {
if (parameter.getExpression() != null) {
staticParameters.put(parameter.getName(), parameter.getExpression());
}
}
return staticParameters;
}
/**
* Utility method that converts a Collection of {@link JpaParameter} to
* a Map containing only static parameters.
*
* @param jpaParameters Must not be null.
* @return Map containing only the static parameters. Will never be null.
*/
public static Map<String, Object> convertStaticParameters(Collection<JpaParameter> jpaParameters) {
Assert.notNull(jpaParameters, "The Collection of jpaParameters must not be null.");
for (JpaParameter parameter : jpaParameters) {
Assert.notNull(parameter, "'jpaParameters' must not contain null values.");
}
final Map<String, Object> staticParameters = new HashMap<String, Object>();
for (JpaParameter parameter : jpaParameters) {
if (parameter.getValue() != null) {
staticParameters.put(parameter.getName(), parameter.getValue());
}
}
return staticParameters;
}
public class ParameterExpressionEvaluator extends AbstractExpressionEvaluator {
@Override
public StandardEvaluationContext getEvaluationContext() {
return super.getEvaluationContext();
}
@Override
public Object evaluateExpression(String expression, Object input) {
return super.evaluateExpression(expression, input);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.jpa.support.parametersource;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public interface ParameterSource {
/**
* Determine whether there is a value for the specified named parameter.
* @param paramName the name of the parameter
* @return whether there is a value defined
*/
boolean hasValue(String paramName);
/**
* Return the parameter value for the requested named parameter.
* @param paramName the name of the parameter
* @return the value of the specified parameter
*/
Object getValue(String paramName);
}

View File

@@ -0,0 +1,32 @@
/*
* 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.jpa.support.parametersource;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public interface ParameterSourceFactory {
/**
* Return a new {@link ParameterSource}.
* @param input the raw message or query result to be transformed into a {@link ParameterSource}
*/
ParameterSource createParameterSource(Object input);
}

View File

@@ -0,0 +1,29 @@
/*
* 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.jpa.support.parametersource;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public interface PositionSupportingParameterSource extends ParameterSource {
Object getValueByPosition(int position);
}

View File

@@ -0,0 +1,6 @@
/**
* Provides generic support for ParameterSources and ParameterSource Factories.
* This classes are modeled after the equivalent classes in the JDBC Module. However,
* the provided classes here do not have any SQL or JPA specific dependencies.
*/
package org.springframework.integration.jpa.support.parametersource;

View File

@@ -0,0 +1 @@
http\://www.springframework.org/schema/integration/jpa=org.springframework.integration.jpa.config.xml.JpaNamespaceHandler

View File

@@ -0,0 +1,2 @@
http\://www.springframework.org/schema/integration/jpa/spring-integration-jpa-2.2.xsd=org/springframework/integration/jpa/config/xml/spring-integration-jpa-2.2.xsd
http\://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd=org/springframework/integration/jpa/config/xml/spring-integration-jpa-2.2.xsd

View File

@@ -0,0 +1,4 @@
# Tooling related information for the integration jpa namespace
http\://www.springframework.org/schema/integration/jpa@name=integration JPA Namespace
http\://www.springframework.org/schema/integration/jpa@prefix=int-jpa
http\://www.springframework.org/schema/integration/jpa@icon=org/springframework/integration/jdbc/config/xml/spring-integration-jpa.gif

View File

@@ -0,0 +1,578 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.org/schema/integration/jpa"
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/jpa"
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.1.xsd" />
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the configuration elements for Spring Integration's JPA Adapter.
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
The definition for the Spring Integration JPA Inbound Channel Adapter.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attributeGroup ref="coreJpaComponentAttributes"/>
<xsd:attribute name="channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="parameter-source" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.jpa.core.JpaQLParameterSource" />
</tool:annotation>
</xsd:appinfo>
<xsd:documentation>
specifies the parameter source that would be used to
provide additional parameters.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="expect-single-result" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
This parameter indicates that only one result object shall be
returned as a result from the executed JPA operation.
If set to 'true' and the result list from the JPA operations
contains only 1 element, then that 1 element is extracted
and returned as payload.
If the result map contains more than 1 element and
'expect-single-result' is true, then a 'MessagingException'
is thrown.
If set to 'false', the complete result list is returned
as the payload.
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="delete-after-poll" default="false" use="optional">
<xsd:annotation>
<xsd:documentation>
Once entities have been retrieved from the database, shall
they be removed from the database?
If instead of deleting the retrieved entities, you would
rather like to updated them, e.g. setting a flag in a
column marking the record as retrieved, please consider
using a subsequent Outbound Gateway (coupled with a payload enricher).
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="delete-per-row" default="false" use="optional">
<xsd:annotation>
<xsd:documentation>
If you want to automatically remove retrieved entities from
the database you can also specify using the 'delete-per-row'
attribute, whether the list of retrieved objects shall be
deleted on a 'per-object-basis (true) or whether the objects
shall be removed using a batch operation (false). The
attribute defaults to 'false'.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="send-timeout" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Allows you to specify how long this inbound-channel-adapter
will wait for the message (containing the retrieved entities)
to be sent successfully to the message channel, before throwing
an exception.
Keep in mind that when sending to a DirectChannel, the
invocation will occur in the sender's thread so the failing
of the send operation may be caused by other components
further downstream. By default the Inbound Channel Adapter
will wait indefinitely. The value is specified in milliseconds.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
Defines an outbound Channel Adapter for updating a
database using the Java Persistence API (JPA).
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1" />
<xsd:element name="transactional" type="integration:transactionalType" minOccurs="0" maxOccurs="1" />
<xsd:element name="parameter" minOccurs="0" maxOccurs="unbounded" type="parameterSubElementType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Provides a mechanism to provide
parameters for the queries that are either based
on the Java Persistence Query Language (JPQL) or
native SQL queries.
Parameters can also be provided for Named Queries.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attributeGroup ref="coreJpaComponentAttributes"/>
<xsd:attribute name="persist-mode" use="optional" default="MERGE">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the persistence mode which is used when soley using
the entity-class. This attribute instructs to either Merge
entities, to Persist them. Furthermore and entity can also
be deleted. By Default 'MERGE' is used.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="persistMode xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="use-payload-as-parameter-source">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
If set to 'true', the payload of the Message will be used
as a source for providing parameters. If false the entire
Message will be available as a source for parameters.
If no JPA Parameters are passed in, this property
will default to 'true'. This means that using a default
BeanPropertyParameterSourceFactory, the bean properties
of the payload will be used as a source for parameter
values for the to-be-executed JPA query.
However, if JPA Parameters are passed in, then this
property will by default evaluate to 'false'. JPA Parameters
allow for SpEL Expressions to be provided and therefore
it is highly beneficial to have access to the entire Message.
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="parameter-source-factory"
type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation>
Reference to a ParameterSourceFactory.
</xsd:documentation>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.jpa.support.parametersource.ParameterSourceFactory" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation>
Channel from which messages will be output.
When a message is sent to this channel it will
cause the query
to be executed.
</xsd:documentation>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="order">
<xsd:annotation>
<xsd:documentation>
Specifies the order for invocation when this endpoint is connected as a
subscriber to a SubscribableChannel.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="outbound-gateway">
<xsd:annotation>
<xsd:documentation>
Defines the Spring Integration JPA Outbound Gateway
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1" />
<xsd:element name="transactional" type="integration:transactionalType" minOccurs="0" maxOccurs="1" />
<xsd:element name="parameter" minOccurs="0" maxOccurs="unbounded" type="parameterSubElementType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Provides a mechanism to provide
parameters for the queries that are either based
on the Java Persistence Query Language (JPQL) or
native SQL queries.
Parameters can also be provided for Named Queries.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attributeGroup ref="coreJpaComponentAttributes" />
<xsd:attribute name="gateway-type" use="optional" default="UPDATING">
<xsd:annotation>
<xsd:documentation><![CDATA[
The outbound JPA gateway basically wraps the functionality
of the 'outbound-channel-adapter' and the 'inbound-channel-adapter'.
By specifying the gateway-type, you bascially specify which
set of functionlity you would like to use. The attribute defaults
to 'UPDATING'.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="gatewayType xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="persist-mode" use="optional" default="MERGE">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the persistence mode which is used when soley using
the entity-class. This attribute instructs to either Merge
entities, to Persist them. Furthermore and entity can also
be deleted. By Default 'MERGE' is used.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="persistMode xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="use-payload-as-parameter-source">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
If set to 'true', the payload of the Message will be used
as a source for providing parameters. If false the entire
Message will be available as a source for parameters.
If no JPA Parameters are passed in, this property
will default to 'true'. This means that using a default
BeanPropertyParameterSourceFactory, the bean properties
of the payload will be used as a source for parameter
values for the to-be-executed JPA query.
However, if JPA Parameters are passed in, then this
property will by default evaluate to 'false'. JPA Parameters
allow for SpEL Expressions to be provided and therefore
it is highly beneficial to have access to the entire Message.
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="request-channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
The receiving Message Channel of this endpoint.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Message Channel to which replies should be
sent, after receiving the database response.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-timeout" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Allows you to specify how long this gateway will wait for
the reply message to be sent successfully before throwing
an exception. Keep in mind that when sending to a
DirectChannel, the invocation will occur in the sender's thread
so the failing of the send operation may be caused by other
components further downstream. By default the Gateway will
wait indefinitely. The value is specified in milliseconds.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="parameter-source-factory" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.jpa.JPAQLParameterSourceFactory" />
</tool:annotation>
</xsd:appinfo>
<xsd:documentation>
The parameter source factory that would be used for evaluating the
parameters of the response JPA QL that would be evaluated
JPA outbound gateway
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="order">
<xsd:annotation>
<xsd:documentation>
Specifies the order for invocation when this endpoint is connected as a
subscriber to a SubscribableChannel.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="max-number-of-results">
<xsd:annotation>
<xsd:documentation>
Specifies the maximum number of entities that shall be returned
by a JPA Operation. Using this attribute you basically set
the 'maxResults' property of the JPA Query object.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="expect-single-result" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
This parameter indicates that only one result object shall be
returned as a result from the executed JPA operation.
If set to 'true' and the result list from the JPA operations
contains only 1 element, then that 1 element is extracted
and returned as payload.
If the result map contains more than 1 element and
'expect-single-result' is true, then a 'MessagingException'
is thrown.
If set to 'false', the complete result list is returned
as the payload.
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="parameterSubElementType">
<xsd:attribute name="name" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of Jpa parameter. This parameter can also be used for
native SQL query parameters. The name attribute is optional.
If the name is not provided, this parameter will act as a positional
parameters, in which case the order of the parameter sub-element
matters.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="value" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The value of the parameter. Either this or the 'expression'
attribute must be provided.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="type" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The type of the value used. If nothing is provided this attribute
will default to java.lang.String. This attribute is not used
when the 'expression' attribute is used instead.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="expression" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Expression to be evaluated to produce a parameter value.
Either this or the 'value' attribute must be provided.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:attributeGroup name="coreJpaComponentAttributes">
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation>
Identifies the underlying Spring bean definition, which is an
instance of either 'EventDrivenConsumer' or 'PollingConsumer',
depending on whether the component's input channel is a
'SubscribableChannel' or 'PollableChannel'.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="entity-manager-factory" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The reference to the JPA Entity Manager Factory
that will be used by the adapter to create the EntityManager.
Either this attribute or the 'enity-manager' attribute or the
'jpa-operations' attribute must be provided.
]]>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="javax.persistence.EntityManagerFactory" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="entity-manager" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The reference to the JPA Entity Manager that will be used by
the adapter. Either this attribute or the 'enity-manager-factory'
attribute or the 'jpa-operations' attribute must be provided.
]]>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="javax.persistence.EntityManager" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="jpa-operations" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Reference to a bean implementing the JpaOperations interface.
In rare cases it might be advisable to provide your own implementation
of the JpaOperations interface, instead of relying on the
default implementation. As JpaOperations wraps the necessay
datasource; the JPA Entity Manager or JPA Entity Manager Factory
must not be provided if the 'jpa-operations' attribute is used.
]]>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.jpa.core.JpaOperations" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="entity-class">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The reference to the JPA Persistence Entity. If not specified the
entity class will be retrieved from the Message's payload (for
operation that involve an enityClass).
]]>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="value">
<tool:expected-type type="java.lang.Class" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="jpa-query" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Defines the JPA query (Java Persistence Query Language) to be used.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="native-query" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the native SQL query to be used.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="named-query" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
This attribute refers to a named query. A named query can be
either be defined in Native SQL or JPAQL but the underlying JPA
persistence provider handles that distinction internally.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" default="true" use="optional">
<xsd:annotation>
<xsd:documentation>
Flag to indicate that the component should start automatically
on startup (default true).
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
</xsd:attributeGroup>
<xsd:simpleType name="persistMode">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="DELETE"/>
<xsd:enumeration value="MERGE"/>
<xsd:enumeration value="PERSIST"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="gatewayType">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="UPDATING"/>
<xsd:enumeration value="RETRIEVING"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>

View File

@@ -0,0 +1,78 @@
/*
* 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.jpa.config.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.jpa.core.JpaOperations;
import org.springframework.integration.test.util.TestUtils;
/**
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaInboundChannelAdapterParserTests {
private ConfigurableApplicationContext context;
private SourcePollingChannelAdapter consumer;
@Test
public void testJpaInboundChannelAdapterParser() throws Exception {
setUp("JpaInboundChannelAdapterParserTests.xml", getClass());
final AbstractMessageChannel outputChannel = TestUtils.getPropertyValue(this.consumer, "outputChannel", AbstractMessageChannel.class);
assertEquals("out", outputChannel.getComponentName());
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "source.jpaExecutor", JpaExecutor.class);
assertNotNull(jpaExecutor);
final Class<?> entityClass = TestUtils.getPropertyValue(jpaExecutor, "entityClass", Class.class);
assertEquals("org.springframework.integration.jpa.test.entity.StudentDomain", entityClass.getName());
final JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class);
assertNotNull(jpaOperations);
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "expectSingleResult", Boolean.class));
}
@After
public void tearDown(){
if(context != null){
context.close();
}
}
public void setUp(String name, Class<?> cls){
context = new ClassPathXmlApplicationContext(name, cls);
consumer = this.context.getBean("jpaInboundChannelAdapter", SourcePollingChannelAdapter.class);
}
}

View File

@@ -0,0 +1,24 @@
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa-2.2.xsd">
<import resource="classpath:/hibernateJpa-context.xml" />
<int:channel id="out"/>
<int-jpa:inbound-channel-adapter id="jpaInboundChannelAdapter"
entity-manager-factory="entityManagerFactory"
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
expect-single-result="true"
channel="out">
<int:poller fixed-rate="5000"/>
</int-jpa:inbound-channel-adapter>
</beans>

View File

@@ -0,0 +1,163 @@
/*
* 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.jpa.config.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Proxy;
import java.util.List;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.jpa.core.JpaOperations;
import org.springframework.integration.jpa.support.JpaParameter;
import org.springframework.integration.jpa.support.PersistMode;
import org.springframework.integration.test.util.TestUtils;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaMessageHandlerParserTests {
private ConfigurableApplicationContext context;
private EventDrivenConsumer consumer;
@Test
public void testJpaMessageHandlerParser() throws Exception {
setUp("JpaMessageHandlerParserTests.xml", getClass());
final AbstractMessageChannel inputChannel = TestUtils.getPropertyValue(this.consumer, "inputChannel", AbstractMessageChannel.class);
assertEquals("target", inputChannel.getComponentName());
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "handler.jpaExecutor", JpaExecutor.class);
assertNotNull(jpaExecutor);
final String query = TestUtils.getPropertyValue(jpaExecutor, "jpaQuery", String.class);
assertEquals("from Student", query);
final JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class);
assertNotNull(jpaOperations);
final PersistMode persistMode = TestUtils.getPropertyValue(jpaExecutor, "persistMode", PersistMode.class);
assertEquals(PersistMode.PERSIST, persistMode);
@SuppressWarnings("unchecked")
List<JpaParameter> jpaParameters = TestUtils.getPropertyValue(jpaExecutor, "jpaParameters", List.class);
assertNotNull(jpaParameters);
assertTrue(jpaParameters.size() == 3);
}
@Test
public void testJpaMessageHandlerParserWithEntityManagerFactory() throws Exception {
setUp("JpaMessageHandlerParserTestsWithEmFactory.xml", getClass());
final AbstractMessageChannel inputChannel = TestUtils.getPropertyValue(this.consumer, "inputChannel", AbstractMessageChannel.class);
assertEquals("target", inputChannel.getComponentName());
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "handler.jpaExecutor", JpaExecutor.class);
assertNotNull(jpaExecutor);
final String query = TestUtils.getPropertyValue(jpaExecutor, "jpaQuery", String.class);
assertEquals("select student from Student student", query);
final JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class);
assertNotNull(jpaOperations);
final PersistMode persistMode = TestUtils.getPropertyValue(jpaExecutor, "persistMode", PersistMode.class);
assertEquals(PersistMode.PERSIST, persistMode);
@SuppressWarnings("unchecked")
List<JpaParameter> jpaParameters = TestUtils.getPropertyValue(jpaExecutor, "jpaParameters", List.class);
assertNotNull(jpaParameters);
assertTrue(jpaParameters.size() == 3);
}
@SuppressWarnings("unchecked")
@Test
public void testProcedurepParametersAreSet() throws Exception {
setUp("JpaMessageHandlerParserTestsWithEmFactory.xml", getClass());
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "handler.jpaExecutor", JpaExecutor.class);
final List<JpaParameter> jpaParameters = TestUtils.getPropertyValue(jpaExecutor, "jpaParameters", List.class);
assertTrue(jpaParameters.size() == 3);
JpaParameter parameter1 = jpaParameters.get(0);
JpaParameter parameter2 = jpaParameters.get(1);
JpaParameter parameter3 = jpaParameters.get(2);
assertEquals("firstName", parameter1.getName());
assertEquals("firstaName", parameter2.getName());
assertEquals("updatedDateTime", parameter3.getName());
assertEquals("kenny", parameter1.getValue());
assertEquals("cartman", parameter2.getValue());
assertNull(parameter3.getValue());
assertNull(parameter1.getExpression());
assertNull(parameter2.getExpression());
assertEquals("new java.util.Date()", parameter3.getExpression());
}
@Test
public void testTransactionalSettings() throws Exception {
setUp("JpaMessageHandlerTransactionalParserTests.xml", getClass());
final Proxy proxy = TestUtils.getPropertyValue(this.consumer, "handler", Proxy.class);
assertNotNull(proxy);
}
@After
public void tearDown(){
if(context != null){
context.close();
}
}
public void setUp(String name, Class<?> cls){
context = new ClassPathXmlApplicationContext(name, cls);
consumer = this.context.getBean("jpaOutboundChannelAdapter", EventDrivenConsumer.class);
}
}

View File

@@ -0,0 +1,29 @@
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa-2.2.xsd">
<import resource="classpath:/hibernateJpa-context.xml" />
<int:channel id="target"/>
<int-jpa:outbound-channel-adapter id="jpaOutboundChannelAdapter"
entity-manager="entityManager"
auto-startup="true"
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
jpa-query="from Student"
persist-mode="PERSIST"
order="1"
channel="target">
<int-jpa:parameter name="firstName" value="kenny" type="java.lang.String"/>
<int-jpa:parameter name="firstaName" value="cartman"/>
<int-jpa:parameter name="updatedDateTime" expression="new java.util.Date()"/>
</int-jpa:outbound-channel-adapter>
</beans>

View File

@@ -0,0 +1,29 @@
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa-2.2.xsd">
<import resource="classpath:/hibernateJpa-context.xml" />
<int:channel id="target"/>
<int-jpa:outbound-channel-adapter id="jpaOutboundChannelAdapter"
entity-manager-factory="entityManagerFactory"
auto-startup="true"
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
jpa-query="select student from Student student"
persist-mode="PERSIST"
order="1"
channel="target">
<int-jpa:parameter name="firstName" value="kenny" type="java.lang.String"/>
<int-jpa:parameter name="firstaName" value="cartman"/>
<int-jpa:parameter name="updatedDateTime" expression="new java.util.Date()"/>
</int-jpa:outbound-channel-adapter>
</beans>

View File

@@ -0,0 +1,30 @@
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa-2.2.xsd">
<import resource="classpath:/hibernateJpa-context.xml" />
<int:channel id="target"/>
<int-jpa:outbound-channel-adapter id="jpaOutboundChannelAdapter"
entity-manager="entityManager"
auto-startup="true"
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
jpa-query="select student from Student student"
persist-mode="PERSIST"
order="1"
channel="target">
<int-jpa:transactional transaction-manager="transactionManager"/>
<int-jpa:parameter name="firstName" value="kenny" type="java.lang.String"/>
<int-jpa:parameter name="firstaName" value="cartman"/>
<int-jpa:parameter name="updatedDateTime" expression="new java.util.Date()"/>
</int-jpa:outbound-channel-adapter>
</beans>

View File

@@ -0,0 +1,90 @@
/*
* 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.jpa.config.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.jpa.core.JpaOperations;
import org.springframework.integration.jpa.outbound.JpaOutboundGateway;
import org.springframework.integration.jpa.support.OutboundGatewayType;
import org.springframework.integration.jpa.support.PersistMode;
import org.springframework.integration.test.util.TestUtils;
/**
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaOutboundGatewayParserTests {
private ConfigurableApplicationContext context;
private EventDrivenConsumer consumer;
@Test
public void testJpaOutboundGatewayParser() throws Exception {
setUp("JpaOutboundGatewayParserTests.xml", getClass());
final AbstractMessageChannel inputChannel = TestUtils.getPropertyValue(this.consumer, "inputChannel", AbstractMessageChannel.class);
assertEquals("in", inputChannel.getComponentName());
final JpaOutboundGateway jpaOutboundGateway = TestUtils.getPropertyValue(this.consumer, "handler", JpaOutboundGateway.class);
final OutboundGatewayType gatewayType = TestUtils.getPropertyValue(jpaOutboundGateway, "gatewayType", OutboundGatewayType.class);
assertEquals(OutboundGatewayType.RETRIEVING, gatewayType);
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "handler.jpaExecutor", JpaExecutor.class);
assertNotNull(jpaExecutor);
final Class<?> entityClass = TestUtils.getPropertyValue(jpaExecutor, "entityClass", Class.class);
assertEquals("org.springframework.integration.jpa.test.entity.StudentDomain", entityClass.getName());
final JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class);
assertNotNull(jpaOperations);
final PersistMode persistMode = TestUtils.getPropertyValue(jpaExecutor, "persistMode", PersistMode.class);
assertEquals(PersistMode.PERSIST, persistMode);
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "expectSingleResult", Boolean.class));
}
@After
public void tearDown(){
if(context != null){
context.close();
}
}
public void setUp(String name, Class<?> cls){
context = new ClassPathXmlApplicationContext(name, cls);
consumer = this.context.getBean("jpaOutboundGateway", EventDrivenConsumer.class);
}
}

View File

@@ -0,0 +1,28 @@
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa-2.2.xsd">
<import resource="classpath:/hibernateJpa-context.xml" />
<int:channel id="in"/>
<int:channel id="out"/>
<int-jpa:outbound-gateway id="jpaOutboundGateway"
entity-manager-factory="entityManagerFactory"
auto-startup="true"
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
expect-single-result="true"
persist-mode="PERSIST"
gateway-type="RETRIEVING"
order="1"
request-channel="in"
reply-channel="out"/>
</beans>

View File

@@ -0,0 +1,343 @@
/*
* 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.jpa.core;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import org.junit.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.jpa.support.parametersource.ExpressionEvaluatingParameterSourceFactory;
import org.springframework.integration.jpa.support.parametersource.ParameterSource;
import org.springframework.integration.jpa.support.parametersource.ParameterSourceFactory;
import org.springframework.integration.jpa.test.JpaTestUtils;
import org.springframework.integration.jpa.test.entity.Gender;
import org.springframework.integration.jpa.test.entity.StudentDomain;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
/**
* @author Gunnar Hillert
* @since 2.2
*
*/
@Transactional
public class AbstractJpaOperationsTests {
@Autowired
protected PlatformTransactionManager transactionManager;
@Autowired
protected EntityManager entityManager;
/**
* Test method for {@link org.springframework.integration.jpa.core.DefaultJpaOperations#executeUpdate(java.lang.String, org.springframework.integration.jpa.core.JpaQLParameterSource)}.
*/
public void testGetAllStudents() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0);
Assert.assertTrue(students.size() == 3);
}
/**
* Test method for {@link org.springframework.integration.jpa.core.DefaultJpaOperations#executeUpdate(java.lang.String, org.springframework.integration.jpa.core.JpaQLParameterSource)}.
*/
public void testGetAllStudentsWithMaxResults() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 2);
Assert.assertTrue(String.format("Was expecting 2 Students to be returned but got '%s'.", students.size()),
students.size() == 2);
}
/**
* Test method for {@link org.springframework.integration.jpa.core.DefaultJpaOperations#executeUpdate(java.lang.String, org.springframework.integration.jpa.core.JpaQLParameterSource)}.
*/
public void testExecuteUpdate() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final StudentDomain student = JpaTestUtils.getTestStudent();
List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0);
Assert.assertTrue(students.size() == 3);
ParameterSourceFactory requestParameterSourceFactory = new ExpressionEvaluatingParameterSourceFactory();
ParameterSource source = requestParameterSourceFactory.createParameterSource(student);
int updatedRecords = jpaOperations.executeUpdate("update Student s set s.lastName = :lastName, s.lastUpdated = :lastUpdated "
+ "where s.rollNumber in (select max(a.rollNumber) from Student a)", source);
entityManager.flush();
Assert.assertTrue( 1 == updatedRecords);
Assert.assertNull(student.getRollNumber());
}
/**
* Test method for {@link org.springframework.integration.jpa.core.DefaultJpaOperations#executeUpdateWithNamedQuery(java.lang.String, org.springframework.integration.jpa.core.JpaQLParameterSource)}.
*/
public void testExecuteUpdateWithNamedQuery() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final StudentDomain student = JpaTestUtils.getTestStudent();
ParameterSourceFactory requestParameterSourceFactory = new ExpressionEvaluatingParameterSourceFactory();
ParameterSource source = requestParameterSourceFactory.createParameterSource(student);
int updatedRecords = jpaOperations.executeUpdateWithNamedQuery("updateStudent", source);
entityManager.flush();
Assert.assertTrue( 1 == updatedRecords);
Assert.assertNull(student.getRollNumber());
}
/**
* Test method for {@link org.springframework.integration.jpa.core.DefaultJpaOperations#executeUpdateWithNativeQuery(java.lang.String, org.springframework.integration.jpa.core.JpaQLParameterSource)}.
*/
public void testExecuteUpdateWithNativeQuery() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final StudentDomain student = JpaTestUtils.getTestStudent();
ParameterSourceFactory requestParameterSourceFactory = new ExpressionEvaluatingParameterSourceFactory();
ParameterSource source = requestParameterSourceFactory.createParameterSource(student);
int updatedRecords = jpaOperations.executeUpdateWithNativeQuery("update Student set lastName = :lastName, lastUpdated = :lastUpdated "
+ "where rollNumber in (select max(a.rollNumber) from Student a)", source);
entityManager.flush();
Assert.assertTrue( 1 == updatedRecords);
Assert.assertNull(student.getRollNumber());
}
/**
* Test method for {@link DefaultJpaOperations#getResultListForNativeQuery(String, Class, JpaQLParameterSource, int, int)}.
* @throws ParseException
*/
public void testExecuteSelectWithNativeQueryReturningEntityClass() throws ParseException {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
String selectSqlQuery = "select * from Student where lastName = 'Last One'";
Class<?> entityClass = StudentDomain.class;
List<?> students = jpaOperations.getResultListForNativeQuery(selectSqlQuery, entityClass, null, 0);
Assert.assertTrue(students.size() == 1);
StudentDomain retrievedStudent = (StudentDomain) students.iterator().next();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
assertEquals(formatter.parse("1980/01/01"), retrievedStudent.getDateOfBirth());
assertEquals("First One", retrievedStudent.getFirstName());
assertEquals(Gender.MALE, retrievedStudent.getGender());
assertEquals("Last One", retrievedStudent.getLastName());
assertNotNull(retrievedStudent.getLastUpdated());
}
/**
* Test method for {@link DefaultJpaOperations#getResultListForNativeQuery(String, Class, JpaQLParameterSource, int, int)}.
* @throws ParseException
*/
public void testExecuteSelectWithNativeQuery() throws ParseException {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
String selectSqlQuery = "select rollNumber, firstName, lastName, gender, dateOfBirth, lastUpdated from Student where lastName = 'Last One'";
List<?> students = jpaOperations.getResultListForNativeQuery(selectSqlQuery, null, null, 0);
Assert.assertTrue(students.size() == 1);
Object[] retrievedStudent = (Object[]) students.iterator().next();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
assertNotNull(retrievedStudent[0]);
assertEquals("First One", retrievedStudent[1]);
assertEquals("Last One", retrievedStudent[2]);
assertEquals("M", retrievedStudent[3]);
assertEquals(formatter.parse("1980/01/01"), retrievedStudent[4]);
assertNotNull(retrievedStudent[5]);
}
public void testExecuteUpdateWithNativeNamedQuery() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final StudentDomain student = JpaTestUtils.getTestStudent();
ParameterSourceFactory requestParameterSourceFactory = new ExpressionEvaluatingParameterSourceFactory();
ParameterSource source = requestParameterSourceFactory.createParameterSource(student);
int updatedRecords = jpaOperations.executeUpdateWithNamedQuery("updateStudentNativeQuery", source);
entityManager.flush();
Assert.assertTrue( 1 == updatedRecords);
Assert.assertNull(student.getRollNumber());
}
/**
* Test method for {@link org.springframework.integration.jpa.core.DefaultJpaOperations#merge(java.lang.Object)}.
*/
public void testMerge() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final StudentDomain student = JpaTestUtils.getTestStudent();
Assert.assertNull(student.getRollNumber());
final StudentDomain savedStudent = (StudentDomain) jpaOperations.merge(student);
entityManager.flush();
Assert.assertNull(student.getRollNumber());
Assert.assertNotNull(savedStudent);
Assert.assertNotNull(savedStudent.getRollNumber());
Assert.assertTrue(student != savedStudent);
}
/**
* Test method for {@link org.springframework.integration.jpa.core.DefaultJpaOperations#persist(java.lang.Object)}.
*/
public void testPersist() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final StudentDomain student = JpaTestUtils.getTestStudent();
Assert.assertNull(student.getRollNumber());
jpaOperations.persist(student);
entityManager.flush();
Assert.assertNotNull(student.getRollNumber());
}
public void testDeleteInBatch() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0);
Assert.assertNotNull(students);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName("SomeOtherTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
jpaOperations.deleteInBatch(students);
entityManager.flush();
transactionManager.commit(status);
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0);
Assert.assertNotNull(studentsFromDb);
Assert.assertTrue(studentsFromDb.size() == 0);
}
protected JpaOperations getJpaOperations(EntityManager entityManager) {
final DefaultJpaOperations jpaOperationsImpl = new DefaultJpaOperations();
jpaOperationsImpl.setEntityManager(entityManager);
jpaOperationsImpl.afterPropertiesSet();
return jpaOperationsImpl;
}
public void testDelete() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0);
Assert.assertNotNull(studentsFromDb);
Assert.assertTrue(studentsFromDb.size() == 3);
final StudentDomain student = jpaOperations.find(StudentDomain.class, 1001L);
Assert.assertNotNull(student);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName("SomeOtherTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
jpaOperations.delete(student);
entityManager.flush();
transactionManager.commit(status);
final List<?> studentsFromDbAfterDelete = jpaOperations.getResultListForClass(StudentDomain.class, 0);
Assert.assertNotNull(studentsFromDbAfterDelete);
Assert.assertTrue(studentsFromDbAfterDelete.size() == 2);
}
public void testDeleteInBatchWithEmptyCollection() {
final JpaOperations jpaOperations = getJpaOperations(entityManager);
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0);
Assert.assertNotNull(students);
Assert.assertTrue(students.size() == 3);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName("SomeOtherTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
jpaOperations.deleteInBatch(new ArrayList<StudentDomain>(0));
entityManager.flush();
transactionManager.commit(status);
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0);
Assert.assertNotNull(studentsFromDb);
Assert.assertTrue(studentsFromDb.size() == 3); //Nothing should have happened
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="classpath:/commonJpa-context.xml" />
<bean id="vendorAdaptor" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"
parent="abstractVendorAdaptor">
<property name="database" value="H2" />
</bean>
</beans>

View File

@@ -0,0 +1,138 @@
/*
* 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.jpa.core;
import java.text.ParseException;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Tests the functionality of {@link JpaOperations} and {@link DefaultJpaOperations}
* using the EclipseLink persistence provider.
*
* If you want to run these tests from your IDE, please ensure that you execute
* the tests using a <i>javaagent</i>:
*
* <pre>
* {@code
* -javaagent:/home/<user>/.m2/repository/org/springframework/spring-instrument/3.1.1.RELEASE/spring-instrument-3.1.1.RELEASE.jar
* }
* </pre>
*
* @author Gunnar Hillert
* @since 2.2
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class EclipseLinkJpaOperationsTests extends AbstractJpaOperationsTests {
@Test
@Override
public void testExecuteUpdateWithNativeQuery() {
try {
super.testExecuteUpdateWithNativeQuery();
} catch (Exception e) {
return;
}
Assert.fail("Was expecting an Exception as OpenJPA does not support Native SQL Queries with Named Parameters.");
}
@Test
@Override
public void testExecuteUpdateWithNativeNamedQuery() {
try {
super.testExecuteUpdateWithNativeNamedQuery();
} catch (Exception e) {
return;
}
Assert.fail("Was expecting an Exception as OpenJPA does not support Native SQL Queries with Named Parameters.");
}
@Test
@Override
public void testExecuteUpdate() {
super.testExecuteUpdate();
}
@Test
@Override
public void testExecuteUpdateWithNamedQuery() {
super.testExecuteUpdateWithNamedQuery();
}
@Test
@Override
public void testExecuteSelectWithNativeQueryReturningEntityClass()
throws ParseException {
super.testExecuteSelectWithNativeQueryReturningEntityClass();
}
@Test
@Override
public void testExecuteSelectWithNativeQuery() throws ParseException {
super.testExecuteSelectWithNativeQuery();
}
@Test
@Override
public void testMerge() {
super.testMerge();
}
@Test
@Override
public void testPersist() {
super.testPersist();
}
@Test
@Override
public void testGetAllStudents() {
super.testGetAllStudents();
}
@Test
@Override
public void testGetAllStudentsWithMaxResults() {
super.testGetAllStudentsWithMaxResults();
}
@Test
@Override
public void testDeleteInBatch() {
super.testDeleteInBatch();
}
@Test
@Override
public void testDelete() {
super.testDelete();
}
@Test
@Override
public void testDeleteInBatchWithEmptyCollection() {
super.testDeleteInBatchWithEmptyCollection();
}
}

View File

@@ -0,0 +1,10 @@
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<import resource="classpath:/hibernateJpa-context.xml" />
</beans>

View File

@@ -0,0 +1,157 @@
/*
* 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.jpa.core;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.Map;
import javax.sql.DataSource;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Configuration;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Gunnar Hillert
* @since 2.2
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class HibernateJpaOperationsTests extends AbstractJpaOperationsTests {
@Autowired
private DataSource dataSource;
@Autowired
private LocalContainerEntityManagerFactoryBean fb;
/**
* Little helper that allows you to generate the DDL via Hibernate. The
* DDL is printed to the console.
*/
@Test
public void generateDdl() {
final Ejb3Configuration cfg = new Ejb3Configuration();
Map properties = fb.getJpaPropertyMap();
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
final Ejb3Configuration configured = cfg.configure( fb.getPersistenceUnitInfo(), fb.getJpaPropertyMap() );
final Configuration configuration = configured.getHibernateConfiguration();
final SchemaExport schemaExport;
try {
schemaExport = new SchemaExport(configuration, dataSource.getConnection());
} catch (HibernateException e) {
throw new IllegalStateException(e);
} catch (SQLException e) {
throw new IllegalStateException(e);
}
schemaExport.create(true, false);
}
@Test
@Override
public void testExecuteUpdate() {
super.testExecuteUpdate();
}
@Test
@Override
public void testGetAllStudents() {
super.testGetAllStudents();
}
@Test
@Override
public void testGetAllStudentsWithMaxResults() {
super.testGetAllStudentsWithMaxResults();
}
@Test
@Override
public void testExecuteUpdateWithNamedQuery() {
super.testExecuteUpdateWithNamedQuery();
}
@Test
@Override
public void testExecuteUpdateWithNativeQuery() {
super.testExecuteUpdateWithNativeQuery();
}
@Test
@Override
public void testExecuteSelectWithNativeQueryReturningEntityClass()
throws ParseException {
super.testExecuteSelectWithNativeQueryReturningEntityClass();
}
@Test
@Override
public void testExecuteSelectWithNativeQuery() throws ParseException {
super.testExecuteSelectWithNativeQuery();
}
@Test
@Override
public void testExecuteUpdateWithNativeNamedQuery() {
super.testExecuteUpdateWithNativeNamedQuery();
}
@Test
@Override
public void testMerge() {
super.testMerge();
}
@Test
@Override
public void testPersist() {
super.testPersist();
}
@Test
@Override
public void testDeleteInBatch() {
super.testDeleteInBatch();
}
@Test
@Override
public void testDelete() {
super.testDelete();
}
@Test
@Override
public void testDeleteInBatchWithEmptyCollection() {
super.testDeleteInBatchWithEmptyCollection();
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.jpa.core;
import static org.mockito.Mockito.mock;
import javax.persistence.EntityManager;
import junit.framework.Assert;
import org.junit.Test;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaExecutorTests {
/**
* In this test, the {@link JpaExecutor}'s poll method will be called without
* specifying a 'query', 'namedQuery' or 'entityClass' property. This should
* result in an {@link IllegalArgumentException}.
*
* @throws Exception
*/
@Test
public void testExecutePollWithNoEntityClassSpecified() throws Exception {
final JpaExecutor jpaExecutor = new JpaExecutor(mock(EntityManager.class));
try {
jpaExecutor.poll();
} catch (IllegalStateException e) {
Assert.assertEquals("Exception Message does not match.",
"For the polling operation, one of "
+ "the following properties must be specified: "
+ "query, namedQuery or entityClass.", e.getMessage());
return;
}
Assert.fail("Was expecting an IllegalStateException to be thrown.");
}
/**
*/
@Test
public void testInstatiateJpaExecutorWithNullJpaOperations() {
JpaOperations jpaOperations = null;
try {
new JpaExecutor(jpaOperations);
} catch (IllegalArgumentException e) {
Assert.assertEquals("jpaOperations must not be null.", e.getMessage());
}
}
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="classpath:/commonJpa-context.xml" />
<!-- EclipseLink vendor adaptor with workaround platform class for HSQL usage -->
<bean id="vendorAdaptor" class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"
parent="abstractVendorAdaptor">
<property name="database" value="H2" />
</bean>
</beans>

View File

@@ -0,0 +1,182 @@
/*
* 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.jpa.core;
import java.io.IOException;
import java.sql.SQLException;
import java.text.ParseException;
import junit.framework.Assert;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
import org.apache.openjpa.jdbc.meta.MappingTool;
import org.apache.openjpa.lib.conf.Configurations;
import org.apache.openjpa.lib.util.Options;
import org.apache.openjpa.persistence.InvalidStateException;
import org.apache.openjpa.persistence.PersistenceException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Tests the functionality of {@link JpaOperations} and {@link DefaultJpaOperations}
* using the OpenJPA persistence provider.
*
* If you want to run these tests from your IDE, please ensure that you execute
* the tests using a <i>javaagent</i>:
*
* <pre>
* {@code
* -javaagent:/<path_to>/openjpa-2.1.1.jar
* }
* </pre>
*
* @author Gunnar Hillert
* @since 2.2
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class OpenJpaJpaOperationsTests extends AbstractJpaOperationsTests {
@Test
@Override
public void testExecuteUpdateWithNativeQuery() {
try {
super.testExecuteUpdateWithNativeQuery();
} catch (PersistenceException e) {
return;
}
Assert.fail("Was expecting an Exception as OpenJPA does not support Native SQL Queries with Named Parameters.");
}
@Test
@Override
public void testExecuteUpdateWithNativeNamedQuery() {
try {
super.testExecuteUpdateWithNativeNamedQuery();
} catch (InvalidStateException e) {
return;
}
Assert.fail("Was expecting an Exception as OpenJPA does not support Native SQL Queries with Named Parameters.");
}
/**
* Test method for {@link org.springframework.integration.jpa.core.DefaultJpaOperations#persist(java.lang.Object)}.
*
* http://openjpa.apache.org/builds/1.0.4/apache-openjpa-1.0.4/docs/manual/manual.html#ref_guide_ddl_examples
*/
//@Test
public void testGenerateSchema() {
String[] arguments = {};
Options opts = new Options();
opts.put("schemaAction", "build");
opts.put("sql", "build/database/openjpa-h2.sql");
opts.put("org.springframework.integration.jpa.test.entity.Student", "true");
final String[] args = opts.setFromCmdLine(arguments);
boolean ret = Configurations.runAgainstAllAnchors(opts,
new Configurations.Runnable() {
public boolean run(Options opts) throws IOException, SQLException {
JDBCConfiguration conf = new JDBCConfigurationImpl();
conf.setConnectionDriverName("org.h2.Driver");
conf.setConnectionURL("jdbc:h2:~/test");
conf.setConnectionUserName("sa");
conf.setConnectionPassword("");
try {
return MappingTool.run(conf, args, opts);
} finally {
conf.close();
}
}
});
}
@Test
@Override
public void testExecuteUpdate() {
super.testExecuteUpdate();
}
@Test
@Override
public void testExecuteUpdateWithNamedQuery() {
super.testExecuteUpdateWithNamedQuery();
}
@Test
@Override
public void testExecuteSelectWithNativeQueryReturningEntityClass()
throws ParseException {
super.testExecuteSelectWithNativeQueryReturningEntityClass();
}
@Test
@Override
public void testExecuteSelectWithNativeQuery() throws ParseException {
super.testExecuteSelectWithNativeQuery();
}
@Test
@Override
public void testMerge() {
super.testMerge();
}
@Test
@Override
public void testPersist() {
super.testPersist();
}
@Test
@Override
public void testGetAllStudents() {
super.testGetAllStudents();
}
@Test
@Override
public void testGetAllStudentsWithMaxResults() {
super.testGetAllStudentsWithMaxResults();
}
@Test
@Override
public void testDeleteInBatch() {
super.testDeleteInBatch();
}
@Test
@Override
public void testDelete() {
super.testDelete();
}
@Test
@Override
public void testDeleteInBatchWithEmptyCollection() {
super.testDeleteInBatchWithEmptyCollection();
}
}

View File

@@ -0,0 +1,60 @@
<?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:task="http://www.springframework.org/schema/task"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.2.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<jdbc:embedded-database id="dataSource" type="H2"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS" >
<jdbc:script location="classpath:H2-DropTables.sql" />
<jdbc:script location="classpath:H2-CreateTables.sql" />
<jdbc:script location="classpath:H2-PopulateData.sql" />
</jdbc:initialize-database>
<bean id="lc"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
<property name="showSql" value="true"/>
</bean>
</property>
</bean>
<bean id="em"
class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="lc" />
</bean>
<!-- Define the JPA transaction mgr -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<constructor-arg ref="lc" />
</bean>
<!-- -->
<int:service-activator id="consumerEndpoint" input-channel="outputChannel" ref="consumer" method="receive" />
<bean id="consumer" class="org.springframework.integration.jpa.test.Consumer" />
<bean id="testtrigger" class="org.springframework.integration.jpa.test.TestTrigger" />
<int:poller id="defaultPoller" default="true" fixed-rate="10000" />
<int:poller id="jpaPoller" trigger="testtrigger">
<int:transactional transaction-manager="transactionManager"/>
</int:poller>
</beans>

View File

@@ -0,0 +1,21 @@
<?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:task="http://www.springframework.org/schema/task"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:util="http://www.springframework.org/schema/util"
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-2.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<import resource="BaseJpaPollingChannelAdapterTests-context.xml"/>
<bean id="jpaOperations" class="org.springframework.integration.jpa.core.DefaultJpaOperations">
<property name="entityManager" ref="em"/>
</bean>
</beans>

View File

@@ -0,0 +1,477 @@
/*
* 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.jpa.inbound;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.jpa.core.JpaOperations;
import org.springframework.integration.jpa.test.Consumer;
import org.springframework.integration.jpa.test.JpaTestUtils;
import org.springframework.integration.jpa.test.TestTrigger;
import org.springframework.integration.jpa.test.entity.StudentDomain;
import org.springframework.integration.scheduling.PollerMetadata;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration tests for the Jpa Polling Channel Adapter {@link JpaPollingChannelAdapter}.
*
* @author Gunnar Hillert
* @since 2.2
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
public class JpaPollingChannelAdapterTests {
@Autowired
private GenericApplicationContext context;
@Autowired
EntityManager entityManager;
@Autowired
JpaOperations jpaOperations;
@Autowired
@Qualifier("jpaPoller")
PollerMetadata poller;
@Autowired
@Qualifier("outputChannel")
private MessageChannel outputChannel;
@Autowired
TestTrigger testTrigger;
/**
* In this test, a Jpa Polling Channel Adapter will use a plain entity class
* to retrieve a list of records from the database.
*
* @throws Exception
*/
@Test
@DirtiesContext
public void testWithEntityClass() throws Exception {
testTrigger.reset();
//~~~~SETUP~~~~~
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setEntityClass(StudentDomain.class);
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader());
adapter.start();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<Message<Collection<?>>> received = new ArrayList<Message<Collection<?>>>();
final Consumer consumer = new Consumer();
received.add(consumer.poll(5000));
Message<Collection<?>> message = received.get(0);
adapter.stop();
assertNotNull(message);
assertNotNull(message.getPayload());
assertNotNull(message.getPayload() instanceof Collection<?>);
Collection<?> primeNumbers = message.getPayload();
assertTrue(primeNumbers.size() == 3);
}
/**
* In this test, a Jpa Polling Channel Adapter will use JpQL query
* to retrieve a list of records from the database.
*
* @throws Exception
*/
@Test
public void testWithJpaQuery() throws Exception {
testTrigger.reset();
//~~~~SETUP~~~~~
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setJpaQuery("from Student");
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader());
adapter.start();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<Message<Collection<?>>> received = new ArrayList<Message<Collection<?>>>();
final Consumer consumer = new Consumer();
received.add(consumer.poll(5000));
Message<Collection<?>> message = received.get(0);
adapter.stop();
assertNotNull(message);
assertNotNull(message.getPayload());
assertNotNull(message.getPayload() instanceof Collection<?>);
Collection<?> primeNumbers = message.getPayload();
assertTrue(primeNumbers.size() == 3);
}
/**
* In this test, a Jpa Polling Channel Adapter will use JpQL query
* to retrieve a list of records from the database with a maxRows value of 1.
*
* @throws Exception
*/
@Test
public void testWithJpaQueryAndMaxResults() throws Exception {
testTrigger.reset();
//~~~~SETUP~~~~~
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setJpaQuery("from Student");
jpaExecutor.setMaxRows(1);
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader());
adapter.start();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<Message<Collection<?>>> received = new ArrayList<Message<Collection<?>>>();
final Consumer consumer = new Consumer();
received.add(consumer.poll(5000));
Message<Collection<?>> message = received.get(0);
adapter.stop();
assertNotNull(message);
assertNotNull(message.getPayload());
assertNotNull(message.getPayload() instanceof Collection<?>);
Collection<?> primeNumbers = message.getPayload();
assertTrue(primeNumbers.size() == 1);
}
/**
* In this test, a Jpa Polling Channel Adapter will use JpQL query
* to retrieve a list of records from the database.
*
* @throws Exception
*/
@Test
public void testWithJpaQueryOneResultOnly() throws Exception {
testTrigger.reset();
//~~~~SETUP~~~~~
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setJpaQuery("from Student s where s.firstName = 'First Two'");
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader());
adapter.start();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<Message<Collection<?>>> received = new ArrayList<Message<Collection<?>>>();
final Consumer consumer = new Consumer();
received.add(consumer.poll(5000));
Message<Collection<?>> message = received.get(0);
adapter.stop();
assertNotNull(message);
assertNotNull(message.getPayload());
assertNotNull(message.getPayload() instanceof Collection<?>);
Collection<?> students = message.getPayload();
assertTrue(students.size() == 1);
StudentDomain student = (StudentDomain) students.iterator().next();
assertEquals("Last Two", student.getLastName());
}
/**
* In this test, a Jpa Polling Channel Adapter will use JpQL query
* to retrieve a list of records from the database. Additionaly, the records
* will be deleted after the polling.
*
* @throws Exception
*/
@Test
@DirtiesContext
@Transactional
public void testWithJpaQueryAndDelete() throws Exception {
testTrigger.reset();
//~~~~SETUP~~~~~
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setJpaQuery("from Student s");
jpaExecutor.setDeleteAfterPoll(true);
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader());
adapter.start();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<Message<Collection<?>>> received = new ArrayList<Message<Collection<?>>>();
final Consumer consumer = new Consumer();
received.add(consumer.poll(5000));
Message<Collection<?>> message = received.get(0);
adapter.stop();
assertNotNull("Message is null.", message);
assertNotNull(message.getPayload());
assertNotNull(message.getPayload() instanceof Collection<?>);
Collection<?> students = message.getPayload();
assertTrue(students.size() == 3);
Long studentCount = entityManager.createQuery("select count(*) from Student", Long.class).getSingleResult();
assertEquals(Long.valueOf(0), studentCount);
}
@Test
@DirtiesContext
@Transactional
public void testWithJpaQueryButNoResultsAndDelete() throws Exception {
testTrigger.reset();
//~~~~SETUP~~~~~
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setJpaQuery("from Student s where s.lastName = 'Something Else'");
jpaExecutor.setDeleteAfterPoll(true);
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader());
adapter.start();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<Message<Collection<?>>> received = new ArrayList<Message<Collection<?>>>();
final Consumer consumer = new Consumer();
received.add(consumer.poll(5000));
Message<Collection<?>> message = received.get(0);
adapter.stop();
assertNull(message);
}
/**
* In this test, a Jpa Polling Channel Adapter will use JpQL query
* to retrieve a list of records from the database. Additionaly, the records
* will be deleted after the polling.
*
* @throws Exception
*/
@Test
@DirtiesContext
public void testWithJpaQueryAndDeletePerRow() throws Exception {
testTrigger.reset();
//~~~~SETUP~~~~~
final JpaExecutor jpaExecutor = new JpaExecutor(jpaOperations);
jpaExecutor.setJpaQuery("from Student s");
jpaExecutor.setDeleteAfterPoll(true);
jpaExecutor.setDeletePerRow(true);
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader());
adapter.start();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<Message<Collection<?>>> received = new ArrayList<Message<Collection<?>>>();
final Consumer consumer = new Consumer();
received.add(consumer.poll(5000));
Message<Collection<?>> message = received.get(0);
//adapter.stop();
assertNotNull("Message is null.", message);
assertNotNull(message.getPayload());
assertNotNull(message.getPayload() instanceof Collection<?>);
Collection<?> students = message.getPayload();
assertTrue(students.size() == 3);
Long studentCount = entityManager.createQuery("select count(*) from Student", Long.class).getSingleResult();
assertEquals(Long.valueOf(0), studentCount);
}
/**
* In this test, a Jpa Polling Channel Adapter will use a Native SQL query
* to retrieve a list of records from the database.
*
* @throws Exception
*/
@Test
public void testWithNativeSqlQuery() throws Exception {
testTrigger.reset();
//~~~~SETUP~~~~~
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setNativeQuery("select * from Student where lastName = 'Last One'");
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader());
adapter.start();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<Message<Collection<?>>> received = new ArrayList<Message<Collection<?>>>();
final Consumer consumer = new Consumer();
received.add(consumer.poll(5000));
Message<Collection<?>> message = received.get(0);
adapter.stop();
assertNotNull(message);
assertNotNull(message.getPayload());
assertNotNull(message.getPayload() instanceof Collection<?>);
Collection<?> students = message.getPayload();
assertTrue(students.size() == 1);
}
/**
* In this test, a Jpa Polling Channel Adapter will use Named query
* to retrieve a list of records from the database.
*
* @throws Exception
*/
@Test
public void testWithNamedQuery() throws Exception {
testTrigger.reset();
//~~~~SETUP~~~~~
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setNamedQuery("selectStudent");
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader());
adapter.start();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<Message<Collection<?>>> received = new ArrayList<Message<Collection<?>>>();
final Consumer consumer = new Consumer();
received.add(consumer.poll(5000));
Message<Collection<?>> message = received.get(0);
adapter.stop();
assertNotNull(message);
assertNotNull(message.getPayload());
assertNotNull(message.getPayload() instanceof Collection<?>);
Collection<?> students = message.getPayload();
assertTrue(students.size() == 1);
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.jpa.inbound;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.springframework.integration.jpa.core.JpaExecutor;
/**
* @author Gunnar Hillert
* @since 2.2
*
*/
public class JpaPollingChannelAdapterUnitTests {
/**
*
*/
@Test
public void testReceiveNull() {
JpaExecutor jpaExecutor = mock(JpaExecutor.class);
when(jpaExecutor.poll()).thenReturn(null);
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
assertNull(jpaPollingChannelAdapter.receive());
}
/**
*
*/
@Test
public void testReceiveNotNull() {
JpaExecutor jpaExecutor = mock(JpaExecutor.class);
when(jpaExecutor.poll()).thenReturn("Spring");
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
assertNotNull("Expecting a Message to be returned.", jpaPollingChannelAdapter.receive());
assertEquals("Spring", jpaPollingChannelAdapter.receive().getPayload());
}
/**
*
*/
@Test
public void testGetComponentType() {
JpaExecutor jpaExecutor = mock(JpaExecutor.class);
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
assertEquals("jpa:inbound-channel-adapter", jpaPollingChannelAdapter.getComponentType());
}
}

View File

@@ -0,0 +1,17 @@
<?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:task="http://www.springframework.org/schema/task"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:util="http://www.springframework.org/schema/util"
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-2.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<import resource="classpath:/hibernateJpa-context.xml" />
</beans>

View File

@@ -0,0 +1,18 @@
<?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:jpa="http://www.springframework.org/schema/integration/jpa"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa-2.1.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<import resource="BaseJpaPollingChannelAdapterTests-context.xml"/>
</beans>

View File

@@ -0,0 +1,168 @@
/*
* 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.jpa.outbound;
import java.util.List;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.Message;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.jpa.support.PersistMode;
import org.springframework.integration.jpa.test.JpaTestUtils;
import org.springframework.integration.jpa.test.entity.StudentDomain;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
public class JpaOutboundChannelAdapterTests {
@Autowired
private EntityManager entityManager;
@Autowired
DataSource dataSource;
@Autowired
private PlatformTransactionManager transactionManager;
@Test
@DirtiesContext
public void saveEntityWithMerge() throws InterruptedException {
List<?> results1 = new JdbcTemplate(dataSource).queryForList("Select * from Student");
Assert.assertNotNull(results1);
Assert.assertTrue(results1.size() == 3);
JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setEntityClass(StudentDomain.class);
jpaExecutor.afterPropertiesSet();
JpaOutboundGateway jpaOutboundChannelAdapter = new JpaOutboundGateway(jpaExecutor);
jpaOutboundChannelAdapter.setProducesReply(false);
StudentDomain testStudent = JpaTestUtils.getTestStudent();
Message<StudentDomain> message = MessageBuilder.withPayload(testStudent).build();
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
jpaOutboundChannelAdapter.handleMessage(message);
transactionManager.commit(status);
List<?> results2 = new JdbcTemplate(dataSource).queryForList("Select * from Student");
Assert.assertNotNull(results2);
Assert.assertTrue(results2.size() == 4);
Assert.assertNull(testStudent.getRollNumber());
}
@Test
@DirtiesContext
public void saveEntityWithMergeWithoutSpecifyingEntityClass() throws InterruptedException {
List<?> results1 = new JdbcTemplate(dataSource).queryForList("Select * from Student");
Assert.assertNotNull(results1);
Assert.assertTrue(results1.size() == 3);
JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.afterPropertiesSet();
JpaOutboundGateway jpaOutboundChannelAdapter = new JpaOutboundGateway(jpaExecutor);
jpaOutboundChannelAdapter.setProducesReply(false);
StudentDomain testStudent = JpaTestUtils.getTestStudent();
Message<StudentDomain> message = MessageBuilder.withPayload(testStudent).build();
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
jpaOutboundChannelAdapter.handleMessage(message);
transactionManager.commit(status);
List<?> results2 = new JdbcTemplate(dataSource).queryForList("Select * from Student");
Assert.assertNotNull(results2);
Assert.assertTrue(results2.size() == 4);
Assert.assertNull(testStudent.getRollNumber());
}
@Test
public void saveEntityWithPersist() throws InterruptedException {
List<?> results1 = new JdbcTemplate(dataSource).queryForList("Select * from Student");
Assert.assertNotNull(results1);
Assert.assertTrue(results1.size() == 3);
JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
jpaExecutor.setEntityClass(StudentDomain.class);
jpaExecutor.setPersistMode(PersistMode.PERSIST);
jpaExecutor.afterPropertiesSet();
JpaOutboundGateway jpaOutboundChannelAdapter = new JpaOutboundGateway(jpaExecutor);
jpaOutboundChannelAdapter.setProducesReply(false);
StudentDomain testStudent = JpaTestUtils.getTestStudent();
Assert.assertNull(testStudent.getRollNumber());
Message<StudentDomain> message = MessageBuilder.withPayload(testStudent).build();
jpaOutboundChannelAdapter.afterPropertiesSet();
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
jpaOutboundChannelAdapter.handleMessage(message);
transactionManager.commit(status);
List<?> results2 = new JdbcTemplate(dataSource).queryForList("Select * from Student");
Assert.assertNotNull(results2);
Assert.assertTrue(results2.size() == 4);
Assert.assertNotNull(testStudent.getRollNumber());
}
}

View File

@@ -0,0 +1,23 @@
<?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-jpa="http://www.springframework.org/schema/integration/jpa"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd">
<import resource="BaseJpaPollingChannelAdapterTests-context.xml"/>
<int:channel id="input"/>
<int-jpa:outbound-channel-adapter id="jpaAdapter" channel="input" entity-manager-factory="entityManagerFactory">
<int-jpa:transactional transaction-manager="transactionManager"/>
</int-jpa:outbound-channel-adapter>
</beans>

View File

@@ -0,0 +1,73 @@
/*
* 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.jpa.outbound;
import java.util.List;
import javax.sql.DataSource;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.jpa.test.JpaTestUtils;
import org.springframework.integration.jpa.test.entity.StudentDomain;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class JpaOutboundChannelAdapterTransactionalTests {
@Autowired
@Qualifier("input")
private MessageChannel channel;
@Autowired
DataSource dataSource;
@Test
@DirtiesContext
public void saveEntityWithTransaction() throws InterruptedException {
List<?> results1 = new JdbcTemplate(dataSource).queryForList("Select * from Student");
Assert.assertNotNull(results1);
Assert.assertTrue(results1.size() == 3);
StudentDomain testStudent = JpaTestUtils.getTestStudent();
Message<StudentDomain> message = MessageBuilder.withPayload(testStudent).build();
channel.send(message);
List<?> results2 = new JdbcTemplate(dataSource).queryForList("Select * from Student");
Assert.assertNotNull(results2);
Assert.assertTrue(results2.size() == 4);
Assert.assertNull(testStudent.getRollNumber());
}
}

View File

@@ -0,0 +1,195 @@
<?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:jpa="http://www.springframework.org/schema/integration/jpa"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.2.xsd
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa-2.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<import resource="BaseJpaPollingChannelAdapterTests-context.xml"/>
<int:poller default="true" fixed-rate="2000"/>
<int:gateway default-reply-channel="studentReplyChannel"
service-interface="org.springframework.integration.jpa.outbound.StudentService" default-reply-timeout="3000">
<int:method name="deleteStudent" request-channel="deleteStudentChannel" />
<int:method name="getStudent" request-channel="getStudentChannel" />
<int:method name="getStudentWithException" request-channel="getStudentEndpointWithExceptionChannel"/>
<int:method name="getStudentWithParameters" request-channel="getStudentWithParametersChannel"/>
<int:method name="getAllStudents" request-channel="getAllStudentsChannel" />
<int:method name="persistStudent" request-channel="persistStudentChannel" />
<int:method name="persistStudentUsingMerge" request-channel="persistStudentUsingMergeChannel" />
</int:gateway>
<int:channel id="deleteStudentChannel"/>
<int:channel id="getStudentChannel"/>
<int:channel id="getStudentWithParametersChannel"/>
<int:channel id="getAllStudentsChannel"/>
<int:channel id="persistStudentChannel"/>
<int:channel id="persistStudentUsingMergeChannel"/>
<int:channel id="studentReplyChannel"/>
<int:channel id="getStudentEndpointWithExceptionChannel"/>
<bean id="deleteStudentEndpoint"
class="org.springframework.integration.endpoint.EventDrivenConsumer">
<constructor-arg name="inputChannel" ref="deleteStudentChannel"/>
<constructor-arg name="handler">
<bean class="org.springframework.integration.jpa.outbound.JpaOutboundGateway">
<constructor-arg name="jpaExecutor">
<bean class="org.springframework.integration.jpa.core.JpaExecutor">
<constructor-arg name="entityManager" ref="entityManager"/>
<property name="entityClass" value="org.springframework.integration.jpa.test.entity.StudentDomain"/>
<property name="persistMode" value="DELETE"/>
</bean>
</constructor-arg>
<property name="gatewayType" value="UPDATING"/>
<property name="outputChannel" ref="studentReplyChannel"/>
</bean>
</constructor-arg>
</bean>
<bean id="getStudentEndpoint"
class="org.springframework.integration.endpoint.EventDrivenConsumer">
<constructor-arg name="inputChannel" ref="getStudentChannel"/>
<constructor-arg name="handler">
<bean class="org.springframework.integration.jpa.outbound.JpaOutboundGateway">
<constructor-arg name="jpaExecutor">
<bean class="org.springframework.integration.jpa.core.JpaExecutor">
<constructor-arg name="entityManager" ref="entityManager"/>
<property name="entityClass" value="org.springframework.integration.jpa.test.entity.StudentDomain"/>
<property name="jpaQuery" value="from Student s where s.id = :id"/>
<property name="expectSingleResult" value="true"/>
<property name="jpaParameters" >
<util:list>
<bean class="org.springframework.integration.jpa.support.JpaParameter">
<property name="name" value="id"/>
<property name="expression" value="payload"/>
</bean>
</util:list>
</property>
</bean>
</constructor-arg>
<property name="gatewayType" value="RETRIEVING"/>
<property name="outputChannel" ref="studentReplyChannel"/>
</bean>
</constructor-arg>
</bean>
<bean id="getStudentEndpointWithException"
class="org.springframework.integration.endpoint.EventDrivenConsumer">
<constructor-arg name="inputChannel" ref="getStudentEndpointWithExceptionChannel"/>
<constructor-arg name="handler">
<bean class="org.springframework.integration.jpa.outbound.JpaOutboundGateway">
<constructor-arg name="jpaExecutor">
<bean class="org.springframework.integration.jpa.core.JpaExecutor">
<constructor-arg name="entityManager" ref="entityManager"/>
<property name="entityClass" value="org.springframework.integration.jpa.test.entity.StudentDomain"/>
<property name="jpaQuery" value="from Student s"/>
<property name="expectSingleResult" value="true"/>
<property name="jpaParameters" >
<util:list>
<bean class="org.springframework.integration.jpa.support.JpaParameter">
<property name="name" value="id"/>
<property name="expression" value="payload"/>
</bean>
</util:list>
</property>
</bean>
</constructor-arg>
<property name="gatewayType" value="RETRIEVING"/>
<property name="outputChannel" ref="studentReplyChannel"/>
</bean>
</constructor-arg>
</bean>
<bean id="getAllStudentsEndpoint"
class="org.springframework.integration.endpoint.EventDrivenConsumer">
<constructor-arg name="inputChannel" ref="getAllStudentsChannel"/>
<constructor-arg name="handler">
<bean class="org.springframework.integration.jpa.outbound.JpaOutboundGateway">
<constructor-arg name="jpaExecutor">
<bean class="org.springframework.integration.jpa.core.JpaExecutor">
<constructor-arg name="entityManager" ref="entityManager"/>
<property name="entityClass" value="org.springframework.integration.jpa.test.entity.StudentDomain"/>
</bean>
</constructor-arg>
<property name="gatewayType" value="RETRIEVING"/>
<property name="outputChannel" ref="studentReplyChannel"/>
</bean>
</constructor-arg>
</bean>
<bean id="persitStudentEndpoint"
class="org.springframework.integration.endpoint.EventDrivenConsumer">
<constructor-arg name="inputChannel" ref="persistStudentChannel"/>
<constructor-arg name="handler">
<bean class="org.springframework.integration.jpa.outbound.JpaOutboundGateway">
<constructor-arg name="jpaExecutor">
<bean class="org.springframework.integration.jpa.core.JpaExecutor">
<constructor-arg name="entityManager" ref="entityManager"/>
<property name="entityClass" value="org.springframework.integration.jpa.test.entity.StudentDomain"/>
</bean>
</constructor-arg>
<property name="gatewayType" value="UPDATING"/>
<property name="outputChannel" ref="studentReplyChannel"/>
</bean>
</constructor-arg>
</bean>
<bean id="persitStudentUsingMergeEndpoint"
class="org.springframework.integration.endpoint.EventDrivenConsumer">
<constructor-arg name="inputChannel" ref="persistStudentUsingMergeChannel"/>
<constructor-arg name="handler">
<bean class="org.springframework.integration.jpa.outbound.JpaOutboundGateway">
<constructor-arg name="jpaExecutor">
<bean class="org.springframework.integration.jpa.core.JpaExecutor">
<constructor-arg name="entityManager" ref="entityManager"/>
<property name="entityClass" value="org.springframework.integration.jpa.test.entity.StudentDomain"/>
<property name="persistMode" value="MERGE"/>
</bean>
</constructor-arg>
<property name="gatewayType" value="UPDATING"/>
<property name="outputChannel" ref="studentReplyChannel"/>
</bean>
</constructor-arg>
</bean>
<bean id="getStudentWithParametersEndpoint"
class="org.springframework.integration.endpoint.EventDrivenConsumer">
<constructor-arg name="inputChannel" ref="getStudentWithParametersChannel"/>
<constructor-arg name="handler">
<bean class="org.springframework.integration.jpa.outbound.JpaOutboundGateway">
<constructor-arg name="jpaExecutor">
<bean class="org.springframework.integration.jpa.core.JpaExecutor">
<constructor-arg name="entityManager" ref="entityManager"/>
<property name="entityClass" value="org.springframework.integration.jpa.test.entity.StudentDomain"/>
<property name="jpaQuery" value="from Student s where s.firstName = ? and s.lastName=?"/>
<property name="expectSingleResult" value="true"/>
<property name="jpaParameters" >
<util:list>
<bean class="org.springframework.integration.jpa.support.JpaParameter">
<property name="expression" value="payload"/>
</bean>
<bean class="org.springframework.integration.jpa.support.JpaParameter">
<property name="value" value="Last Two"/>
</bean>
</util:list>
</property>
</bean>
</constructor-arg>
<property name="gatewayType" value="RETRIEVING"/>
<property name="outputChannel" ref="studentReplyChannel"/>
</bean>
</constructor-arg>
</bean>
</beans>

View File

@@ -0,0 +1,132 @@
/*
* 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.jpa.outbound;
import java.util.List;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.jpa.test.JpaTestUtils;
import org.springframework.integration.jpa.test.entity.StudentDomain;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
public class JpaOutboundGatewayTests {
@Autowired
private StudentService studentService;
@Test
@DirtiesContext
public void getStudent() {
final StudentDomain student = studentService.getStudent(1001L);
Assert.assertNotNull(student);
}
@Test
@DirtiesContext
@Transactional
public void deleteNonExistingStudent() {
StudentDomain student = JpaTestUtils.getTestStudent();
student.setRollNumber(3424234234L);
try {
studentService.deleteStudent(student);
} catch (IllegalArgumentException e) {
return;
}
Assert.fail("Was expecting a MessageHandlingException to be thrown.");
}
@Test
@DirtiesContext
public void getStudentWithException() {
try {
studentService.getStudentWithException(1001L);
} catch (MessageHandlingException e) {
Assert.assertEquals("The Jpa operation returned more than 1 result object but expectSingleResult was 'true'.",
e.getMessage());
return;
}
Assert.fail("Was expecting a MessageHandlingException to be thrown.");
}
@Test
@DirtiesContext
public void getStudentStudentWithPositionalParameters() {
StudentDomain student = studentService.getStudentWithParameters("First Two");
Assert.assertEquals("First Two", student.getFirstName());
Assert.assertEquals("Last Two", student.getLastName());
}
@Test
@DirtiesContext
public void getAllStudents() {
final List<StudentDomain> students = studentService.getAllStudents();
Assert.assertNotNull(students);
Assert.assertTrue(students.size() == 3);
}
@Test
@DirtiesContext
@Transactional
public void persistStudent() {
final StudentDomain studentToPersist = JpaTestUtils.getTestStudent();
Assert.assertNull(studentToPersist.getRollNumber());
final StudentDomain persistedStudent = studentService.persistStudent(studentToPersist);
Assert.assertNotNull(persistedStudent);
Assert.assertNotNull(persistedStudent.getRollNumber());
}
@Test
@DirtiesContext
@Transactional
public void persistStudentUsingMerge() {
final StudentDomain studentToPersist = JpaTestUtils.getTestStudent();
Assert.assertNull(studentToPersist.getRollNumber());
final StudentDomain persistedStudent = studentService.persistStudentUsingMerge(studentToPersist);
Assert.assertNotNull(persistedStudent);
Assert.assertNotNull(persistedStudent.getRollNumber());
}
}

View File

@@ -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.jpa.outbound;
import java.util.List;
import org.springframework.integration.annotation.Payload;
import org.springframework.integration.jpa.test.entity.StudentDomain;
public interface StudentService {
StudentDomain getStudent(StudentDomain student);
StudentDomain getStudentWithException(Long id);
StudentDomain getStudent(Long id);
StudentDomain deleteStudent(StudentDomain student);
@Payload("new java.util.Date()")
List<StudentDomain> getAllStudents();
StudentDomain persistStudent(StudentDomain student);
StudentDomain persistStudentUsingMerge(StudentDomain studentToPersist);
StudentDomain getStudentWithParameters(String firstName);
}

View File

@@ -0,0 +1,154 @@
/*
* 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.jpa.support.parametersource;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.springframework.integration.jpa.support.JpaParameter;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class ExpressionEvaluatingParameterSourceFactoryTests {
private ExpressionEvaluatingParameterSourceFactory factory = new ExpressionEvaluatingParameterSourceFactory();
@Test
public void testSetStaticParameters() {
factory.setParameters(Collections.singletonList(new JpaParameter("foo", "bar", null)));
ParameterSource source = factory.createParameterSource(null);
assertTrue(source.hasValue("foo"));
assertEquals("bar", source.getValue("foo"));
}
@Test
public void testMapInput() {
ParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar"));
assertTrue(source.hasValue("foo"));
assertEquals("bar", source.getValue("foo"));
}
@Test
public void testListOfMapsInput() {
@SuppressWarnings("unchecked")
ParameterSource source = factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"),
Collections.singletonMap("foo", "bucket")));
String expression = "foo";
assertTrue(source.hasValue(expression));
assertEquals("[bar, bucket]", source.getValue(expression).toString());
}
@Test
public void testMapInputWithExpression() {
ParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar"));
// This is an illegal parameter name in Spring JDBC so we'd never get this as input
assertTrue(source.hasValue("foo.toUpperCase()"));
assertEquals("BAR", source.getValue("foo.toUpperCase()"));
}
@Test
public void testMapInputWithMappedExpression() {
factory.setParameters(Collections.singletonList(new JpaParameter("spam", null, "foo.toUpperCase()")));
ParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar"));
assertTrue(source.hasValue("spam"));
assertEquals("BAR", source.getValue("spam"));
}
@Test
public void testMapInputWithMappedExpressionResolveStatic() {
List<JpaParameter> parameters = new ArrayList<JpaParameter>();
parameters.add(new JpaParameter("spam", null, "#staticParameters['foo'].toUpperCase()"));
parameters.add(new JpaParameter("foo", "bar", null));
factory.setParameters(parameters);
ParameterSource source = factory.createParameterSource(Collections.singletonMap("crap", "bucket"));
assertTrue(source.hasValue("spam"));
assertEquals("BAR", source.getValue("spam"));
}
@Test
public void testListOfMapsInputWithExpression() {
factory.setParameters(Collections.singletonList(new JpaParameter("spam", null, "foo.toUpperCase()")));
@SuppressWarnings("unchecked")
ParameterSource source = factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"),
Collections.singletonMap("foo", "bucket")));
String expression = "spam";
assertTrue(source.hasValue(expression));
assertEquals("[BAR, BUCKET]", source.getValue(expression).toString());
}
@Test
public void testPositionalStaticParameters() {
List<JpaParameter> parameters = new ArrayList<JpaParameter>();
parameters.add(new JpaParameter("foo", null));
parameters.add(new JpaParameter("bar", null));
factory.setParameters(parameters);
PositionSupportingParameterSource source = factory.createParameterSource("not important");
String position0 = (String) source.getValueByPosition(0);
String position1 = (String) source.getValueByPosition(1);
assertEquals("foo", position0);
assertEquals("bar", position1);
}
@Test
public void testPositionalExpressionParameters() {
List<JpaParameter> parameters = new ArrayList<JpaParameter>();
parameters.add(new JpaParameter(null, "#root.toUpperCase()"));
parameters.add(new JpaParameter("bar", null));
factory.setParameters(parameters);
PositionSupportingParameterSource source = factory.createParameterSource("very important");
String position0 = (String) source.getValueByPosition(0);
String position1 = (String) source.getValueByPosition(1);
assertEquals("VERY IMPORTANT", position0);
assertEquals("bar", position1);
}
@Test
public void testPositionalExpressionParameters2() {
List<JpaParameter> parameters = new ArrayList<JpaParameter>();
parameters.add(new JpaParameter("bar", null));
parameters.add(new JpaParameter(null, "#root.toUpperCase()"));
factory.setParameters(parameters);
PositionSupportingParameterSource source = factory.createParameterSource("very important");
String position0 = (String) source.getValueByPosition(0);
String position1 = (String) source.getValueByPosition(1);
assertEquals("VERY IMPORTANT", position1);
assertEquals("bar", position0);
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.jpa.test;
import java.util.Collection;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.Message;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public final class Consumer {
private static final Log logger = LogFactory.getLog(Consumer.class);
private static final BlockingQueue<Message<Collection<?>>> MESSAGES = new LinkedBlockingQueue<Message<Collection<?>>>();
public void receive(Message<Collection<?>>message) {
logger.info("Service Activator received Message: " + message);
MESSAGES.add(message);
}
public Message<Collection<?>> poll(long timeoutInMillis) throws InterruptedException {
return MESSAGES.poll(timeoutInMillis, TimeUnit.MILLISECONDS);
}
}

View File

@@ -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.jpa.test;
import java.util.Calendar;
import java.util.Date;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.jpa.test.entity.Gender;
import org.springframework.integration.jpa.test.entity.StudentDomain;
import org.springframework.integration.scheduling.PollerMetadata;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public final class JpaTestUtils {
public static StudentDomain getTestStudent() {
Calendar dateOfBirth = Calendar.getInstance();
dateOfBirth.set(1984, 0, 31);
StudentDomain student = new StudentDomain()
.withFirstName("First Executor")
.withLastName("Last Executor")
.withGender(Gender.MALE)
.withDateOfBirth(dateOfBirth.getTime())
.withLastUpdated(new Date());
return student;
}
public static SourcePollingChannelAdapter getSourcePollingChannelAdapter(MessageSource<?> adapter,
MessageChannel channel,
PollerMetadata poller,
GenericApplicationContext context,
ClassLoader beanClassLoader) throws Exception {
SourcePollingChannelAdapterFactoryBean fb = new SourcePollingChannelAdapterFactoryBean();
fb.setSource(adapter);
fb.setOutputChannel(channel);
fb.setPollerMetadata(poller);
fb.setBeanClassLoader(beanClassLoader);
fb.setAutoStartup(false);
fb.setBeanFactory(context.getBeanFactory());
fb.afterPropertiesSet();
return fb.getObject();
}
}

View File

@@ -0,0 +1,96 @@
/*
* 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.jpa.test;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
/**
*
* @author Gunnar Hillert
* @since 2.2
*
*/
public class TestTrigger implements Trigger {
private static final AtomicBoolean hasRun = new AtomicBoolean();
private final Date executionTime;
private static volatile CountDownLatch latch = new CountDownLatch(1);
public TestTrigger() {
super();
executionTime = new Date();
}
public Date nextExecutionTime(TriggerContext triggerContext) {
if (TestTrigger.hasRun.getAndSet(true)) {
TestTrigger.latch.countDown();
return null;
}
return this.executionTime;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((executionTime == null) ? 0 : executionTime.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TestTrigger other = (TestTrigger) obj;
if (executionTime == null) {
if (other.executionTime != null)
return false;
} else if (!executionTime.equals(other.executionTime))
return false;
return true;
}
public void reset() {
TestTrigger.latch = new CountDownLatch(1);
TestTrigger.hasRun.set(false);
}
public void await() {
try {
TestTrigger.latch.await(5000, TimeUnit.MILLISECONDS);
if (latch.getCount() != 0) {
throw new RuntimeException("test latch.await() did not count down");
}
}
catch (InterruptedException e) {
throw new RuntimeException("test latch.await() interrupted");
}
}
}

View File

@@ -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.jpa.test.entity;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
/**
* Represents the gender of the person
*
* @author Amol Nayak
*
*/
public enum Gender {
MALE("M"),FEMALE("F");
private String identifier;
private static Map<String, Gender> identifierMap;
private Gender(String identifier) {
this.identifier = identifier;
}
public String getIdentifier() {
return identifier;
}
static {
EnumSet<Gender> all = EnumSet.allOf(Gender.class);
identifierMap = new HashMap<String, Gender>();
for(Gender gender:all) {
identifierMap.put(gender.getIdentifier(), gender);
}
}
public static Gender getGenderFromIdentifier(String identifier) {
return identifierMap.get(identifier);
}
}

View File

@@ -0,0 +1,151 @@
/*
* 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.jpa.test.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
* The JPA Entity for the Student class
*
* @author Amol Nayak
* @author Gunnar Hillert
*
*/
@Entity(name="Student")
@Table(name="Student")
@NamedQueries({
@NamedQuery(name="selectStudent", query="select s from Student s where s.lastName = 'Last One'"),
@NamedQuery(name="updateStudent", query="update Student s set s.lastName = :lastName, s.lastUpdated = :lastUpdated where s.rollNumber in (select max(a.rollNumber) from Student a)")
})
@NamedNativeQuery(resultClass=StudentDomain.class, name="updateStudentNativeQuery", query="update Student s set s.lastName = :lastName, lastUpdated = :lastUpdated where s.rollNumber in (select max(a.rollNumber) from Student a)")
public class StudentDomain {
@Id
@Column(name="rollNumber")
@GeneratedValue(strategy=GenerationType.AUTO)
private Long rollNumber;
@Column(name="firstName")
private String firstName;
@Column(name="lastName")
private String lastName;
@Column(name="gender")
private String gender;
@Column(name="dateOfBirth")
@Temporal(TemporalType.DATE)
private Date dateOfBirth;
@Column(name="lastUpdated")
@Temporal(TemporalType.TIMESTAMP)
private Date lastUpdated;
public Long getRollNumber() {
return rollNumber;
}
public void setRollNumber(Long rollNumber) {
this.rollNumber = rollNumber;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Gender getGender() {
return Gender.getGenderFromIdentifier(gender);
}
public void setGender(Gender gender) {
this.gender = gender.getIdentifier();
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public Date getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
//Convenience methods for chaining method calls
public StudentDomain withRollNumber(Long rollNumber) {
setRollNumber(rollNumber);
return this;
}
public StudentDomain withFirstName(String firstName) {
setFirstName(firstName);
return this;
}
public StudentDomain withLastName(String lastName) {
setLastName(lastName);
return this;
}
public StudentDomain withGender(Gender gender) {
setGender(gender);
return this;
}
public StudentDomain withDateOfBirth(Date dateOfBirth) {
setDateOfBirth(dateOfBirth);
return this;
}
public StudentDomain withLastUpdated(Date lastUpdated) {
setLastUpdated(lastUpdated);
return this;
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.jpa.test.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
* The Entity for Student read status
*
* @author Amol Nayak
*
*/
@Entity
@Table(name="StudentReadStatus")
public class StudentReadStatus {
@Id
@Column(name="rollNumber")
private int rollNumber;
@Column(name="readAt")
@Temporal(TemporalType.TIMESTAMP)
private Date readAt;
public int getRollNumber() {
return rollNumber;
}
public void setRollNumber(int rollNumber) {
this.rollNumber = rollNumber;
}
public Date getReadAt() {
return readAt;
}
public void setReadAt(Date readAt) {
this.readAt = readAt;
}
}

View File

@@ -0,0 +1,7 @@
drop table StudentReadStatus;
drop table Student;
DROP TABLE OPENJPA_SEQUENCE_TABLE;
CREATE TABLE OPENJPA_SEQUENCE_TABLE (ID TINYINT NOT NULL, SEQUENCE_VALUE BIGINT, PRIMARY KEY (ID));
CREATE TABLE Student (rollNumber BIGINT generated by default as identity, dateOfBirth DATE, firstName VARCHAR(255), gender VARCHAR(255), lastName VARCHAR(255), lastUpdated TIMESTAMP, PRIMARY KEY (rollNumber));
CREATE TABLE StudentReadStatus (rollNumber INTEGER NOT NULL, readAt TIMESTAMP, PRIMARY KEY (rollNumber));

View File

@@ -0,0 +1,2 @@
drop table StudentReadStatus;
drop table Student;

View File

@@ -0,0 +1,6 @@
insert into Student(rollNumber, firstName,lastName, gender, dateOfBirth,lastUpdated)
values ('1001', 'First One','Last One','M','1980-1-1',NOW());
insert into Student(rollNumber, firstName,lastName, gender, dateOfBirth,lastUpdated)
values ('1002', 'First Two','Last Two','F','1984-1-1',NOW());
insert into Student(rollNumber, firstName,lastName, gender, dateOfBirth,lastUpdated)
values ('1003', 'First Three','Last Three','F','1984-3-3',NOW());

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<class>org.springframework.integration.jpa.test.entity.StudentDomain</class>
<class>org.springframework.integration.jpa.test.entity.StudentReadStatus</class>
</persistence-unit>
</persistence>

View File

@@ -0,0 +1,51 @@
<?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:jpa="http://www.springframework.org/schema/integration/jpa"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:integration="http://www.springframework.org/schema/integration"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa-2.1.xsd">
<jdbc:embedded-database id="dataSource" type="H2"/>
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS" >
<jdbc:script location="classpath:H2-DropTables.sql" />
<jdbc:script location="classpath:H2-CreateTables.sql" />
<jdbc:script location="classpath:H2-PopulateData.sql" />
</jdbc:initialize-database>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- <context:load-time-weaver />
-->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="persistenceUnit" />
<property name="jpaVendorAdapter" ref="vendorAdaptor" />
<!-- <property name="jpaProperties" ref="jpaProperties" /> -->
</bean>
<bean id="abstractVendorAdaptor" abstract="true">
<property name="generateDdl" value="true" />
<property name="database" value="HSQL" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
</beans>

View File

@@ -0,0 +1,16 @@
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<import resource="classpath:/commonJpa-context.xml" />
<bean id="vendorAdaptor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
parent="abstractVendorAdaptor">
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect"/>
<property name="showSql" value="true"/>
</bean>
</beans>

View File

@@ -0,0 +1,8 @@
log4j.rootCategory=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.category.org.springframework.integration=WARN
log4j.category.org.springframework.integration.jpa=INFO

View File

@@ -140,6 +140,7 @@
<xi:include href="./http.xml"/>
<xi:include href="./ip.xml"/>
<xi:include href="./jdbc.xml"/>
<xi:include href="./jpa.xml"/>
<xi:include href="./jms.xml"/>
<xi:include href="./mail.xml"/>
<xi:include href="./mongodb.xml"/>

File diff suppressed because it is too large Load Diff