You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2014/11/14 18:47:28 UTC
[27/50] [abbrv] cayenne git commit: CAY-1959 Chainable API for
SelectQuery
CAY-1959 Chainable API for SelectQuery
* merge method for PrefetchTreeNode for more comprehensive prefetch subtree merging
* using the new merge in SelectQuery as well
UPGRADE NOTES:
The most visible side effect of this change is that Property.xyzPrefetch() method will now return
a root of the prefetch tree that can merged into the query instead of a leaf that can't.
So in an unlikely case someone did MyEntity.MY_PROPERTY.disjoint().setSemantics(JOINT), the last part in this chain
is not longer going to work.
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/4d8b2e1a
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/4d8b2e1a
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/4d8b2e1a
Branch: refs/heads/CAY-1946
Commit: 4d8b2e1a6a6db08bd68ffab227381eb981111893
Parents: fb8660e
Author: aadamchik <aa...@apache.org>
Authored: Sun Nov 9 21:20:21 2014 +0300
Committer: aadamchik <aa...@apache.org>
Committed: Sun Nov 9 21:24:50 2014 +0300
----------------------------------------------------------------------
.../cayenne/query/PrefetchTreeNodeTest.java | 169 ++-
.../java/org/apache/cayenne/exp/Property.java | 812 ++++++-------
.../apache/cayenne/query/BaseQueryMetadata.java | 839 ++++++-------
.../apache/cayenne/query/PrefetchTreeNode.java | 1106 +++++++++---------
.../org/apache/cayenne/query/SelectQuery.java | 7 +-
...ataContextDisjointByIdPrefetch_ExtrasIT.java | 1 +
6 files changed, 1546 insertions(+), 1388 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4d8b2e1a/cayenne-client/src/test/java/org/apache/cayenne/query/PrefetchTreeNodeTest.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/query/PrefetchTreeNodeTest.java b/cayenne-client/src/test/java/org/apache/cayenne/query/PrefetchTreeNodeTest.java
index 90d4169..1dee8a9 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/query/PrefetchTreeNodeTest.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/query/PrefetchTreeNodeTest.java
@@ -18,51 +18,142 @@
****************************************************************/
package org.apache.cayenne.query;
-import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.remote.hessian.service.HessianUtil;
-import org.junit.Test;
-
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.remote.hessian.service.HessianUtil;
+import org.junit.Test;
public class PrefetchTreeNodeTest {
- @Test
- public void testTreeSerializationWithHessian() throws Exception {
- PrefetchTreeNode n1 = new PrefetchTreeNode();
- PrefetchTreeNode n2 = n1.addPath("abc");
-
- PrefetchTreeNode nc1 = (PrefetchTreeNode) HessianUtil.cloneViaClientServerSerialization(n1,
- new EntityResolver());
- assertNotNull(nc1);
-
- PrefetchTreeNode nc2 = nc1.getNode("abc");
- assertNotNull(nc2);
- assertNotSame(nc2, n2);
- assertSame(nc1, nc2.getParent());
- assertEquals("abc", nc2.getName());
- }
-
- @Test
- public void testSubtreeSerializationWithHessian() throws Exception {
- PrefetchTreeNode n1 = new PrefetchTreeNode();
- PrefetchTreeNode n2 = n1.addPath("abc");
- PrefetchTreeNode n3 = n2.addPath("xyz");
-
- // test that substree was serialized as independent tree, instead of
- // sucking
- PrefetchTreeNode nc2 = (PrefetchTreeNode) HessianUtil.cloneViaClientServerSerialization(n2,
- new EntityResolver());
- assertNotNull(nc2);
- assertNull(nc2.getParent());
-
- PrefetchTreeNode nc3 = nc2.getNode("xyz");
- assertNotNull(nc3);
- assertNotSame(nc3, n3);
- assertSame(nc2, nc3.getParent());
- assertEquals("xyz", nc3.getName());
- }
+ @Test
+ public void testTreeSerializationWithHessian() throws Exception {
+ PrefetchTreeNode n1 = new PrefetchTreeNode();
+ PrefetchTreeNode n2 = n1.addPath("abc");
+
+ PrefetchTreeNode nc1 = (PrefetchTreeNode) HessianUtil.cloneViaClientServerSerialization(n1,
+ new EntityResolver());
+ assertNotNull(nc1);
+
+ PrefetchTreeNode nc2 = nc1.getNode("abc");
+ assertNotNull(nc2);
+ assertNotSame(nc2, n2);
+ assertSame(nc1, nc2.getParent());
+ assertEquals("abc", nc2.getName());
+ }
+
+ @Test
+ public void testSubtreeSerializationWithHessian() throws Exception {
+ PrefetchTreeNode n1 = new PrefetchTreeNode();
+ PrefetchTreeNode n2 = n1.addPath("abc");
+ PrefetchTreeNode n3 = n2.addPath("xyz");
+
+ // test that substree was serialized as independent tree, instead of
+ // sucking
+ PrefetchTreeNode nc2 = (PrefetchTreeNode) HessianUtil.cloneViaClientServerSerialization(n2,
+ new EntityResolver());
+ assertNotNull(nc2);
+ assertNull(nc2.getParent());
+
+ PrefetchTreeNode nc3 = nc2.getNode("xyz");
+ assertNotNull(nc3);
+ assertNotSame(nc3, n3);
+ assertSame(nc2, nc3.getParent());
+ assertEquals("xyz", nc3.getName());
+ }
+
+ @Test
+ public void testMerge() {
+ PrefetchTreeNode original = new PrefetchTreeNode();
+ original.addPath("a").setPhantom(true);
+ original.addPath("a.b").setSemantics(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+ original.addPath("a.b").setPhantom(false);
+ original.addPath("c").setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
+ original.addPath("c").setPhantom(false);
+ original.addPath("f").setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
+ original.addPath("f").setPhantom(false);
+
+ PrefetchTreeNode toMerge = new PrefetchTreeNode();
+ toMerge.addPath("a").setPhantom(false);
+ toMerge.addPath("a.b").setSemantics(PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS);
+ toMerge.addPath("d.e").setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
+ toMerge.addPath("d.e").setPhantom(false);
+ toMerge.addPath("c").setSemantics(PrefetchTreeNode.UNDEFINED_SEMANTICS);
+
+ original.merge(toMerge);
+
+ assertSame(original, original.getRoot());
+ assertEquals(4, original.getChildren().size());
+
+ PrefetchTreeNode mergedA = original.getChild("a");
+ assertEquals(1, mergedA.getChildren().size());
+ assertFalse("Phantom flag wasn't turned off", mergedA.isPhantom());
+ assertEquals(PrefetchTreeNode.UNDEFINED_SEMANTICS, mergedA.getSemantics());
+
+ PrefetchTreeNode mergedB = mergedA.getChild("b");
+ assertEquals(0, mergedB.getChildren().size());
+ assertFalse(mergedB.isPhantom());
+ assertEquals("Semantics was't merged", PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS,
+ mergedB.getSemantics());
+
+ PrefetchTreeNode mergedC = original.getChild("c");
+ assertEquals(0, mergedC.getChildren().size());
+ assertFalse(mergedC.isPhantom());
+ assertEquals("Semantics was overridden to undefined", PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS,
+ mergedC.getSemantics());
+
+ PrefetchTreeNode mergedD = original.getChild("d");
+ assertEquals(1, mergedD.getChildren().size());
+ assertTrue(mergedD.isPhantom());
+ assertEquals(PrefetchTreeNode.UNDEFINED_SEMANTICS, mergedD.getSemantics());
+ assertNotSame("Merged node wasn't cloned", toMerge.getChild("d"), mergedD);
+
+ PrefetchTreeNode mergedE = mergedD.getChild("e");
+ assertEquals(0, mergedE.getChildren().size());
+ assertFalse(mergedE.isPhantom());
+ assertEquals(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS, mergedE.getSemantics());
+
+ PrefetchTreeNode mergedF = original.getChild("f");
+ assertEquals(0, mergedF.getChildren().size());
+ assertFalse(mergedF.isPhantom());
+ assertEquals(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS, mergedF.getSemantics());
+ }
+
+ @Test
+ public void testMerge_NonRoot() {
+ PrefetchTreeNode original = new PrefetchTreeNode();
+ original.addPath("a").setPhantom(true);
+ original.addPath("a.b").setSemantics(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+ original.addPath("a.b").setPhantom(false);
+
+ PrefetchTreeNode toMerge = new PrefetchTreeNode(null, "a.b.c");
+ toMerge.setPhantom(false);
+ toMerge.setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
+
+ original.merge(toMerge);
+
+ assertSame(original, original.getRoot());
+ assertEquals(1, original.getChildren().size());
+
+ PrefetchTreeNode mergedA = original.getChild("a");
+ assertEquals(1, mergedA.getChildren().size());
+ assertTrue(mergedA.isPhantom());
+ assertEquals(PrefetchTreeNode.UNDEFINED_SEMANTICS, mergedA.getSemantics());
+
+ PrefetchTreeNode mergedB = mergedA.getChild("b");
+ assertEquals(1, mergedB.getChildren().size());
+ assertFalse(mergedB.isPhantom());
+ assertEquals(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS, mergedB.getSemantics());
+
+ PrefetchTreeNode mergedC = mergedB.getChild("c");
+ assertEquals(0, mergedC.getChildren().size());
+ assertFalse(mergedC.isPhantom());
+ assertEquals(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS, mergedC.getSemantics());
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4d8b2e1a/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java
index 999b346..48f1549 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/Property.java
@@ -48,405 +48,417 @@ import org.apache.cayenne.reflect.PropertyUtils;
*/
public class Property<E> {
- /**
- * Name of the property in the object
- */
- private final String name;
-
- /**
- * Constructs a new property with the given name.
- */
- public Property(String name) {
- this.name = name;
- }
-
- /**
- * @return Name of the property in the object.
- */
- public String getName() {
- return name;
- }
-
- @Override
- public int hashCode() {
- return getName().hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof Property && ((Property<?>) obj).getName().equals(getName());
- }
-
- /**
- * @return Constructs a property path by appending the argument to the
- * existing property separated by a dot
- */
- public Property<Object> dot(String property) {
- return new Property<Object>(getName() + "." + property);
- }
-
- /**
- * @return Constructs a property path by appending the argument to the
- * existing property separated by a dot
- */
- public <T> Property<T> dot(Property<T> property) {
- return new Property<T>(getName() + "." + property.getName());
- }
-
- /**
- * Returns a version of this property that represents an OUTER join. It is
- * up to caller to ensure that the property corresponds to a relationship,
- * as "outer" attributes make no sense.
- */
- public Property<E> outer() {
- return isOuter() ? this: new Property<E>(name + "+");
- }
-
- private boolean isOuter() {
- return name.endsWith("+");
- }
-
- /**
- * @return An expression representing null.
- */
- public Expression isNull() {
- return ExpressionFactory.matchExp(getName(), null);
- }
-
- /**
- * @return An expression representing a non-null value.
- */
- public Expression isNotNull() {
- return ExpressionFactory.matchExp(getName(), null).notExp();
- }
-
- /**
- * @return An expression representing equality to TRUE.
- */
- public Expression isTrue() {
- return ExpressionFactory.matchExp(getName(), Boolean.TRUE);
- }
-
- /**
- * @return An expression representing equality to FALSE.
- */
- public Expression isFalse() {
- return ExpressionFactory.matchExp(getName(), Boolean.FALSE);
- }
-
- /**
- * @return An expression representing equality to a value.
- */
- public Expression eq(E value) {
- return ExpressionFactory.matchExp(getName(), value);
- }
-
- /**
- * @return An expression representing equality between two attributes
- * (columns).
- */
- public Expression eq(Property<?> value) {
- return ExpressionFactory.matchExp(getName(), new ASTObjPath(value.getName()));
- }
-
- /**
- * @return An expression representing inequality to a value.
- */
- public Expression ne(E value) {
- return ExpressionFactory.noMatchExp(getName(), value);
- }
-
- /**
- * @return An expression representing inequality between two attributes
- * (columns).
- */
- public Expression ne(Property<?> value) {
- return ExpressionFactory.noMatchExp(getName(), new ASTObjPath(value.getName()));
- }
-
- /**
- * @return An expression for a Database "Like" query.
- */
- public Expression like(E value) {
- return ExpressionFactory.likeExp(getName(), value);
- }
-
- /**
- * @return An expression for a case insensitive "Like" query.
- */
- public Expression likeInsensitive(E value) {
- return ExpressionFactory.likeIgnoreCaseExp(getName(), value);
- }
-
- /**
- * @return An expression for a Database "NOT LIKE" query.
- */
- public Expression nlike(E value) {
- return ExpressionFactory.notLikeExp(getName(), value);
- }
-
- /**
- * @return An expression for a case insensitive "NOT LIKE" query.
- */
- public Expression nlikeInsensitive(E value) {
- return ExpressionFactory.notLikeIgnoreCaseExp(getName(), value);
- }
-
- /**
- * @return An expression checking for objects between a lower and upper
- * bound inclusive
- *
- * @param lower
- * The lower bound.
- * @param upper
- * The upper bound.
- */
- public Expression between(E lower, E upper) {
- return ExpressionFactory.betweenExp(getName(), lower, upper);
- }
-
- /**
- * @return An expression for finding objects with values in the given set.
- */
- public Expression in(E firstValue, E... moreValues) {
-
- int moreValuesLength = moreValues != null ? moreValues.length : 0;
-
- Object[] values = new Object[moreValuesLength + 1];
- values[0] = firstValue;
-
- if (moreValuesLength > 0) {
- System.arraycopy(moreValues, 0, values, 1, moreValuesLength);
- }
-
- return ExpressionFactory.inExp(getName(), values);
- }
-
- /**
- * @return An expression for finding objects with values not in the given
- * set.
- */
- public Expression nin(E firstValue, E... moreValues) {
-
- int moreValuesLength = moreValues != null ? moreValues.length : 0;
-
- Object[] values = new Object[moreValuesLength + 1];
- values[0] = firstValue;
-
- if (moreValuesLength > 0) {
- System.arraycopy(moreValues, 0, values, 1, moreValuesLength);
- }
-
- return ExpressionFactory.notInExp(getName(), values);
- }
-
- /**
- * @return An expression for finding objects with values in the given set.
- */
- public Expression in(Collection<E> values) {
- return ExpressionFactory.inExp(getName(), values);
- }
-
- /**
- * @return An expression for finding objects with values not in the given
- * set.
- */
- public Expression nin(Collection<E> values) {
- return ExpressionFactory.notInExp(getName(), values);
- }
-
- /**
- * @return A greater than Expression.
- */
- public Expression gt(E value) {
- return ExpressionFactory.greaterExp(getName(), value);
- }
-
- /**
- * @return Represents a greater than relationship between two attributes
- * (columns).
- */
- public Expression gt(Property<?> value) {
- return ExpressionFactory.greaterExp(getName(), new ASTObjPath(value.getName()));
- }
-
- /**
- * @return A greater than or equal to Expression.
- */
- public Expression gte(E value) {
- return ExpressionFactory.greaterOrEqualExp(getName(), value);
- }
-
- /**
- * @return Represents a greater than or equal relationship between two
- * attributes (columns).
- */
- public Expression gte(Property<?> value) {
- return ExpressionFactory.greaterOrEqualExp(getName(), new ASTObjPath(value.getName()));
- }
-
- /**
- * @return A less than Expression.
- */
- public Expression lt(E value) {
- return ExpressionFactory.lessExp(getName(), value);
- }
-
- /**
- * @return Represents a less than relationship between two attributes
- * (columns).
- */
- public Expression lt(Property<?> value) {
- return ExpressionFactory.lessExp(getName(), new ASTObjPath(value.getName()));
- }
-
- /**
- * @return A less than or equal to Expression.
- */
- public Expression lte(E value) {
- return ExpressionFactory.lessOrEqualExp(getName(), value);
- }
-
- /**
- * @return Represents a less than or equal relationship between two
- * attributes (columns).
- */
- public Expression lte(Property<?> value) {
- return ExpressionFactory.lessOrEqualExp(getName(), new ASTObjPath(value.getName()));
- }
-
- /**
- * @return Ascending sort orderings on this property.
- */
- public Ordering asc() {
- return new Ordering(getName(), SortOrder.ASCENDING);
- }
-
- /**
- * @return Ascending sort orderings on this property.
- */
- public List<Ordering> ascs() {
- List<Ordering> result = new ArrayList<Ordering>(1);
- result.add(asc());
- return result;
- }
-
- /**
- * @return Ascending case insensitive sort orderings on this property.
- */
- public Ordering ascInsensitive() {
- return new Ordering(getName(), SortOrder.ASCENDING_INSENSITIVE);
- }
-
- /**
- * @return Ascending case insensitive sort orderings on this property.
- */
- public List<Ordering> ascInsensitives() {
- List<Ordering> result = new ArrayList<Ordering>(1);
- result.add(ascInsensitive());
- return result;
- }
-
- /**
- * @return Descending sort orderings on this property.
- */
- public Ordering desc() {
- return new Ordering(getName(), SortOrder.DESCENDING);
- }
-
- /**
- * @return Descending sort orderings on this property.
- */
- public List<Ordering> descs() {
- List<Ordering> result = new ArrayList<Ordering>(1);
- result.add(desc());
- return result;
- }
-
- /**
- * @return Descending case insensitive sort orderings on this property.
- */
- public Ordering descInsensitive() {
- return new Ordering(getName(), SortOrder.DESCENDING_INSENSITIVE);
- }
-
- /**
- * @return Descending case insensitive sort orderings on this property.
- */
- public List<Ordering> descInsensitives() {
- List<Ordering> result = new ArrayList<Ordering>(1);
- result.add(descInsensitive());
- return result;
- }
-
- public PrefetchTreeNode joint() {
- PrefetchTreeNode node = prefetch();
- node.setSemantics(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
- return node;
- }
-
- public PrefetchTreeNode disjoint() {
- PrefetchTreeNode node = prefetch();
- node.setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
- return node;
- }
-
- public PrefetchTreeNode disjointById() {
- PrefetchTreeNode node = prefetch();
- node.setSemantics(PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS);
- return node;
- }
-
- PrefetchTreeNode prefetch() {
-
- // TODO: not very efficient - we are creating a prefetch that
- // SelectQuery would throw away and recreate...
- PrefetchTreeNode root = new PrefetchTreeNode();
- PrefetchTreeNode node = root.addPath(name);
- node.setPhantom(false);
- return node;
- }
-
- /**
- * Extracts property value from an object using JavaBean-compatible
- * introspection with one addition - a property can be a dot-separated
- * property name path.
- */
- @SuppressWarnings("unchecked")
- public E getFrom(Object bean) {
- return (E) PropertyUtils.getProperty(bean, getName());
- }
-
- /**
- * Extracts property value from a collection of objects using
- * JavaBean-compatible introspection with one addition - a property can be a
- * dot-separated property name path.
- */
- public List<E> getFromAll(Collection<?> beans) {
- List<E> result = new ArrayList<E>(beans.size());
- for (Object bean : beans) {
- result.add(getFrom(bean));
- }
- return result;
- }
-
- /**
- * Sets a property value in 'obj' using JavaBean-compatible introspection
- * with one addition - a property can be a dot-separated property name path.
- */
- public void setIn(Object bean, E value) {
- PropertyUtils.setProperty(bean, getName(), value);
- }
-
- /**
- * Sets a property value in a collection of objects using
- * JavaBean-compatible introspection with one addition - a property can be a
- * dot-separated property name path.
- */
- public void setInAll(Collection<?> beans, E value) {
- for (Object bean : beans) {
- setIn(bean, value);
- }
- }
+ /**
+ * Name of the property in the object
+ */
+ private final String name;
+
+ /**
+ * Constructs a new property with the given name.
+ */
+ public Property(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return Name of the property in the object.
+ */
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ return getName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof Property && ((Property<?>) obj).getName().equals(getName());
+ }
+
+ /**
+ * @return Constructs a property path by appending the argument to the
+ * existing property separated by a dot
+ */
+ public Property<Object> dot(String property) {
+ return new Property<Object>(getName() + "." + property);
+ }
+
+ /**
+ * @return Constructs a property path by appending the argument to the
+ * existing property separated by a dot
+ */
+ public <T> Property<T> dot(Property<T> property) {
+ return new Property<T>(getName() + "." + property.getName());
+ }
+
+ /**
+ * Returns a version of this property that represents an OUTER join. It is
+ * up to caller to ensure that the property corresponds to a relationship,
+ * as "outer" attributes make no sense.
+ */
+ public Property<E> outer() {
+ return isOuter() ? this : new Property<E>(name + "+");
+ }
+
+ private boolean isOuter() {
+ return name.endsWith("+");
+ }
+
+ /**
+ * @return An expression representing null.
+ */
+ public Expression isNull() {
+ return ExpressionFactory.matchExp(getName(), null);
+ }
+
+ /**
+ * @return An expression representing a non-null value.
+ */
+ public Expression isNotNull() {
+ return ExpressionFactory.matchExp(getName(), null).notExp();
+ }
+
+ /**
+ * @return An expression representing equality to TRUE.
+ */
+ public Expression isTrue() {
+ return ExpressionFactory.matchExp(getName(), Boolean.TRUE);
+ }
+
+ /**
+ * @return An expression representing equality to FALSE.
+ */
+ public Expression isFalse() {
+ return ExpressionFactory.matchExp(getName(), Boolean.FALSE);
+ }
+
+ /**
+ * @return An expression representing equality to a value.
+ */
+ public Expression eq(E value) {
+ return ExpressionFactory.matchExp(getName(), value);
+ }
+
+ /**
+ * @return An expression representing equality between two attributes
+ * (columns).
+ */
+ public Expression eq(Property<?> value) {
+ return ExpressionFactory.matchExp(getName(), new ASTObjPath(value.getName()));
+ }
+
+ /**
+ * @return An expression representing inequality to a value.
+ */
+ public Expression ne(E value) {
+ return ExpressionFactory.noMatchExp(getName(), value);
+ }
+
+ /**
+ * @return An expression representing inequality between two attributes
+ * (columns).
+ */
+ public Expression ne(Property<?> value) {
+ return ExpressionFactory.noMatchExp(getName(), new ASTObjPath(value.getName()));
+ }
+
+ /**
+ * @return An expression for a Database "Like" query.
+ */
+ public Expression like(E value) {
+ return ExpressionFactory.likeExp(getName(), value);
+ }
+
+ /**
+ * @return An expression for a case insensitive "Like" query.
+ */
+ public Expression likeInsensitive(E value) {
+ return ExpressionFactory.likeIgnoreCaseExp(getName(), value);
+ }
+
+ /**
+ * @return An expression for a Database "NOT LIKE" query.
+ */
+ public Expression nlike(E value) {
+ return ExpressionFactory.notLikeExp(getName(), value);
+ }
+
+ /**
+ * @return An expression for a case insensitive "NOT LIKE" query.
+ */
+ public Expression nlikeInsensitive(E value) {
+ return ExpressionFactory.notLikeIgnoreCaseExp(getName(), value);
+ }
+
+ /**
+ * @return An expression checking for objects between a lower and upper
+ * bound inclusive
+ *
+ * @param lower
+ * The lower bound.
+ * @param upper
+ * The upper bound.
+ */
+ public Expression between(E lower, E upper) {
+ return ExpressionFactory.betweenExp(getName(), lower, upper);
+ }
+
+ /**
+ * @return An expression for finding objects with values in the given set.
+ */
+ public Expression in(E firstValue, E... moreValues) {
+
+ int moreValuesLength = moreValues != null ? moreValues.length : 0;
+
+ Object[] values = new Object[moreValuesLength + 1];
+ values[0] = firstValue;
+
+ if (moreValuesLength > 0) {
+ System.arraycopy(moreValues, 0, values, 1, moreValuesLength);
+ }
+
+ return ExpressionFactory.inExp(getName(), values);
+ }
+
+ /**
+ * @return An expression for finding objects with values not in the given
+ * set.
+ */
+ public Expression nin(E firstValue, E... moreValues) {
+
+ int moreValuesLength = moreValues != null ? moreValues.length : 0;
+
+ Object[] values = new Object[moreValuesLength + 1];
+ values[0] = firstValue;
+
+ if (moreValuesLength > 0) {
+ System.arraycopy(moreValues, 0, values, 1, moreValuesLength);
+ }
+
+ return ExpressionFactory.notInExp(getName(), values);
+ }
+
+ /**
+ * @return An expression for finding objects with values in the given set.
+ */
+ public Expression in(Collection<E> values) {
+ return ExpressionFactory.inExp(getName(), values);
+ }
+
+ /**
+ * @return An expression for finding objects with values not in the given
+ * set.
+ */
+ public Expression nin(Collection<E> values) {
+ return ExpressionFactory.notInExp(getName(), values);
+ }
+
+ /**
+ * @return A greater than Expression.
+ */
+ public Expression gt(E value) {
+ return ExpressionFactory.greaterExp(getName(), value);
+ }
+
+ /**
+ * @return Represents a greater than relationship between two attributes
+ * (columns).
+ */
+ public Expression gt(Property<?> value) {
+ return ExpressionFactory.greaterExp(getName(), new ASTObjPath(value.getName()));
+ }
+
+ /**
+ * @return A greater than or equal to Expression.
+ */
+ public Expression gte(E value) {
+ return ExpressionFactory.greaterOrEqualExp(getName(), value);
+ }
+
+ /**
+ * @return Represents a greater than or equal relationship between two
+ * attributes (columns).
+ */
+ public Expression gte(Property<?> value) {
+ return ExpressionFactory.greaterOrEqualExp(getName(), new ASTObjPath(value.getName()));
+ }
+
+ /**
+ * @return A less than Expression.
+ */
+ public Expression lt(E value) {
+ return ExpressionFactory.lessExp(getName(), value);
+ }
+
+ /**
+ * @return Represents a less than relationship between two attributes
+ * (columns).
+ */
+ public Expression lt(Property<?> value) {
+ return ExpressionFactory.lessExp(getName(), new ASTObjPath(value.getName()));
+ }
+
+ /**
+ * @return A less than or equal to Expression.
+ */
+ public Expression lte(E value) {
+ return ExpressionFactory.lessOrEqualExp(getName(), value);
+ }
+
+ /**
+ * @return Represents a less than or equal relationship between two
+ * attributes (columns).
+ */
+ public Expression lte(Property<?> value) {
+ return ExpressionFactory.lessOrEqualExp(getName(), new ASTObjPath(value.getName()));
+ }
+
+ /**
+ * @return Ascending sort orderings on this property.
+ */
+ public Ordering asc() {
+ return new Ordering(getName(), SortOrder.ASCENDING);
+ }
+
+ /**
+ * @return Ascending sort orderings on this property.
+ */
+ public List<Ordering> ascs() {
+ List<Ordering> result = new ArrayList<Ordering>(1);
+ result.add(asc());
+ return result;
+ }
+
+ /**
+ * @return Ascending case insensitive sort orderings on this property.
+ */
+ public Ordering ascInsensitive() {
+ return new Ordering(getName(), SortOrder.ASCENDING_INSENSITIVE);
+ }
+
+ /**
+ * @return Ascending case insensitive sort orderings on this property.
+ */
+ public List<Ordering> ascInsensitives() {
+ List<Ordering> result = new ArrayList<Ordering>(1);
+ result.add(ascInsensitive());
+ return result;
+ }
+
+ /**
+ * @return Descending sort orderings on this property.
+ */
+ public Ordering desc() {
+ return new Ordering(getName(), SortOrder.DESCENDING);
+ }
+
+ /**
+ * @return Descending sort orderings on this property.
+ */
+ public List<Ordering> descs() {
+ List<Ordering> result = new ArrayList<Ordering>(1);
+ result.add(desc());
+ return result;
+ }
+
+ /**
+ * @return Descending case insensitive sort orderings on this property.
+ */
+ public Ordering descInsensitive() {
+ return new Ordering(getName(), SortOrder.DESCENDING_INSENSITIVE);
+ }
+
+ /**
+ * @return Descending case insensitive sort orderings on this property.
+ */
+ public List<Ordering> descInsensitives() {
+ List<Ordering> result = new ArrayList<Ordering>(1);
+ result.add(descInsensitive());
+ return result;
+ }
+
+ /**
+ * Returns a prefetch tree that follows this property path, potentially
+ * spanning a number of phantom nodes, and having a single leaf with "joint"
+ * prefetch semantics.
+ */
+ public PrefetchTreeNode joint() {
+ PrefetchTreeNode node = prefetch();
+ node.setSemantics(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+ return node.getRoot();
+ }
+
+ /**
+ * Returns a prefetch tree that follows this property path, potentially
+ * spanning a number of phantom nodes, and having a single leaf with
+ * "disjoint" prefetch semantics.
+ */
+ public PrefetchTreeNode disjoint() {
+ PrefetchTreeNode node = prefetch();
+ node.setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
+ return node.getRoot();
+ }
+
+ /**
+ * Returns a prefetch tree that follows this property path, potentially
+ * spanning a number of phantom nodes, and having a single leaf with
+ * "disjoint by id" prefetch semantics.
+ */
+ public PrefetchTreeNode disjointById() {
+ PrefetchTreeNode node = prefetch();
+ node.setSemantics(PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS);
+ return node.getRoot();
+ }
+
+ PrefetchTreeNode prefetch() {
+ PrefetchTreeNode root = new PrefetchTreeNode();
+ PrefetchTreeNode node = root.addPath(name);
+ node.setPhantom(false);
+ return node;
+ }
+
+ /**
+ * Extracts property value from an object using JavaBean-compatible
+ * introspection with one addition - a property can be a dot-separated
+ * property name path.
+ */
+ @SuppressWarnings("unchecked")
+ public E getFrom(Object bean) {
+ return (E) PropertyUtils.getProperty(bean, getName());
+ }
+
+ /**
+ * Extracts property value from a collection of objects using
+ * JavaBean-compatible introspection with one addition - a property can be a
+ * dot-separated property name path.
+ */
+ public List<E> getFromAll(Collection<?> beans) {
+ List<E> result = new ArrayList<E>(beans.size());
+ for (Object bean : beans) {
+ result.add(getFrom(bean));
+ }
+ return result;
+ }
+
+ /**
+ * Sets a property value in 'obj' using JavaBean-compatible introspection
+ * with one addition - a property can be a dot-separated property name path.
+ */
+ public void setIn(Object bean, E value) {
+ PropertyUtils.setProperty(bean, getName(), value);
+ }
+
+ /**
+ * Sets a property value in a collection of objects using
+ * JavaBean-compatible introspection with one addition - a property can be a
+ * dot-separated property name path.
+ */
+ public void setInAll(Collection<?> beans, E value) {
+ for (Object bean : beans) {
+ setIn(bean, value);
+ }
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4d8b2e1a/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java b/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java
index d97e811..7f7c6dd 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/BaseQueryMetadata.java
@@ -43,417 +43,430 @@ import org.apache.cayenne.util.XMLSerializable;
*/
class BaseQueryMetadata implements QueryMetadata, XMLSerializable, Serializable {
- int fetchLimit = QueryMetadata.FETCH_LIMIT_DEFAULT;
- int fetchOffset = QueryMetadata.FETCH_OFFSET_DEFAULT;
-
- int statementFetchSize = QueryMetadata.FETCH_OFFSET_DEFAULT;
-
- int pageSize = QueryMetadata.PAGE_SIZE_DEFAULT;
- boolean fetchingDataRows = QueryMetadata.FETCHING_DATA_ROWS_DEFAULT;
- QueryCacheStrategy cacheStrategy = QueryCacheStrategy.getDefaultStrategy();
-
- PrefetchTreeNode prefetchTree;
- String cacheKey;
- String[] cacheGroups;
-
- transient List<Object> resultSetMapping;
- transient DbEntity dbEntity;
- transient DataMap dataMap;
- transient Object lastRoot;
- transient ClassDescriptor classDescriptor;
- transient EntityResolver lastEntityResolver;
-
- /**
- * Copies values of another QueryMetadata object to this object.
- */
- void copyFromInfo(QueryMetadata info) {
- this.lastEntityResolver = null;
- this.lastRoot = null;
- this.classDescriptor = null;
- this.dbEntity = null;
- this.dataMap = null;
-
- this.fetchingDataRows = info.isFetchingDataRows();
- this.fetchLimit = info.getFetchLimit();
- this.pageSize = info.getPageSize();
- this.cacheStrategy = info.getCacheStrategy();
- this.cacheKey = info.getCacheKey();
- this.cacheGroups = info.getCacheGroups();
- this.resultSetMapping = info.getResultSetMapping();
-
- setPrefetchTree(info.getPrefetchTree());
- }
-
- boolean resolve(Object root, EntityResolver resolver, String cacheKey) {
-
- if (lastRoot != root || lastEntityResolver != resolver) {
-
- this.cacheKey = cacheKey;
-
- this.classDescriptor = null;
- this.dbEntity = null;
- this.dataMap = null;
-
- ObjEntity entity = null;
-
- if (root != null) {
- if (root instanceof Class<?>) {
- entity = resolver.getObjEntity((Class<?>) root);
- if (entity == null) { // entity not found, try to resolve it
- // with
- // client resolver
- EntityResolver clientResolver = resolver.getClientEntityResolver();
- if (clientResolver != resolver) {
- ObjEntity clientEntity = clientResolver.getObjEntity((Class<?>) root);
-
- if (clientEntity != null) {
- entity = resolver.getObjEntity(clientEntity.getName());
- }
- }
- }
-
- if (entity != null) {
- this.dbEntity = entity.getDbEntity();
- this.dataMap = entity.getDataMap();
- }
- } else if (root instanceof ObjEntity) {
- entity = (ObjEntity) root;
- this.dbEntity = entity.getDbEntity();
- this.dataMap = entity.getDataMap();
- } else if (root instanceof String) {
- entity = resolver.getObjEntity((String) root);
- if (entity != null) {
- this.dbEntity = entity.getDbEntity();
- this.dataMap = entity.getDataMap();
- }
- } else if (root instanceof DbEntity) {
- this.dbEntity = (DbEntity) root;
- this.dataMap = dbEntity.getDataMap();
- } else if (root instanceof DataMap) {
- this.dataMap = (DataMap) root;
- } else if (root instanceof Persistent) {
- entity = resolver.getObjEntity((Persistent) root);
- if (entity != null) {
- this.dbEntity = entity.getDbEntity();
- this.dataMap = entity.getDataMap();
- }
- }
- }
-
- if (entity != null) {
- this.classDescriptor = resolver.getClassDescriptor(entity.getName());
- }
-
- this.lastRoot = root;
- this.lastEntityResolver = resolver;
-
- return true;
- }
-
- return false;
- }
-
- void initWithProperties(Map<String, ?> properties) {
- // must init defaults even if properties are empty
- if (properties == null) {
- properties = Collections.EMPTY_MAP;
- }
-
- Object fetchOffset = properties.get(QueryMetadata.FETCH_OFFSET_PROPERTY);
- Object fetchLimit = properties.get(QueryMetadata.FETCH_LIMIT_PROPERTY);
- Object pageSize = properties.get(QueryMetadata.PAGE_SIZE_PROPERTY);
- Object statementFetchSize = properties.get(QueryMetadata.STATEMENT_FETCH_SIZE_PROPERTY);
- Object fetchingDataRows = properties.get(QueryMetadata.FETCHING_DATA_ROWS_PROPERTY);
-
- Object cacheStrategy = properties.get(QueryMetadata.CACHE_STRATEGY_PROPERTY);
-
- Object cacheGroups = properties.get(QueryMetadata.CACHE_GROUPS_PROPERTY);
-
- // init ivars from properties
- this.fetchOffset = (fetchOffset != null) ? Integer.parseInt(fetchOffset.toString())
- : QueryMetadata.FETCH_OFFSET_DEFAULT;
-
- this.fetchLimit = (fetchLimit != null) ? Integer.parseInt(fetchLimit.toString())
- : QueryMetadata.FETCH_LIMIT_DEFAULT;
-
- this.pageSize = (pageSize != null) ? Integer.parseInt(pageSize.toString()) : QueryMetadata.PAGE_SIZE_DEFAULT;
-
- this.statementFetchSize = (statementFetchSize != null) ? Integer.parseInt(statementFetchSize.toString())
- : QueryMetadata.STATEMENT_FETCH_SIZE_DEFAULT;
-
- this.fetchingDataRows = (fetchingDataRows != null) ? "true".equalsIgnoreCase(fetchingDataRows.toString())
- : QueryMetadata.FETCHING_DATA_ROWS_DEFAULT;
-
- this.cacheStrategy = (cacheStrategy != null) ? QueryCacheStrategy.safeValueOf(cacheStrategy.toString())
- : QueryCacheStrategy.getDefaultStrategy();
-
- this.cacheGroups = null;
- if (cacheGroups instanceof String[]) {
- this.cacheGroups = (String[]) cacheGroups;
- } else if (cacheGroups instanceof String) {
- StringTokenizer toks = new StringTokenizer(cacheGroups.toString(), ",");
- this.cacheGroups = new String[toks.countTokens()];
- for (int i = 0; i < this.cacheGroups.length; i++) {
- this.cacheGroups[i] = toks.nextToken();
- }
- }
- }
-
- public void encodeAsXML(XMLEncoder encoder) {
-
- if (fetchingDataRows != QueryMetadata.FETCHING_DATA_ROWS_DEFAULT) {
- encoder.printProperty(QueryMetadata.FETCHING_DATA_ROWS_PROPERTY, fetchingDataRows);
- }
-
- if (fetchOffset != QueryMetadata.FETCH_OFFSET_DEFAULT) {
- encoder.printProperty(QueryMetadata.FETCH_OFFSET_PROPERTY, fetchOffset);
- }
-
- if (fetchLimit != QueryMetadata.FETCH_LIMIT_DEFAULT) {
- encoder.printProperty(QueryMetadata.FETCH_LIMIT_PROPERTY, fetchLimit);
- }
-
- if (pageSize != QueryMetadata.PAGE_SIZE_DEFAULT) {
- encoder.printProperty(QueryMetadata.PAGE_SIZE_PROPERTY, pageSize);
- }
-
- if (cacheStrategy != null && QueryCacheStrategy.getDefaultStrategy() != cacheStrategy) {
- encoder.printProperty(QueryMetadata.CACHE_STRATEGY_PROPERTY, cacheStrategy.name());
- }
-
- if (statementFetchSize != QueryMetadata.STATEMENT_FETCH_SIZE_DEFAULT) {
- encoder.printProperty(QueryMetadata.STATEMENT_FETCH_SIZE_PROPERTY, statementFetchSize);
- }
-
- if (prefetchTree != null) {
- prefetchTree.encodeAsXML(encoder);
- }
-
- if (cacheGroups != null && cacheGroups.length > 0) {
- StringBuilder buffer = new StringBuilder(cacheGroups[0]);
- for (int i = 1; i < cacheGroups.length; i++) {
- buffer.append(',').append(cacheGroups[i]);
- }
- encoder.printProperty(QueryMetadata.CACHE_GROUPS_PROPERTY, buffer.toString());
- }
- }
-
- /**
- * @since 1.2
- */
- public String getCacheKey() {
- return cacheKey;
- }
-
- /**
- * @since 1.2
- */
- public DataMap getDataMap() {
- return dataMap;
- }
-
- /**
- * @since 1.2
- */
- public Procedure getProcedure() {
- return null;
- }
-
- /**
- * @since 3.0
- */
- public Map<String, String> getPathSplitAliases() {
- return Collections.emptyMap();
- }
-
- /**
- * @since 1.2
- */
- public DbEntity getDbEntity() {
- return dbEntity;
- }
-
- /**
- * @since 1.2
- */
- public ObjEntity getObjEntity() {
- return classDescriptor != null ? classDescriptor.getEntity() : null;
- }
-
- /**
- * @since 3.0
- */
- public ClassDescriptor getClassDescriptor() {
- return classDescriptor;
- }
-
- /**
- * @since 3.0
- */
- public List<Object> getResultSetMapping() {
- return resultSetMapping;
- }
-
- /**
- * @since 1.2
- */
- public PrefetchTreeNode getPrefetchTree() {
- return prefetchTree;
- }
-
- void setPrefetchTree(PrefetchTreeNode prefetchTree) {
- this.prefetchTree = prefetchTree != null ? deepClone(prefetchTree, null) : null;
- }
-
- private PrefetchTreeNode deepClone(PrefetchTreeNode source, PrefetchTreeNode targetParent) {
-
- PrefetchTreeNode target = new PrefetchTreeNode(targetParent, source.getName());
- target.setEjbqlPathEntityId(source.getEjbqlPathEntityId());
- target.setEntityName(source.getEntityName());
- target.setPhantom(source.isPhantom());
- target.setSemantics(source.getSemantics());
-
- for (PrefetchTreeNode child : source.getChildren()) {
- target.addChild(deepClone(child, target));
- }
-
- return target;
- }
-
- /**
- * @since 3.0
- */
- public QueryCacheStrategy getCacheStrategy() {
- return cacheStrategy;
- }
-
- /**
- * @since 3.0
- */
- void setCacheStrategy(QueryCacheStrategy cacheStrategy) {
- this.cacheStrategy = cacheStrategy;
- }
-
- /**
- * @since 3.0
- */
- public String[] getCacheGroups() {
- return cacheGroups;
- }
-
- /**
- * @since 3.0
- */
- void setCacheGroups(String... groups) {
- this.cacheGroups = groups;
- }
-
- public boolean isFetchingDataRows() {
- return fetchingDataRows;
- }
-
- public int getFetchLimit() {
- return fetchLimit;
- }
-
- public int getPageSize() {
- return pageSize;
- }
-
- public Query getOrginatingQuery() {
- return null;
- }
-
- /**
- * @since 3.0
- */
- public int getFetchOffset() {
- return fetchOffset;
- }
-
- public boolean isRefreshingObjects() {
- return true;
- }
-
- void setFetchingDataRows(boolean b) {
- fetchingDataRows = b;
- }
-
- void setFetchLimit(int i) {
- fetchLimit = i;
- }
-
- void setFetchOffset(int i) {
- fetchOffset = i;
- }
-
- void setPageSize(int i) {
- pageSize = i;
- }
-
- /**
- * Sets statement's fetch size (0 for no default size)
- *
- * @since 3.0
- */
- void setStatementFetchSize(int size) {
- this.statementFetchSize = size;
- }
-
- /**
- * @return statement's fetch size
- * @since 3.0
- */
- public int getStatementFetchSize() {
- return statementFetchSize;
- }
-
- /**
- * Adds a joint prefetch.
- *
- * @since 1.2
- */
- PrefetchTreeNode addPrefetch(String path, int semantics) {
- if (prefetchTree == null) {
- prefetchTree = new PrefetchTreeNode();
- }
-
- PrefetchTreeNode node = prefetchTree.addPath(path);
- node.setSemantics(semantics);
- node.setPhantom(false);
- return node;
- }
-
- /**
- * Adds all prefetches from a provided collection.
- *
- * @since 1.2
- */
- void addPrefetches(Collection<String> prefetches, int semantics) {
- if (prefetches != null) {
- for (String prefetch : prefetches) {
- addPrefetch(prefetch, semantics);
- }
- }
- }
-
- /**
- * Clears all joint prefetches.
- *
- * @since 1.2
- */
- void clearPrefetches() {
- prefetchTree = null;
- }
-
- /**
- * Removes joint prefetch.
- *
- * @since 1.2
- */
- void removePrefetch(String prefetch) {
- if (prefetchTree != null) {
- prefetchTree.removePath(prefetch);
- }
- }
+ int fetchLimit = QueryMetadata.FETCH_LIMIT_DEFAULT;
+ int fetchOffset = QueryMetadata.FETCH_OFFSET_DEFAULT;
+
+ int statementFetchSize = QueryMetadata.FETCH_OFFSET_DEFAULT;
+
+ int pageSize = QueryMetadata.PAGE_SIZE_DEFAULT;
+ boolean fetchingDataRows = QueryMetadata.FETCHING_DATA_ROWS_DEFAULT;
+ QueryCacheStrategy cacheStrategy = QueryCacheStrategy.getDefaultStrategy();
+
+ PrefetchTreeNode prefetchTree;
+ String cacheKey;
+ String[] cacheGroups;
+
+ transient List<Object> resultSetMapping;
+ transient DbEntity dbEntity;
+ transient DataMap dataMap;
+ transient Object lastRoot;
+ transient ClassDescriptor classDescriptor;
+ transient EntityResolver lastEntityResolver;
+
+ /**
+ * Copies values of another QueryMetadata object to this object.
+ */
+ void copyFromInfo(QueryMetadata info) {
+ this.lastEntityResolver = null;
+ this.lastRoot = null;
+ this.classDescriptor = null;
+ this.dbEntity = null;
+ this.dataMap = null;
+
+ this.fetchingDataRows = info.isFetchingDataRows();
+ this.fetchLimit = info.getFetchLimit();
+ this.pageSize = info.getPageSize();
+ this.cacheStrategy = info.getCacheStrategy();
+ this.cacheKey = info.getCacheKey();
+ this.cacheGroups = info.getCacheGroups();
+ this.resultSetMapping = info.getResultSetMapping();
+
+ setPrefetchTree(info.getPrefetchTree());
+ }
+
+ boolean resolve(Object root, EntityResolver resolver, String cacheKey) {
+
+ if (lastRoot != root || lastEntityResolver != resolver) {
+
+ this.cacheKey = cacheKey;
+
+ this.classDescriptor = null;
+ this.dbEntity = null;
+ this.dataMap = null;
+
+ ObjEntity entity = null;
+
+ if (root != null) {
+ if (root instanceof Class<?>) {
+ entity = resolver.getObjEntity((Class<?>) root);
+ if (entity == null) { // entity not found, try to resolve it
+ // with
+ // client resolver
+ EntityResolver clientResolver = resolver.getClientEntityResolver();
+ if (clientResolver != resolver) {
+ ObjEntity clientEntity = clientResolver.getObjEntity((Class<?>) root);
+
+ if (clientEntity != null) {
+ entity = resolver.getObjEntity(clientEntity.getName());
+ }
+ }
+ }
+
+ if (entity != null) {
+ this.dbEntity = entity.getDbEntity();
+ this.dataMap = entity.getDataMap();
+ }
+ } else if (root instanceof ObjEntity) {
+ entity = (ObjEntity) root;
+ this.dbEntity = entity.getDbEntity();
+ this.dataMap = entity.getDataMap();
+ } else if (root instanceof String) {
+ entity = resolver.getObjEntity((String) root);
+ if (entity != null) {
+ this.dbEntity = entity.getDbEntity();
+ this.dataMap = entity.getDataMap();
+ }
+ } else if (root instanceof DbEntity) {
+ this.dbEntity = (DbEntity) root;
+ this.dataMap = dbEntity.getDataMap();
+ } else if (root instanceof DataMap) {
+ this.dataMap = (DataMap) root;
+ } else if (root instanceof Persistent) {
+ entity = resolver.getObjEntity((Persistent) root);
+ if (entity != null) {
+ this.dbEntity = entity.getDbEntity();
+ this.dataMap = entity.getDataMap();
+ }
+ }
+ }
+
+ if (entity != null) {
+ this.classDescriptor = resolver.getClassDescriptor(entity.getName());
+ }
+
+ this.lastRoot = root;
+ this.lastEntityResolver = resolver;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ void initWithProperties(Map<String, ?> properties) {
+ // must init defaults even if properties are empty
+ if (properties == null) {
+ properties = Collections.EMPTY_MAP;
+ }
+
+ Object fetchOffset = properties.get(QueryMetadata.FETCH_OFFSET_PROPERTY);
+ Object fetchLimit = properties.get(QueryMetadata.FETCH_LIMIT_PROPERTY);
+ Object pageSize = properties.get(QueryMetadata.PAGE_SIZE_PROPERTY);
+ Object statementFetchSize = properties.get(QueryMetadata.STATEMENT_FETCH_SIZE_PROPERTY);
+ Object fetchingDataRows = properties.get(QueryMetadata.FETCHING_DATA_ROWS_PROPERTY);
+
+ Object cacheStrategy = properties.get(QueryMetadata.CACHE_STRATEGY_PROPERTY);
+
+ Object cacheGroups = properties.get(QueryMetadata.CACHE_GROUPS_PROPERTY);
+
+ // init ivars from properties
+ this.fetchOffset = (fetchOffset != null) ? Integer.parseInt(fetchOffset.toString())
+ : QueryMetadata.FETCH_OFFSET_DEFAULT;
+
+ this.fetchLimit = (fetchLimit != null) ? Integer.parseInt(fetchLimit.toString())
+ : QueryMetadata.FETCH_LIMIT_DEFAULT;
+
+ this.pageSize = (pageSize != null) ? Integer.parseInt(pageSize.toString()) : QueryMetadata.PAGE_SIZE_DEFAULT;
+
+ this.statementFetchSize = (statementFetchSize != null) ? Integer.parseInt(statementFetchSize.toString())
+ : QueryMetadata.STATEMENT_FETCH_SIZE_DEFAULT;
+
+ this.fetchingDataRows = (fetchingDataRows != null) ? "true".equalsIgnoreCase(fetchingDataRows.toString())
+ : QueryMetadata.FETCHING_DATA_ROWS_DEFAULT;
+
+ this.cacheStrategy = (cacheStrategy != null) ? QueryCacheStrategy.safeValueOf(cacheStrategy.toString())
+ : QueryCacheStrategy.getDefaultStrategy();
+
+ this.cacheGroups = null;
+ if (cacheGroups instanceof String[]) {
+ this.cacheGroups = (String[]) cacheGroups;
+ } else if (cacheGroups instanceof String) {
+ StringTokenizer toks = new StringTokenizer(cacheGroups.toString(), ",");
+ this.cacheGroups = new String[toks.countTokens()];
+ for (int i = 0; i < this.cacheGroups.length; i++) {
+ this.cacheGroups[i] = toks.nextToken();
+ }
+ }
+ }
+
+ public void encodeAsXML(XMLEncoder encoder) {
+
+ if (fetchingDataRows != QueryMetadata.FETCHING_DATA_ROWS_DEFAULT) {
+ encoder.printProperty(QueryMetadata.FETCHING_DATA_ROWS_PROPERTY, fetchingDataRows);
+ }
+
+ if (fetchOffset != QueryMetadata.FETCH_OFFSET_DEFAULT) {
+ encoder.printProperty(QueryMetadata.FETCH_OFFSET_PROPERTY, fetchOffset);
+ }
+
+ if (fetchLimit != QueryMetadata.FETCH_LIMIT_DEFAULT) {
+ encoder.printProperty(QueryMetadata.FETCH_LIMIT_PROPERTY, fetchLimit);
+ }
+
+ if (pageSize != QueryMetadata.PAGE_SIZE_DEFAULT) {
+ encoder.printProperty(QueryMetadata.PAGE_SIZE_PROPERTY, pageSize);
+ }
+
+ if (cacheStrategy != null && QueryCacheStrategy.getDefaultStrategy() != cacheStrategy) {
+ encoder.printProperty(QueryMetadata.CACHE_STRATEGY_PROPERTY, cacheStrategy.name());
+ }
+
+ if (statementFetchSize != QueryMetadata.STATEMENT_FETCH_SIZE_DEFAULT) {
+ encoder.printProperty(QueryMetadata.STATEMENT_FETCH_SIZE_PROPERTY, statementFetchSize);
+ }
+
+ if (prefetchTree != null) {
+ prefetchTree.encodeAsXML(encoder);
+ }
+
+ if (cacheGroups != null && cacheGroups.length > 0) {
+ StringBuilder buffer = new StringBuilder(cacheGroups[0]);
+ for (int i = 1; i < cacheGroups.length; i++) {
+ buffer.append(',').append(cacheGroups[i]);
+ }
+ encoder.printProperty(QueryMetadata.CACHE_GROUPS_PROPERTY, buffer.toString());
+ }
+ }
+
+ /**
+ * @since 1.2
+ */
+ public String getCacheKey() {
+ return cacheKey;
+ }
+
+ /**
+ * @since 1.2
+ */
+ public DataMap getDataMap() {
+ return dataMap;
+ }
+
+ /**
+ * @since 1.2
+ */
+ public Procedure getProcedure() {
+ return null;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public Map<String, String> getPathSplitAliases() {
+ return Collections.emptyMap();
+ }
+
+ /**
+ * @since 1.2
+ */
+ public DbEntity getDbEntity() {
+ return dbEntity;
+ }
+
+ /**
+ * @since 1.2
+ */
+ public ObjEntity getObjEntity() {
+ return classDescriptor != null ? classDescriptor.getEntity() : null;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public ClassDescriptor getClassDescriptor() {
+ return classDescriptor;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public List<Object> getResultSetMapping() {
+ return resultSetMapping;
+ }
+
+ /**
+ * @since 1.2
+ */
+ public PrefetchTreeNode getPrefetchTree() {
+ return prefetchTree;
+ }
+
+ void setPrefetchTree(PrefetchTreeNode prefetchTree) {
+ this.prefetchTree = prefetchTree != null ? deepClone(prefetchTree, null) : null;
+ }
+
+ private PrefetchTreeNode deepClone(PrefetchTreeNode source, PrefetchTreeNode targetParent) {
+
+ PrefetchTreeNode target = new PrefetchTreeNode(targetParent, source.getName());
+ target.setEjbqlPathEntityId(source.getEjbqlPathEntityId());
+ target.setEntityName(source.getEntityName());
+ target.setPhantom(source.isPhantom());
+ target.setSemantics(source.getSemantics());
+
+ for (PrefetchTreeNode child : source.getChildren()) {
+ target.addChild(deepClone(child, target));
+ }
+
+ return target;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public QueryCacheStrategy getCacheStrategy() {
+ return cacheStrategy;
+ }
+
+ /**
+ * @since 3.0
+ */
+ void setCacheStrategy(QueryCacheStrategy cacheStrategy) {
+ this.cacheStrategy = cacheStrategy;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public String[] getCacheGroups() {
+ return cacheGroups;
+ }
+
+ /**
+ * @since 3.0
+ */
+ void setCacheGroups(String... groups) {
+ this.cacheGroups = groups;
+ }
+
+ public boolean isFetchingDataRows() {
+ return fetchingDataRows;
+ }
+
+ public int getFetchLimit() {
+ return fetchLimit;
+ }
+
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ public Query getOrginatingQuery() {
+ return null;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public int getFetchOffset() {
+ return fetchOffset;
+ }
+
+ public boolean isRefreshingObjects() {
+ return true;
+ }
+
+ void setFetchingDataRows(boolean b) {
+ fetchingDataRows = b;
+ }
+
+ void setFetchLimit(int i) {
+ fetchLimit = i;
+ }
+
+ void setFetchOffset(int i) {
+ fetchOffset = i;
+ }
+
+ void setPageSize(int i) {
+ pageSize = i;
+ }
+
+ /**
+ * Sets statement's fetch size (0 for no default size)
+ *
+ * @since 3.0
+ */
+ void setStatementFetchSize(int size) {
+ this.statementFetchSize = size;
+ }
+
+ /**
+ * @return statement's fetch size
+ * @since 3.0
+ */
+ public int getStatementFetchSize() {
+ return statementFetchSize;
+ }
+
+ /**
+ * Adds a joint prefetch.
+ *
+ * @since 1.2
+ */
+ PrefetchTreeNode addPrefetch(String path, int semantics) {
+ if (prefetchTree == null) {
+ prefetchTree = new PrefetchTreeNode();
+ }
+
+ PrefetchTreeNode node = prefetchTree.addPath(path);
+ node.setSemantics(semantics);
+ node.setPhantom(false);
+ return node;
+ }
+
+ /**
+ * Adds a joint prefetch.
+ *
+ * @since 4.0
+ */
+ void mergePrefetch(PrefetchTreeNode node) {
+ if (prefetchTree == null) {
+ prefetchTree = new PrefetchTreeNode();
+ }
+
+ prefetchTree.merge(node);
+ }
+
+ /**
+ * Adds all prefetches from a provided collection.
+ *
+ * @since 1.2
+ */
+ void addPrefetches(Collection<String> prefetches, int semantics) {
+ if (prefetches != null) {
+ for (String prefetch : prefetches) {
+ addPrefetch(prefetch, semantics);
+ }
+ }
+ }
+
+ /**
+ * Clears all joint prefetches.
+ *
+ * @since 1.2
+ */
+ void clearPrefetches() {
+ prefetchTree = null;
+ }
+
+ /**
+ * Removes joint prefetch.
+ *
+ * @since 1.2
+ */
+ void removePrefetch(String prefetch) {
+ if (prefetchTree != null) {
+ prefetchTree.removePath(prefetch);
+ }
+ }
}