INT-2881: Add support for the firstRecord to retrieving JPA gateway
JIRA: https://jira.springsource.org/browse/INT-2881
This commit is contained in:
@@ -470,5 +470,4 @@ public abstract class IntegrationNamespaceUtils {
|
||||
.addConstructorArgValue(methodSignature);
|
||||
registry.registerBeanDefinition(functionId, builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -15,13 +15,17 @@
|
||||
*/
|
||||
package org.springframework.integration.jpa.config.xml;
|
||||
|
||||
import static org.springframework.integration.config.xml.IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
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.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.jpa.support.OutboundGatewayType;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* The Parser for the Retrieving Jpa Outbound Gateway.
|
||||
@@ -41,6 +45,13 @@ public class RetrievingJpaOutboundGatewayParser extends AbstractJpaOutboundGatew
|
||||
|
||||
final BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getOutboundGatewayJpaExecutorBuilder(gatewayElement, parserContext);
|
||||
|
||||
|
||||
RootBeanDefinition firstResultExpression = createExpressionDefinitionFromValueOrExpression("first-result",
|
||||
"first-result-expression", parserContext, gatewayElement, false);
|
||||
|
||||
if(firstResultExpression != null) {
|
||||
jpaExecutorBuilder.addPropertyValue("firstResultExpression", firstResultExpression);
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "max-number-of-results");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "delete-after-poll");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "delete-in-batch");
|
||||
@@ -55,7 +66,5 @@ public class RetrievingJpaOutboundGatewayParser extends AbstractJpaOutboundGatew
|
||||
jpaOutboundGatewayBuilder.addConstructorArgReference(jpaExecutorBeanName);
|
||||
jpaOutboundGatewayBuilder.addPropertyValue("gatewayType", OutboundGatewayType.RETRIEVING);
|
||||
return jpaOutboundGatewayBuilder;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import javax.persistence.Query;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.integration.jpa.support.JpaUtils;
|
||||
import org.springframework.integration.jpa.support.parametersource.ParameterSource;
|
||||
import org.springframework.integration.jpa.support.parametersource.PositionSupportingParameterSource;
|
||||
@@ -45,11 +46,13 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DefaultJpaOperations.class);
|
||||
|
||||
@Override
|
||||
public void delete(Object entity) {
|
||||
Assert.notNull(entity, "The entity must not be null!");
|
||||
entityManager.remove(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteInBatch(Iterable<?> entities) {
|
||||
|
||||
Assert.notNull(entities, "entities must not be null.");
|
||||
@@ -80,24 +83,28 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String updateQuery, ParameterSource source) {
|
||||
Query query = entityManager.createQuery(updateQuery);
|
||||
setParametersIfRequired(updateQuery, source, query);
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdateWithNamedQuery(String updateQuery, ParameterSource source) {
|
||||
Query query = entityManager.createNamedQuery(updateQuery);
|
||||
setParametersIfRequired(updateQuery, source, query);
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdateWithNativeQuery(String updateQuery, ParameterSource source) {
|
||||
Query query = entityManager.createNativeQuery(updateQuery);
|
||||
setParametersIfRequired(updateQuery, source, query);
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(Class<T> entityType, Object id) {
|
||||
return entityManager.find(entityType, id);
|
||||
}
|
||||
@@ -108,11 +115,15 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
return query;
|
||||
}
|
||||
|
||||
public List<?> getResultListForClass(Class<?> entityClass, int maxNumberOfResults) {
|
||||
|
||||
@Override
|
||||
public List<?> getResultListForClass(Class<?> entityClass, int firstResult, int maxNumberOfResults) {
|
||||
|
||||
final String entityName = JpaUtils.getEntityName(entityManager, entityClass);
|
||||
final Query query = entityManager.createQuery("select x from " + entityName + " x", entityClass);
|
||||
|
||||
if(firstResult > 0) {
|
||||
query.setFirstResult(firstResult);
|
||||
}
|
||||
if(maxNumberOfResults > 0) {
|
||||
query.setMaxResults(maxNumberOfResults);
|
||||
}
|
||||
@@ -121,12 +132,16 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getResultListForNamedQuery(String selectNamedQuery,
|
||||
ParameterSource parameterSource, int maxNumberOfResults) {
|
||||
ParameterSource parameterSource, int firstResult, int maxNumberOfResults) {
|
||||
|
||||
final Query query = entityManager.createNamedQuery(selectNamedQuery);
|
||||
setParametersIfRequired(selectNamedQuery, parameterSource, query);
|
||||
|
||||
if(firstResult > 0) {
|
||||
query.setFirstResult(firstResult);
|
||||
}
|
||||
if(maxNumberOfResults > 0) {
|
||||
query.setMaxResults(maxNumberOfResults);
|
||||
}
|
||||
@@ -135,8 +150,9 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getResultListForNativeQuery(String selectQuery, Class<?> entityClass,
|
||||
ParameterSource parameterSource, int maxNumberOfResults) {
|
||||
ParameterSource parameterSource, int firstResult, int maxNumberOfResults) {
|
||||
|
||||
final Query query;
|
||||
|
||||
@@ -148,6 +164,9 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
|
||||
setParametersIfRequired(selectQuery, parameterSource, query);
|
||||
|
||||
if(firstResult > 0) {
|
||||
query.setFirstResult(firstResult);
|
||||
}
|
||||
if(maxNumberOfResults > 0) {
|
||||
query.setMaxResults(maxNumberOfResults);
|
||||
}
|
||||
@@ -155,15 +174,20 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getResultListForQuery(String query, ParameterSource source) {
|
||||
return getResultListForQuery(query,source, 0);
|
||||
return getResultListForQuery(query,source, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getResultListForQuery(String queryString, ParameterSource source,
|
||||
int maxNumberOfResults) {
|
||||
int firstResult, int maxNumberOfResults) {
|
||||
|
||||
Query query = getQuery(queryString,source);
|
||||
|
||||
if(firstResult > 0) {
|
||||
query.setFirstResult(firstResult);
|
||||
}
|
||||
if(maxNumberOfResults > 0) {
|
||||
query.setMaxResults(maxNumberOfResults);
|
||||
}
|
||||
@@ -171,16 +195,19 @@ public class DefaultJpaOperations extends AbstractJpaOperations {
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSingleResultForQuery(String queryString, ParameterSource source) {
|
||||
Query query = getQuery(queryString,source);
|
||||
return query.getSingleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object merge(Object entity) {
|
||||
Assert.notNull(entity, "The object to merge must not be null.");
|
||||
return persistOrMerge(entity, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persist(Object entity) {
|
||||
Assert.notNull(entity, "The object to persist must not be null.");
|
||||
persistOrMerge(entity, false);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -25,8 +25,11 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.expression.IntegrationEvaluationContextAware;
|
||||
import org.springframework.integration.jpa.support.JpaParameter;
|
||||
import org.springframework.integration.jpa.support.PersistMode;
|
||||
import org.springframework.integration.jpa.support.parametersource.BeanPropertyParameterSourceFactory;
|
||||
@@ -60,7 +63,7 @@ import org.springframework.util.Assert;
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
public class JpaExecutor implements InitializingBean, BeanFactoryAware, IntegrationEvaluationContextAware {
|
||||
|
||||
private volatile JpaOperations jpaOperations;
|
||||
private volatile List<JpaParameter> jpaParameters;
|
||||
@@ -73,6 +76,8 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
/** 0 means all possible objects shall be retrieved. */
|
||||
private volatile int maxNumberOfResults = 0;
|
||||
|
||||
private volatile Expression firstResultExpression;
|
||||
|
||||
private volatile PersistMode persistMode = PersistMode.MERGE;
|
||||
|
||||
private volatile ParameterSourceFactory parameterSourceFactory = null;
|
||||
@@ -93,6 +98,8 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
private volatile EvaluationContext evaluationContext;
|
||||
|
||||
/**
|
||||
* Constructor taking an {@link EntityManagerFactory} from which the
|
||||
* {@link EntityManager} can be obtained.
|
||||
@@ -148,6 +155,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
* {@link ParameterSourceFactory}.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
if (this.jpaParameters != null) {
|
||||
@@ -247,6 +255,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute a (typically retrieving) JPA operation. The <i>requestMessage</i>
|
||||
* can be used to provide additional query parameters using
|
||||
@@ -259,18 +268,18 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object poll(final Message<?> requestMessage) {
|
||||
|
||||
final Object payload;
|
||||
|
||||
final List<?> result;
|
||||
|
||||
if (requestMessage == null) {
|
||||
result = doPoll(this.parameterSource);
|
||||
result = doPoll(this.parameterSource, 0);
|
||||
}
|
||||
else {
|
||||
int firstResult = 0;
|
||||
if(firstResultExpression != null) {
|
||||
firstResult = getFirstResult(requestMessage);
|
||||
}
|
||||
ParameterSource parameterSource = determineParameterSource(requestMessage);
|
||||
|
||||
result = doPoll(parameterSource);
|
||||
result = doPoll(parameterSource, firstResult);
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
@@ -283,21 +292,17 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
payload = result.iterator().next();
|
||||
}
|
||||
else {
|
||||
|
||||
throw new MessagingException(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.deleteInBatch) {
|
||||
this.jpaOperations.deleteInBatch((Iterable<Object>) payload);
|
||||
@@ -313,10 +318,34 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
private int getFirstResult(final Message<?> requestMessage) {
|
||||
int firstResult = 0;
|
||||
Object firstRecordEvaluationResult = firstResultExpression.getValue(evaluationContext, requestMessage);
|
||||
if(firstRecordEvaluationResult != null) {
|
||||
if(firstRecordEvaluationResult instanceof Number) {
|
||||
firstResult = ((Number)firstRecordEvaluationResult).intValue();
|
||||
}
|
||||
else if(firstRecordEvaluationResult instanceof String){
|
||||
try {
|
||||
firstResult = Integer.parseInt((String)firstRecordEvaluationResult);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Value " + firstRecordEvaluationResult + " passed as firstRecord cannot be " +
|
||||
"parsed to a number");
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Expected the value of the firstRecord to be a Number" +
|
||||
" got " + firstRecordEvaluationResult.getClass().getName());
|
||||
}
|
||||
}
|
||||
return firstResult;
|
||||
}
|
||||
|
||||
private ParameterSource determineParameterSource(final Message<?> requestMessage) {
|
||||
ParameterSource parameterSource;
|
||||
if (usePayloadAsParameterSource) {
|
||||
@@ -335,28 +364,29 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
return poll(null);
|
||||
}
|
||||
|
||||
protected List<?> doPoll(ParameterSource jpaQLParameterSource) {
|
||||
|
||||
protected List<?> doPoll(ParameterSource jpaQLParameterSource, int firstResult) {
|
||||
List<?> payload = null;
|
||||
|
||||
if (this.jpaQuery != null) {
|
||||
payload = jpaOperations.getResultListForQuery(this.jpaQuery, jpaQLParameterSource, maxNumberOfResults);
|
||||
payload = jpaOperations.getResultListForQuery(this.jpaQuery, jpaQLParameterSource,
|
||||
firstResult, maxNumberOfResults);
|
||||
}
|
||||
else if (this.nativeQuery != null) {
|
||||
payload = jpaOperations.getResultListForNativeQuery(this.nativeQuery, this.entityClass, jpaQLParameterSource, maxNumberOfResults);
|
||||
payload = jpaOperations.getResultListForNativeQuery(this.nativeQuery, this.entityClass, jpaQLParameterSource,
|
||||
firstResult, maxNumberOfResults);
|
||||
}
|
||||
else if (this.namedQuery != null) {
|
||||
payload = jpaOperations.getResultListForNamedQuery(this.namedQuery, jpaQLParameterSource, maxNumberOfResults);
|
||||
payload = jpaOperations.getResultListForNamedQuery(this.namedQuery, jpaQLParameterSource,
|
||||
firstResult, maxNumberOfResults);
|
||||
}
|
||||
else if (this.entityClass != null) {
|
||||
payload = jpaOperations.getResultListForClass(this.entityClass, maxNumberOfResults);
|
||||
payload = jpaOperations.getResultListForClass(this.entityClass,
|
||||
firstResult, maxNumberOfResults);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("For the polling operation, one of "
|
||||
+ "the following properties must be specified: "
|
||||
+ "query, namedQuery or entityClass.");
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
@@ -509,4 +539,28 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
|
||||
this.maxNumberOfResults = maxNumberOfResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expression that will be evaluated to get the first result in the query executed.
|
||||
* If a null expression is set, all the results in the result set will be retrieved
|
||||
*
|
||||
* @param firstResultExpression
|
||||
*
|
||||
* @see Query#setFirstResult(int)
|
||||
*/
|
||||
public void setFirstResultExpression(Expression firstResultExpression) {
|
||||
this.firstResultExpression = firstResultExpression;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the evaluation context for evaluating the expression to get the from record of the
|
||||
* result set retrieved by the retrieving gateway.
|
||||
*
|
||||
* @param evaluationContext
|
||||
*/
|
||||
@Override
|
||||
public void setIntegrationEvaluationContext(
|
||||
EvaluationContext evaluationContext) {
|
||||
this.evaluationContext = evaluationContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,20 +85,24 @@ public interface JpaOperations {
|
||||
/**
|
||||
*
|
||||
* @param entityClass
|
||||
* @param firstResult
|
||||
* @param maxNumberOfReturnedObjects
|
||||
* @return List of found entities
|
||||
*/
|
||||
List<?> getResultListForClass(Class<?> entityClass,
|
||||
int firstResult,
|
||||
int maxNumberOfReturnedObjects);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param selectNamedQuery
|
||||
* @param jpaQLParameterSource
|
||||
* @param firstResult
|
||||
* @param maxNumberOfResults
|
||||
* @return List of found entities
|
||||
*/
|
||||
List<?> getResultListForNamedQuery(String selectNamedQuery, ParameterSource jpaQLParameterSource,
|
||||
int firstResult,
|
||||
int maxNumberOfResults);
|
||||
|
||||
/**
|
||||
@@ -106,11 +110,14 @@ public interface JpaOperations {
|
||||
* @param selectQuery
|
||||
* @param entityClass
|
||||
* @param jpaQLParameterSource
|
||||
* @param firstResult
|
||||
* @param maxNumberOfResults
|
||||
* @return List of found entities
|
||||
*/
|
||||
List<?> getResultListForNativeQuery(String selectQuery,
|
||||
Class<?> entityClass, ParameterSource jpaQLParameterSource, int maxNumberOfResults);
|
||||
Class<?> entityClass, ParameterSource jpaQLParameterSource,
|
||||
int firstResult,
|
||||
int maxNumberOfResults);
|
||||
|
||||
/**
|
||||
* Executes the provided query to return a list of results
|
||||
@@ -124,11 +131,12 @@ public interface JpaOperations {
|
||||
* Executes the provided query to return a list of results.
|
||||
*
|
||||
* @param query Must not be null or empty
|
||||
* @param firstResult The first result
|
||||
* @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);
|
||||
List<?> getResultListForQuery(String query, ParameterSource source, int firstResult, int maxNumberOfResults);
|
||||
|
||||
/**
|
||||
* Executes the provided query to return a single element
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -39,6 +39,8 @@ import org.springframework.util.Assert;
|
||||
* constructor.
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
@@ -57,6 +59,7 @@ public class JpaOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
public JpaOutboundGateway(JpaExecutor jpaExecutor) {
|
||||
Assert.notNull(jpaExecutor, "jpaExecutor must not be null.");
|
||||
this.jpaExecutor = jpaExecutor;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,21 +73,13 @@ public class JpaOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
|
||||
@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) {
|
||||
@@ -114,5 +109,4 @@ public class JpaOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
public void setProducesReply(boolean producesReply) {
|
||||
this.producesReply = producesReply;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -155,7 +155,6 @@ public class JpaOutboundGatewayFactoryBean extends AbstractFactoryBean<MessageHa
|
||||
}
|
||||
jpaOutboundGateway.setBeanFactory(this.getBeanFactory());
|
||||
jpaOutboundGateway.afterPropertiesSet();
|
||||
|
||||
if (!CollectionUtils.isEmpty(this.txAdviceChain)) {
|
||||
|
||||
ProxyFactory proxyFactory = new ProxyFactory(jpaOutboundGateway);
|
||||
@@ -170,5 +169,4 @@ public class JpaOutboundGatewayFactoryBean extends AbstractFactoryBean<MessageHa
|
||||
|
||||
return jpaOutboundGateway;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -222,6 +222,29 @@
|
||||
</xsd:element>
|
||||
<xsd:element name="request-handler-advice-chain" type="integration:adviceChainType" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="first-result" type="xsd:integer">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The attribute that is used to set the first result marker while executing the
|
||||
results. A negative value will retrieve from first record in the result set.
|
||||
It is a way for the application to use the gateway to paginate the results in
|
||||
combination with the max-number-of-results attribute. This attribute is mutually
|
||||
exclusive to first-result-expression attribute
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="first-result-expression">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The attribute that is used to set the first result expression that would
|
||||
be evaluated to get the first record while executing the JPA query for result
|
||||
A negative value will retrieve from first record in the result set.
|
||||
It is a way for the application to use the gateway to paginate the results in
|
||||
combination with the max-number-of-results attribute. This attribute is mutually
|
||||
exclusive to first-result attribute
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="coreJpaComponentAttributes" />
|
||||
<xsd:attributeGroup ref="commonJpaOutboundGatewayAttributes"/>
|
||||
<xsd:attributeGroup ref="commonRetrievingJpaAttributes" />
|
||||
|
||||
@@ -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.xsd">
|
||||
|
||||
<import resource="classpath:/hibernateJpa-context.xml" />
|
||||
|
||||
<int:channel id="in"/>
|
||||
<int:channel id="out"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway id="invalidRetrievingJpaOutboundGateway"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
order="1"
|
||||
max-number-of-results="55"
|
||||
first-result="1"
|
||||
first-result-expression="header['firstResult']"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
</beans>
|
||||
@@ -18,13 +18,17 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
@@ -57,43 +61,47 @@ public class JpaOutboundGatewayParserTests extends AbstractRequestHandlerAdvice
|
||||
@Test
|
||||
public void testRetrievingJpaOutboundGatewayParser() throws Exception {
|
||||
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "retrievingJpaOutboundGateway");
|
||||
|
||||
|
||||
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);
|
||||
|
||||
long sendTimeout = TestUtils.getPropertyValue(jpaOutboundGateway, "messagingTemplate.sendTimeout", Long.class);
|
||||
|
||||
assertEquals(100, sendTimeout);
|
||||
|
||||
assertFalse(TestUtils.getPropertyValue(jpaOutboundGateway, "requiresReply", Boolean.class));
|
||||
|
||||
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);
|
||||
|
||||
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "expectSingleResult", Boolean.class));
|
||||
|
||||
final Integer maxNumberOfResults = TestUtils.getPropertyValue(jpaExecutor, "maxNumberOfResults", Integer.class);
|
||||
|
||||
assertEquals(Integer.valueOf(55), maxNumberOfResults);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrievingJpaOutboundGatewayParserWithFirstResult() throws Exception {
|
||||
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "retrievingJpaOutboundGatewayWithFirstResult");
|
||||
final JpaOutboundGateway jpaOutboundGateway = TestUtils.getPropertyValue(this.consumer, "handler", JpaOutboundGateway.class);
|
||||
Expression firstResultExpression =
|
||||
TestUtils.getPropertyValue(jpaOutboundGateway, "jpaExecutor.firstResultExpression", Expression.class);
|
||||
assertNotNull(firstResultExpression);
|
||||
assertEquals(LiteralExpression.class, firstResultExpression.getClass());
|
||||
assertEquals("1", TestUtils.getPropertyValue(firstResultExpression, "literalValue", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrievingJpaOutboundGatewayParserWithFirstResultExpression() throws Exception {
|
||||
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "retrievingJpaOutboundGatewayWithFirstResultExpression");
|
||||
final JpaOutboundGateway jpaOutboundGateway = TestUtils.getPropertyValue(this.consumer, "handler", JpaOutboundGateway.class);
|
||||
Expression firstResultExpression =
|
||||
TestUtils.getPropertyValue(jpaOutboundGateway, "jpaExecutor.firstResultExpression", Expression.class);
|
||||
assertNotNull(firstResultExpression);
|
||||
assertEquals(SpelExpression.class, firstResultExpression.getClass());
|
||||
assertEquals("header['firstResult']", TestUtils.getPropertyValue(firstResultExpression, "expression", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdatingJpaOutboundGatewayParser() throws Exception {
|
||||
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "updatingJpaOutboundGateway");
|
||||
@@ -170,6 +178,18 @@ public class JpaOutboundGatewayParserTests extends AbstractRequestHandlerAdvice
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withBothFirstResultAndFirstResultExpressionPresent() {
|
||||
try {
|
||||
this.context = new ClassPathXmlApplicationContext("JpaInvalidOutboundGatewayParserTests.xml", getClass());
|
||||
} catch (BeanDefinitionStoreException e) {
|
||||
assertTrue(e.getMessage().startsWith("Configuration problem: Only one of 'first-result' or 'first-result-expression' is allowed"));
|
||||
return;
|
||||
}
|
||||
fail("BeanDefinitionStoreException expected.");
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (context != null) {
|
||||
|
||||
@@ -26,6 +26,46 @@
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway id="retrievingJpaOutboundGatewayWithFirstResult"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
expect-single-result="true"
|
||||
order="1"
|
||||
first-result="1"
|
||||
max-number-of-results="55"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway id="retrievingJpaOutboundGatewayWithFirstResultExpression"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
expect-single-result="true"
|
||||
order="1"
|
||||
first-result-expression="header['firstResult']"
|
||||
max-number-of-results="55"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway id="retrievingJpaOutboundGatewayWithExpressionExecutor"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
expect-single-result="true"
|
||||
order="1"
|
||||
first-result-expression="header['firstResult']"
|
||||
max-number-of-results="55"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
|
||||
<int-jpa:updating-outbound-gateway id="updatingJpaOutboundGateway"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="false"
|
||||
@@ -59,5 +99,4 @@
|
||||
<bean class="org.springframework.integration.jpa.config.xml.JpaOutboundGatewayParserTests$FooAdvice"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.jpa.support.parametersource.ExpressionEvaluatingParameterSourceFactory;
|
||||
@@ -60,7 +61,7 @@ public class AbstractJpaOperationsTests {
|
||||
|
||||
final JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
|
||||
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
Assert.assertTrue(students.size() == 3);
|
||||
|
||||
}
|
||||
@@ -72,7 +73,7 @@ public class AbstractJpaOperationsTests {
|
||||
|
||||
final JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
|
||||
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 2);
|
||||
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0, 2);
|
||||
Assert.assertTrue(String.format("Was expecting 2 Students to be returned but got '%s'.", students.size()),
|
||||
students.size() == 2);
|
||||
|
||||
@@ -87,7 +88,7 @@ public class AbstractJpaOperationsTests {
|
||||
|
||||
final StudentDomain student = JpaTestUtils.getTestStudent();
|
||||
|
||||
List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
Assert.assertTrue(students.size() == 3);
|
||||
|
||||
ParameterSourceFactory requestParameterSourceFactory =
|
||||
@@ -156,7 +157,7 @@ public class AbstractJpaOperationsTests {
|
||||
|
||||
Class<?> entityClass = StudentDomain.class;
|
||||
|
||||
List<?> students = jpaOperations.getResultListForNativeQuery(selectSqlQuery, entityClass, null, 0);
|
||||
List<?> students = jpaOperations.getResultListForNativeQuery(selectSqlQuery, entityClass, null, 0, 0);
|
||||
|
||||
Assert.assertTrue(students.size() == 1);
|
||||
|
||||
@@ -181,7 +182,7 @@ public class AbstractJpaOperationsTests {
|
||||
|
||||
String selectSqlQuery = "select rollNumber, firstName, lastName, gender, dateOfBirth, lastUpdated from Student where lastName = 'Last One'";
|
||||
|
||||
List<?> students = jpaOperations.getResultListForNativeQuery(selectSqlQuery, null, null, 0);
|
||||
List<?> students = jpaOperations.getResultListForNativeQuery(selectSqlQuery, null, null, 0, 0);
|
||||
|
||||
Assert.assertTrue(students.size() == 1);
|
||||
|
||||
@@ -285,7 +286,7 @@ public class AbstractJpaOperationsTests {
|
||||
public void testMergeCollectionWithNullElement() {
|
||||
final JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
|
||||
final List<?> studentsFromDbBeforeTest = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> studentsFromDbBeforeTest = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
|
||||
Assert.assertEquals(3, studentsFromDbBeforeTest.size());
|
||||
|
||||
@@ -379,7 +380,7 @@ public class AbstractJpaOperationsTests {
|
||||
public void testPersistCollectionWithNullElement() {
|
||||
final JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
|
||||
final List<?> studentsFromDbBeforeTest = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> studentsFromDbBeforeTest = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
|
||||
Assert.assertEquals(3, studentsFromDbBeforeTest.size());
|
||||
|
||||
@@ -405,7 +406,7 @@ public class AbstractJpaOperationsTests {
|
||||
Assert.assertNotNull(student1.getRollNumber());
|
||||
Assert.assertNotNull(student3.getRollNumber());
|
||||
|
||||
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
|
||||
Assert.assertNotNull(studentsFromDb);
|
||||
Assert.assertEquals(5, studentsFromDb.size());
|
||||
@@ -414,7 +415,7 @@ public class AbstractJpaOperationsTests {
|
||||
public void testDeleteInBatch() {
|
||||
final JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
|
||||
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
|
||||
Assert.assertNotNull(students);
|
||||
|
||||
@@ -432,7 +433,7 @@ public class AbstractJpaOperationsTests {
|
||||
|
||||
transactionManager.commit(status);
|
||||
|
||||
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
|
||||
Assert.assertNotNull(studentsFromDb);
|
||||
Assert.assertTrue(studentsFromDb.size() == 0);
|
||||
@@ -451,7 +452,7 @@ public class AbstractJpaOperationsTests {
|
||||
public void testDelete() {
|
||||
final JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
|
||||
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
|
||||
Assert.assertNotNull(studentsFromDb);
|
||||
Assert.assertTrue(studentsFromDb.size() == 3);
|
||||
@@ -475,7 +476,7 @@ public class AbstractJpaOperationsTests {
|
||||
|
||||
transactionManager.commit(status);
|
||||
|
||||
final List<?> studentsFromDbAfterDelete = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> studentsFromDbAfterDelete = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
|
||||
Assert.assertNotNull(studentsFromDbAfterDelete);
|
||||
Assert.assertTrue(studentsFromDbAfterDelete.size() == 2);
|
||||
@@ -485,7 +486,7 @@ public class AbstractJpaOperationsTests {
|
||||
public void testDeleteInBatchWithEmptyCollection() {
|
||||
final JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
|
||||
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> students = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
|
||||
Assert.assertNotNull(students);
|
||||
Assert.assertTrue(students.size() == 3);
|
||||
@@ -503,11 +504,38 @@ public class AbstractJpaOperationsTests {
|
||||
|
||||
transactionManager.commit(status);
|
||||
|
||||
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0);
|
||||
final List<?> studentsFromDb = jpaOperations.getResultListForClass(StudentDomain.class, 0, 0);
|
||||
|
||||
Assert.assertNotNull(studentsFromDb);
|
||||
Assert.assertTrue(studentsFromDb.size() == 3); //Nothing should have happened
|
||||
|
||||
}
|
||||
|
||||
public void testGetAllStudentsFromThirdRecord() {
|
||||
JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
List<?> results = jpaOperations.getResultListForClass(StudentDomain.class, 2, 0);
|
||||
assertEquals(1, results.size());
|
||||
}
|
||||
|
||||
|
||||
public void testGetAllStudentsUsingNativeQueryFromThirdRecord() {
|
||||
JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
String query = "select * from Student";
|
||||
List<?> results = jpaOperations.getResultListForNativeQuery(query, StudentDomain.class, null, 2, 0);
|
||||
assertEquals(1, results.size());
|
||||
}
|
||||
|
||||
|
||||
public void testGetAllStudentsUsingNamedQueryFromThirdRecord() {
|
||||
JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
List<?> results = jpaOperations.getResultListForNamedQuery("selectAllStudents", null, 2, 0);
|
||||
assertEquals(1, results.size());
|
||||
}
|
||||
|
||||
public void testGetAllStudentsUsingJPAQueryFromThirdRecord() {
|
||||
JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
String query = "select s from Student s";
|
||||
List<?> results = jpaOperations.getResultListForQuery(query, null, 2, 0);
|
||||
assertEquals(1, results.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ package org.springframework.integration.jpa.core;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -25,6 +26,7 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.jpa.support.JpaParameter;
|
||||
import org.springframework.integration.jpa.support.parametersource.ExpressionEvaluatingParameterSourceFactory;
|
||||
@@ -224,4 +226,48 @@ public class JpaExecutorTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultStartingFromThirdRecordForJPAQuery() throws Exception {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setJpaQuery("select s from Student s");
|
||||
jpaExecutor.setFirstResultExpression(new LiteralExpression("2"));
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
List<?> results = (List<?>)jpaExecutor.poll(MessageBuilder.withPayload("").build());
|
||||
Assert.assertNotNull(results);
|
||||
Assert.assertEquals(1, results.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultStartingFromThirdRecordForNativeQuery() throws Exception {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setNativeQuery("select * from Student s");
|
||||
jpaExecutor.setFirstResultExpression(new LiteralExpression("2"));
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
List<?> results = (List<?>)jpaExecutor.poll(MessageBuilder.withPayload("").build());
|
||||
Assert.assertNotNull(results);
|
||||
Assert.assertEquals(1, results.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultStartingFromThirdRecordForNamedQuery() throws Exception {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setNamedQuery("selectAllStudents");
|
||||
jpaExecutor.setFirstResultExpression(new LiteralExpression("2"));
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
List<?> results = (List<?>)jpaExecutor.poll(MessageBuilder.withPayload("").build());
|
||||
Assert.assertNotNull(results);
|
||||
Assert.assertEquals(1, results.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultStartingFromThirdRecordUsingEntity() throws Exception {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setEntityClass(StudentDomain.class);
|
||||
jpaExecutor.setFirstResultExpression(new LiteralExpression("2"));
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
List<?> results = (List<?>)jpaExecutor.poll(MessageBuilder.withPayload("").build());
|
||||
Assert.assertNotNull(results);
|
||||
Assert.assertEquals(1, results.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?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:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation=
|
||||
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd">
|
||||
|
||||
<import resource="classpath:/hibernateJpa-context.xml" />
|
||||
|
||||
<int:channel id="in"/>
|
||||
<int:channel id="out"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway
|
||||
id="retrievingGateway"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
first-result-expression="payload"
|
||||
reply-timeout="100"/>
|
||||
</beans>
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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 static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.MessagingException;
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.integration.core.SubscribableChannel;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* The test cases for testing out a complete flow of the JPA gateways/adapters with all
|
||||
* the components integrated.
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @since 3.0
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class JpaOutboundGatewayIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("in")
|
||||
private SubscribableChannel requestChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("out")
|
||||
private SubscribableChannel responseChannel;
|
||||
|
||||
/**
|
||||
* Sends a message with the payload as a integer representing the start number in the result
|
||||
* set.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void retrieveFromSecondRecord() throws Exception {
|
||||
responseChannel.subscribe(new MessageHandler() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
assertEquals(1, ((List)message.getPayload()).size());
|
||||
}
|
||||
});
|
||||
Message<Integer> message = MessageBuilder.withPayload(2).build();
|
||||
requestChannel.send(message);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@
|
||||
<int:method name="persistStudentUsingMerge" request-channel="persistStudentUsingMergeChannel" />
|
||||
<int:method name="getStudent2" request-channel="retrievingGatewayInsideChain" />
|
||||
<int:method name="persistStudent2" request-channel="updatingGatewayInsideChain" />
|
||||
<int:method name="getAllStudentsFromGivenRecord" request-channel="getStudentsFromGivenRecordChannel"/>
|
||||
</int:gateway>
|
||||
|
||||
<int:channel id="studentReplyChannel"/>
|
||||
@@ -43,6 +44,7 @@
|
||||
<int:channel id="getStudentEndpointWithExceptionChannel"/>
|
||||
<int:channel id="retrievingGatewayInsideChain"/>
|
||||
<int:channel id="updatingGatewayInsideChain"/>
|
||||
<int:channel id="getStudentsFromGivenRecordChannel"/>
|
||||
|
||||
<bean id="deleteStudentEndpoint"
|
||||
class="org.springframework.integration.endpoint.EventDrivenConsumer">
|
||||
@@ -198,6 +200,26 @@
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="getStudentsFromGivenFromRecord"
|
||||
class="org.springframework.integration.endpoint.EventDrivenConsumer">
|
||||
<constructor-arg name="inputChannel" ref="getStudentsFromGivenRecordChannel"/>
|
||||
<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="jpaQuery" value="select s from Student s"/>
|
||||
<property name="expectSingleResult" value="false"/>
|
||||
<property name="firstResultExpression"
|
||||
value="#{new org.springframework.expression.spel.standard.SpelExpressionParser().parseExpression('payload')}"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<property name="gatewayType" value="RETRIEVING"/>
|
||||
<property name="outputChannel" ref="studentReplyChannel"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<int:chain input-channel="retrievingGatewayInsideChain" output-channel="studentReplyChannel">
|
||||
<jpa:retrieving-outbound-gateway entity-manager="entityManager"
|
||||
expect-single-result="true"
|
||||
|
||||
@@ -14,11 +14,11 @@ package org.springframework.integration.jpa.outbound;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.jpa.test.JpaTestUtils;
|
||||
@@ -33,6 +33,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
@@ -58,6 +60,13 @@ public class JpaOutboundGatewayTests {
|
||||
Assert.assertNotNull(student);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllStudentsStartingFromGivenRecord() {
|
||||
List<?> students = studentService.getAllStudentsFromGivenRecord(1);
|
||||
Assert.assertNotNull(students);
|
||||
Assert.assertEquals(2, students.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteNonExistingStudent() {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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
|
||||
@@ -29,6 +29,8 @@ public interface StudentService {
|
||||
@Payload("new java.util.Date()")
|
||||
List<StudentDomain> getAllStudents();
|
||||
|
||||
List<StudentDomain> getAllStudentsFromGivenRecord(int recordNumber);
|
||||
|
||||
StudentDomain persistStudent(StudentDomain student);
|
||||
|
||||
StudentDomain persistStudentUsingMerge(StudentDomain studentToPersist);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -36,10 +36,13 @@ import javax.persistence.TemporalType;
|
||||
* @author Amol Nayak
|
||||
* @author Gunnar Hillert
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
@Entity(name="Student")
|
||||
@Table(name="Student")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name="selectAllStudents", query="select s from Student s"),
|
||||
@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)")
|
||||
})
|
||||
|
||||
@@ -1138,6 +1138,8 @@ public class Student {
|
||||
jpa-operations=""
|
||||
jpa-query=""
|
||||
max-number-of-results="" ]]><co id="outGateMaxNumOfResults"/><![CDATA[
|
||||
first-result="" ]]><co id="outGateFirstResult"/><![CDATA[
|
||||
first-result-expression="" ]]><co id="outGateFirstResultExpression"/><![CDATA[
|
||||
named-query=""
|
||||
native-query=""
|
||||
order=""
|
||||
@@ -1168,6 +1170,20 @@ public class Student {
|
||||
all the possible records are selected by given query.<emphasis>Optional</emphasis>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="outGateFirstResult">
|
||||
<para>
|
||||
This non zero, non negative integer value tells the adapter the first record from which the
|
||||
results are to be retrieved This attribute is mutually exclusive to <code>first-result-expression</code>.
|
||||
This attribute is introduced since version 3.0. <emphasis>Optional</emphasis>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="outGateFirstResultExpression">
|
||||
<para>
|
||||
This expression is evaluated against the message to find the position of first record in the
|
||||
result set to be retrieved This attribute is mutually exclusive to <code>first-result</code>.
|
||||
This attribute is introduced since version 3.0. <emphasis>Optional</emphasis>.
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
<important>
|
||||
<para>
|
||||
|
||||
@@ -452,5 +452,14 @@
|
||||
least 1.
|
||||
</para>
|
||||
</section>
|
||||
<section id="3.0-jpa-first-result">
|
||||
<title>JPA Adapters: first-result attribute</title>
|
||||
<para>
|
||||
Retrieving gateways had no mechanism to specify the first record to be retrieved which
|
||||
is a common use case. The retrieving gateways now support specifying this parameter
|
||||
using a <code>first-result</code> and <code>first-result-expression</code> attributes
|
||||
to the gateway definition.<xref linkend="jpa-retrieving-outbound-gateway"/>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
Reference in New Issue
Block a user