From 8237072f5be774a8de14ff737bd8aa93341c9a6b Mon Sep 17 00:00:00 2001
From: rbygrave
Date: Mon, 1 Dec 2014 23:09:25 +1300
Subject: [PATCH] #217 - ENH: Restore findFutureList() removing its previous
deprecated status. Change implementation to use its own PersistenceContext
(aka PersistenceContextScope.QUERY)
---
.../java/com/avaje/ebean/EbeanServer.java | 16 +-
src/main/java/com/avaje/ebean/FutureList.java | 37 ++-
src/main/java/com/avaje/ebean/Query.java | 6 +-
.../server/core/DefaultServer.java | 14 +-
.../server/expression/JunctionExpression.java | 72 +++++-
.../server/query/QueryFutureList.java | 30 ++-
.../util/DefaultExpressionList.java | 84 ++++++-
.../util/FilterExpressionList.java | 213 ++++++++++--------
.../tests/query/TestQueryFindFutureList.java | 68 ++++++
9 files changed, 399 insertions(+), 141 deletions(-)
create mode 100644 src/test/java/com/avaje/tests/query/TestQueryFindFutureList.java
diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java
index bab70c33e..3d506826f 100644
--- a/src/main/java/com/avaje/ebean/EbeanServer.java
+++ b/src/main/java/com/avaje/ebean/EbeanServer.java
@@ -545,19 +545,20 @@ public interface EbeanServer {
public FutureIds findFutureIds(Query query, Transaction transaction);
/**
- * Execute find list query in a background thread.
+ * Execute find list query in a background thread returning a FutureList object.
*
* This returns a Future object which can be used to cancel, check the
- * execution status (isDone etc) and get the value (with or without a
- * timeout).
- *
- *
+ * execution status (isDone etc) and get the value (with or without a timeout).
+ *
+ * This query will execute in it's own PersistenceContext and using its own transaction.
+ * What that means is that it will not share any bean instances with other queries.
+ *
+ *
* @param query
* the query to execute in the background
* @param transaction
* the transaction (can be null).
* @return a Future object for the list result of the query
- * @deprecated
*/
public FutureList findFutureList(Query query, Transaction transaction);
@@ -568,13 +569,12 @@ public interface EbeanServer {
* execution status (isDone etc) and get the value (with or without a
* timeout).
*
- *
+ *
* @param query
* the query to execute in the background
* @param transaction
* the transaction (can be null).
* @return a Future object for the list result of the query
- * @deprecated
*/
public SqlFutureList findFutureList(SqlQuery query, Transaction transaction);
diff --git a/src/main/java/com/avaje/ebean/FutureList.java b/src/main/java/com/avaje/ebean/FutureList.java
index c0eeb3523..cb4efcb7d 100644
--- a/src/main/java/com/avaje/ebean/FutureList.java
+++ b/src/main/java/com/avaje/ebean/FutureList.java
@@ -1,7 +1,11 @@
package com.avaje.ebean;
+import javax.persistence.PersistenceException;
import java.util.List;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* FutureList represents the result of a background query execution that will
@@ -15,13 +19,13 @@ import java.util.concurrent.Future;
* A simple example:
*
*
- *
+ *
{@code
* // create a query to find all orders
- * Query<Order> query = Ebean.find(Order.class);
+ * Query query = Ebean.find(Order.class);
*
* // execute the query in a background thread
* // immediately returning the futureList
- * FutureList<Order> futureList = query.findFutureList();
+ * FutureList futureList = query.findFutureList();
*
* // do something else ...
*
@@ -35,13 +39,11 @@ import java.util.concurrent.Future;
*
* if (!futureList.isCancelled()){
* // wait for the query to finish and return the list
- * List<Order> list = futureList.get();
+ * List list = futureList.get();
* ...
* }
*
- *
- *
- * @author rbygrave
+ * }
*/
public interface FutureList extends Future> {
@@ -50,4 +52,25 @@ public interface FutureList extends Future> {
*/
public Query getQuery();
+ /**
+ * Same as {@link #get()} but wraps InterruptedException and ExecutionException in the
+ * unchecked PersistenceException.
+ *
+ * @return The query list result
+ *
+ * @throws PersistenceException when a InterruptedException or ExecutionException occurs.
+ */
+ public List getUnchecked();
+
+ /**
+ * Same as {@link #get(long, java.util.concurrent.TimeUnit)} but wraps InterruptedException
+ * and ExecutionException in the unchecked PersistenceException.
+ *
+ * @return The query list result
+ *
+ * @throws TimeoutException if the wait timed out
+ * @throws PersistenceException if a InterruptedException or ExecutionException occurs.
+ */
+ public List getUnchecked(long timeout, TimeUnit unit) throws TimeoutException;
+
}
diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java
index fc26f05f2..f817fb67f 100644
--- a/src/main/java/com/avaje/ebean/Query.java
+++ b/src/main/java/com/avaje/ebean/Query.java
@@ -676,11 +676,11 @@ public interface Query extends Serializable {
/**
* Execute find list query in a background thread.
*
- * Deprecated with a view to simplifying internals.
+ * This query will execute in it's own PersistenceContext and using its own transaction.
+ * What that means is that it will not share any bean instances with other queries.
*
- *
+ *
* @return a Future object for the list result of the query
- * @deprecated
*/
public FutureList findFutureList();
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
index 3acd632d9..eeed0025e 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
@@ -1317,24 +1317,14 @@ public final class DefaultServer implements SpiEbeanServer {
SpiQuery spiQuery = (SpiQuery) query;
spiQuery.setFutureFetch(true);
- // transfer the persistence content from the transaction
- if (spiQuery.getPersistenceContext() == null) {
- if (t != null) {
- spiQuery.setPersistenceContext(((SpiTransaction) t).getPersistenceContext());
- } else {
- SpiTransaction st = getCurrentServerTransaction();
- if (st != null) {
- spiQuery.setPersistenceContext(st.getPersistenceContext());
- }
- }
- }
+ // FutureList query always run in it's own persistence content
+ spiQuery.setPersistenceContext(new DefaultPersistenceContext());
// Create a new transaction solely to execute the findList() at some future time
Transaction newTxn = createTransaction();
CallableQueryList call = new CallableQueryList(this, spiQuery, newTxn);
QueryFutureList queryFuture = new QueryFutureList(call);
backgroundExecutor.execute(queryFuture.getFutureTask());
-
return queryFuture;
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java
index 38ffba170..447034efd 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java
@@ -59,6 +59,7 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr
this.exprList = new DefaultExpressionList(query, parent);
}
+ @Override
public void containsMany(BeanDescriptor> desc, ManyWhereJoins manyWhereJoin) {
List list = exprList.internalList();
@@ -79,17 +80,20 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr
}
}
+ @Override
public Junction add(Expression item) {
SpiExpression i = (SpiExpression) item;
exprList.add(i);
return this;
}
+ @Override
public Junction addAll(ExpressionList addList) {
exprList.addAll(addList);
return this;
}
-
+
+ @Override
public void addBindValues(SpiExpressionRequest request) {
List list = exprList.internalList();
@@ -100,6 +104,7 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr
}
}
+ @Override
public void addSql(SpiExpressionRequest request) {
List list = exprList.internalList();
@@ -122,6 +127,7 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr
/**
* Based on Junction type and all the expression contained.
*/
+ @Override
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
builder.add(JunctionExpression.class).add(joinType);
List list = exprList.internalList();
@@ -130,6 +136,7 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr
}
}
+ @Override
public void queryPlanHash(BeanQueryRequest> request, HashQueryPlanBuilder builder) {
builder.add(JunctionExpression.class).add(joinType);
List list = exprList.internalList();
@@ -138,6 +145,7 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr
}
}
+ @Override
public int queryBindHash() {
int hc = JunctionExpression.class.getName().hashCode();
@@ -149,50 +157,62 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr
return hc;
}
+ @Override
public ExpressionList endJunction() {
return exprList.endJunction();
}
+ @Override
public ExpressionList allEq(Map propertyMap) {
return exprList.allEq(propertyMap);
}
+ @Override
public ExpressionList and(Expression expOne, Expression expTwo) {
return exprList.and(expOne, expTwo);
}
+ @Override
public ExpressionList between(String propertyName, Object value1, Object value2) {
return exprList.between(propertyName, value1, value2);
}
+ @Override
public ExpressionList betweenProperties(String lowProperty, String highProperty, Object value) {
return exprList.betweenProperties(lowProperty, highProperty, value);
}
+ @Override
public Junction conjunction() {
return exprList.conjunction();
}
+ @Override
public ExpressionList contains(String propertyName, String value) {
return exprList.contains(propertyName, value);
}
+ @Override
public Junction disjunction() {
return exprList.disjunction();
}
+ @Override
public ExpressionList endsWith(String propertyName, String value) {
return exprList.endsWith(propertyName, value);
}
+ @Override
public ExpressionList eq(String propertyName, Object value) {
return exprList.eq(propertyName, value);
}
+ @Override
public ExpressionList exampleLike(Object example) {
return exprList.exampleLike(example);
}
+ @Override
public ExpressionList filterMany(String prop) {
throw new RuntimeException("filterMany not allowed on Junction expression list");
}
@@ -202,18 +222,22 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr
return exprList.apply(pathProperties);
}
+ @Override
public FutureIds findFutureIds() {
return exprList.findFutureIds();
}
+ @Override
public FutureList findFutureList() {
return exprList.findFutureList();
}
+ @Override
public FutureRowCount findFutureRowCount() {
return exprList.findFutureRowCount();
}
+ @Override
public List