You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/08/06 05:09:12 UTC

[camel] 02/03: CAMEL-7550: camel-jpa producer now has findEntity option to find a single entity using enity manager find which should be faster and more optimized via jpa.

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit f1d33ff95602498569274c913a7c6972d95a5b57
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Aug 6 07:08:15 2019 +0200

    CAMEL-7550: camel-jpa producer now has findEntity option to find a single entity using enity manager find which should be faster and more optimized via jpa.
---
 .../camel-jpa/src/main/docs/jpa-component.adoc     |  3 +-
 .../apache/camel/component/jpa/JpaEndpoint.java    | 16 ++++-
 .../apache/camel/component/jpa/JpaProducer.java    | 41 ++++++++++-
 .../processor/jpa/JpaProducerFindEntityTest.java   | 82 ++++++++++++++++++++++
 .../endpoint/dsl/JpaEndpointBuilderFactory.java    | 26 +++++++
 .../modules/ROOT/pages/jpa-component.adoc          |  3 +-
 6 files changed, 166 insertions(+), 5 deletions(-)

diff --git a/components/camel-jpa/src/main/docs/jpa-component.adoc b/components/camel-jpa/src/main/docs/jpa-component.adoc
index 628535e..4613901 100644
--- a/components/camel-jpa/src/main/docs/jpa-component.adoc
+++ b/components/camel-jpa/src/main/docs/jpa-component.adoc
@@ -136,7 +136,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (44 parameters):
+=== Query Parameters (45 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -163,6 +163,7 @@ with the following path and query parameters:
 | *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
 | *parameters* (consumer) | This key/value mapping is used for building the query parameters. It is expected to be of the generic type java.util.Map where the keys are the named parameters of a given JPA query and the values are their corresponding effective values you want to select for. When it's used for producer, Simple expression can be used as a parameter value. It allows you to retrieve parameter values from the message body, header and etc. |  | Map
 | *pollStrategy* (consumer) | A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel. |  | PollingConsumerPoll Strategy
+| *findEntity* (producer) | If enabled then the producer will find a single entity by using the message body as key and entityType as the class type. This can be used instead of a query to find a single entity. | false | boolean
 | *flushOnSend* (producer) | Flushes the EntityManager after the entity bean has been persisted. | true | boolean
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
 | *remove* (producer) | Indicates to use entityManager.remove(entity). | false | boolean
diff --git a/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaEndpoint.java b/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaEndpoint.java
index 5c6d6a5..70ef706 100644
--- a/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaEndpoint.java
+++ b/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaEndpoint.java
@@ -103,6 +103,8 @@ public class JpaEndpoint extends ScheduledPollEndpoint {
     private boolean remove;
     @UriParam(label = "producer")
     private Boolean useExecuteUpdate;
+    @UriParam(label = "producer")
+    private boolean findEntity;
 
     @UriParam(label = "advanced", prefix = "emf.", multiValue = true)
     private Map<String, Object> entityManagerProperties;
@@ -132,6 +134,7 @@ public class JpaEndpoint extends ScheduledPollEndpoint {
         producer.setNativeQuery(getNativeQuery());
         producer.setParameters(getParameters());
         producer.setResultClass(getResultClass());
+        producer.setFindEntity(isFindEntity());
         producer.setUseExecuteUpdate(isUseExecuteUpdate());
         return producer;
     }
@@ -181,7 +184,6 @@ public class JpaEndpoint extends ScheduledPollEndpoint {
         return "jpa" + (entityType != null ? "://" + entityType.getName() : "");
     }
 
-
     // Properties
     // -------------------------------------------------------------------------
     public Expression getProducerExpression() {
@@ -510,6 +512,18 @@ public class JpaEndpoint extends ScheduledPollEndpoint {
         this.useExecuteUpdate = useExecuteUpdate;
     }
 
+    public boolean isFindEntity() {
+        return findEntity;
+    }
+
+    /**
+     * If enabled then the producer will find a single entity by using the message body as key and entityType as the class type.
+     * This can be used instead of a query to find a single entity.
+     */
+    public void setFindEntity(boolean findEntity) {
+        this.findEntity = findEntity;
+    }
+
     // Implementation methods
     // -------------------------------------------------------------------------
 
diff --git a/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaProducer.java b/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaProducer.java
index 77a5ac9..2db38da 100644
--- a/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaProducer.java
+++ b/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaProducer.java
@@ -42,6 +42,7 @@ public class JpaProducer extends DefaultProducer {
     private String query;
     private String namedQuery;
     private String nativeQuery;
+    private boolean findEntity;
     private Map<String, Object> parameters;
     private Class<?> resultClass;
     private QueryFactory queryFactory;
@@ -111,7 +112,15 @@ public class JpaProducer extends DefaultProducer {
     public void setQuery(String query) {
         this.query = query;
     }
-    
+
+    public boolean isFindEntity() {
+        return findEntity;
+    }
+
+    public void setFindEntity(boolean findEntity) {
+        this.findEntity = findEntity;
+    }
+
     public Class<?> getResultClass() {
         return resultClass;
     }
@@ -151,7 +160,9 @@ public class JpaProducer extends DefaultProducer {
         final EntityManager entityManager = getTargetEntityManager(exchange, entityManagerFactory,
                 getEndpoint().isUsePassedInEntityManager(), getEndpoint().isSharedEntityManager(), true);
 
-        if (getQueryFactory() != null) {
+        if (findEntity) {
+            processFind(exchange, entityManager);
+        } else if (getQueryFactory() != null) {
             processQuery(exchange, entityManager);
         } else {
             processEntity(exchange, entityManager);
@@ -205,6 +216,32 @@ public class JpaProducer extends DefaultProducer {
         }
     }
 
+    protected void processFind(Exchange exchange, EntityManager entityManager) {
+        final Object key = exchange.getMessage().getBody();
+
+        if (key != null) {
+            transactionTemplate.execute(new TransactionCallback<Object>() {
+                public Object doInTransaction(TransactionStatus status) {
+                    if (getEndpoint().isJoinTransaction()) {
+                        entityManager.joinTransaction();
+                    }
+
+                    Object answer = entityManager.find(getEndpoint().getEntityType(), key);
+                    log.debug("Find: {} -> {}", key, answer);
+
+                    Message target = exchange.getPattern().isOutCapable() ? exchange.getOut() : exchange.getIn();
+                    target.setBody(answer);
+
+                    if (getEndpoint().isFlushOnSend()) {
+                        entityManager.flush();
+                    }
+
+                    return null;
+                }
+            });
+        }
+    }
+
     protected void processEntity(Exchange exchange, EntityManager entityManager) {
         final Object values = expression.evaluate(exchange, Object.class);
 
diff --git a/components/camel-jpa/src/test/java/org/apache/camel/processor/jpa/JpaProducerFindEntityTest.java b/components/camel-jpa/src/test/java/org/apache/camel/processor/jpa/JpaProducerFindEntityTest.java
new file mode 100644
index 0000000..62f661d
--- /dev/null
+++ b/components/camel-jpa/src/test/java/org/apache/camel/processor/jpa/JpaProducerFindEntityTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.camel.processor.jpa;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.examples.SendEmail;
+import org.apache.camel.spring.SpringRouteBuilder;
+import org.junit.Test;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.TransactionCallback;
+
+public class JpaProducerFindEntityTest extends AbstractJpaTest {
+    protected static final String SELECT_ALL_STRING = "select x from " + SendEmail.class.getName() + " x";
+
+    @Test
+    public void testFind() throws Exception {
+        SendEmail one = new SendEmail("foo");
+        SendEmail two = new SendEmail("bar");
+
+        save(one);
+        save(two);
+
+        long id = one.getId();
+        long id2 = two.getId();
+
+        getMockEndpoint("mock:result").expectedMessageCount(2);
+
+        SendEmail out = template.requestBody("direct:start", id, SendEmail.class);
+        SendEmail out2 = template.requestBody("direct:start", id2, SendEmail.class);
+
+        assertMockEndpointsSatisfied();
+
+        assertEquals(one.getAddress(), out.getAddress());
+        assertEquals(two.getAddress(), out2.getAddress());
+    }
+
+    protected void save(final Object persistable) {
+        transactionTemplate.execute(new TransactionCallback<Object>() {
+            public Object doInTransaction(TransactionStatus status) {
+                entityManager.joinTransaction();
+                entityManager.persist(persistable);
+                entityManager.flush();
+                return null;
+            }
+        });
+    }
+
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new SpringRouteBuilder() {
+            public void configure() {
+                from("direct:start").to("jpa://" + SendEmail.class.getName() + "?findEntity=true").to("mock:result");
+            }
+        };
+    }
+
+    @Override
+    protected String routeXml() {
+        return "org/apache/camel/processor/jpa/springJpaRouteTest.xml";
+    }
+
+    @Override
+    protected String selectAllString() {
+        return SELECT_ALL_STRING;
+    }
+
+}
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/JpaEndpointBuilderFactory.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/JpaEndpointBuilderFactory.java
index a7d83b0..0bf468f 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/JpaEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/JpaEndpointBuilderFactory.java
@@ -1193,6 +1193,32 @@ public interface JpaEndpointBuilderFactory {
             return this;
         }
         /**
+         * If enabled then the producer will find a single entity by using the
+         * message body as key and entityType as the class type. This can be
+         * used instead of a query to find a single entity.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Group: producer
+         */
+        default JpaEndpointProducerBuilder findEntity(boolean findEntity) {
+            setProperty("findEntity", findEntity);
+            return this;
+        }
+        /**
+         * If enabled then the producer will find a single entity by using the
+         * message body as key and entityType as the class type. This can be
+         * used instead of a query to find a single entity.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Group: producer
+         */
+        default JpaEndpointProducerBuilder findEntity(String findEntity) {
+            setProperty("findEntity", findEntity);
+            return this;
+        }
+        /**
          * Flushes the EntityManager after the entity bean has been persisted.
          * 
          * The option is a: <code>boolean</code> type.
diff --git a/docs/components/modules/ROOT/pages/jpa-component.adoc b/docs/components/modules/ROOT/pages/jpa-component.adoc
index 628535e..3b7d3f5 100644
--- a/docs/components/modules/ROOT/pages/jpa-component.adoc
+++ b/docs/components/modules/ROOT/pages/jpa-component.adoc
@@ -136,7 +136,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (44 parameters):
+=== Query Parameters (45 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -163,6 +163,7 @@ with the following path and query parameters:
 | *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
 | *parameters* (consumer) | This key/value mapping is used for building the query parameters. It is expected to be of the generic type java.util.Map where the keys are the named parameters of a given JPA query and the values are their corresponding effective values you want to select for. When it's used for producer, Simple expression can be used as a parameter value. It allows you to retrieve parameter values from the message body, header and etc. |  | Map
 | *pollStrategy* (consumer) | A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel. |  | PollingConsumerPoll Strategy
+| *findEntity* (producer) | If enabled then the producer will find a single entity by using the message body as key and resultClass as the class type. This can be used instead of using query to find a single entity. | false | boolean
 | *flushOnSend* (producer) | Flushes the EntityManager after the entity bean has been persisted. | true | boolean
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
 | *remove* (producer) | Indicates to use entityManager.remove(entity). | false | boolean