summaryrefslogtreecommitdiffstats
path: root/document
diff options
context:
space:
mode:
Diffstat (limited to 'document')
-rw-r--r--document/AUTHORS5
-rw-r--r--document/src/main/java/com/yahoo/document/BucketDistribution.java408
-rw-r--r--document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java2
-rw-r--r--document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java2
-rw-r--r--document/src/main/java/com/yahoo/document/select/BucketSet.java142
-rw-r--r--document/src/main/java/com/yahoo/document/select/Result.java104
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/ArithmeticNode.java416
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/AttributeNode.java408
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/ComparisonNode.java868
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/DocumentNode.java128
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/EmbracedNode.java102
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/ExpressionNode.java94
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/IdNode.java214
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/LiteralNode.java120
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/LogicNode.java630
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/NegationNode.java104
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/NowNode.java66
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/SearchColumnNode.java110
-rw-r--r--document/src/main/java/com/yahoo/document/select/rule/VariableNode.java114
-rw-r--r--document/src/main/java/com/yahoo/document/serialization/DocumentUpdateFlags.java2
-rw-r--r--document/src/main/java/com/yahoo/vespaxmlparser/FeedReader.java2
-rw-r--r--document/src/test/java/com/yahoo/document/IncompatibleFieldTypesTest.java86
-rw-r--r--document/src/test/java/com/yahoo/document/annotation/Bug6394548TestCase.java244
-rw-r--r--document/src/test/java/com/yahoo/document/annotation/Bug6425939TestCase.java130
-rw-r--r--document/src/vespa/document/fieldvalue/variablemap.h2
25 files changed, 2249 insertions, 2254 deletions
diff --git a/document/AUTHORS b/document/AUTHORS
deleted file mode 100644
index d88ca23dc13..00000000000
--- a/document/AUTHORS
+++ /dev/null
@@ -1,5 +0,0 @@
-thomasg
-bratseth
-fledsbo
-borud
-larschri
diff --git a/document/src/main/java/com/yahoo/document/BucketDistribution.java b/document/src/main/java/com/yahoo/document/BucketDistribution.java
index bb4792b5982..28ae01dd957 100644
--- a/document/src/main/java/com/yahoo/document/BucketDistribution.java
+++ b/document/src/main/java/com/yahoo/document/BucketDistribution.java
@@ -1,205 +1,205 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document;
-
-import com.yahoo.document.BucketId;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class BucketDistribution {
-
- // A logger object to enable proper logging.
- private static Logger log = Logger.getLogger(BucketDistribution.class.getName());
-
- // A map from bucket id to column index.
- private int[] bucketToColumn;
-
- // The number of columns to distribute to.
- private int numColumns;
-
- // The number of bits to use for bucket identification.
- private int numBucketBits;
-
- /**
- * Constructs a new bucket distribution object with a given number of columns and buckets.
- *
- * @param numColumns The number of columns to distribute to.
- * @param numBucketBits The number of bits to use for bucket id.
- */
- public BucketDistribution(int numColumns, int numBucketBits) {
- this.numBucketBits = numBucketBits;
- bucketToColumn = new int[getNumBuckets()];
- reset();
- setNumColumns(numColumns);
- }
-
- /**
- * Constructs a new bucket distribution object as a copy of another.
- *
- * @param other The distribution object to copy.
- */
- public BucketDistribution(BucketDistribution other) {
- bucketToColumn = other.bucketToColumn.clone();
- numColumns = other.numColumns;
- numBucketBits = other.numBucketBits;
- }
-
- /**
- * Returns the number of buckets that the given number of bucket bits will allow.
- *
- * @param numBucketBits The number of bits to use for bucket id.
- * @return The number of buckets allowed.
- */
- private static int getNumBuckets(int numBucketBits) {
- return 1 << numBucketBits;
- }
-
- /**
- * This method returns a list that contains the distributions of the given number of buckets over the given number
- * of columns.
- *
- * @param numColumns The number of columns to distribute to.
- * @param numBucketBits The number of bits to use for bucket id.
- * @return The bucket distribution.
- */
- private static List<Integer> getBucketCount(int numColumns, int numBucketBits) {
- List<Integer> ret = new ArrayList<Integer>(numColumns);
- int cnt = getNumBuckets(numBucketBits) / numColumns;
- int rst = getNumBuckets(numBucketBits) % numColumns;
- for (int i = 0; i < numColumns; ++i) {
- ret.add(cnt + (i < rst ? 1 : 0));
- }
- return ret;
- }
-
- /**
- * This method returns a list similar to {@link BucketDistribution#getBucketCount(int, int)}, except that the returned list
- * contains the number of buckets that will have to be migrated from each column if an additional column was added.
- *
- * @param numColumns The original number of columns.
- * @param numBucketBits The number of bits to use for bucket id.
- * @return The number of buckets to migrate, one value per column.
- */
- private static List<Integer> getBucketMigrateCount(int numColumns, int numBucketBits) {
- List<Integer> ret = getBucketCount(numColumns++, numBucketBits);
- int cnt = getNumBuckets(numBucketBits) / numColumns;
- int rst = getNumBuckets(numBucketBits) % numColumns;
- for (int i = 0; i < numColumns - 1; ++i) {
- ret.set(i, ret.get(i) - (cnt + (i < rst ? 1 : 0)));
- }
- return ret;
- }
-
- /**
- * Sets the number of columns to distribute to to 1, and resets the content of the internal bucket-to-column map so
- * that it all buckets point to that single column.
- */
- public void reset() {
- for (int i = 0; i < bucketToColumn.length; ++i) {
- bucketToColumn[i] = 0;
- }
- numColumns = 1;
- }
-
- /**
- * Adds a single column to this bucket distribution object. This will modify the internal bucket-to-column map so
- * that it takes into account the new column.
- */
- private void addColumn() {
- int newColumns = numColumns + 1;
- List<Integer> migrate = getBucketMigrateCount(numColumns, numBucketBits);
- int numBuckets = getNumBuckets(numBucketBits);
- for (int i = 0; i < numBuckets; ++i) {
- int old = bucketToColumn[i];
- if (migrate.get(old) > 0) {
- bucketToColumn[i] = numColumns; // move this bucket to the new column
- migrate.set(old, migrate.get(old) - 1);
- }
- }
- numColumns = newColumns;
- }
-
- /**
- * Sets the number of columns to use for this document distribution object. This will reset and setup this object
- * from scratch. The original number of buckets is maintained.
- *
- * @param numColumns The new number of columns to distribute to.
- */
- public synchronized void setNumColumns(int numColumns) {
- if (numColumns < this.numColumns) {
- reset();
- }
- if (numColumns == this.numColumns) {
- return;
- }
- for (int i = numColumns - this.numColumns; --i >= 0; ) {
- addColumn();
- }
- }
-
- /**
- * Returns the number of columns to distribute to.
- *
- * @return The number of columns.
- */
- public int getNumColumns() {
- return numColumns;
- }
-
- /**
- * Sets the number of buckets to use for this document distribution object. This will reset and setup this object
- * from scratch. The original number of columns is maintained.
- *
- * @param numBucketBits The new number of bits to use for bucket id.
- */
- public synchronized void setNumBucketBits(int numBucketBits) {
- if (numBucketBits == this.numBucketBits) {
- return;
- }
- this.numBucketBits = numBucketBits;
- bucketToColumn = new int[getNumBuckets(numBucketBits)];
- int numColumns = this.numColumns;
- reset();
- setNumColumns(numColumns);
- }
-
- /**
- * Returns the number of bits used for bucket identifiers.
- *
- * @return The number of bits.
- */
- public int getNumBucketBits() {
- return numBucketBits;
- }
-
- /**
- * Returns the number of buckets available using the configured number of bucket bits.
- *
- * @return The number of buckets.
- */
- public int getNumBuckets() {
- return getNumBuckets(numBucketBits);
- }
-
- /**
- * This method maps the given bucket id to its corresponding column.
- *
- * @param bucketId The bucket whose column to lookup.
- * @return The column to distribute the bucket to.
- */
- public int getColumn(BucketId bucketId) {
- int ret = (int)(bucketId.getId() & (getNumBuckets(numBucketBits) - 1));
- if (ret >= bucketToColumn.length) {
- log.log(Level.SEVERE,
- "The bucket distribution map is not in sync with the number of bucket bits. " +
- "This should never happen! Distribution is broken!!");
- return 0;
- }
- return bucketToColumn[ret];
- }
-}
+package com.yahoo.document;
+
+import com.yahoo.document.BucketId;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class BucketDistribution {
+
+ // A logger object to enable proper logging.
+ private static Logger log = Logger.getLogger(BucketDistribution.class.getName());
+
+ // A map from bucket id to column index.
+ private int[] bucketToColumn;
+
+ // The number of columns to distribute to.
+ private int numColumns;
+
+ // The number of bits to use for bucket identification.
+ private int numBucketBits;
+
+ /**
+ * Constructs a new bucket distribution object with a given number of columns and buckets.
+ *
+ * @param numColumns The number of columns to distribute to.
+ * @param numBucketBits The number of bits to use for bucket id.
+ */
+ public BucketDistribution(int numColumns, int numBucketBits) {
+ this.numBucketBits = numBucketBits;
+ bucketToColumn = new int[getNumBuckets()];
+ reset();
+ setNumColumns(numColumns);
+ }
+
+ /**
+ * Constructs a new bucket distribution object as a copy of another.
+ *
+ * @param other The distribution object to copy.
+ */
+ public BucketDistribution(BucketDistribution other) {
+ bucketToColumn = other.bucketToColumn.clone();
+ numColumns = other.numColumns;
+ numBucketBits = other.numBucketBits;
+ }
+
+ /**
+ * Returns the number of buckets that the given number of bucket bits will allow.
+ *
+ * @param numBucketBits The number of bits to use for bucket id.
+ * @return The number of buckets allowed.
+ */
+ private static int getNumBuckets(int numBucketBits) {
+ return 1 << numBucketBits;
+ }
+
+ /**
+ * This method returns a list that contains the distributions of the given number of buckets over the given number
+ * of columns.
+ *
+ * @param numColumns The number of columns to distribute to.
+ * @param numBucketBits The number of bits to use for bucket id.
+ * @return The bucket distribution.
+ */
+ private static List<Integer> getBucketCount(int numColumns, int numBucketBits) {
+ List<Integer> ret = new ArrayList<Integer>(numColumns);
+ int cnt = getNumBuckets(numBucketBits) / numColumns;
+ int rst = getNumBuckets(numBucketBits) % numColumns;
+ for (int i = 0; i < numColumns; ++i) {
+ ret.add(cnt + (i < rst ? 1 : 0));
+ }
+ return ret;
+ }
+
+ /**
+ * This method returns a list similar to {@link BucketDistribution#getBucketCount(int, int)}, except that the returned list
+ * contains the number of buckets that will have to be migrated from each column if an additional column was added.
+ *
+ * @param numColumns The original number of columns.
+ * @param numBucketBits The number of bits to use for bucket id.
+ * @return The number of buckets to migrate, one value per column.
+ */
+ private static List<Integer> getBucketMigrateCount(int numColumns, int numBucketBits) {
+ List<Integer> ret = getBucketCount(numColumns++, numBucketBits);
+ int cnt = getNumBuckets(numBucketBits) / numColumns;
+ int rst = getNumBuckets(numBucketBits) % numColumns;
+ for (int i = 0; i < numColumns - 1; ++i) {
+ ret.set(i, ret.get(i) - (cnt + (i < rst ? 1 : 0)));
+ }
+ return ret;
+ }
+
+ /**
+ * Sets the number of columns to distribute to to 1, and resets the content of the internal bucket-to-column map so
+ * that it all buckets point to that single column.
+ */
+ public void reset() {
+ for (int i = 0; i < bucketToColumn.length; ++i) {
+ bucketToColumn[i] = 0;
+ }
+ numColumns = 1;
+ }
+
+ /**
+ * Adds a single column to this bucket distribution object. This will modify the internal bucket-to-column map so
+ * that it takes into account the new column.
+ */
+ private void addColumn() {
+ int newColumns = numColumns + 1;
+ List<Integer> migrate = getBucketMigrateCount(numColumns, numBucketBits);
+ int numBuckets = getNumBuckets(numBucketBits);
+ for (int i = 0; i < numBuckets; ++i) {
+ int old = bucketToColumn[i];
+ if (migrate.get(old) > 0) {
+ bucketToColumn[i] = numColumns; // move this bucket to the new column
+ migrate.set(old, migrate.get(old) - 1);
+ }
+ }
+ numColumns = newColumns;
+ }
+
+ /**
+ * Sets the number of columns to use for this document distribution object. This will reset and setup this object
+ * from scratch. The original number of buckets is maintained.
+ *
+ * @param numColumns The new number of columns to distribute to.
+ */
+ public synchronized void setNumColumns(int numColumns) {
+ if (numColumns < this.numColumns) {
+ reset();
+ }
+ if (numColumns == this.numColumns) {
+ return;
+ }
+ for (int i = numColumns - this.numColumns; --i >= 0; ) {
+ addColumn();
+ }
+ }
+
+ /**
+ * Returns the number of columns to distribute to.
+ *
+ * @return The number of columns.
+ */
+ public int getNumColumns() {
+ return numColumns;
+ }
+
+ /**
+ * Sets the number of buckets to use for this document distribution object. This will reset and setup this object
+ * from scratch. The original number of columns is maintained.
+ *
+ * @param numBucketBits The new number of bits to use for bucket id.
+ */
+ public synchronized void setNumBucketBits(int numBucketBits) {
+ if (numBucketBits == this.numBucketBits) {
+ return;
+ }
+ this.numBucketBits = numBucketBits;
+ bucketToColumn = new int[getNumBuckets(numBucketBits)];
+ int numColumns = this.numColumns;
+ reset();
+ setNumColumns(numColumns);
+ }
+
+ /**
+ * Returns the number of bits used for bucket identifiers.
+ *
+ * @return The number of bits.
+ */
+ public int getNumBucketBits() {
+ return numBucketBits;
+ }
+
+ /**
+ * Returns the number of buckets available using the configured number of bucket bits.
+ *
+ * @return The number of buckets.
+ */
+ public int getNumBuckets() {
+ return getNumBuckets(numBucketBits);
+ }
+
+ /**
+ * This method maps the given bucket id to its corresponding column.
+ *
+ * @param bucketId The bucket whose column to lookup.
+ * @return The column to distribute the bucket to.
+ */
+ public int getColumn(BucketId bucketId) {
+ int ret = (int)(bucketId.getId() & (getNumBuckets(numBucketBits) - 1));
+ if (ret >= bucketToColumn.length) {
+ log.log(Level.SEVERE,
+ "The bucket distribution map is not in sync with the number of bucket bits. " +
+ "This should never happen! Distribution is broken!!");
+ return 0;
+ }
+ return bucketToColumn[ret];
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java b/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java
index 96a3fadc66c..3e911afb305 100644
--- a/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java
+++ b/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java
@@ -52,4 +52,4 @@ public class RemoveFieldPathUpdate extends FieldPathUpdate {
public String toString() {
return "Remove: " + super.toString();
}
-} \ No newline at end of file
+}
diff --git a/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java b/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java
index 1c5e6efdda6..36dbacfcde1 100644
--- a/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java
+++ b/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java
@@ -407,4 +407,4 @@ public class DocumentUpdateJsonSerializer
return this;
}
}
-} \ No newline at end of file
+}
diff --git a/document/src/main/java/com/yahoo/document/select/BucketSet.java b/document/src/main/java/com/yahoo/document/select/BucketSet.java
index e7bb4ac7807..286c66969d9 100644
--- a/document/src/main/java/com/yahoo/document/select/BucketSet.java
+++ b/document/src/main/java/com/yahoo/document/select/BucketSet.java
@@ -1,72 +1,72 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select;
-
-import com.yahoo.document.BucketId;
-
-import java.util.HashSet;
-
-/**
- * A set of bucket ids covered by a document selector.
- *
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class BucketSet extends HashSet<BucketId> {
-
- /**
- * Constructs a new bucket set that contains no ids.
- */
- public BucketSet() {
- // empty
- }
-
- /**
- * Constructs a new bucket set that contains a single id.
- *
- * @param id The id to add to this as initial value.
- */
- public BucketSet(BucketId id) {
- add(id);
- }
-
- /**
- * Constructs a new bucket set that is a copy of another.
- *
- * @param set The set to copy.
- */
- public BucketSet(BucketSet set) {
- this.addAll(set);
- }
-
- /**
- * Returns the intersection between this bucket set and another.
- *
- * @param rhs The set to form an intersection with.
- * @return The intersection.
- */
- public BucketSet intersection(BucketSet rhs) {
- if (rhs == null) {
- return new BucketSet(this); // The other has all buckets marked, this is the smaller.
- } else {
- BucketSet ret = new BucketSet(this);
- ret.retainAll(rhs);
- return ret;
- }
- }
-
- /**
- * Returns the union between this bucket set and another.
- *
- * @param rhs The set to form a union with.
- * @return The union.
- */
- public BucketSet union(BucketSet rhs) {
- if (rhs == null) {
- return null;
- } else {
- BucketSet ret = new BucketSet(this);
- ret.addAll(rhs);
- return ret;
- }
- }
-
-}
+package com.yahoo.document.select;
+
+import com.yahoo.document.BucketId;
+
+import java.util.HashSet;
+
+/**
+ * A set of bucket ids covered by a document selector.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class BucketSet extends HashSet<BucketId> {
+
+ /**
+ * Constructs a new bucket set that contains no ids.
+ */
+ public BucketSet() {
+ // empty
+ }
+
+ /**
+ * Constructs a new bucket set that contains a single id.
+ *
+ * @param id The id to add to this as initial value.
+ */
+ public BucketSet(BucketId id) {
+ add(id);
+ }
+
+ /**
+ * Constructs a new bucket set that is a copy of another.
+ *
+ * @param set The set to copy.
+ */
+ public BucketSet(BucketSet set) {
+ this.addAll(set);
+ }
+
+ /**
+ * Returns the intersection between this bucket set and another.
+ *
+ * @param rhs The set to form an intersection with.
+ * @return The intersection.
+ */
+ public BucketSet intersection(BucketSet rhs) {
+ if (rhs == null) {
+ return new BucketSet(this); // The other has all buckets marked, this is the smaller.
+ } else {
+ BucketSet ret = new BucketSet(this);
+ ret.retainAll(rhs);
+ return ret;
+ }
+ }
+
+ /**
+ * Returns the union between this bucket set and another.
+ *
+ * @param rhs The set to form a union with.
+ * @return The union.
+ */
+ public BucketSet union(BucketSet rhs) {
+ if (rhs == null) {
+ return null;
+ } else {
+ BucketSet ret = new BucketSet(this);
+ ret.addAll(rhs);
+ return ret;
+ }
+ }
+
+}
diff --git a/document/src/main/java/com/yahoo/document/select/Result.java b/document/src/main/java/com/yahoo/document/select/Result.java
index 3f1fa75d4ef..e0b8f02c47b 100644
--- a/document/src/main/java/com/yahoo/document/select/Result.java
+++ b/document/src/main/java/com/yahoo/document/select/Result.java
@@ -1,53 +1,53 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select;
-
-import com.yahoo.document.select.rule.AttributeNode;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public enum Result {
-
- /**
- * Defines all enumeration constants.
- */
- TRUE,
- FALSE,
- INVALID;
-
- // Inherit doc from Object.
- public String toString() {
- return name().toLowerCase();
- }
-
- /**
- * Inverts the result value to the appropriate value. True → False, False → True and Invalid → Invalid.
- * @return inverted result
- */
- public static Result invert(Result result) {
- if (result == Result.TRUE) return Result.FALSE;
- if (result == Result.FALSE) return Result.TRUE;
- return Result.INVALID;
- }
-
- /**
- * Converts the given object value into an instance of this Result enumeration.
- *
- * @param value The object to convert.
- * @return The corresponding result value.
- */
- public static Result toResult(Object value) {
- if (value == null || value == Result.FALSE || value == Boolean.FALSE ||
- (Number.class.isInstance(value) && ((Number)value).doubleValue() == 0)) {
- return Result.FALSE;
- } else if (value == INVALID) {
- return Result.INVALID;
- } else if (value instanceof AttributeNode.VariableValueList) {
- return ((AttributeNode.VariableValueList)value).isEmpty() ? Result.FALSE : Result.TRUE;
- } else if (value instanceof ResultList) {
- return ((ResultList)value).toResult();
- } else {
- return Result.TRUE;
- }
- }
-}
+package com.yahoo.document.select;
+
+import com.yahoo.document.select.rule.AttributeNode;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public enum Result {
+
+ /**
+ * Defines all enumeration constants.
+ */
+ TRUE,
+ FALSE,
+ INVALID;
+
+ // Inherit doc from Object.
+ public String toString() {
+ return name().toLowerCase();
+ }
+
+ /**
+ * Inverts the result value to the appropriate value. True → False, False → True and Invalid → Invalid.
+ * @return inverted result
+ */
+ public static Result invert(Result result) {
+ if (result == Result.TRUE) return Result.FALSE;
+ if (result == Result.FALSE) return Result.TRUE;
+ return Result.INVALID;
+ }
+
+ /**
+ * Converts the given object value into an instance of this Result enumeration.
+ *
+ * @param value The object to convert.
+ * @return The corresponding result value.
+ */
+ public static Result toResult(Object value) {
+ if (value == null || value == Result.FALSE || value == Boolean.FALSE ||
+ (Number.class.isInstance(value) && ((Number)value).doubleValue() == 0)) {
+ return Result.FALSE;
+ } else if (value == INVALID) {
+ return Result.INVALID;
+ } else if (value instanceof AttributeNode.VariableValueList) {
+ return ((AttributeNode.VariableValueList)value).isEmpty() ? Result.FALSE : Result.TRUE;
+ } else if (value instanceof ResultList) {
+ return ((ResultList)value).toResult();
+ } else {
+ return Result.TRUE;
+ }
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/ArithmeticNode.java b/document/src/main/java/com/yahoo/document/select/rule/ArithmeticNode.java
index 2fe4609b4e6..3bb558c2eb2 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/ArithmeticNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/ArithmeticNode.java
@@ -1,209 +1,209 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.datatypes.NumericFieldValue;
-import com.yahoo.document.select.*;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Stack;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class ArithmeticNode implements ExpressionNode {
-
- public static final int NOP = 0;
- public static final int ADD = 1;
- public static final int SUB = 2;
- public static final int MOD = 3;
- public static final int DIV = 4;
- public static final int MUL = 5;
-
- private final List<NodeItem> items = new ArrayList<NodeItem>();
-
- public ArithmeticNode() {
- // empty
- }
-
- public ArithmeticNode add(String operator, ExpressionNode node) {
- items.add(new NodeItem(stringToOperator(operator), node));
- return this;
- }
-
- public List<NodeItem> getItems() {
- return items;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- StringBuilder ret = null;
- Stack<ValueItem> buf = new Stack<ValueItem>();
- for (int i = 0; i < items.size(); ++i) {
- NodeItem item = items.get(i);
- Object val = item.node.evaluate(context);
-
- if (val == null) {
- throw new IllegalStateException("Null value found!");
- }
-
- if (val instanceof AttributeNode.VariableValueList) {
- AttributeNode.VariableValueList value = (AttributeNode.VariableValueList)val;
- if (value.size() == 0) {
- throw new IllegalArgumentException("Can not perform arithmetic on missing field: "
- + item.node.toString());
- } else if (value.size() != 1) {
- throw new IllegalStateException("Arithmetic is only valid for single values.");
- } else {
- val = value.get(0).getValue();
- }
- }
-
- if (val instanceof NumericFieldValue) {
- val = ((NumericFieldValue)val).getNumber();
- }
-
- if (val instanceof String) {
- if (i == 0) {
- ret = new StringBuilder();
- }
- if (ret != null) {
- ret.append(val);
- continue;
- }
- } else if (Number.class.isInstance(val)) {
- if (!buf.isEmpty()) {
- while (buf.peek().operator > item.operator) {
- popOffTheTop(buf);
- }
- }
- buf.push(new ValueItem(item.operator, (Number)val));
- continue;
- }
- throw new IllegalStateException("Term '" + item.node + " with class " + val.getClass() + "' does not evaluate to a number.");
- }
- if (ret != null) {
- return ret.toString();
- }
- while (buf.size() > 1) {
- popOffTheTop(buf);
- }
- return buf.pop().value;
- }
-
- private void popOffTheTop(Stack<ValueItem> buf) {
- ValueItem rhs = buf.pop();
- ValueItem lhs = buf.pop();
- switch (rhs.operator) {
- case ADD:
- lhs.value = lhs.value.doubleValue() + rhs.value.doubleValue();
- break;
- case SUB:
- lhs.value = lhs.value.doubleValue() - rhs.value.doubleValue();
- break;
- case DIV:
- lhs.value = lhs.value.doubleValue() / rhs.value.doubleValue();
- break;
- case MUL:
- lhs.value = lhs.value.doubleValue() * rhs.value.doubleValue();
- break;
- case MOD:
- lhs.value = lhs.value.longValue() % rhs.value.longValue();
- break;
- default:
- throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported.");
- }
- buf.push(lhs);
- }
-
- @Override
- public String toString() {
- StringBuilder ret = new StringBuilder();
- for (NodeItem item : items) {
- if (item.operator != NOP) {
- ret.append(" ").append(operatorToString(item.operator)).append(" ");
- }
- ret.append(item.node);
- }
- return ret.toString();
- }
-
- public String operatorToString(int operator) {
- switch (operator) {
- case NOP:
- return null;
- case ADD:
- return "+";
- case SUB:
- return "-";
- case MOD:
- return "%";
- case DIV:
- return "/";
- case MUL:
- return "*";
- default:
- throw new IllegalStateException("Arithmetic operator " + operator + " not supported.");
- }
- }
-
- private int stringToOperator(String operator) {
- if (operator == null) {
- return NOP;
- } else if (operator.equals("+")) {
- return ADD;
- } else if (operator.equals("-")) {
- return SUB;
- } else if (operator.equals("%")) {
- return MOD;
- } else if (operator.equals("/")) {
- return DIV;
- } else if (operator.equals("*")) {
- return MUL;
- } else {
- throw new IllegalStateException("Arithmetic operator '" + operator + "' not supported.");
- }
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- private class ValueItem {
- public int operator;
- public Number value;
-
- public ValueItem(int operator, Number value) {
- this.operator = operator;
- this.value = value;
- }
- }
-
- public static class NodeItem {
- private int operator;
- private ExpressionNode node;
-
- public NodeItem(int operator, ExpressionNode node) {
- this.operator = operator;
- this.node = node;
- }
-
- public int getOperator() {
- return operator;
- }
-
- public ExpressionNode getNode() {
- return node;
- }
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.datatypes.NumericFieldValue;
+import com.yahoo.document.select.*;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Stack;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class ArithmeticNode implements ExpressionNode {
+
+ public static final int NOP = 0;
+ public static final int ADD = 1;
+ public static final int SUB = 2;
+ public static final int MOD = 3;
+ public static final int DIV = 4;
+ public static final int MUL = 5;
+
+ private final List<NodeItem> items = new ArrayList<NodeItem>();
+
+ public ArithmeticNode() {
+ // empty
+ }
+
+ public ArithmeticNode add(String operator, ExpressionNode node) {
+ items.add(new NodeItem(stringToOperator(operator), node));
+ return this;
+ }
+
+ public List<NodeItem> getItems() {
+ return items;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return null;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public Object evaluate(Context context) {
+ StringBuilder ret = null;
+ Stack<ValueItem> buf = new Stack<ValueItem>();
+ for (int i = 0; i < items.size(); ++i) {
+ NodeItem item = items.get(i);
+ Object val = item.node.evaluate(context);
+
+ if (val == null) {
+ throw new IllegalStateException("Null value found!");
+ }
+
+ if (val instanceof AttributeNode.VariableValueList) {
+ AttributeNode.VariableValueList value = (AttributeNode.VariableValueList)val;
+ if (value.size() == 0) {
+ throw new IllegalArgumentException("Can not perform arithmetic on missing field: "
+ + item.node.toString());
+ } else if (value.size() != 1) {
+ throw new IllegalStateException("Arithmetic is only valid for single values.");
+ } else {
+ val = value.get(0).getValue();
+ }
+ }
+
+ if (val instanceof NumericFieldValue) {
+ val = ((NumericFieldValue)val).getNumber();
+ }
+
+ if (val instanceof String) {
+ if (i == 0) {
+ ret = new StringBuilder();
+ }
+ if (ret != null) {
+ ret.append(val);
+ continue;
+ }
+ } else if (Number.class.isInstance(val)) {
+ if (!buf.isEmpty()) {
+ while (buf.peek().operator > item.operator) {
+ popOffTheTop(buf);
+ }
+ }
+ buf.push(new ValueItem(item.operator, (Number)val));
+ continue;
+ }
+ throw new IllegalStateException("Term '" + item.node + " with class " + val.getClass() + "' does not evaluate to a number.");
+ }
+ if (ret != null) {
+ return ret.toString();
+ }
+ while (buf.size() > 1) {
+ popOffTheTop(buf);
+ }
+ return buf.pop().value;
+ }
+
+ private void popOffTheTop(Stack<ValueItem> buf) {
+ ValueItem rhs = buf.pop();
+ ValueItem lhs = buf.pop();
+ switch (rhs.operator) {
+ case ADD:
+ lhs.value = lhs.value.doubleValue() + rhs.value.doubleValue();
+ break;
+ case SUB:
+ lhs.value = lhs.value.doubleValue() - rhs.value.doubleValue();
+ break;
+ case DIV:
+ lhs.value = lhs.value.doubleValue() / rhs.value.doubleValue();
+ break;
+ case MUL:
+ lhs.value = lhs.value.doubleValue() * rhs.value.doubleValue();
+ break;
+ case MOD:
+ lhs.value = lhs.value.longValue() % rhs.value.longValue();
+ break;
+ default:
+ throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported.");
+ }
+ buf.push(lhs);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder ret = new StringBuilder();
+ for (NodeItem item : items) {
+ if (item.operator != NOP) {
+ ret.append(" ").append(operatorToString(item.operator)).append(" ");
+ }
+ ret.append(item.node);
+ }
+ return ret.toString();
+ }
+
+ public String operatorToString(int operator) {
+ switch (operator) {
+ case NOP:
+ return null;
+ case ADD:
+ return "+";
+ case SUB:
+ return "-";
+ case MOD:
+ return "%";
+ case DIV:
+ return "/";
+ case MUL:
+ return "*";
+ default:
+ throw new IllegalStateException("Arithmetic operator " + operator + " not supported.");
+ }
+ }
+
+ private int stringToOperator(String operator) {
+ if (operator == null) {
+ return NOP;
+ } else if (operator.equals("+")) {
+ return ADD;
+ } else if (operator.equals("-")) {
+ return SUB;
+ } else if (operator.equals("%")) {
+ return MOD;
+ } else if (operator.equals("/")) {
+ return DIV;
+ } else if (operator.equals("*")) {
+ return MUL;
+ } else {
+ throw new IllegalStateException("Arithmetic operator '" + operator + "' not supported.");
+ }
+ }
+
+ public OrderingSpecification getOrdering(int order) {
+ return null;
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ private class ValueItem {
+ public int operator;
+ public Number value;
+
+ public ValueItem(int operator, Number value) {
+ this.operator = operator;
+ this.value = value;
+ }
+ }
+
+ public static class NodeItem {
+ private int operator;
+ private ExpressionNode node;
+
+ public NodeItem(int operator, ExpressionNode node) {
+ this.operator = operator;
+ this.node = node;
+ }
+
+ public int getOperator() {
+ return operator;
+ }
+
+ public ExpressionNode getNode() {
+ return node;
+ }
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/AttributeNode.java b/document/src/main/java/com/yahoo/document/select/rule/AttributeNode.java
index 048eb70ac94..7e51834d871 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/AttributeNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/AttributeNode.java
@@ -1,205 +1,205 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.collections.BobHash;
-import com.yahoo.document.*;
-import com.yahoo.document.datatypes.FieldPathIteratorHandler;
-import com.yahoo.document.datatypes.FieldValue;
-import com.yahoo.document.select.*;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class AttributeNode implements ExpressionNode {
-
- private ExpressionNode value;
- private final List<Item> items = new ArrayList<Item>();
-
- public AttributeNode(ExpressionNode value, List items) {
- this.value = value;
- for (Object obj : items) {
- if (obj instanceof Item) {
- this.items.add((Item)obj);
- } else {
- throw new IllegalStateException("Can not add an instance of " + obj.getClass().getName() +
- " as a function item.");
- }
- }
- }
-
- public ExpressionNode getValue() {
- return value;
- }
-
- public AttributeNode setValue(ExpressionNode value) {
- this.value = value;
- return this;
- }
-
- public List<Item> getItems() {
- return items;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- String pos = value.toString();
- Object obj = value.evaluate(context);
-
- StringBuilder builder = new StringBuilder();
- for (Item item : items) {
- if (obj == null) {
- throw new IllegalStateException("Can not invoke '" + item + "' on '" + pos + "' because that term " +
- "evaluated to null.");
- }
- if (item.getType() != Item.FUNCTION) {
- if (builder.length() > 0) {
- builder.append(".");
- }
-
- builder.append(item.getName());
- } else {
- if (builder.length() > 0) {
- obj = evaluateFieldPath(builder.toString(), obj);
- builder = new StringBuilder();
- }
-
- obj = evaluateFunction(item.getName(), obj);
- }
-
- pos = pos + "." + item;
- }
-
- if (builder.length() > 0) {
- obj = evaluateFieldPath(builder.toString(), obj);
- }
- return obj;
- }
-
- public static class VariableValueList extends ArrayList<ResultList.VariableValue> {
-
- }
-
- static class IteratorHandler extends FieldPathIteratorHandler {
- VariableValueList values = new VariableValueList();
-
- @Override
- public void onPrimitive(FieldValue fv) {
- values.add(new ResultList.VariableValue((VariableMap)getVariables().clone(), fv));
- }
- }
-
- private static Object applyFunction(String function, Object value) {
- if (function.equalsIgnoreCase("abs")) {
- if (Number.class.isInstance(value)) {
- Number nValue = (Number)value;
- if (value instanceof Double) {
- return nValue.doubleValue() * (nValue.doubleValue() < 0 ? -1 : 1);
- } else if (value instanceof Float) {
- return nValue.floatValue() * (nValue.floatValue() < 0 ? -1 : 1);
- } else if (value instanceof Long) {
- return nValue.longValue() * (nValue.longValue() < 0 ? -1 : 1);
- } else if (value instanceof Integer) {
- return nValue.intValue() * (nValue.intValue() < 0 ? -1 : 1);
- }
- }
- throw new IllegalStateException("Function 'abs' is only available for numerical values.");
- } else if (function.equalsIgnoreCase("hash")) {
- return BobHash.hash(value.toString());
- } else if (function.equalsIgnoreCase("lowercase")) {
- return value.toString().toLowerCase();
- } else if (function.equalsIgnoreCase("uppercase")) {
- return value.toString().toUpperCase();
- }
- throw new IllegalStateException("Function '" + function + "' is not supported.");
- }
-
- private static Object evaluateFieldPath(String fieldPth, Object value) {
- if (value instanceof DocumentPut) {
- final Document doc = ((DocumentPut) value).getDocument();
- FieldPath fieldPath = doc.getDataType().buildFieldPath(fieldPth);
- IteratorHandler handler = new IteratorHandler();
- doc.iterateNested(fieldPath, 0, handler);
- return handler.values;
- } else if (value instanceof DocumentUpdate) {
- return Result.INVALID;
- }
- return Result.FALSE;
- //throw new IllegalStateException("Attributes are only available for document types for value '" + value + "'. Looking for " + fieldPth);
- }
-
- private static Object evaluateFunction(String function, Object value) {
- if (value instanceof VariableValueList) {
- VariableValueList retVal = new VariableValueList();
-
- for (ResultList.VariableValue val : ((VariableValueList)value)) {
- retVal.add(new ResultList.VariableValue(
- (FieldPathIteratorHandler.VariableMap)val.getVariables().clone(),
- applyFunction(function, val.getValue())));
- }
-
- return retVal;
- }
-
- return applyFunction(function, value);
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- StringBuilder ret = new StringBuilder();
- ret.append(value);
- for (Item item : items) {
- ret.append(".").append(item);
- }
- return ret.toString();
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-
- public static class Item {
- public static final int ATTRIBUTE = 0;
- public static final int FUNCTION = 1;
-
- private String name;
- private int type = ATTRIBUTE;
-
- public Item(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- public Item setName(String name) {
- this.name = name;
- return this;
- }
-
- public int getType() {
- return type;
- }
-
- public Item setType(int type) {
- this.type = type;
- return this;
- }
-
- @Override public String toString() {
- return name + (type == FUNCTION ? "()" : "");
- }
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.collections.BobHash;
+import com.yahoo.document.*;
+import com.yahoo.document.datatypes.FieldPathIteratorHandler;
+import com.yahoo.document.datatypes.FieldValue;
+import com.yahoo.document.select.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class AttributeNode implements ExpressionNode {
+
+ private ExpressionNode value;
+ private final List<Item> items = new ArrayList<Item>();
+
+ public AttributeNode(ExpressionNode value, List items) {
+ this.value = value;
+ for (Object obj : items) {
+ if (obj instanceof Item) {
+ this.items.add((Item)obj);
+ } else {
+ throw new IllegalStateException("Can not add an instance of " + obj.getClass().getName() +
+ " as a function item.");
+ }
+ }
+ }
+
+ public ExpressionNode getValue() {
+ return value;
+ }
+
+ public AttributeNode setValue(ExpressionNode value) {
+ this.value = value;
+ return this;
+ }
+
+ public List<Item> getItems() {
+ return items;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return null;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public Object evaluate(Context context) {
+ String pos = value.toString();
+ Object obj = value.evaluate(context);
+
+ StringBuilder builder = new StringBuilder();
+ for (Item item : items) {
+ if (obj == null) {
+ throw new IllegalStateException("Can not invoke '" + item + "' on '" + pos + "' because that term " +
+ "evaluated to null.");
+ }
+ if (item.getType() != Item.FUNCTION) {
+ if (builder.length() > 0) {
+ builder.append(".");
+ }
+
+ builder.append(item.getName());
+ } else {
+ if (builder.length() > 0) {
+ obj = evaluateFieldPath(builder.toString(), obj);
+ builder = new StringBuilder();
+ }
+
+ obj = evaluateFunction(item.getName(), obj);
+ }
+
+ pos = pos + "." + item;
+ }
+
+ if (builder.length() > 0) {
+ obj = evaluateFieldPath(builder.toString(), obj);
+ }
+ return obj;
+ }
+
+ public static class VariableValueList extends ArrayList<ResultList.VariableValue> {
+
+ }
+
+ static class IteratorHandler extends FieldPathIteratorHandler {
+ VariableValueList values = new VariableValueList();
+
+ @Override
+ public void onPrimitive(FieldValue fv) {
+ values.add(new ResultList.VariableValue((VariableMap)getVariables().clone(), fv));
+ }
+ }
+
+ private static Object applyFunction(String function, Object value) {
+ if (function.equalsIgnoreCase("abs")) {
+ if (Number.class.isInstance(value)) {
+ Number nValue = (Number)value;
+ if (value instanceof Double) {
+ return nValue.doubleValue() * (nValue.doubleValue() < 0 ? -1 : 1);
+ } else if (value instanceof Float) {
+ return nValue.floatValue() * (nValue.floatValue() < 0 ? -1 : 1);
+ } else if (value instanceof Long) {
+ return nValue.longValue() * (nValue.longValue() < 0 ? -1 : 1);
+ } else if (value instanceof Integer) {
+ return nValue.intValue() * (nValue.intValue() < 0 ? -1 : 1);
+ }
+ }
+ throw new IllegalStateException("Function 'abs' is only available for numerical values.");
+ } else if (function.equalsIgnoreCase("hash")) {
+ return BobHash.hash(value.toString());
+ } else if (function.equalsIgnoreCase("lowercase")) {
+ return value.toString().toLowerCase();
+ } else if (function.equalsIgnoreCase("uppercase")) {
+ return value.toString().toUpperCase();
+ }
+ throw new IllegalStateException("Function '" + function + "' is not supported.");
+ }
+
+ private static Object evaluateFieldPath(String fieldPth, Object value) {
+ if (value instanceof DocumentPut) {
+ final Document doc = ((DocumentPut) value).getDocument();
+ FieldPath fieldPath = doc.getDataType().buildFieldPath(fieldPth);
+ IteratorHandler handler = new IteratorHandler();
+ doc.iterateNested(fieldPath, 0, handler);
+ return handler.values;
+ } else if (value instanceof DocumentUpdate) {
+ return Result.INVALID;
+ }
+ return Result.FALSE;
+ //throw new IllegalStateException("Attributes are only available for document types for value '" + value + "'. Looking for " + fieldPth);
+ }
+
+ private static Object evaluateFunction(String function, Object value) {
+ if (value instanceof VariableValueList) {
+ VariableValueList retVal = new VariableValueList();
+
+ for (ResultList.VariableValue val : ((VariableValueList)value)) {
+ retVal.add(new ResultList.VariableValue(
+ (FieldPathIteratorHandler.VariableMap)val.getVariables().clone(),
+ applyFunction(function, val.getValue())));
+ }
+
+ return retVal;
+ }
+
+ return applyFunction(function, value);
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder ret = new StringBuilder();
+ ret.append(value);
+ for (Item item : items) {
+ ret.append(".").append(item);
+ }
+ return ret.toString();
+ }
+
+ public OrderingSpecification getOrdering(int order) {
+ return null;
+ }
+
+ public static class Item {
+ public static final int ATTRIBUTE = 0;
+ public static final int FUNCTION = 1;
+
+ private String name;
+ private int type = ATTRIBUTE;
+
+ public Item(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Item setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public Item setType(int type) {
+ this.type = type;
+ return this;
+ }
+
+ @Override public String toString() {
+ return name + (type == FUNCTION ? "()" : "");
+ }
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/ComparisonNode.java b/document/src/main/java/com/yahoo/document/select/rule/ComparisonNode.java
index b0d5030978e..9db5ff0384b 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/ComparisonNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/ComparisonNode.java
@@ -1,435 +1,435 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketId;
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.DocumentId;
-import com.yahoo.document.datatypes.FieldPathIteratorHandler;
-import com.yahoo.document.datatypes.NumericFieldValue;
-import com.yahoo.document.idstring.GroupDocIdString;
-import com.yahoo.document.select.*;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class ComparisonNode implements ExpressionNode {
-
- // The left- and right-hand-side of this comparison.
- private ExpressionNode lhs, rhs;
-
- // The operator string for this.
- private String operator;
-
- /**
- * Constructs a new comparison node.
- *
- * @param lhs The left-hand-side of the comparison.
- * @param operator The comparison operator.
- * @param rhs The right-hand-side of the comparison.
- */
- public ComparisonNode(ExpressionNode lhs, String operator, ExpressionNode rhs) {
- this.lhs = lhs;
- this.operator = operator;
- this.rhs = rhs;
- }
-
- /**
- * Returns the left hand side of this comparison.
- *
- * @return The left hand side expression.
- */
- public ExpressionNode getLHS() {
- return lhs;
- }
-
- /**
- * Sets the left hand side of this comparison.
- *
- * @param lhs The new left hand side.
- * @return This, to allow chaining.
- */
- public ComparisonNode setLHS(ExpressionNode lhs) {
- this.lhs = lhs;
- return this;
- }
-
- /**
- * Returns the comparison operator of this.
- *
- * @return The operator.
- */
- public String getOperator() {
- return operator;
- }
-
- /**
- * Sets the comparison operator of this.
- *
- * @param operator The operator string.
- * @return This, to allow chaining.
- */
- public ComparisonNode setOperator(String operator) {
- this.operator = operator;
- return this;
- }
-
- /**
- * Returns the right hand side of this comparison.
- *
- * @return The right hand side expression.
- */
- public ExpressionNode getRHS() {
- return rhs;
- }
-
- /**
- * Sets the right hand side of this comparison.
- *
- * @param rhs The new right hand side.
- * @return This, to allow chaining.
- */
- public ComparisonNode setRHS(ExpressionNode rhs) {
- this.rhs = rhs;
- return this;
- }
-
- public OrderingSpecification getOrdering(IdNode lhs, LiteralNode rhs, String operator, int order) {
- if (lhs.getWidthBits() == -1 || lhs.getDivisionBits() == -1 || !(rhs.getValue() instanceof Long)) {
- return null;
- }
-
- if (operator.equals("==") || operator.equals("=")) {
- return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits());
- }
-
- if (order == OrderingSpecification.ASCENDING) {
- if ((operator.equals("<") || operator.equals("<="))) {
- return new OrderingSpecification(order, 0, lhs.getWidthBits(), lhs.getDivisionBits());
- }
- if (operator.equals(">")) {
- return new OrderingSpecification(order, (Long)rhs.getValue() + 1, lhs.getWidthBits(), lhs.getDivisionBits());
- }
- if (operator.equals(">=")) {
- return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits());
- }
- } else {
- if (operator.equals("<")) {
- return new OrderingSpecification(order, (Long)rhs.getValue() - 1, lhs.getWidthBits(), lhs.getDivisionBits());
- }
- if (operator.equals("<=")) {
- return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits());
- }
- }
- return null;
- }
-
- public OrderingSpecification getOrdering(int order) {
- if (lhs instanceof IdNode && rhs instanceof LiteralNode) {
- return getOrdering((IdNode)lhs, (LiteralNode)rhs, operator, order);
- } else if (rhs instanceof IdNode && lhs instanceof LiteralNode) {
- return getOrdering((IdNode)rhs, (LiteralNode)rhs, operator, order);
- }
-
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- if (operator.equals("==") || operator.equals("=")) {
- if (lhs instanceof IdNode && rhs instanceof LiteralNode) {
- return compare(factory, (IdNode)lhs, (LiteralNode)rhs, operator);
- } else if (rhs instanceof IdNode && lhs instanceof LiteralNode) {
- return compare(factory, (IdNode)rhs, (LiteralNode)lhs, operator);
- } else if (lhs instanceof SearchColumnNode && rhs instanceof LiteralNode) {
- return compare(factory, (SearchColumnNode)lhs, (LiteralNode)rhs);
- } else if (rhs instanceof SearchColumnNode && lhs instanceof LiteralNode) {
- return compare(factory, (SearchColumnNode)rhs, (LiteralNode)lhs);
- }
- }
- return null;
- }
-
- /**
- * Compares a search column node with a literal node.
- *
- * @param factory The bucket id factory used.
- * @param node The search column node.
- * @param literal The literal node to compare to.
- * @return The bucket set containing the buckets covered.
- */
- private BucketSet compare(BucketIdFactory factory, SearchColumnNode node, LiteralNode literal) {
- Object value = literal.getValue();
- int bucketCount = (int) Math.pow(2, 16);
- if (value instanceof Long) {
- BucketSet ret = new BucketSet();
- for (int i = 0; i < bucketCount; i++) {
- BucketId id = new BucketId(16, i);
- if ((Long)value == node.getDistribution().getColumn(id)) {
- ret.add(new BucketId(16, i));
- }
- }
- return ret;
- }
- return null;
- }
-
- private BucketSet compare(BucketIdFactory factory, IdNode id, LiteralNode literal, String operator) {
- String field = id.getField();
- Object value = literal.getValue();
- if (field == null) {
- if (value instanceof String) {
- String name = (String)value;
- if ((operator.equals("=") && name.contains("*")) ||
- (operator.equals("=~") && ((name.contains("*") || name.contains("?")))))
- {
- return null; // no idea
- }
- return new BucketSet(factory.getBucketId(new DocumentId(name)));
- }
- } else if (field.equalsIgnoreCase("user")) {
- if (value instanceof Long) {
- return new BucketSet(new BucketId(factory.getLocationBitCount(), (Long)value));
- }
- } else if (field.equalsIgnoreCase("group")) {
- if (value instanceof String) {
- String name = (String)value;
- if ((operator.equals("=") && name.contains("*")) ||
- (operator.equals("=~") && ((name.contains("*") || name.contains("?")))))
- {
- return null; // no idea
- }
- return new BucketSet(new BucketId(factory.getLocationBitCount(), new GroupDocIdString("", name, "").getLocation()));
- }
- } else if (field.equalsIgnoreCase("bucket")) {
- if (value instanceof Long) {
- return new BucketSet(new BucketId((Long)value));
- }
- }
- return null;
- }
-
- // Inherit doc from Node.
- public Object evaluate(Context context) {
- Object oLeft = lhs.evaluate(context);
- Object oRight = rhs.evaluate(context);
- if (oLeft == null && oRight == null) {
- return new ResultList(Result.TRUE);
- }
- if (oLeft == Result.INVALID || oRight == Result.INVALID) {
- return new ResultList(Result.INVALID);
- }
- if (oLeft instanceof AttributeNode.VariableValueList && oRight instanceof AttributeNode.VariableValueList) {
- if (operator.equals("==")) {
- return evaluateListsTrue((AttributeNode.VariableValueList)oLeft, (AttributeNode.VariableValueList)oRight);
- } else if (operator.equals("!=")) {
- return evaluateListsFalse((AttributeNode.VariableValueList)oLeft, (AttributeNode.VariableValueList)oRight);
- } else {
- return new ResultList(Result.INVALID);
- }
- } else if (oLeft instanceof AttributeNode.VariableValueList) {
- return evaluateListAndSingle((AttributeNode.VariableValueList)oLeft, oRight);
- } else if (oRight instanceof AttributeNode.VariableValueList) {
- return evaluateListAndSingle((AttributeNode.VariableValueList)oRight, oLeft);
- }
- return new ResultList(evaluateBool(oLeft, oRight));
- }
-
- public ResultList evaluateListsTrue(AttributeNode.VariableValueList lhs, AttributeNode.VariableValueList rhs) {
- if (lhs.size() != rhs.size()) {
- return new ResultList(Result.FALSE);
- }
-
- for (int i = 0; i < lhs.size(); i++) {
- if (!lhs.get(i).getVariables().equals(rhs.get(i).getVariables())) {
- return new ResultList(Result.FALSE);
- }
-
- if (evaluateEquals(lhs.get(i).getValue(), rhs.get(i).getValue()) == Result.FALSE) {
- return new ResultList(Result.FALSE);
- }
- }
-
- return new ResultList(Result.TRUE);
- }
-
- public ResultList evaluateListsFalse(AttributeNode.VariableValueList lhs, AttributeNode.VariableValueList rhs) {
- ResultList lst = evaluateListsTrue(lhs, rhs);
- if (lst.toResult() == Result.TRUE) {
- return new ResultList(Result.FALSE);
- } else if (lst.toResult() == Result.FALSE) {
- return new ResultList(Result.TRUE);
- } else {
- return lst;
- }
- }
-
- public ResultList evaluateListAndSingle(AttributeNode.VariableValueList lhs, Object rhs) {
- if (rhs == null && lhs == null) {
- return new ResultList(Result.TRUE);
- }
-
- if (rhs == null || lhs == null) {
- return new ResultList(Result.FALSE);
- }
-
- ResultList retVal = new ResultList();
- for (int i = 0; i < lhs.size(); i++) {
- Result result = evaluateBool(lhs.get(i).getValue(), rhs);
- retVal.add((FieldPathIteratorHandler.VariableMap)lhs.get(i).getVariables().clone(), result);
- }
-
- return retVal;
- }
-
- /**
- * Evaluate this expression on two operands, given that they are not invalid.
- *
- * @param lhs Left hand side of operation.
- * @param rhs Right hand side of operation.
- * @return The evaluation result.
- */
- private Result evaluateBool(Object lhs, Object rhs) {
- if (operator.equals("==")) {
- return evaluateEquals(lhs, rhs);
- } else if (operator.equals("!=")) {
- return Result.invert(evaluateEquals(lhs, rhs));
- } else if (operator.equals("<") || operator.equals("<=") ||
- operator.equals(">") || operator.equals(">=")) {
- return evaluateNumber(lhs, rhs);
- } else if (operator.equals("=~") || operator.equals("=")) {
- return evaluateString(lhs, rhs);
- }
- throw new IllegalStateException("Comparison operator '" + operator + "' is not supported.");
- }
-
- /**
- * Compare two operands for equality.
- *
- * @param lhs Left hand side of operation.
- * @param rhs Right hand side of operation.
- * @return Wether or not the two operands are equal.
- */
- private Result evaluateEquals(Object lhs, Object rhs) {
- if (lhs == null || rhs == null) {
- return Result.toResult(lhs == rhs);
- }
-
- double a = getAsNumber(lhs);
- double b = getAsNumber(rhs);
- if (Double.isNaN(a) || Double.isNaN(b)) {
- return Result.toResult(lhs.toString().equals(rhs.toString()));
- }
- return Result.toResult(a == b); // Ugh, comparing doubles? Should be converted to long value perhaps...
- }
-
- private double getAsNumber(Object value) {
- if (value instanceof Number) {
- return ((Number)value).doubleValue();
- } else if (value instanceof NumericFieldValue) {
- return getAsNumber(((NumericFieldValue)value).getNumber());
- } else {
- return Double.NaN; //new IllegalStateException("Term '" + value + "' (" + value.getClass() + ") does not evaluate to a number.");
- }
- }
-
- /**
- * Evalutes the value of this term over a document, given that both operands must be numbers.
- *
- * @param lhs Left hand side of operation.
- * @param rhs Right hand side of operation.
- * @return The evaluation result.
- */
- private Result evaluateNumber(Object lhs, Object rhs) {
- double a = getAsNumber(lhs);
- double b = getAsNumber(rhs);
- if (Double.isNaN(a) || Double.isNaN(b)) {
- return Result.INVALID;
- }
- if (operator.equals("<")) {
- return Result.toResult(a < b);
- } else if (operator.equals("<=")) {
- return Result.toResult(a <= b);
- } else if (operator.equals(">")) {
- return Result.toResult(a > b);
- } else {
- return Result.toResult(a >= b);
- }
- }
-
- /**
- * Evalutes the value of this term over a document, given that both operands must be strings.
- *
- * @param lhs Left hand side of operation.
- * @param rhs Right hand side of operation.
- * @return The evaluation result.
- */
- private Result evaluateString(Object lhs, Object rhs) {
- String left = "" + lhs; // Allows null objects to evaluate to string.
- String right = "" + rhs;
- if (operator.equals("=~")) {
- return Result.toResult(Pattern.compile(right).matcher(left).find());
- } else {
- return Result.toResult(Pattern.compile(globToRegex(right)).matcher(left).find());
- }
- }
-
- /**
- * Converts a glob pattern to a corresponding regular expression string.
- *
- * @param glob The glob pattern.
- * @return The regex string.
- */
- private String globToRegex(String glob) {
- StringBuilder ret = new StringBuilder();
- ret.append("^");
- for (int i = 0; i < glob.length(); i++) {
- ret.append(globToRegex(glob.charAt(i)));
- }
- ret.append("$");
-
- return ret.toString();
- }
-
- /**
- * Converts a single character in a glob expression to the corresponding regular expression string.
- *
- * @param glob The glob character.
- * @return The regex string.
- */
- private String globToRegex(char glob) {
- switch (glob) {
- case'*':
- return ".*";
- case'?':
- return ".";
- case'^':
- case'$':
- case'|':
- case'{':
- case'}':
- case'(':
- case')':
- case'[':
- case']':
- case'\\':
- case'+':
- case'.':
- return "\\" + glob;
- default:
- return "" + glob;
- }
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- // Inherit doc from Object.
- @Override
- public String toString() {
- return lhs + " " + operator + " " + rhs;
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.BucketId;
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.DocumentId;
+import com.yahoo.document.datatypes.FieldPathIteratorHandler;
+import com.yahoo.document.datatypes.NumericFieldValue;
+import com.yahoo.document.idstring.GroupDocIdString;
+import com.yahoo.document.select.*;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class ComparisonNode implements ExpressionNode {
+
+ // The left- and right-hand-side of this comparison.
+ private ExpressionNode lhs, rhs;
+
+ // The operator string for this.
+ private String operator;
+
+ /**
+ * Constructs a new comparison node.
+ *
+ * @param lhs The left-hand-side of the comparison.
+ * @param operator The comparison operator.
+ * @param rhs The right-hand-side of the comparison.
+ */
+ public ComparisonNode(ExpressionNode lhs, String operator, ExpressionNode rhs) {
+ this.lhs = lhs;
+ this.operator = operator;
+ this.rhs = rhs;
+ }
+
+ /**
+ * Returns the left hand side of this comparison.
+ *
+ * @return The left hand side expression.
+ */
+ public ExpressionNode getLHS() {
+ return lhs;
+ }
+
+ /**
+ * Sets the left hand side of this comparison.
+ *
+ * @param lhs The new left hand side.
+ * @return This, to allow chaining.
+ */
+ public ComparisonNode setLHS(ExpressionNode lhs) {
+ this.lhs = lhs;
+ return this;
+ }
+
+ /**
+ * Returns the comparison operator of this.
+ *
+ * @return The operator.
+ */
+ public String getOperator() {
+ return operator;
+ }
+
+ /**
+ * Sets the comparison operator of this.
+ *
+ * @param operator The operator string.
+ * @return This, to allow chaining.
+ */
+ public ComparisonNode setOperator(String operator) {
+ this.operator = operator;
+ return this;
+ }
+
+ /**
+ * Returns the right hand side of this comparison.
+ *
+ * @return The right hand side expression.
+ */
+ public ExpressionNode getRHS() {
+ return rhs;
+ }
+
+ /**
+ * Sets the right hand side of this comparison.
+ *
+ * @param rhs The new right hand side.
+ * @return This, to allow chaining.
+ */
+ public ComparisonNode setRHS(ExpressionNode rhs) {
+ this.rhs = rhs;
+ return this;
+ }
+
+ public OrderingSpecification getOrdering(IdNode lhs, LiteralNode rhs, String operator, int order) {
+ if (lhs.getWidthBits() == -1 || lhs.getDivisionBits() == -1 || !(rhs.getValue() instanceof Long)) {
+ return null;
+ }
+
+ if (operator.equals("==") || operator.equals("=")) {
+ return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits());
+ }
+
+ if (order == OrderingSpecification.ASCENDING) {
+ if ((operator.equals("<") || operator.equals("<="))) {
+ return new OrderingSpecification(order, 0, lhs.getWidthBits(), lhs.getDivisionBits());
+ }
+ if (operator.equals(">")) {
+ return new OrderingSpecification(order, (Long)rhs.getValue() + 1, lhs.getWidthBits(), lhs.getDivisionBits());
+ }
+ if (operator.equals(">=")) {
+ return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits());
+ }
+ } else {
+ if (operator.equals("<")) {
+ return new OrderingSpecification(order, (Long)rhs.getValue() - 1, lhs.getWidthBits(), lhs.getDivisionBits());
+ }
+ if (operator.equals("<=")) {
+ return new OrderingSpecification(order, (Long)rhs.getValue(), lhs.getWidthBits(), lhs.getDivisionBits());
+ }
+ }
+ return null;
+ }
+
+ public OrderingSpecification getOrdering(int order) {
+ if (lhs instanceof IdNode && rhs instanceof LiteralNode) {
+ return getOrdering((IdNode)lhs, (LiteralNode)rhs, operator, order);
+ } else if (rhs instanceof IdNode && lhs instanceof LiteralNode) {
+ return getOrdering((IdNode)rhs, (LiteralNode)rhs, operator, order);
+ }
+
+ return null;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ if (operator.equals("==") || operator.equals("=")) {
+ if (lhs instanceof IdNode && rhs instanceof LiteralNode) {
+ return compare(factory, (IdNode)lhs, (LiteralNode)rhs, operator);
+ } else if (rhs instanceof IdNode && lhs instanceof LiteralNode) {
+ return compare(factory, (IdNode)rhs, (LiteralNode)lhs, operator);
+ } else if (lhs instanceof SearchColumnNode && rhs instanceof LiteralNode) {
+ return compare(factory, (SearchColumnNode)lhs, (LiteralNode)rhs);
+ } else if (rhs instanceof SearchColumnNode && lhs instanceof LiteralNode) {
+ return compare(factory, (SearchColumnNode)rhs, (LiteralNode)lhs);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Compares a search column node with a literal node.
+ *
+ * @param factory The bucket id factory used.
+ * @param node The search column node.
+ * @param literal The literal node to compare to.
+ * @return The bucket set containing the buckets covered.
+ */
+ private BucketSet compare(BucketIdFactory factory, SearchColumnNode node, LiteralNode literal) {
+ Object value = literal.getValue();
+ int bucketCount = (int) Math.pow(2, 16);
+ if (value instanceof Long) {
+ BucketSet ret = new BucketSet();
+ for (int i = 0; i < bucketCount; i++) {
+ BucketId id = new BucketId(16, i);
+ if ((Long)value == node.getDistribution().getColumn(id)) {
+ ret.add(new BucketId(16, i));
+ }
+ }
+ return ret;
+ }
+ return null;
+ }
+
+ private BucketSet compare(BucketIdFactory factory, IdNode id, LiteralNode literal, String operator) {
+ String field = id.getField();
+ Object value = literal.getValue();
+ if (field == null) {
+ if (value instanceof String) {
+ String name = (String)value;
+ if ((operator.equals("=") && name.contains("*")) ||
+ (operator.equals("=~") && ((name.contains("*") || name.contains("?")))))
+ {
+ return null; // no idea
+ }
+ return new BucketSet(factory.getBucketId(new DocumentId(name)));
+ }
+ } else if (field.equalsIgnoreCase("user")) {
+ if (value instanceof Long) {
+ return new BucketSet(new BucketId(factory.getLocationBitCount(), (Long)value));
+ }
+ } else if (field.equalsIgnoreCase("group")) {
+ if (value instanceof String) {
+ String name = (String)value;
+ if ((operator.equals("=") && name.contains("*")) ||
+ (operator.equals("=~") && ((name.contains("*") || name.contains("?")))))
+ {
+ return null; // no idea
+ }
+ return new BucketSet(new BucketId(factory.getLocationBitCount(), new GroupDocIdString("", name, "").getLocation()));
+ }
+ } else if (field.equalsIgnoreCase("bucket")) {
+ if (value instanceof Long) {
+ return new BucketSet(new BucketId((Long)value));
+ }
+ }
+ return null;
+ }
+
+ // Inherit doc from Node.
+ public Object evaluate(Context context) {
+ Object oLeft = lhs.evaluate(context);
+ Object oRight = rhs.evaluate(context);
+ if (oLeft == null && oRight == null) {
+ return new ResultList(Result.TRUE);
+ }
+ if (oLeft == Result.INVALID || oRight == Result.INVALID) {
+ return new ResultList(Result.INVALID);
+ }
+ if (oLeft instanceof AttributeNode.VariableValueList && oRight instanceof AttributeNode.VariableValueList) {
+ if (operator.equals("==")) {
+ return evaluateListsTrue((AttributeNode.VariableValueList)oLeft, (AttributeNode.VariableValueList)oRight);
+ } else if (operator.equals("!=")) {
+ return evaluateListsFalse((AttributeNode.VariableValueList)oLeft, (AttributeNode.VariableValueList)oRight);
+ } else {
+ return new ResultList(Result.INVALID);
+ }
+ } else if (oLeft instanceof AttributeNode.VariableValueList) {
+ return evaluateListAndSingle((AttributeNode.VariableValueList)oLeft, oRight);
+ } else if (oRight instanceof AttributeNode.VariableValueList) {
+ return evaluateListAndSingle((AttributeNode.VariableValueList)oRight, oLeft);
+ }
+ return new ResultList(evaluateBool(oLeft, oRight));
+ }
+
+ public ResultList evaluateListsTrue(AttributeNode.VariableValueList lhs, AttributeNode.VariableValueList rhs) {
+ if (lhs.size() != rhs.size()) {
+ return new ResultList(Result.FALSE);
+ }
+
+ for (int i = 0; i < lhs.size(); i++) {
+ if (!lhs.get(i).getVariables().equals(rhs.get(i).getVariables())) {
+ return new ResultList(Result.FALSE);
+ }
+
+ if (evaluateEquals(lhs.get(i).getValue(), rhs.get(i).getValue()) == Result.FALSE) {
+ return new ResultList(Result.FALSE);
+ }
+ }
+
+ return new ResultList(Result.TRUE);
+ }
+
+ public ResultList evaluateListsFalse(AttributeNode.VariableValueList lhs, AttributeNode.VariableValueList rhs) {
+ ResultList lst = evaluateListsTrue(lhs, rhs);
+ if (lst.toResult() == Result.TRUE) {
+ return new ResultList(Result.FALSE);
+ } else if (lst.toResult() == Result.FALSE) {
+ return new ResultList(Result.TRUE);
+ } else {
+ return lst;
+ }
+ }
+
+ public ResultList evaluateListAndSingle(AttributeNode.VariableValueList lhs, Object rhs) {
+ if (rhs == null && lhs == null) {
+ return new ResultList(Result.TRUE);
+ }
+
+ if (rhs == null || lhs == null) {
+ return new ResultList(Result.FALSE);
+ }
+
+ ResultList retVal = new ResultList();
+ for (int i = 0; i < lhs.size(); i++) {
+ Result result = evaluateBool(lhs.get(i).getValue(), rhs);
+ retVal.add((FieldPathIteratorHandler.VariableMap)lhs.get(i).getVariables().clone(), result);
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Evaluate this expression on two operands, given that they are not invalid.
+ *
+ * @param lhs Left hand side of operation.
+ * @param rhs Right hand side of operation.
+ * @return The evaluation result.
+ */
+ private Result evaluateBool(Object lhs, Object rhs) {
+ if (operator.equals("==")) {
+ return evaluateEquals(lhs, rhs);
+ } else if (operator.equals("!=")) {
+ return Result.invert(evaluateEquals(lhs, rhs));
+ } else if (operator.equals("<") || operator.equals("<=") ||
+ operator.equals(">") || operator.equals(">=")) {
+ return evaluateNumber(lhs, rhs);
+ } else if (operator.equals("=~") || operator.equals("=")) {
+ return evaluateString(lhs, rhs);
+ }
+ throw new IllegalStateException("Comparison operator '" + operator + "' is not supported.");
+ }
+
+ /**
+ * Compare two operands for equality.
+ *
+ * @param lhs Left hand side of operation.
+ * @param rhs Right hand side of operation.
+ * @return Wether or not the two operands are equal.
+ */
+ private Result evaluateEquals(Object lhs, Object rhs) {
+ if (lhs == null || rhs == null) {
+ return Result.toResult(lhs == rhs);
+ }
+
+ double a = getAsNumber(lhs);
+ double b = getAsNumber(rhs);
+ if (Double.isNaN(a) || Double.isNaN(b)) {
+ return Result.toResult(lhs.toString().equals(rhs.toString()));
+ }
+ return Result.toResult(a == b); // Ugh, comparing doubles? Should be converted to long value perhaps...
+ }
+
+ private double getAsNumber(Object value) {
+ if (value instanceof Number) {
+ return ((Number)value).doubleValue();
+ } else if (value instanceof NumericFieldValue) {
+ return getAsNumber(((NumericFieldValue)value).getNumber());
+ } else {
+ return Double.NaN; //new IllegalStateException("Term '" + value + "' (" + value.getClass() + ") does not evaluate to a number.");
+ }
+ }
+
+ /**
+ * Evalutes the value of this term over a document, given that both operands must be numbers.
+ *
+ * @param lhs Left hand side of operation.
+ * @param rhs Right hand side of operation.
+ * @return The evaluation result.
+ */
+ private Result evaluateNumber(Object lhs, Object rhs) {
+ double a = getAsNumber(lhs);
+ double b = getAsNumber(rhs);
+ if (Double.isNaN(a) || Double.isNaN(b)) {
+ return Result.INVALID;
+ }
+ if (operator.equals("<")) {
+ return Result.toResult(a < b);
+ } else if (operator.equals("<=")) {
+ return Result.toResult(a <= b);
+ } else if (operator.equals(">")) {
+ return Result.toResult(a > b);
+ } else {
+ return Result.toResult(a >= b);
+ }
+ }
+
+ /**
+ * Evalutes the value of this term over a document, given that both operands must be strings.
+ *
+ * @param lhs Left hand side of operation.
+ * @param rhs Right hand side of operation.
+ * @return The evaluation result.
+ */
+ private Result evaluateString(Object lhs, Object rhs) {
+ String left = "" + lhs; // Allows null objects to evaluate to string.
+ String right = "" + rhs;
+ if (operator.equals("=~")) {
+ return Result.toResult(Pattern.compile(right).matcher(left).find());
+ } else {
+ return Result.toResult(Pattern.compile(globToRegex(right)).matcher(left).find());
+ }
+ }
+
+ /**
+ * Converts a glob pattern to a corresponding regular expression string.
+ *
+ * @param glob The glob pattern.
+ * @return The regex string.
+ */
+ private String globToRegex(String glob) {
+ StringBuilder ret = new StringBuilder();
+ ret.append("^");
+ for (int i = 0; i < glob.length(); i++) {
+ ret.append(globToRegex(glob.charAt(i)));
+ }
+ ret.append("$");
+
+ return ret.toString();
+ }
+
+ /**
+ * Converts a single character in a glob expression to the corresponding regular expression string.
+ *
+ * @param glob The glob character.
+ * @return The regex string.
+ */
+ private String globToRegex(char glob) {
+ switch (glob) {
+ case'*':
+ return ".*";
+ case'?':
+ return ".";
+ case'^':
+ case'$':
+ case'|':
+ case'{':
+ case'}':
+ case'(':
+ case')':
+ case'[':
+ case']':
+ case'\\':
+ case'+':
+ case'.':
+ return "\\" + glob;
+ default:
+ return "" + glob;
+ }
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ // Inherit doc from Object.
+ @Override
+ public String toString() {
+ return lhs + " " + operator + " " + rhs;
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/DocumentNode.java b/document/src/main/java/com/yahoo/document/select/rule/DocumentNode.java
index c071e6674aa..2b095db16c9 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/DocumentNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/DocumentNode.java
@@ -1,65 +1,65 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.*;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class DocumentNode implements ExpressionNode {
-
- private String type;
-
- public DocumentNode(String type) {
- this.type = type;
- }
-
- public String getType() {
- return type;
- }
-
- public DocumentNode setType(String type) {
- this.type = type;
- return this;
- }
-
- @Override
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- @Override
- public Object evaluate(Context context) {
- return evaluate(context.getDocumentOperation());
- }
-
- public Object evaluate(DocumentOperation op) {
- DocumentType doct;
- if (op instanceof DocumentPut) {
- doct = ((DocumentPut)op).getDocument().getDataType();
- } else if (op instanceof DocumentUpdate) {
- doct = ((DocumentUpdate)op).getDocumentType();
- } else {
- throw new IllegalStateException("Document class '" + op.getClass().getName() + "' is not supported.");
- }
- return doct.isA(this.type) ? op : Boolean.FALSE;
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return type;
- }
-
- @Override
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.*;
+import com.yahoo.document.select.BucketSet;
+import com.yahoo.document.select.Context;
+import com.yahoo.document.select.OrderingSpecification;
+import com.yahoo.document.select.Visitor;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class DocumentNode implements ExpressionNode {
+
+ private String type;
+
+ public DocumentNode(String type) {
+ this.type = type;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public DocumentNode setType(String type) {
+ this.type = type;
+ return this;
+ }
+
+ @Override
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return null;
+ }
+
+ @Override
+ public Object evaluate(Context context) {
+ return evaluate(context.getDocumentOperation());
+ }
+
+ public Object evaluate(DocumentOperation op) {
+ DocumentType doct;
+ if (op instanceof DocumentPut) {
+ doct = ((DocumentPut)op).getDocument().getDataType();
+ } else if (op instanceof DocumentUpdate) {
+ doct = ((DocumentUpdate)op).getDocumentType();
+ } else {
+ throw new IllegalStateException("Document class '" + op.getClass().getName() + "' is not supported.");
+ }
+ return doct.isA(this.type) ? op : Boolean.FALSE;
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ return type;
+ }
+
+ @Override
+ public OrderingSpecification getOrdering(int order) {
+ return null;
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/EmbracedNode.java b/document/src/main/java/com/yahoo/document/select/rule/EmbracedNode.java
index 13b20695cab..12192af7607 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/EmbracedNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/EmbracedNode.java
@@ -1,51 +1,51 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class EmbracedNode implements ExpressionNode {
-
- private ExpressionNode node;
-
- public EmbracedNode(ExpressionNode node) {
- this.node = node;
- }
-
- public ExpressionNode getNode() {
- return node;
- }
-
- public EmbracedNode setNode(ExpressionNode node) {
- this.node = node;
- return this;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return node.getBucketSet(factory);
- }
-
- public Object evaluate(Context context) {
- return node.evaluate(context);
- }
-
- @Override
- public String toString() {
- return "(" + node + ")";
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.select.BucketSet;
+import com.yahoo.document.select.Context;
+import com.yahoo.document.select.OrderingSpecification;
+import com.yahoo.document.select.Visitor;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class EmbracedNode implements ExpressionNode {
+
+ private ExpressionNode node;
+
+ public EmbracedNode(ExpressionNode node) {
+ this.node = node;
+ }
+
+ public ExpressionNode getNode() {
+ return node;
+ }
+
+ public EmbracedNode setNode(ExpressionNode node) {
+ this.node = node;
+ return this;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return node.getBucketSet(factory);
+ }
+
+ public Object evaluate(Context context) {
+ return node.evaluate(context);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + node + ")";
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ public OrderingSpecification getOrdering(int order) {
+ return null;
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/ExpressionNode.java b/document/src/main/java/com/yahoo/document/select/rule/ExpressionNode.java
index ba51ec840d4..d84259f2643 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/ExpressionNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/ExpressionNode.java
@@ -1,48 +1,48 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-
-/**
- * This is the interface of all expression nodes. It declares the methods requires by all expression nodes to maintain
- * a working document selector language.
- *
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public interface ExpressionNode {
-
- /**
- * Evaluate the content of this node based on document object, and return that value.
- *
- * @param doc The document to evaluate over.
- * @return The value of this.
- */
- public Object evaluate(Context doc);
-
- /**
- * Returns the set of bucket ids covered by this node.
- *
- * @param factory The factory used by the current application.
- */
- public BucketSet getBucketSet(BucketIdFactory factory);
-
- /**
- * If this document selection implies a specific ordering (using the orderdoc scheme),
- * return that specification.
- *
- * @param order The order in which we are looking to traverse the ordering (ASCENDING or DESCENDING)
- */
- public OrderingSpecification getOrdering(int order);
-
- /**
- * Perform visitation of this node.
- *
- * @param visitor The visitor that wishes to visit the node.
- */
- public void accept(Visitor visitor);
-
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.select.BucketSet;
+import com.yahoo.document.select.Context;
+import com.yahoo.document.select.OrderingSpecification;
+import com.yahoo.document.select.Visitor;
+
+/**
+ * This is the interface of all expression nodes. It declares the methods requires by all expression nodes to maintain
+ * a working document selector language.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public interface ExpressionNode {
+
+ /**
+ * Evaluate the content of this node based on document object, and return that value.
+ *
+ * @param doc The document to evaluate over.
+ * @return The value of this.
+ */
+ public Object evaluate(Context doc);
+
+ /**
+ * Returns the set of bucket ids covered by this node.
+ *
+ * @param factory The factory used by the current application.
+ */
+ public BucketSet getBucketSet(BucketIdFactory factory);
+
+ /**
+ * If this document selection implies a specific ordering (using the orderdoc scheme),
+ * return that specification.
+ *
+ * @param order The order in which we are looking to traverse the ordering (ASCENDING or DESCENDING)
+ */
+ public OrderingSpecification getOrdering(int order);
+
+ /**
+ * Perform visitation of this node.
+ *
+ * @param visitor The visitor that wishes to visit the node.
+ */
+ public void accept(Visitor visitor);
+
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/IdNode.java b/document/src/main/java/com/yahoo/document/select/rule/IdNode.java
index f12ecbb752b..75b4890af80 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/IdNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/IdNode.java
@@ -1,108 +1,108 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.DocumentId;
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.*;
-import com.yahoo.document.idstring.*;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class IdNode implements ExpressionNode {
-
- private String field;
- private short widthBits = -1;
- private short divisionBits = -1;
-
- public IdNode() {
- // empty
- }
-
- public String getField() {
- return field;
- }
-
- public IdNode setField(String field) {
- this.field = field;
- return this;
- }
-
- public IdNode setWidthBits(short widthBits) {
- this.widthBits = widthBits;
- return this;
- }
-
- public IdNode setDivisionBits(short divisionBits) {
- this.divisionBits = divisionBits;
- return this;
- }
-
- public short getWidthBits() {
- return widthBits;
- }
-
- public short getDivisionBits() {
- return divisionBits;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- public OrderingSpecification getOrdering(int ordering) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- DocumentId id = context.getDocumentOperation().getId();
- if (id == null) {
- throw new IllegalStateException("Document has no identifier.");
- }
- if (field == null) {
- return id.toString();
- } else if (field.equalsIgnoreCase("scheme")) {
- return id.getScheme().getType().toString();
- } else if (field.equalsIgnoreCase("namespace")) {
- return id.getScheme().getNamespace();
- } else if (field.equalsIgnoreCase("specific")) {
- return id.getScheme().getNamespaceSpecific();
- } else if (field.equalsIgnoreCase("group")) {
- if (id.getScheme().hasGroup()) {
- return id.getScheme().getGroup();
- }
- throw new IllegalStateException("Group identifier is null.");
- } else if (field.equalsIgnoreCase("user")) {
- if (id.getScheme().hasNumber()) {
- return id.getScheme().getNumber();
- }
- throw new IllegalStateException("User identifier is null.");
- } else if (field.equalsIgnoreCase("type")) {
- if (id.getScheme().hasDocType()) {
- return id.getScheme().getDocType();
- }
- throw new IllegalStateException("Document id doesn't have doc type.");
- } else if (field.equalsIgnoreCase("order")) {
- if (id.getScheme() instanceof OrderDocIdString) {
- OrderDocIdString ods = (OrderDocIdString)id.getScheme();
- if (ods.getWidthBits() == widthBits && ods.getDivisionBits() == divisionBits) {
- return ods.getOrdering();
- }
- }
- } else{
- throw new IllegalStateException("Identifier field '" + field + "' is not supported.");
- }
- return null;
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return "id" + (field != null ? "." + field : "") + (widthBits != -1 ? "(" + widthBits + "," + divisionBits + ")" : "");
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.DocumentId;
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.select.*;
+import com.yahoo.document.idstring.*;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class IdNode implements ExpressionNode {
+
+ private String field;
+ private short widthBits = -1;
+ private short divisionBits = -1;
+
+ public IdNode() {
+ // empty
+ }
+
+ public String getField() {
+ return field;
+ }
+
+ public IdNode setField(String field) {
+ this.field = field;
+ return this;
+ }
+
+ public IdNode setWidthBits(short widthBits) {
+ this.widthBits = widthBits;
+ return this;
+ }
+
+ public IdNode setDivisionBits(short divisionBits) {
+ this.divisionBits = divisionBits;
+ return this;
+ }
+
+ public short getWidthBits() {
+ return widthBits;
+ }
+
+ public short getDivisionBits() {
+ return divisionBits;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return null;
+ }
+
+ public OrderingSpecification getOrdering(int ordering) {
+ return null;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public Object evaluate(Context context) {
+ DocumentId id = context.getDocumentOperation().getId();
+ if (id == null) {
+ throw new IllegalStateException("Document has no identifier.");
+ }
+ if (field == null) {
+ return id.toString();
+ } else if (field.equalsIgnoreCase("scheme")) {
+ return id.getScheme().getType().toString();
+ } else if (field.equalsIgnoreCase("namespace")) {
+ return id.getScheme().getNamespace();
+ } else if (field.equalsIgnoreCase("specific")) {
+ return id.getScheme().getNamespaceSpecific();
+ } else if (field.equalsIgnoreCase("group")) {
+ if (id.getScheme().hasGroup()) {
+ return id.getScheme().getGroup();
+ }
+ throw new IllegalStateException("Group identifier is null.");
+ } else if (field.equalsIgnoreCase("user")) {
+ if (id.getScheme().hasNumber()) {
+ return id.getScheme().getNumber();
+ }
+ throw new IllegalStateException("User identifier is null.");
+ } else if (field.equalsIgnoreCase("type")) {
+ if (id.getScheme().hasDocType()) {
+ return id.getScheme().getDocType();
+ }
+ throw new IllegalStateException("Document id doesn't have doc type.");
+ } else if (field.equalsIgnoreCase("order")) {
+ if (id.getScheme() instanceof OrderDocIdString) {
+ OrderDocIdString ods = (OrderDocIdString)id.getScheme();
+ if (ods.getWidthBits() == widthBits && ods.getDivisionBits() == divisionBits) {
+ return ods.getOrdering();
+ }
+ }
+ } else{
+ throw new IllegalStateException("Identifier field '" + field + "' is not supported.");
+ }
+ return null;
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ return "id" + (field != null ? "." + field : "") + (widthBits != -1 ? "(" + widthBits + "," + divisionBits + ")" : "");
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/LiteralNode.java b/document/src/main/java/com/yahoo/document/select/rule/LiteralNode.java
index ae0d640d471..702026b59d3 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/LiteralNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/LiteralNode.java
@@ -1,61 +1,61 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-import com.yahoo.document.select.parser.SelectParserUtils;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class LiteralNode implements ExpressionNode {
-
- private Object value;
-
- public LiteralNode(Object value) {
- this.value = value;
- }
-
- public Object getValue() {
- return value;
- }
-
- public LiteralNode setValue(Object value) {
- this.value = value;
- return this;
- }
-
- @Override
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- @Override
- public Object evaluate(Context context) {
- return value;
- }
-
- @Override
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- if (value == null) {
- return "null";
- } else if (value instanceof String) {
- return SelectParserUtils.quote((String)value, '"');
- } else {
- return value.toString();
- }
- }
-
- @Override
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.select.BucketSet;
+import com.yahoo.document.select.Context;
+import com.yahoo.document.select.OrderingSpecification;
+import com.yahoo.document.select.Visitor;
+import com.yahoo.document.select.parser.SelectParserUtils;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class LiteralNode implements ExpressionNode {
+
+ private Object value;
+
+ public LiteralNode(Object value) {
+ this.value = value;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public LiteralNode setValue(Object value) {
+ this.value = value;
+ return this;
+ }
+
+ @Override
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return null;
+ }
+
+ @Override
+ public Object evaluate(Context context) {
+ return value;
+ }
+
+ @Override
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ if (value == null) {
+ return "null";
+ } else if (value instanceof String) {
+ return SelectParserUtils.quote((String)value, '"');
+ } else {
+ return value.toString();
+ }
+ }
+
+ @Override
+ public OrderingSpecification getOrdering(int order) {
+ return null;
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/LogicNode.java b/document/src/main/java/com/yahoo/document/select/rule/LogicNode.java
index 145c655fae2..edff3a0adaa 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/LogicNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/LogicNode.java
@@ -1,316 +1,316 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.ResultList;
-import com.yahoo.document.select.Visitor;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Stack;
-
-/**
- * This class defines a logical expression of nodes. This implementation uses a stack to evaluate its content as to
- * avoid deep recursions when building the parse tree.
- *
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class LogicNode implements ExpressionNode {
-
- // A no-op value is defined for completeness.
- public static final int NOP = 0;
-
- // The OR operator has lower precedence than AND.
- public static final int OR = 1;
-
- // The AND operator has the highest precedence.
- public static final int AND = 2;
-
- // The items contained in this.
- private final List<NodeItem> items = new ArrayList<NodeItem>();
-
- /**
- * Construct an empty logic expression.
- */
- public LogicNode() {
- // empty
- }
-
- public List<NodeItem> getItems() {
- return items;
- }
-
- /**
- * Adds an (operator, node) pair to this expression.
- *
- * @param operator The operator that combines the previous with the node given.
- * @param node The node to add to this.
- * @return This, to allow chaining.
- */
- public LogicNode add(String operator, ExpressionNode node) {
- items.add(new LogicNode.NodeItem(stringToOperator(operator), node));
- return this;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- Stack<BucketItem> buf = new Stack<>();
- for (NodeItem item : items) {
- if (!buf.isEmpty()) {
- while (buf.peek().operator > item.operator) {
- combineBuckets(buf);
- }
- }
- buf.push(new BucketItem(item.operator, item.node.getBucketSet(factory)));
- }
- while (buf.size() > 1) {
- combineBuckets(buf);
- }
- return buf.pop().buckets;
- }
-
- public OrderingSpecification getOrdering(int order) {
- Stack<OrderingItem> buf = new Stack<>();
- for (NodeItem item : items) {
- if (!buf.isEmpty()) {
- while (buf.peek().operator > item.operator) {
- pickOrdering(buf);
- }
- }
- buf.push(new OrderingItem(item.operator, item.node.getOrdering(order)));
- }
- while (buf.size() > 1) {
- pickOrdering(buf);
- }
- return buf.pop().ordering;
- }
-
- private OrderingSpecification pickOrdering(OrderingSpecification a, OrderingSpecification b, boolean isAnd) {
- if (a.getWidthBits() == b.getWidthBits() && a.getDivisionBits() == b.getDivisionBits() && a.getOrder() == b.getOrder()) {
- if ((a.getOrder() == OrderingSpecification.ASCENDING && isAnd) ||
- (a.getOrder() == OrderingSpecification.DESCENDING && !isAnd)) {
- return new OrderingSpecification(a.getOrder(), Math.max(a.getOrderingStart(), b.getOrderingStart()), b.getWidthBits(), a.getDivisionBits());
- } else {
- return new OrderingSpecification(a.getOrder(), Math.min(a.getOrderingStart(), b.getOrderingStart()), b.getWidthBits(), a.getDivisionBits());
- }
- }
- return null;
- }
-
- private void pickOrdering(Stack<OrderingItem> buf) {
- OrderingItem rhs = buf.pop();
- OrderingItem lhs = buf.pop();
- switch (rhs.operator) {
- case AND:
- if (lhs.ordering == null) {
- lhs.ordering = rhs.ordering;
- } else if (rhs.ordering == null) {
- // empty
- } else {
- lhs.ordering = pickOrdering(lhs.ordering, rhs.ordering, true);
- }
- break;
- case OR:
- if (lhs.ordering != null && rhs.ordering != null) {
- lhs.ordering = pickOrdering(lhs.ordering, rhs.ordering, false);
- } else {
- lhs.ordering = null;
- }
- break;
- default:
- lhs.ordering = null;
- }
- buf.push(lhs);
- }
-
- /**
- * Combines the top two items of the given stack using the operator of the second.
- *
- * @param buf The stack of bucket items.
- */
- private void combineBuckets(Stack<BucketItem> buf) {
- BucketItem rhs = buf.pop();
- BucketItem lhs = buf.pop();
- switch (rhs.operator) {
- case AND:
- if (lhs.buckets == null) {
- lhs.buckets = rhs.buckets;
- } else if (rhs.buckets == null) {
- // empty
- } else {
- lhs.buckets = lhs.buckets.intersection(rhs.buckets);
- }
- break;
- case OR:
- if (lhs.buckets == null) {
- // empty
- } else if (rhs.buckets == null) {
- lhs.buckets = null;
- } else {
- lhs.buckets = lhs.buckets.union(rhs.buckets);
- }
- break;
- default:
- throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported.");
- }
- buf.push(lhs);
- }
-
- // Inherit doc from ExpressionNode.
- @Override
- public Object evaluate(Context context) {
- Stack<ValueItem> buf = new Stack<>();
- for (NodeItem item : items) {
- if ( ! buf.isEmpty()) {
- while (buf.peek().operator > item.operator) {
- combineValues(buf);
- }
- }
-
- buf.push(new ValueItem(item.operator, ResultList.toResultList(item.node.evaluate(context))));
- }
- while (buf.size() > 1) {
- combineValues(buf);
- }
- return buf.pop().value;
- }
-
- /**
- * Combines the top two items of the given stack using the operator of the second.
- *
- * @param buf The stack of values.
- */
- private void combineValues(Stack<ValueItem> buf) {
- ValueItem rhs = buf.pop();
- ValueItem lhs = buf.pop();
-
- switch (rhs.operator) {
- case AND:
- buf.push(new ValueItem(lhs.operator, lhs.value.combineAND(rhs.value)));
- break;
- case OR:
- buf.push(new ValueItem(lhs.operator, lhs.value.combineOR(rhs.value)));
- break;
- default:
- throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported.");
- }
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- // Inherit doc from Object.
- @Override
- public String toString() {
- StringBuilder ret = new StringBuilder();
- for (LogicNode.NodeItem item : items) {
- if (item.operator != NOP) {
- ret.append(" ").append(operatorToString(item.operator)).append(" ");
- }
- ret.append(item.node);
- }
- return ret.toString();
- }
-
- /**
- * Converts the given operator index to a string representation.
- *
- * @param operator The operator index to convert.
- * @return The string representation.
- */
- public String operatorToString(int operator) {
- switch (operator) {
- case NOP:
- return null;
- case OR:
- return "or";
- case AND:
- return "and";
- default:
- throw new IllegalStateException("Logical operator " + operator + " not supported.");
- }
- }
-
- /**
- * Converts the given operator string to a corresponding operator index. This is necessary to perform a stack
- * traversal of logic expression.
- *
- * @param operator The operator to convert.
- * @return The corresponding index.
- */
- private int stringToOperator(String operator) {
- if (operator == null) {
- return NOP;
- } else if (operator.equalsIgnoreCase("or")) {
- return OR;
- } else if (operator.equalsIgnoreCase("and")) {
- return AND;
- } else {
- throw new IllegalStateException("Logical operator '" + operator + "' not supported.");
- }
- }
-
- /**
- * Private class to store results in a stack.
- */
- private final class ValueItem {
- private int operator;
- private ResultList value;
-
- public ValueItem(int operator, ResultList value) {
- this.operator = operator;
- this.value = value;
- }
- }
-
- /**
- * Private class to store bucket sets in a stack.
- */
- private final class BucketItem {
- private int operator;
- private BucketSet buckets;
-
- public BucketItem(int operator, BucketSet buckets) {
- this.operator = operator;
- this.buckets = buckets;
- }
- }
-
- /**
- * Private class to store ordering expressions in a stack.
- */
- private final class OrderingItem {
- private int operator;
- private OrderingSpecification ordering;
-
- public OrderingItem(int operator, OrderingSpecification orderSpec) {
- this.operator = operator;
- this.ordering = orderSpec;
- }
- }
-
- /**
- * Private class to store expression nodes in a stack.
- */
- public final class NodeItem {
- private int operator;
- private ExpressionNode node;
-
- public NodeItem(int operator, ExpressionNode node) {
- this.operator = operator;
- this.node = node;
- }
-
- public int getOperator() {
- return operator;
- }
-
- public ExpressionNode getNode() {
- return node;
- }
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.select.BucketSet;
+import com.yahoo.document.select.Context;
+import com.yahoo.document.select.OrderingSpecification;
+import com.yahoo.document.select.ResultList;
+import com.yahoo.document.select.Visitor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * This class defines a logical expression of nodes. This implementation uses a stack to evaluate its content as to
+ * avoid deep recursions when building the parse tree.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class LogicNode implements ExpressionNode {
+
+ // A no-op value is defined for completeness.
+ public static final int NOP = 0;
+
+ // The OR operator has lower precedence than AND.
+ public static final int OR = 1;
+
+ // The AND operator has the highest precedence.
+ public static final int AND = 2;
+
+ // The items contained in this.
+ private final List<NodeItem> items = new ArrayList<NodeItem>();
+
+ /**
+ * Construct an empty logic expression.
+ */
+ public LogicNode() {
+ // empty
+ }
+
+ public List<NodeItem> getItems() {
+ return items;
+ }
+
+ /**
+ * Adds an (operator, node) pair to this expression.
+ *
+ * @param operator The operator that combines the previous with the node given.
+ * @param node The node to add to this.
+ * @return This, to allow chaining.
+ */
+ public LogicNode add(String operator, ExpressionNode node) {
+ items.add(new LogicNode.NodeItem(stringToOperator(operator), node));
+ return this;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ Stack<BucketItem> buf = new Stack<>();
+ for (NodeItem item : items) {
+ if (!buf.isEmpty()) {
+ while (buf.peek().operator > item.operator) {
+ combineBuckets(buf);
+ }
+ }
+ buf.push(new BucketItem(item.operator, item.node.getBucketSet(factory)));
+ }
+ while (buf.size() > 1) {
+ combineBuckets(buf);
+ }
+ return buf.pop().buckets;
+ }
+
+ public OrderingSpecification getOrdering(int order) {
+ Stack<OrderingItem> buf = new Stack<>();
+ for (NodeItem item : items) {
+ if (!buf.isEmpty()) {
+ while (buf.peek().operator > item.operator) {
+ pickOrdering(buf);
+ }
+ }
+ buf.push(new OrderingItem(item.operator, item.node.getOrdering(order)));
+ }
+ while (buf.size() > 1) {
+ pickOrdering(buf);
+ }
+ return buf.pop().ordering;
+ }
+
+ private OrderingSpecification pickOrdering(OrderingSpecification a, OrderingSpecification b, boolean isAnd) {
+ if (a.getWidthBits() == b.getWidthBits() && a.getDivisionBits() == b.getDivisionBits() && a.getOrder() == b.getOrder()) {
+ if ((a.getOrder() == OrderingSpecification.ASCENDING && isAnd) ||
+ (a.getOrder() == OrderingSpecification.DESCENDING && !isAnd)) {
+ return new OrderingSpecification(a.getOrder(), Math.max(a.getOrderingStart(), b.getOrderingStart()), b.getWidthBits(), a.getDivisionBits());
+ } else {
+ return new OrderingSpecification(a.getOrder(), Math.min(a.getOrderingStart(), b.getOrderingStart()), b.getWidthBits(), a.getDivisionBits());
+ }
+ }
+ return null;
+ }
+
+ private void pickOrdering(Stack<OrderingItem> buf) {
+ OrderingItem rhs = buf.pop();
+ OrderingItem lhs = buf.pop();
+ switch (rhs.operator) {
+ case AND:
+ if (lhs.ordering == null) {
+ lhs.ordering = rhs.ordering;
+ } else if (rhs.ordering == null) {
+ // empty
+ } else {
+ lhs.ordering = pickOrdering(lhs.ordering, rhs.ordering, true);
+ }
+ break;
+ case OR:
+ if (lhs.ordering != null && rhs.ordering != null) {
+ lhs.ordering = pickOrdering(lhs.ordering, rhs.ordering, false);
+ } else {
+ lhs.ordering = null;
+ }
+ break;
+ default:
+ lhs.ordering = null;
+ }
+ buf.push(lhs);
+ }
+
+ /**
+ * Combines the top two items of the given stack using the operator of the second.
+ *
+ * @param buf The stack of bucket items.
+ */
+ private void combineBuckets(Stack<BucketItem> buf) {
+ BucketItem rhs = buf.pop();
+ BucketItem lhs = buf.pop();
+ switch (rhs.operator) {
+ case AND:
+ if (lhs.buckets == null) {
+ lhs.buckets = rhs.buckets;
+ } else if (rhs.buckets == null) {
+ // empty
+ } else {
+ lhs.buckets = lhs.buckets.intersection(rhs.buckets);
+ }
+ break;
+ case OR:
+ if (lhs.buckets == null) {
+ // empty
+ } else if (rhs.buckets == null) {
+ lhs.buckets = null;
+ } else {
+ lhs.buckets = lhs.buckets.union(rhs.buckets);
+ }
+ break;
+ default:
+ throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported.");
+ }
+ buf.push(lhs);
+ }
+
+ // Inherit doc from ExpressionNode.
+ @Override
+ public Object evaluate(Context context) {
+ Stack<ValueItem> buf = new Stack<>();
+ for (NodeItem item : items) {
+ if ( ! buf.isEmpty()) {
+ while (buf.peek().operator > item.operator) {
+ combineValues(buf);
+ }
+ }
+
+ buf.push(new ValueItem(item.operator, ResultList.toResultList(item.node.evaluate(context))));
+ }
+ while (buf.size() > 1) {
+ combineValues(buf);
+ }
+ return buf.pop().value;
+ }
+
+ /**
+ * Combines the top two items of the given stack using the operator of the second.
+ *
+ * @param buf The stack of values.
+ */
+ private void combineValues(Stack<ValueItem> buf) {
+ ValueItem rhs = buf.pop();
+ ValueItem lhs = buf.pop();
+
+ switch (rhs.operator) {
+ case AND:
+ buf.push(new ValueItem(lhs.operator, lhs.value.combineAND(rhs.value)));
+ break;
+ case OR:
+ buf.push(new ValueItem(lhs.operator, lhs.value.combineOR(rhs.value)));
+ break;
+ default:
+ throw new IllegalStateException("Arithmetic operator " + rhs.operator + " not supported.");
+ }
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ // Inherit doc from Object.
+ @Override
+ public String toString() {
+ StringBuilder ret = new StringBuilder();
+ for (LogicNode.NodeItem item : items) {
+ if (item.operator != NOP) {
+ ret.append(" ").append(operatorToString(item.operator)).append(" ");
+ }
+ ret.append(item.node);
+ }
+ return ret.toString();
+ }
+
+ /**
+ * Converts the given operator index to a string representation.
+ *
+ * @param operator The operator index to convert.
+ * @return The string representation.
+ */
+ public String operatorToString(int operator) {
+ switch (operator) {
+ case NOP:
+ return null;
+ case OR:
+ return "or";
+ case AND:
+ return "and";
+ default:
+ throw new IllegalStateException("Logical operator " + operator + " not supported.");
+ }
+ }
+
+ /**
+ * Converts the given operator string to a corresponding operator index. This is necessary to perform a stack
+ * traversal of logic expression.
+ *
+ * @param operator The operator to convert.
+ * @return The corresponding index.
+ */
+ private int stringToOperator(String operator) {
+ if (operator == null) {
+ return NOP;
+ } else if (operator.equalsIgnoreCase("or")) {
+ return OR;
+ } else if (operator.equalsIgnoreCase("and")) {
+ return AND;
+ } else {
+ throw new IllegalStateException("Logical operator '" + operator + "' not supported.");
+ }
+ }
+
+ /**
+ * Private class to store results in a stack.
+ */
+ private final class ValueItem {
+ private int operator;
+ private ResultList value;
+
+ public ValueItem(int operator, ResultList value) {
+ this.operator = operator;
+ this.value = value;
+ }
+ }
+
+ /**
+ * Private class to store bucket sets in a stack.
+ */
+ private final class BucketItem {
+ private int operator;
+ private BucketSet buckets;
+
+ public BucketItem(int operator, BucketSet buckets) {
+ this.operator = operator;
+ this.buckets = buckets;
+ }
+ }
+
+ /**
+ * Private class to store ordering expressions in a stack.
+ */
+ private final class OrderingItem {
+ private int operator;
+ private OrderingSpecification ordering;
+
+ public OrderingItem(int operator, OrderingSpecification orderSpec) {
+ this.operator = operator;
+ this.ordering = orderSpec;
+ }
+ }
+
+ /**
+ * Private class to store expression nodes in a stack.
+ */
+ public final class NodeItem {
+ private int operator;
+ private ExpressionNode node;
+
+ public NodeItem(int operator, ExpressionNode node) {
+ this.operator = operator;
+ this.node = node;
+ }
+
+ public int getOperator() {
+ return operator;
+ }
+
+ public ExpressionNode getNode() {
+ return node;
+ }
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/NegationNode.java b/document/src/main/java/com/yahoo/document/select/rule/NegationNode.java
index 2b85bc3eee6..74e6f0286f8 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/NegationNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/NegationNode.java
@@ -1,53 +1,53 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Result;
-import com.yahoo.document.select.Visitor;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class NegationNode implements ExpressionNode {
-
- private ExpressionNode node;
-
- public NegationNode(ExpressionNode node) {
- this.node = node;
- }
-
- public ExpressionNode getNode() {
- return node;
- }
-
- public NegationNode setNode(ExpressionNode node) {
- this.node = node;
- return this;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- return Result.invert(Result.toResult(node.evaluate(context)));
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return "not " + node;
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.select.BucketSet;
+import com.yahoo.document.select.Context;
+import com.yahoo.document.select.OrderingSpecification;
+import com.yahoo.document.select.Result;
+import com.yahoo.document.select.Visitor;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class NegationNode implements ExpressionNode {
+
+ private ExpressionNode node;
+
+ public NegationNode(ExpressionNode node) {
+ this.node = node;
+ }
+
+ public ExpressionNode getNode() {
+ return node;
+ }
+
+ public NegationNode setNode(ExpressionNode node) {
+ this.node = node;
+ return this;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return null;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public Object evaluate(Context context) {
+ return Result.invert(Result.toResult(node.evaluate(context)));
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ return "not " + node;
+ }
+
+ public OrderingSpecification getOrdering(int order) {
+ return null;
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/NowNode.java b/document/src/main/java/com/yahoo/document/select/rule/NowNode.java
index 600dbe536e4..8941f6b2808 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/NowNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/NowNode.java
@@ -1,34 +1,34 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.*;
-
-/**
- * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a>
- */
-public class NowNode implements ExpressionNode {
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- Object ret = System.currentTimeMillis() / 1000;
- return ret;
- }
-
- @Override
- public String toString() {
- return "now()";
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-}
+package com.yahoo.document.select.rule;
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.select.*;
+
+/**
+ * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a>
+ */
+public class NowNode implements ExpressionNode {
+
+ // Inherit doc from ExpressionNode.
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return null;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public Object evaluate(Context context) {
+ Object ret = System.currentTimeMillis() / 1000;
+ return ret;
+ }
+
+ @Override
+ public String toString() {
+ return "now()";
+ }
+
+ public OrderingSpecification getOrdering(int order) {
+ return null;
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/SearchColumnNode.java b/document/src/main/java/com/yahoo/document/select/rule/SearchColumnNode.java
index c63197ae3a4..03c8b273a77 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/SearchColumnNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/SearchColumnNode.java
@@ -1,56 +1,56 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketDistribution;
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.*;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class SearchColumnNode implements ExpressionNode {
-
- private int field;
- private BucketIdFactory factory = new BucketIdFactory(); // why is this not an abstract class?
- private BucketDistribution distribution;
-
- public SearchColumnNode() {
- setField(0);
- }
-
- public int getField() {
- return field;
- }
-
- public SearchColumnNode setField(int field) {
- distribution = new BucketDistribution(this.field = field, 16);
- return this;
- }
-
- public BucketDistribution getDistribution() {
- return distribution;
- }
-
- // Inherit doc from ExpressionNode.
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- // Inherit doc from ExpressionNode.
- public Object evaluate(Context context) {
- return distribution.getColumn(factory.getBucketId(context.getDocumentOperation().getId()));
- }
-
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return "searchcolumn." + field;
- }
-
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.BucketDistribution;
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.select.*;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class SearchColumnNode implements ExpressionNode {
+
+ private int field;
+ private BucketIdFactory factory = new BucketIdFactory(); // why is this not an abstract class?
+ private BucketDistribution distribution;
+
+ public SearchColumnNode() {
+ setField(0);
+ }
+
+ public int getField() {
+ return field;
+ }
+
+ public SearchColumnNode setField(int field) {
+ distribution = new BucketDistribution(this.field = field, 16);
+ return this;
+ }
+
+ public BucketDistribution getDistribution() {
+ return distribution;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return null;
+ }
+
+ // Inherit doc from ExpressionNode.
+ public Object evaluate(Context context) {
+ return distribution.getColumn(factory.getBucketId(context.getDocumentOperation().getId()));
+ }
+
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ return "searchcolumn." + field;
+ }
+
+ public OrderingSpecification getOrdering(int order) {
+ return null;
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/select/rule/VariableNode.java b/document/src/main/java/com/yahoo/document/select/rule/VariableNode.java
index 77c462674db..f988729ebb8 100644
--- a/document/src/main/java/com/yahoo/document/select/rule/VariableNode.java
+++ b/document/src/main/java/com/yahoo/document/select/rule/VariableNode.java
@@ -1,58 +1,58 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.select.rule;
-
-import com.yahoo.document.BucketIdFactory;
-import com.yahoo.document.select.BucketSet;
-import com.yahoo.document.select.Context;
-import com.yahoo.document.select.OrderingSpecification;
-import com.yahoo.document.select.Visitor;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class VariableNode implements ExpressionNode {
-
- private String value;
-
- public VariableNode(String value) {
- this.value = value;
- }
-
- public Object getValue() {
- return value;
- }
-
- public VariableNode setValue(String value) {
- this.value = value;
- return this;
- }
-
- @Override
- public BucketSet getBucketSet(BucketIdFactory factory) {
- return null;
- }
-
- @Override
- public Object evaluate(Context context) {
- Object o = context.getVariables().get(value);
- if (o == null) {
- throw new IllegalArgumentException("Variable " + value + " was not set in the variable list");
- }
- return o;
- }
-
- @Override
- public void accept(Visitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return "$" + value;
- }
-
- @Override
- public OrderingSpecification getOrdering(int order) {
- return null;
- }
-}
+package com.yahoo.document.select.rule;
+
+import com.yahoo.document.BucketIdFactory;
+import com.yahoo.document.select.BucketSet;
+import com.yahoo.document.select.Context;
+import com.yahoo.document.select.OrderingSpecification;
+import com.yahoo.document.select.Visitor;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class VariableNode implements ExpressionNode {
+
+ private String value;
+
+ public VariableNode(String value) {
+ this.value = value;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public VariableNode setValue(String value) {
+ this.value = value;
+ return this;
+ }
+
+ @Override
+ public BucketSet getBucketSet(BucketIdFactory factory) {
+ return null;
+ }
+
+ @Override
+ public Object evaluate(Context context) {
+ Object o = context.getVariables().get(value);
+ if (o == null) {
+ throw new IllegalArgumentException("Variable " + value + " was not set in the variable list");
+ }
+ return o;
+ }
+
+ @Override
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ return "$" + value;
+ }
+
+ @Override
+ public OrderingSpecification getOrdering(int order) {
+ return null;
+ }
+}
diff --git a/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateFlags.java b/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateFlags.java
index d6dd1ad35ac..e2c94c190ab 100644
--- a/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateFlags.java
+++ b/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateFlags.java
@@ -35,4 +35,4 @@ public class DocumentUpdateFlags {
int mask = ~(~0 << 28);
return combined & mask;
}
-} \ No newline at end of file
+}
diff --git a/document/src/main/java/com/yahoo/vespaxmlparser/FeedReader.java b/document/src/main/java/com/yahoo/vespaxmlparser/FeedReader.java
index e97bd43d9bf..e385d0ce731 100644
--- a/document/src/main/java/com/yahoo/vespaxmlparser/FeedReader.java
+++ b/document/src/main/java/com/yahoo/vespaxmlparser/FeedReader.java
@@ -18,4 +18,4 @@ public interface FeedReader {
*/
public abstract void read(Operation operation) throws Exception;
-} \ No newline at end of file
+}
diff --git a/document/src/test/java/com/yahoo/document/IncompatibleFieldTypesTest.java b/document/src/test/java/com/yahoo/document/IncompatibleFieldTypesTest.java
index 9e0c4e353f2..8ba0bd815ea 100644
--- a/document/src/test/java/com/yahoo/document/IncompatibleFieldTypesTest.java
+++ b/document/src/test/java/com/yahoo/document/IncompatibleFieldTypesTest.java
@@ -1,44 +1,44 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document;
-
-import com.yahoo.document.datatypes.*;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Tests for ticket 6394548
- */
-public class IncompatibleFieldTypesTest {
- private DataType arrayOfStrings;
- private StructDataType struct;
- private StructuredFieldValue root;
-
- @Before
- public void setUp() {
- arrayOfStrings = new ArrayDataType(DataType.STRING);
- struct = new StructDataType("fancypants");
- struct.addField(new Field("stringarray", arrayOfStrings, false));
- DataType weightedSetOfStrings = DataType.getWeightedSet(DataType.STRING, false, false);
- struct.addField(new Field("stringws", weightedSetOfStrings, false));
-
- root = struct.createFieldValue();
- root.setFieldValue("stringarray", arrayOfStrings.createFieldValue());
- root.setFieldValue("stringws", weightedSetOfStrings.createFieldValue());
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testAddingIncompatibleFieldToArrayFails() {
- System.out.println(root.getFieldValue("stringarray").getDataType().createFieldValue().getClass().getName());
- System.out.println(root.getFieldValue("stringarray").getDataType().createFieldValue().getDataType().toString());
-
- ((Array)root.getFieldValue("stringarray")).add(new IntegerFieldValue(1234));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testAddingIncompatibleFieldToWeightedSetFails() {
- System.out.println(root.getFieldValue("stringws").getDataType().createFieldValue().getClass().getName());
- System.out.println(root.getFieldValue("stringws").getDataType().createFieldValue().getDataType().toString());
-
- ((WeightedSet<FieldValue>)root.getFieldValue("stringws")).put(new IntegerFieldValue(1234), 100);
- }
-}
+package com.yahoo.document;
+
+import com.yahoo.document.datatypes.*;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for ticket 6394548
+ */
+public class IncompatibleFieldTypesTest {
+ private DataType arrayOfStrings;
+ private StructDataType struct;
+ private StructuredFieldValue root;
+
+ @Before
+ public void setUp() {
+ arrayOfStrings = new ArrayDataType(DataType.STRING);
+ struct = new StructDataType("fancypants");
+ struct.addField(new Field("stringarray", arrayOfStrings, false));
+ DataType weightedSetOfStrings = DataType.getWeightedSet(DataType.STRING, false, false);
+ struct.addField(new Field("stringws", weightedSetOfStrings, false));
+
+ root = struct.createFieldValue();
+ root.setFieldValue("stringarray", arrayOfStrings.createFieldValue());
+ root.setFieldValue("stringws", weightedSetOfStrings.createFieldValue());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddingIncompatibleFieldToArrayFails() {
+ System.out.println(root.getFieldValue("stringarray").getDataType().createFieldValue().getClass().getName());
+ System.out.println(root.getFieldValue("stringarray").getDataType().createFieldValue().getDataType().toString());
+
+ ((Array)root.getFieldValue("stringarray")).add(new IntegerFieldValue(1234));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddingIncompatibleFieldToWeightedSetFails() {
+ System.out.println(root.getFieldValue("stringws").getDataType().createFieldValue().getClass().getName());
+ System.out.println(root.getFieldValue("stringws").getDataType().createFieldValue().getDataType().toString());
+
+ ((WeightedSet<FieldValue>)root.getFieldValue("stringws")).put(new IntegerFieldValue(1234), 100);
+ }
+}
diff --git a/document/src/test/java/com/yahoo/document/annotation/Bug6394548TestCase.java b/document/src/test/java/com/yahoo/document/annotation/Bug6394548TestCase.java
index ee448bb79b0..6c007bad32a 100644
--- a/document/src/test/java/com/yahoo/document/annotation/Bug6394548TestCase.java
+++ b/document/src/test/java/com/yahoo/document/annotation/Bug6394548TestCase.java
@@ -1,123 +1,123 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.annotation;
-
-import com.yahoo.document.Document;
-import com.yahoo.document.DocumentTypeManager;
-import com.yahoo.document.DocumentTypeManagerConfigurer;
-import com.yahoo.document.StructDataType;
-import com.yahoo.document.datatypes.*;
-import com.yahoo.document.serialization.*;
-import com.yahoo.io.GrowableByteBuffer;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-import static org.junit.Assert.*;
-
-public class Bug6394548TestCase {
- @Test
- public void testSerializeAndDeserializeMultipleAdjacentStructAnnotations() {
- DocumentTypeManager manager = new DocumentTypeManager();
- DocumentTypeManagerConfigurer.configure(manager, "file:src/test/java/com/yahoo/document/annotation/documentmanager.6394548.cfg");
-
- AnnotationTypeRegistry registry = manager.getAnnotationTypeRegistry();
- AnnotationType featureSetType = registry.getType("morty.RICK_FEATURESET");
- assertNotNull(featureSetType);
-
- Document doc = new Document(manager.getDocumentType("article"), "doc:article:test");
- StringFieldValue sfv = new StringFieldValue("badger waltz");
-
- SpanList root = new SpanList();
- SpanNode node = new Span(0, sfv.getString().length());
- root.add(node);
-
- SpanTree tree = new SpanTree("rick_features", root);
- for (int i = 0; i < 2; ++i) {
- tree.annotate(createBigFeatureSetAnnotation(featureSetType));
- }
-
- sfv.setSpanTree(tree);
- doc.setFieldValue("title", sfv);
- System.out.println(doc.toXml());
- String annotationsBefore = dumpAllAnnotations(tree);
-
- GrowableByteBuffer buffer = new GrowableByteBuffer();
- DocumentSerializer serializer = DocumentSerializerFactory.create42(buffer);
- serializer.write(doc);
-
- buffer.flip();
- DocumentDeserializer deserializer = DocumentDeserializerFactory.create42(manager, buffer);
- Document doc2 = new Document(deserializer);
-
- System.out.println(doc2.toXml());
-
- StringFieldValue readString = (StringFieldValue)doc2.getFieldValue("title");
- SpanTree readTree = readString.getSpanTree("rick_features");
- assertNotNull(readTree);
- String annotationsAfter = dumpAllAnnotations(readTree);
-
- System.out.println("before:\n" + annotationsBefore);
- System.out.println("after:\n" + annotationsAfter);
-
- assertEquals(annotationsBefore, annotationsAfter);
- }
-
- private String dumpAllAnnotations(SpanTree tree) {
- ArrayList<String> tmp = new ArrayList<>();
- for (Annotation anno : tree) {
- Struct s = (Struct)anno.getFieldValue();
- tmp.add(s.toXml());
- }
- Collections.sort(tmp);
- StringBuilder annotations = new StringBuilder();
- for (String s : tmp) {
- annotations.append(s);
- }
- return annotations.toString();
- }
-
- private Annotation createBigFeatureSetAnnotation(AnnotationType featuresetAnno) {
- StructDataType featuresetType = (StructDataType)featuresetAnno.getDataType();
- Struct featureset = featuresetType.createFieldValue();
- System.out.println("featureset type: " + featureset.getDataType().toString());
-
- MapFieldValue<StringFieldValue, IntegerFieldValue> discreteValued
- = (MapFieldValue<StringFieldValue, IntegerFieldValue>)featuresetType.getField("discretevaluedfeatures").getDataType().createFieldValue();
- discreteValued.put(new StringFieldValue("foo"), new IntegerFieldValue(1234));
- discreteValued.put(new StringFieldValue("bar"), new IntegerFieldValue(567890123));
- featureset.setFieldValue("discretevaluedfeatures", discreteValued);
-
- MapFieldValue<StringFieldValue, DoubleFieldValue> realValued
- = (MapFieldValue<StringFieldValue, DoubleFieldValue>)featuresetType.getField("realvaluedfeatures").getDataType().createFieldValue();
- realValued.put(new StringFieldValue("foo"), new DoubleFieldValue(0.75));
- realValued.put(new StringFieldValue("bar"), new DoubleFieldValue(1.5));
- featureset.setFieldValue("realvaluedfeatures", realValued);
-
- Array<StringFieldValue> nested = (Array<StringFieldValue>)featureset.getField("foo10").getDataType().createFieldValue();
- nested.add(new StringFieldValue("baz"));
- nested.add(new StringFieldValue("blargh"));
- featureset.setFieldValue("foo10", nested);
-
- featureset.setFieldValue("foo1", new StringFieldValue("asdf"));
- featureset.setFieldValue("foo4", new StringFieldValue("qwerty"));
- featureset.setFieldValue("foo2", new IntegerFieldValue(555));
- featureset.setFieldValue("foo2", new IntegerFieldValue(8));
- featureset.setFieldValue("foo7", new IntegerFieldValue(1337));
- featureset.setFieldValue("foo8", new IntegerFieldValue(967867));
- featureset.setFieldValue("foo9", new DoubleFieldValue(123.45));
-
- Array<StringFieldValue> attributes = (Array<StringFieldValue>)featureset.getField("foo6").getDataType().createFieldValue();
- attributes.add(new StringFieldValue("adam"));
- attributes.add(new StringFieldValue("jamie"));
- attributes.add(new StringFieldValue("grant"));
- attributes.add(new StringFieldValue("tory"));
- attributes.add(new StringFieldValue("kari"));
- featureset.setFieldValue("variantattribute", attributes);
-
- Annotation anno = new Annotation(featuresetAnno);
- anno.setFieldValue(featureset);
-
- return anno;
- }
-}
+package com.yahoo.document.annotation;
+
+import com.yahoo.document.Document;
+import com.yahoo.document.DocumentTypeManager;
+import com.yahoo.document.DocumentTypeManagerConfigurer;
+import com.yahoo.document.StructDataType;
+import com.yahoo.document.datatypes.*;
+import com.yahoo.document.serialization.*;
+import com.yahoo.io.GrowableByteBuffer;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import static org.junit.Assert.*;
+
+public class Bug6394548TestCase {
+ @Test
+ public void testSerializeAndDeserializeMultipleAdjacentStructAnnotations() {
+ DocumentTypeManager manager = new DocumentTypeManager();
+ DocumentTypeManagerConfigurer.configure(manager, "file:src/test/java/com/yahoo/document/annotation/documentmanager.6394548.cfg");
+
+ AnnotationTypeRegistry registry = manager.getAnnotationTypeRegistry();
+ AnnotationType featureSetType = registry.getType("morty.RICK_FEATURESET");
+ assertNotNull(featureSetType);
+
+ Document doc = new Document(manager.getDocumentType("article"), "doc:article:test");
+ StringFieldValue sfv = new StringFieldValue("badger waltz");
+
+ SpanList root = new SpanList();
+ SpanNode node = new Span(0, sfv.getString().length());
+ root.add(node);
+
+ SpanTree tree = new SpanTree("rick_features", root);
+ for (int i = 0; i < 2; ++i) {
+ tree.annotate(createBigFeatureSetAnnotation(featureSetType));
+ }
+
+ sfv.setSpanTree(tree);
+ doc.setFieldValue("title", sfv);
+ System.out.println(doc.toXml());
+ String annotationsBefore = dumpAllAnnotations(tree);
+
+ GrowableByteBuffer buffer = new GrowableByteBuffer();
+ DocumentSerializer serializer = DocumentSerializerFactory.create42(buffer);
+ serializer.write(doc);
+
+ buffer.flip();
+ DocumentDeserializer deserializer = DocumentDeserializerFactory.create42(manager, buffer);
+ Document doc2 = new Document(deserializer);
+
+ System.out.println(doc2.toXml());
+
+ StringFieldValue readString = (StringFieldValue)doc2.getFieldValue("title");
+ SpanTree readTree = readString.getSpanTree("rick_features");
+ assertNotNull(readTree);
+ String annotationsAfter = dumpAllAnnotations(readTree);
+
+ System.out.println("before:\n" + annotationsBefore);
+ System.out.println("after:\n" + annotationsAfter);
+
+ assertEquals(annotationsBefore, annotationsAfter);
+ }
+
+ private String dumpAllAnnotations(SpanTree tree) {
+ ArrayList<String> tmp = new ArrayList<>();
+ for (Annotation anno : tree) {
+ Struct s = (Struct)anno.getFieldValue();
+ tmp.add(s.toXml());
+ }
+ Collections.sort(tmp);
+ StringBuilder annotations = new StringBuilder();
+ for (String s : tmp) {
+ annotations.append(s);
+ }
+ return annotations.toString();
+ }
+
+ private Annotation createBigFeatureSetAnnotation(AnnotationType featuresetAnno) {
+ StructDataType featuresetType = (StructDataType)featuresetAnno.getDataType();
+ Struct featureset = featuresetType.createFieldValue();
+ System.out.println("featureset type: " + featureset.getDataType().toString());
+
+ MapFieldValue<StringFieldValue, IntegerFieldValue> discreteValued
+ = (MapFieldValue<StringFieldValue, IntegerFieldValue>)featuresetType.getField("discretevaluedfeatures").getDataType().createFieldValue();
+ discreteValued.put(new StringFieldValue("foo"), new IntegerFieldValue(1234));
+ discreteValued.put(new StringFieldValue("bar"), new IntegerFieldValue(567890123));
+ featureset.setFieldValue("discretevaluedfeatures", discreteValued);
+
+ MapFieldValue<StringFieldValue, DoubleFieldValue> realValued
+ = (MapFieldValue<StringFieldValue, DoubleFieldValue>)featuresetType.getField("realvaluedfeatures").getDataType().createFieldValue();
+ realValued.put(new StringFieldValue("foo"), new DoubleFieldValue(0.75));
+ realValued.put(new StringFieldValue("bar"), new DoubleFieldValue(1.5));
+ featureset.setFieldValue("realvaluedfeatures", realValued);
+
+ Array<StringFieldValue> nested = (Array<StringFieldValue>)featureset.getField("foo10").getDataType().createFieldValue();
+ nested.add(new StringFieldValue("baz"));
+ nested.add(new StringFieldValue("blargh"));
+ featureset.setFieldValue("foo10", nested);
+
+ featureset.setFieldValue("foo1", new StringFieldValue("asdf"));
+ featureset.setFieldValue("foo4", new StringFieldValue("qwerty"));
+ featureset.setFieldValue("foo2", new IntegerFieldValue(555));
+ featureset.setFieldValue("foo2", new IntegerFieldValue(8));
+ featureset.setFieldValue("foo7", new IntegerFieldValue(1337));
+ featureset.setFieldValue("foo8", new IntegerFieldValue(967867));
+ featureset.setFieldValue("foo9", new DoubleFieldValue(123.45));
+
+ Array<StringFieldValue> attributes = (Array<StringFieldValue>)featureset.getField("foo6").getDataType().createFieldValue();
+ attributes.add(new StringFieldValue("adam"));
+ attributes.add(new StringFieldValue("jamie"));
+ attributes.add(new StringFieldValue("grant"));
+ attributes.add(new StringFieldValue("tory"));
+ attributes.add(new StringFieldValue("kari"));
+ featureset.setFieldValue("variantattribute", attributes);
+
+ Annotation anno = new Annotation(featuresetAnno);
+ anno.setFieldValue(featureset);
+
+ return anno;
+ }
+}
diff --git a/document/src/test/java/com/yahoo/document/annotation/Bug6425939TestCase.java b/document/src/test/java/com/yahoo/document/annotation/Bug6425939TestCase.java
index d34d0da8e82..68a97bc557c 100644
--- a/document/src/test/java/com/yahoo/document/annotation/Bug6425939TestCase.java
+++ b/document/src/test/java/com/yahoo/document/annotation/Bug6425939TestCase.java
@@ -1,66 +1,66 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.document.annotation;
-
-import com.yahoo.document.DataType;
-import com.yahoo.document.DocumentTypeManager;
-import com.yahoo.document.Field;
-import com.yahoo.document.StructDataType;
-import com.yahoo.document.datatypes.StringFieldValue;
-import com.yahoo.document.datatypes.Struct;
-import com.yahoo.document.serialization.*;
-import com.yahoo.io.GrowableByteBuffer;
-import org.junit.Before;
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-public class Bug6425939TestCase {
- private DocumentTypeManager man;
- private StructDataType person;
- private AnnotationType personA;
-
- @Before
- public void setUp() {
- man = new DocumentTypeManager();
-
- person = new StructDataType("personStruct");
- person.addField(new Field("foo", DataType.STRING));
- person.addField(new Field("bar", DataType.INT));
- man.register(person);
-
- personA = new AnnotationType("person", person);
- man.getAnnotationTypeRegistry().register(personA);
- }
-
- @Test
- public void canDeserializeAnnotationsOnZeroLengthStrings() {
- StringFieldValue emptyString = new StringFieldValue("");
- emptyString.setSpanTree(createSpanTree());
-
- GrowableByteBuffer buffer = new GrowableByteBuffer(1024);
- DocumentSerializer serializer = DocumentSerializerFactory.create42(buffer);
- Field strField = new Field("flarn", DataType.STRING);
- serializer.write(strField, emptyString);
- buffer.flip();
-
- // Should not throw exception if bug 6425939 is fixed:
- DocumentDeserializer deserializer = DocumentDeserializerFactory.create42(man, buffer);
- StringFieldValue deserializedString = new StringFieldValue();
- deserializer.read(strField, deserializedString);
-
- assertEquals("", deserializedString.getString());
- SpanTree readTree = deserializedString.getSpanTree("SpanTree1");
- assertNotNull(readTree);
- }
-
- private SpanTree createSpanTree() {
- SpanList root = new SpanList();
- SpanTree tree = new SpanTree("SpanTree1", root);
- SpanNode node = new Span(0, 0);
- Struct ps = new Struct(person);
- ps.setFieldValue("foo", "epic badger");
- ps.setFieldValue("bar", 54321);
- tree.annotate(node, new Annotation(personA, ps));
- root.add(node);
- return tree;
- }
-}
+package com.yahoo.document.annotation;
+
+import com.yahoo.document.DataType;
+import com.yahoo.document.DocumentTypeManager;
+import com.yahoo.document.Field;
+import com.yahoo.document.StructDataType;
+import com.yahoo.document.datatypes.StringFieldValue;
+import com.yahoo.document.datatypes.Struct;
+import com.yahoo.document.serialization.*;
+import com.yahoo.io.GrowableByteBuffer;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class Bug6425939TestCase {
+ private DocumentTypeManager man;
+ private StructDataType person;
+ private AnnotationType personA;
+
+ @Before
+ public void setUp() {
+ man = new DocumentTypeManager();
+
+ person = new StructDataType("personStruct");
+ person.addField(new Field("foo", DataType.STRING));
+ person.addField(new Field("bar", DataType.INT));
+ man.register(person);
+
+ personA = new AnnotationType("person", person);
+ man.getAnnotationTypeRegistry().register(personA);
+ }
+
+ @Test
+ public void canDeserializeAnnotationsOnZeroLengthStrings() {
+ StringFieldValue emptyString = new StringFieldValue("");
+ emptyString.setSpanTree(createSpanTree());
+
+ GrowableByteBuffer buffer = new GrowableByteBuffer(1024);
+ DocumentSerializer serializer = DocumentSerializerFactory.create42(buffer);
+ Field strField = new Field("flarn", DataType.STRING);
+ serializer.write(strField, emptyString);
+ buffer.flip();
+
+ // Should not throw exception if bug 6425939 is fixed:
+ DocumentDeserializer deserializer = DocumentDeserializerFactory.create42(man, buffer);
+ StringFieldValue deserializedString = new StringFieldValue();
+ deserializer.read(strField, deserializedString);
+
+ assertEquals("", deserializedString.getString());
+ SpanTree readTree = deserializedString.getSpanTree("SpanTree1");
+ assertNotNull(readTree);
+ }
+
+ private SpanTree createSpanTree() {
+ SpanList root = new SpanList();
+ SpanTree tree = new SpanTree("SpanTree1", root);
+ SpanNode node = new Span(0, 0);
+ Struct ps = new Struct(person);
+ ps.setFieldValue("foo", "epic badger");
+ ps.setFieldValue("bar", 54321);
+ tree.annotate(node, new Annotation(personA, ps));
+ root.add(node);
+ return tree;
+ }
+}
diff --git a/document/src/vespa/document/fieldvalue/variablemap.h b/document/src/vespa/document/fieldvalue/variablemap.h
index 06679682e0c..ccebd3cdb52 100644
--- a/document/src/vespa/document/fieldvalue/variablemap.h
+++ b/document/src/vespa/document/fieldvalue/variablemap.h
@@ -44,4 +44,4 @@ public:
vespalib::string toString() const;
};
-} \ No newline at end of file
+}