Return-Path: X-Original-To: apmail-incubator-accumulo-commits-archive@minotaur.apache.org Delivered-To: apmail-incubator-accumulo-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 2E65A75B5 for ; Mon, 5 Dec 2011 20:06:51 +0000 (UTC) Received: (qmail 18871 invoked by uid 500); 5 Dec 2011 20:06:51 -0000 Delivered-To: apmail-incubator-accumulo-commits-archive@incubator.apache.org Received: (qmail 18848 invoked by uid 500); 5 Dec 2011 20:06:51 -0000 Mailing-List: contact accumulo-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: accumulo-dev@incubator.apache.org Delivered-To: mailing list accumulo-commits@incubator.apache.org Received: (qmail 18841 invoked by uid 99); 5 Dec 2011 20:06:51 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Dec 2011 20:06:51 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Dec 2011 20:06:41 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 2FA082388B4E; Mon, 5 Dec 2011 20:05:55 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1210600 [9/16] - in /incubator/accumulo/trunk/contrib/accumulo_sample: ./ ingest/ ingest/src/main/java/aggregator/ ingest/src/main/java/ingest/ ingest/src/main/java/iterator/ ingest/src/main/java/normalizer/ ingest/src/main/java/protobuf/ ... Date: Mon, 05 Dec 2011 20:05:51 -0000 To: accumulo-commits@incubator.apache.org From: billie@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20111205200555.2FA082388B4E@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/iterator/UniqFieldNameValueIterator.java URL: http://svn.apache.org/viewvc/incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/iterator/UniqFieldNameValueIterator.java?rev=1210600&r1=1210599&r2=1210600&view=diff ============================================================================== --- incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/iterator/UniqFieldNameValueIterator.java (original) +++ incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/iterator/UniqFieldNameValueIterator.java Mon Dec 5 20:05:49 2011 @@ -1,19 +1,19 @@ /* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package iterator; import java.io.IOException; @@ -37,317 +37,312 @@ import org.apache.log4j.Logger; import util.FieldIndexKeyParser; public class UniqFieldNameValueIterator extends WrappingIterator { - - protected static final Logger log = Logger.getLogger(UniqFieldNameValueIterator.class); - // Wrapping iterator only accesses its private source in setSource and getSource - // Since this class overrides these methods, it's safest to keep the source declaration here - private SortedKeyValueIterator source; - private FieldIndexKeyParser keyParser; - private Key topKey = null; - private Value topValue = null; - private Range overallRange = null; - private Range currentSubRange; - private Text fieldName = null; - private String fieldNameString = null; - private Text fieldValueLowerBound = null; - private Text fieldValueUpperBound = null; - private String operator = null; - private Expression expr = null; - private static final Collection EMPTY_COL_FAMS = new ArrayList(); - private static final String NULL_BYTE = "\0"; - private static final String ONE_BYTE = "\1"; - private boolean multiRow = false; - private boolean seekInclusive = false; - - //------------------------------------------------------------------------- - //------------- Static Methods - public static void setLogLevel(Level l) { - log.setLevel(l); - } - - //------------------------------------------------------------------------- - //------------- Constructors - public UniqFieldNameValueIterator(Text fName, Text fValLower, Text fValUpper) { - this.fieldName = fName; - this.fieldNameString = fieldName.toString(); - this.fieldValueLowerBound = fValLower; - this.fieldValueUpperBound = fValUpper; - keyParser = createDefaultKeyParser(); - - } - - public UniqFieldNameValueIterator(UniqFieldNameValueIterator other, IteratorEnvironment env) { - source = other.getSource().deepCopy(env); - //Set a default KeyParser - keyParser = createDefaultKeyParser(); - } - - //------------------------------------------------------------------------- - //------------- Overrides - @Override - public void init(SortedKeyValueIterator source, Map options, IteratorEnvironment env) throws IOException { - super.init(source, options, env); - source = super.getSource(); - } - - @Override - protected void setSource(SortedKeyValueIterator source) { - this.source = source; - } - - @Override - protected SortedKeyValueIterator getSource() { - return source; - } - - @Override - public SortedKeyValueIterator deepCopy(IteratorEnvironment env) { - return new UniqFieldNameValueIterator(this, env); - } - - @Override - public Key getTopKey() { - return this.topKey; - } - - @Override - public Value getTopValue() { - return this.topValue; - } - - @Override - public boolean hasTop() { - return (topKey != null); - } - - @Override - public void next() throws IOException { + + protected static final Logger log = Logger.getLogger(UniqFieldNameValueIterator.class); + // Wrapping iterator only accesses its private source in setSource and getSource + // Since this class overrides these methods, it's safest to keep the source declaration here + private SortedKeyValueIterator source; + private FieldIndexKeyParser keyParser; + private Key topKey = null; + private Value topValue = null; + private Range overallRange = null; + private Range currentSubRange; + private Text fieldName = null; + private String fieldNameString = null; + private Text fieldValueLowerBound = null; + private Text fieldValueUpperBound = null; + private String operator = null; + private Expression expr = null; + private static final Collection EMPTY_COL_FAMS = new ArrayList(); + private static final String NULL_BYTE = "\0"; + private static final String ONE_BYTE = "\1"; + private boolean multiRow = false; + private boolean seekInclusive = false; + + // ------------------------------------------------------------------------- + // ------------- Static Methods + public static void setLogLevel(Level l) { + log.setLevel(l); + } + + // ------------------------------------------------------------------------- + // ------------- Constructors + public UniqFieldNameValueIterator(Text fName, Text fValLower, Text fValUpper) { + this.fieldName = fName; + this.fieldNameString = fieldName.toString(); + this.fieldValueLowerBound = fValLower; + this.fieldValueUpperBound = fValUpper; + keyParser = createDefaultKeyParser(); + + } + + public UniqFieldNameValueIterator(UniqFieldNameValueIterator other, IteratorEnvironment env) { + source = other.getSource().deepCopy(env); + // Set a default KeyParser + keyParser = createDefaultKeyParser(); + } + + // ------------------------------------------------------------------------- + // ------------- Overrides + @Override + public void init(SortedKeyValueIterator source, Map options, IteratorEnvironment env) throws IOException { + super.init(source, options, env); + source = super.getSource(); + } + + @Override + protected void setSource(SortedKeyValueIterator source) { + this.source = source; + } + + @Override + protected SortedKeyValueIterator getSource() { + return source; + } + + @Override + public SortedKeyValueIterator deepCopy(IteratorEnvironment env) { + return new UniqFieldNameValueIterator(this, env); + } + + @Override + public Key getTopKey() { + return this.topKey; + } + + @Override + public Value getTopValue() { + return this.topValue; + } + + @Override + public boolean hasTop() { + return (topKey != null); + } + + @Override + public void next() throws IOException { + if (log.isDebugEnabled()) { + log.debug("next()"); + } + if (!source.hasTop()) { + topKey = null; + topValue = null; + return; + } + + Key currentKey = topKey; + keyParser.parse(topKey); + String fValue = keyParser.getFieldValue(); + + Text currentRow = currentKey.getRow(); + Text currentFam = currentKey.getColumnFamily(); + + if (overallRange.getEndKey() != null && overallRange.getEndKey().getRow().compareTo(currentRow) < 0) { + if (log.isDebugEnabled()) { + log.debug("next, overall endRow: " + overallRange.getEndKey().getRow() + " currentRow: " + currentRow); + } + topKey = null; + topValue = null; + return; + } + + if (fValue.compareTo(this.fieldValueUpperBound.toString()) > 0) { + topKey = null; + topValue = null; + return; + } + Key followingKey = new Key(currentKey.getRow(), this.fieldName, new Text(fValue + ONE_BYTE)); + if (log.isDebugEnabled()) { + log.debug("next, followingKey to seek on: " + followingKey); + } + Range r = new Range(followingKey, followingKey); + source.seek(r, EMPTY_COL_FAMS, false); + while (true) { + if (!source.hasTop()) { + topKey = null; + topValue = null; + return; + } + + Key k = source.getTopKey(); + if (!overallRange.contains(k)) { + topKey = null; + topValue = null; + return; + } + if (log.isDebugEnabled()) { + log.debug("next(), key: " + k + " subrange: " + this.currentSubRange); + } + // if (this.currentSubRange.contains(k)) { + keyParser.parse(k); + Text currentVal = new Text(keyParser.getFieldValue()); + if (k.getRow().equals(currentRow) && k.getColumnFamily().equals(currentFam) && currentVal.compareTo(fieldValueUpperBound) <= 0) { + topKey = k; + topValue = source.getTopValue(); + return; + + } else { // need to move to next row. + if (this.overallRange.contains(k) && this.multiRow) { + // need to find the next sub range + // STEPS + // 1. check if you moved past your current row on last call to next + // 2. figure out next row + // 3. build new start key with lowerbound fvalue + // 4. seek the source + // 5. test the subrange. + if (k.getRow().equals(currentRow)) { + // get next row + currentRow = getNextRow(); + if (currentRow == null) { + topKey = null; + topValue = null; + return; + } + } else { + // i'm already in the next row + currentRow = source.getTopKey().getRow(); + } + + // build new startKey + Key sKey = new Key(currentRow, fieldName, fieldValueLowerBound); + Key eKey = new Key(currentRow, fieldName, fieldValueUpperBound); + currentSubRange = new Range(sKey, eKey); + source.seek(currentSubRange, EMPTY_COL_FAMS, seekInclusive); + + } else { // not multi-row or outside overall range, we're done + topKey = null; + topValue = null; + return; + } + } + + } + + } + + @Override + public void seek(Range range, Collection columnFamilies, boolean inclusive) throws IOException { + if (log.isDebugEnabled()) { + log.debug("seek, range: " + range); + } + this.overallRange = range; + this.seekInclusive = inclusive; + source.seek(range, EMPTY_COL_FAMS, inclusive); + topKey = null; + topValue = null; + Key sKey; + Key eKey; + + if (range.isInfiniteStartKey()) { + sKey = source.getTopKey(); + if (sKey == null) { + return; + } + } else { + sKey = range.getStartKey(); + } + + if (range.isInfiniteStopKey()) { + eKey = null; + this.multiRow = true; // assume we will go to the end of the tablet. + } else { + eKey = range.getEndKey(); + if (sKey.getRow().equals(eKey.getRow())) { + this.multiRow = false; + } else { + this.multiRow = true; + } + } + + if (log.isDebugEnabled()) { + log.debug("seek, multiRow:" + multiRow + " range:" + range); + } + + /* + * NOTE: If the seek range spans multiple rows, we are only interested in the fieldName:fieldValue subranges in each row. Keys will exist in the + * overallRange that we will want to skip over so we need to create subranges per row so we don't have to examine every key in between. + */ + + Text sRow = sKey.getRow(); + Key ssKey = new Key(sRow, this.fieldName, this.fieldValueLowerBound); + Key eeKey = new Key(sRow, this.fieldName, this.fieldValueUpperBound); + this.currentSubRange = new Range(ssKey, eeKey); + + if (log.isDebugEnabled()) { + log.debug("seek, currentSubRange: " + currentSubRange); + } + source.seek(this.currentSubRange, columnFamilies, inclusive); + // cycle until we find a valid topKey, or we get ejected b/c we hit the + // end of the tablet or exceeded the overallRange. + while (topKey == null) { + if (source.hasTop()) { + Key k = source.getTopKey(); if (log.isDebugEnabled()) { - log.debug("next()"); + log.debug("seek, source.topKey: " + k); } - if (!source.hasTop()) { - topKey = null; - topValue = null; - return; - } - - Key currentKey = topKey; - keyParser.parse(topKey); - String fValue = keyParser.getFieldValue(); - - Text currentRow = currentKey.getRow(); - Text currentFam = currentKey.getColumnFamily(); - - if(overallRange.getEndKey() != null && overallRange.getEndKey().getRow().compareTo(currentRow) < 0){ - if(log.isDebugEnabled()){ - log.debug("next, overall endRow: "+overallRange.getEndKey().getRow()+" currentRow: "+currentRow); + if (currentSubRange.contains(k)) { + topKey = k; + topValue = source.getTopValue(); + + if (log.isDebugEnabled()) { + log.debug("seek, source has top in valid range"); + } + + } else { // outside of subRange. + // if multiRow mode, get the next row and seek to it + if (multiRow && overallRange.contains(k)) { + + Key fKey = sKey.followingKey(PartialKey.ROW); + Range fRange = new Range(fKey, eKey); + source.seek(fRange, columnFamilies, inclusive); + + if (source.hasTop()) { + Text row = source.getTopKey().getRow(); + Key nKey = new Key(row, this.fieldName, this.fieldValueLowerBound); + this.currentSubRange = new Range(nKey, eKey); + sKey = this.currentSubRange.getStartKey(); + Range nextRange = new Range(sKey, eKey); + source.seek(nextRange, columnFamilies, inclusive); + } else { + topKey = null; + topValue = null; + return; } + + } else { // not multi row & outside range, we're done. topKey = null; topValue = null; return; + } } - - if (fValue.compareTo(this.fieldValueUpperBound.toString()) > 0) { - topKey = null; - topValue = null; - return; - } - Key followingKey = new Key(currentKey.getRow(), this.fieldName, new Text(fValue + ONE_BYTE)); - if (log.isDebugEnabled()) { - log.debug("next, followingKey to seek on: " + followingKey); - } - Range r = new Range(followingKey, followingKey); - source.seek(r, EMPTY_COL_FAMS, false); - while (true) { - if (!source.hasTop()) { - topKey = null; - topValue = null; - return; - } - - Key k = source.getTopKey(); - if(!overallRange.contains(k)){ - topKey = null; - topValue = null; - return; - } - if (log.isDebugEnabled()) { - log.debug("next(), key: " + k + " subrange: " + this.currentSubRange); - } - //if (this.currentSubRange.contains(k)) { - keyParser.parse(k); - Text currentVal = new Text(keyParser.getFieldValue()); - if(k.getRow().equals(currentRow) - && k.getColumnFamily().equals(currentFam) - && currentVal.compareTo(fieldValueUpperBound) <= 0 ){ - topKey = k; - topValue = source.getTopValue(); - return; - - } else { // need to move to next row. - if (this.overallRange.contains(k) && this.multiRow) { - // need to find the next sub range - //STEPS - //1. check if you moved past your current row on last call to next - //2. figure out next row - //3. build new start key with lowerbound fvalue - //4. seek the source - //5. test the subrange. - if (k.getRow().equals(currentRow)) { - //get next row - currentRow = getNextRow(); - if (currentRow == null) { - topKey = null; - topValue = null; - return; - } - } else { - //i'm already in the next row - currentRow = source.getTopKey().getRow(); - } - - //build new startKey - Key sKey = new Key(currentRow, fieldName, fieldValueLowerBound); - Key eKey = new Key(currentRow, fieldName, fieldValueUpperBound); - currentSubRange = new Range(sKey, eKey); - source.seek(currentSubRange, EMPTY_COL_FAMS, seekInclusive); - - } else { // not multi-row or outside overall range, we're done - topKey = null; - topValue = null; - return; - } - } - - } - - } - - @Override - public void seek(Range range, Collection columnFamilies, boolean inclusive) throws IOException { - if (log.isDebugEnabled()) { - log.debug("seek, range: " + range); - } - this.overallRange = range; - this.seekInclusive = inclusive; - source.seek(range, EMPTY_COL_FAMS, inclusive); + } else { // source does not have top, we're done topKey = null; topValue = null; - Key sKey; - Key eKey; - - if (range.isInfiniteStartKey()) { - sKey = source.getTopKey(); - if (sKey == null) { - return; - } - } else { - sKey = range.getStartKey(); - } - - if (range.isInfiniteStopKey()) { - eKey = null; - this.multiRow = true; // assume we will go to the end of the tablet. - } else { - eKey = range.getEndKey(); - if (sKey.getRow().equals(eKey.getRow())) { - this.multiRow = false; - } else { - this.multiRow = true; - } - } - - if (log.isDebugEnabled()) { - log.debug("seek, multiRow:" + multiRow + " range:" + range); - } - - /* - * NOTE: If the seek range spans multiple rows, we are only interested - * in the fieldName:fieldValue subranges in each row. Keys will - * exist in the overallRange that we will want to skip over so we need - * to create subranges per row so we don't have to examine every key in - * between. - */ - - Text sRow = sKey.getRow(); - Key ssKey = new Key(sRow, this.fieldName, this.fieldValueLowerBound); - Key eeKey = new Key(sRow, this.fieldName, this.fieldValueUpperBound); - this.currentSubRange = new Range(ssKey, eeKey); - - if (log.isDebugEnabled()) { - log.debug("seek, currentSubRange: " + currentSubRange); - } - source.seek(this.currentSubRange, columnFamilies, inclusive); - // cycle until we find a valid topKey, or we get ejected b/c we hit the - // end of the tablet or exceeded the overallRange. - while (topKey == null) { - if (source.hasTop()) { - Key k = source.getTopKey(); - if (log.isDebugEnabled()) { - log.debug("seek, source.topKey: " + k); - } - if (currentSubRange.contains(k)) { - topKey = k; - topValue = source.getTopValue(); - - if (log.isDebugEnabled()) { - log.debug("seek, source has top in valid range"); - } - - } else { //outside of subRange. - // if multiRow mode, get the next row and seek to it - if (multiRow && overallRange.contains(k)) { - - Key fKey = sKey.followingKey(PartialKey.ROW); - Range fRange = new Range(fKey, eKey); - source.seek(fRange, columnFamilies, inclusive); - - if (source.hasTop()) { - Text row = source.getTopKey().getRow(); - Key nKey = new Key(row, this.fieldName, this.fieldValueLowerBound); - this.currentSubRange = new Range(nKey, eKey); - sKey = this.currentSubRange.getStartKey(); - Range nextRange = new Range(sKey, eKey); - source.seek(nextRange, columnFamilies, inclusive); - } else { - topKey = null; - topValue = null; - return; - } - - } else { // not multi row & outside range, we're done. - topKey = null; - topValue = null; - return; - } - } - } else { // source does not have top, we're done - topKey = null; - topValue = null; - return; - } - } - + return; + } } - - //------------------------------------------------------------------------- - //------------- Internal Methods - private FieldIndexKeyParser createDefaultKeyParser() { - FieldIndexKeyParser parser = new FieldIndexKeyParser(); - return parser; - } - - private Text getNextRow() throws IOException { - if (log.isDebugEnabled()) { - log.debug("getNextRow()"); - } - Key fakeKey = new Key(source.getTopKey().followingKey(PartialKey.ROW)); - Range fakeRange = new Range(fakeKey, fakeKey); - source.seek(fakeRange, EMPTY_COL_FAMS, false); - if (source.hasTop()) { - return source.getTopKey().getRow(); - } else { - return null; - } + + } + + // ------------------------------------------------------------------------- + // ------------- Internal Methods + private FieldIndexKeyParser createDefaultKeyParser() { + FieldIndexKeyParser parser = new FieldIndexKeyParser(); + return parser; + } + + private Text getNextRow() throws IOException { + if (log.isDebugEnabled()) { + log.debug("getNextRow()"); + } + Key fakeKey = new Key(source.getTopKey().followingKey(PartialKey.ROW)); + Range fakeRange = new Range(fakeKey, fakeKey); + source.seek(fakeRange, EMPTY_COL_FAMS, false); + if (source.hasTop()) { + return source.getTopKey().getRow(); + } else { + return null; } + } } Modified: incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/jexl/Arithmetic.java URL: http://svn.apache.org/viewvc/incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/jexl/Arithmetic.java?rev=1210600&r1=1210599&r2=1210600&view=diff ============================================================================== --- incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/jexl/Arithmetic.java (original) +++ incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/jexl/Arithmetic.java Mon Dec 5 20:05:49 2011 @@ -1,19 +1,19 @@ /* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package jexl; import java.util.regex.Matcher; @@ -23,108 +23,104 @@ import org.apache.commons.jexl2.JexlArit import org.apache.commons.lang.math.NumberUtils; public class Arithmetic extends JexlArithmetic { - - public Arithmetic(boolean lenient) { - super(lenient); - } - - /** - * This method differs from the parent in that we are not calling - * String.matches() because it does not match on a newline. Instead - * we are handling this case. - * - * @param left first value - * @param right second value - * @return test result. - */ - @Override - public boolean matches(Object left, Object right) { - if (left == null && right == null) { - //if both are null L == R - return true; - } - if (left == null || right == null) { - // we know both aren't null, therefore L != R - return false; - } - final String arg = left.toString(); - if (right instanceof java.util.regex.Pattern) { - return ((java.util.regex.Pattern) right).matcher(arg).matches(); - } else { - //return arg.matches(right.toString()); - Pattern p = Pattern.compile(right.toString(), Pattern.DOTALL); - Matcher m = p.matcher(arg); - return m.matches(); - - } + + public Arithmetic(boolean lenient) { + super(lenient); + } + + /** + * This method differs from the parent in that we are not calling String.matches() because it does not match on a newline. Instead we are handling this case. + * + * @param left + * first value + * @param right + * second value + * @return test result. + */ + @Override + public boolean matches(Object left, Object right) { + if (left == null && right == null) { + // if both are null L == R + return true; } - - - /** - * This method differs from the parent class in that we are going - * to try and do a better job of coercing the types. As a last resort - * we will do a string comparison and try not to throw a NumberFormatException. - * The JexlArithmetic class performs coercion to a particular type if either - * the left or the right match a known type. We will look at the type of the - * right operator and try to make the left of the same type. - */ - @Override - public boolean equals(Object left, Object right) { - Object fixedLeft = fixLeft(left, right); - return super.equals(fixedLeft, right); - } - - @Override - public boolean lessThan(Object left, Object right) { - Object fixedLeft = fixLeft(left, right); - return super.lessThan(fixedLeft, right); - } - - protected Object fixLeft(Object left, Object right) { - - if (null == left || null == right) - return left; - - if (!(right instanceof Number) && left instanceof Number) { - right = NumberUtils.createNumber(right.toString()); - } - - if (right instanceof Number && left instanceof Number) { - if (right instanceof Double) - return ((Double) right).doubleValue(); - else if (right instanceof Float) - return ((Float) right).floatValue(); - else if (right instanceof Long) - return ((Long) right).longValue(); - else if (right instanceof Integer) - return ((Integer) right).intValue(); - else if (right instanceof Short) - return ((Short) right).shortValue(); - else if (right instanceof Byte) - return ((Byte) right).byteValue(); - else - return right; - } - if (right instanceof Number && left instanceof String) { - Number num = NumberUtils.createNumber(left.toString()); - //Let's try to cast left as right's type. - if (this.isFloatingPointNumber(right) && this.isFloatingPointNumber(left)) - return num; - else if (this.isFloatingPointNumber(right)) - return num.doubleValue(); - else if (right instanceof Number) - return num.longValue(); - } else if (right instanceof Boolean && left instanceof String) { - if (left.equals("true") || left.equals("false")) - return Boolean.parseBoolean(left.toString()); - - Number num = NumberUtils.createNumber(left.toString()); - if (num.intValue() == 1) - return (Boolean) true; - else if (num.intValue() == 0) - return (Boolean) false; - } - return left; - } - + if (left == null || right == null) { + // we know both aren't null, therefore L != R + return false; + } + final String arg = left.toString(); + if (right instanceof java.util.regex.Pattern) { + return ((java.util.regex.Pattern) right).matcher(arg).matches(); + } else { + // return arg.matches(right.toString()); + Pattern p = Pattern.compile(right.toString(), Pattern.DOTALL); + Matcher m = p.matcher(arg); + return m.matches(); + + } + } + + /** + * This method differs from the parent class in that we are going to try and do a better job of coercing the types. As a last resort we will do a string + * comparison and try not to throw a NumberFormatException. The JexlArithmetic class performs coercion to a particular type if either the left or the right + * match a known type. We will look at the type of the right operator and try to make the left of the same type. + */ + @Override + public boolean equals(Object left, Object right) { + Object fixedLeft = fixLeft(left, right); + return super.equals(fixedLeft, right); + } + + @Override + public boolean lessThan(Object left, Object right) { + Object fixedLeft = fixLeft(left, right); + return super.lessThan(fixedLeft, right); + } + + protected Object fixLeft(Object left, Object right) { + + if (null == left || null == right) + return left; + + if (!(right instanceof Number) && left instanceof Number) { + right = NumberUtils.createNumber(right.toString()); + } + + if (right instanceof Number && left instanceof Number) { + if (right instanceof Double) + return ((Double) right).doubleValue(); + else if (right instanceof Float) + return ((Float) right).floatValue(); + else if (right instanceof Long) + return ((Long) right).longValue(); + else if (right instanceof Integer) + return ((Integer) right).intValue(); + else if (right instanceof Short) + return ((Short) right).shortValue(); + else if (right instanceof Byte) + return ((Byte) right).byteValue(); + else + return right; + } + if (right instanceof Number && left instanceof String) { + Number num = NumberUtils.createNumber(left.toString()); + // Let's try to cast left as right's type. + if (this.isFloatingPointNumber(right) && this.isFloatingPointNumber(left)) + return num; + else if (this.isFloatingPointNumber(right)) + return num.doubleValue(); + else if (right instanceof Number) + return num.longValue(); + } else if (right instanceof Boolean && left instanceof String) { + if (left.equals("true") || left.equals("false")) + return Boolean.parseBoolean(left.toString()); + + Number num = NumberUtils.createNumber(left.toString()); + if (num.intValue() == 1) + return (Boolean) true; + else if (num.intValue() == 0) + return (Boolean) false; + } + return left; + } + }