blob: d4f9156d03f5a166221419e35d4416c23f7184e8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.asterix.external.classad;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeSet;
import org.apache.asterix.external.classad.Value.NumberFactor;
import org.apache.asterix.external.classad.object.pool.ClassAdObjectPool;
import org.apache.asterix.external.library.ClassAdParser;
import org.apache.asterix.om.base.AMutableDouble;
import org.apache.asterix.om.base.AMutableInt32;
import org.apache.asterix.om.base.AMutableInt64;
import org.apache.asterix.om.base.AMutableString;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.hyracks.api.exceptions.HyracksDataException;
public class ClassAd extends ExprTree {
/*
* Static Variables
*/
public static final int ERR_OK = 0;
public static final int ERR_MEM_ALLOC_FAILED = 1;
public static final int ERR_BAD_VALUE = 255;
public static final int ERR_FAILED_SET_VIEW_NAME = 256;
public static final int ERR_NO_RANK_EXPR = 257;
public static final int ERR_NO_REQUIREMENTS_EXPR = 258;
public static final int ERR_BAD_PARTITION_EXPRS = 259;
public static final int ERR_PARTITION_EXISTS = 260;
public static final int ERR_MISSING_ATTRNAME = 261;
public static final int ERR_BAD_EXPRESSION = 262;
public static final int ERR_INVALID_IDENTIFIER = 263;
public static final int ERR_MISSING_ATTRIBUTE = 264;
public static final int ERR_NO_SUCH_VIEW = 265;
public static final int ERR_VIEW_PRESENT = 266;
public static final int ERR_TRANSACTION_EXISTS = 267;
public static final int ERR_NO_SUCH_TRANSACTION = 268;
public static final int ERR_NO_REPRESENTATIVE = 269;
public static final int ERR_NO_PARENT_VIEW = 270;
public static final int ERR_BAD_VIEW_INFO = 271;
public static final int ERR_BAD_TRANSACTION_STATE = 272;
public static final int ERR_NO_SUCH_CLASSAD = 273;
public static final int ERR_BAD_CLASSAD = 275;
public static final int ERR_NO_KEY = 276;
public static final int ERR_LOG_OPEN_FAILED = 277;
public static final int ERR_BAD_LOG_FILENAME = 278;
public static final int ERR_NO_VIEW_NAME = 379;
public static final int ERR_RENAME_FAILED = 280;
public static final int ERR_NO_TRANSACTION_NAME = 281;
public static final int ERR_PARSE_ERROR = 282;
public static final int ERR_INTERNAL_CACHE_ERROR = 283;
public static final int ERR_FILE_WRITE_FAILED = 284;
public static final int ERR_FATAL_ERROR = 285;
public static final int ERR_CANNOT_CHANGE_MODE = 286;
public static final int ERR_CONNECT_FAILED = 287;
public static final int ERR_CLIENT_NOT_CONNECTED = 288;
public static final int ERR_COMMUNICATION_ERROR = 289;
public static final int ERR_BAD_CONNECTION_TYPE = 290;
public static final int ERR_BAD_SERVER_ACK = 291;
public static final int ERR_CANNOT_REPLACE = 292;
public static final int ERR_CACHE_SWITCH_ERROR = 293;
public static final int ERR_CACHE_FILE_ERROR = 294;
public static final int ERR_CACHE_CLASSAD_ERROR = 295;
public static final int ERR_CANT_LOAD_DYNAMIC_LIBRARY = 296;
public static final String ATTR_TOPLEVEL = "toplevel";
public static final String ATTR_ROOT = "root";
public static final String ATTR_SELF = "self";
public static final String ATTR_PARENT = "parent";
// The two names below are for compatibility
public static final String ATTR_MY = "my";
public static final String ATTR_CURRENT_TIME = "CurrentTime";
// These versions are actually taken from an external file in the original cpp source code
private static final int CLASSAD_VERSION_MAJOR = 8;
private static final int CLASSAD_VERSION_MINOR = 0;
private static final int CLASSAD_VERSION_PATCH = 0;
private static final String CLASSAD_VERSION = "8.0.0";
public static final ArrayList<String> specialAttrNames = new ArrayList<String>();
static {
specialAttrNames.add(ATTR_TOPLEVEL);
specialAttrNames.add(ATTR_ROOT);
specialAttrNames.add(ATTR_SELF);
specialAttrNames.add(ATTR_PARENT);
}
public static final FunctionCall curr_time_expr =
FunctionCall.createFunctionCall("time", new ExprList(new ClassAdObjectPool()), new ClassAdObjectPool());
private ClassAd alternateScope;
private final Map<CaseInsensitiveString, ExprTree> attrList;
private ClassAd chainedParentAd;
private ClassAdParser parser = null;
private ClassAd newAd;
/*
* Constructors
*/
public ClassAd(ClassAdObjectPool objectPool) {
super(objectPool);
parser = new ClassAdParser(this.objectPool);
attrList = new HashMap<CaseInsensitiveString, ExprTree>();
}
@Override
public void reset() {
clear();
}
public boolean isReset() {
return false;
}
public ClassAd getAlternateScope() {
return alternateScope;
}
public void setAlternateScope(ClassAd alternateScope) {
this.alternateScope = alternateScope;
}
public Map<CaseInsensitiveString, ExprTree> getAttrList() {
return attrList;
}
public void classAdLibraryVersion(AMutableInt32 major, AMutableInt32 minor, AMutableInt32 patch) {
major.setValue(CLASSAD_VERSION_MAJOR);
minor.setValue(CLASSAD_VERSION_MINOR);
patch.setValue(CLASSAD_VERSION_PATCH);
}
public static void classAdLibraryVersion(AMutableString version_string) {
version_string.setValue(CLASSAD_VERSION);
}
public static ArrayList<String> getSpecialAttrNames() {
return specialAttrNames;
}
public static FunctionCall getCurrentTimeExpr() {
return curr_time_expr;
}
public boolean copyFrom(ClassAd ad) throws HyracksDataException {
boolean succeeded = true;
if (this == ad) {
succeeded = false;
} else {
clear();
// copy scoping attributes
super.copyFrom(ad);
chainedParentAd = ad.chainedParentAd;
alternateScope = ad.alternateScope;
for (Entry<CaseInsensitiveString, ExprTree> attr : ad.attrList.entrySet()) {
ExprTree tree = objectPool.mutableExprPool.get();
CaseInsensitiveString key = objectPool.caseInsensitiveStringPool.get();
tree.copyFrom(attr.getValue());
key.set(attr.getKey().get());
attrList.put(key, tree);
}
}
return succeeded;
}
public boolean update(ClassAd ad) throws HyracksDataException {
for (Entry<CaseInsensitiveString, ExprTree> attr : ad.attrList.entrySet()) {
ExprTree tree = objectPool.mutableExprPool.get();
CaseInsensitiveString key = objectPool.caseInsensitiveStringPool.get();
tree.copyFrom(attr.getValue());
key.set(attr.getKey().get());
attrList.put(key, tree);
}
return true;
}
public boolean updateFromChain(ClassAd ad) throws HyracksDataException {
ClassAd parent = ad.chainedParentAd;
if (parent != null) {
if (!updateFromChain(parent)) {
return false;
}
}
return update(ad);
}
public boolean copyFromChain(ClassAd ad) throws HyracksDataException {
if (this == ad) {
return false;
}
clear();
super.copyFrom(ad);
return updateFromChain(ad);
}
@Override
public boolean sameAs(ExprTree tree) {
boolean is_same;
ExprTree pSelfTree = tree.self();
if (this == pSelfTree) {
is_same = true;
} else if (pSelfTree.getKind() != NodeKind.CLASSAD_NODE) {
is_same = false;
} else {
ClassAd other_classad;
other_classad = (ClassAd) pSelfTree;
if (attrList.size() != other_classad.attrList.size()) {
is_same = false;
} else {
is_same = true;
for (Entry<CaseInsensitiveString, ExprTree> attr : attrList.entrySet()) {
ExprTree this_tree = attr.getValue();
ExprTree other_tree = other_classad.lookup(attr.getKey());
if (other_tree == null) {
is_same = false;
break;
} else if (!this_tree.sameAs(other_tree)) {
is_same = false;
break;
}
}
}
}
return is_same;
}
public void clear() {
unchain();
attrList.clear();
if (alternateScope != null) {
alternateScope.clear();
}
}
public void unchain() {
if (chainedParentAd != null) {
chainedParentAd.clear();
}
}
public void getComponents(Map<CaseInsensitiveString, ExprTree> attrs, ClassAdObjectPool objectPool)
throws HyracksDataException {
attrs.clear();
for (Entry<CaseInsensitiveString, ExprTree> attr : this.attrList.entrySet()) {
ExprTree tree = objectPool.mutableExprPool.get();
CaseInsensitiveString key = objectPool.caseInsensitiveStringPool.get();
tree.copyFrom(attr.getValue());
key.set(attr.getKey().get());
attrs.put(key, tree);
}
}
public ClassAd privateGetDeepScope(ExprTree tree) throws HyracksDataException {
if (tree == null) {
return (null);
}
ClassAd scope = objectPool.classAdPool.get();
Value val = objectPool.valuePool.get();
tree.setParentScope(this);
if (!tree.publicEvaluate(val) || !val.isClassAdValue(scope)) {
return (null);
}
return (scope);
}
// --- begin integer attribute insertion ----
public boolean insertAttr(String name, int value, NumberFactor f) throws HyracksDataException {
ExprTree plit;
Value val = objectPool.valuePool.get();
val.setIntegerValue(value);
plit = Literal.createLiteral(val, f, objectPool);
return insert(name, plit);
}
public boolean insertAttr(String name, int value) throws HyracksDataException {
return insertAttr(name, value, NumberFactor.NO_FACTOR);
}
public boolean insertAttr(String name, long value, NumberFactor f) throws HyracksDataException {
ExprTree plit;
Value val = objectPool.valuePool.get();
val.setIntegerValue(value);
plit = Literal.createLiteral(val, f, objectPool);
return (insert(name, plit));
}
public boolean insertAttr(String name, long value) throws HyracksDataException {
return insertAttr(name, value, NumberFactor.NO_FACTOR);
}
public boolean deepInsertAttr(ExprTree scopeExpr, String name, int value, NumberFactor f)
throws HyracksDataException {
ClassAd ad = privateGetDeepScope(scopeExpr);
if (ad == null) {
return (false);
}
return (ad.insertAttr(name, value, f));
}
public boolean deepInsertAttr(ExprTree scopeExpr, String name, long value, NumberFactor f)
throws HyracksDataException {
ClassAd ad = privateGetDeepScope(scopeExpr);
if (ad == null) {
return (false);
}
return (ad.insertAttr(name, value, f));
}
// --- end integer attribute insertion ---
// --- begin real attribute insertion ---
public boolean insertAttr(String name, double value, NumberFactor f) throws HyracksDataException {
ExprTree plit;
Value val = objectPool.valuePool.get();
val.setRealValue(value);
plit = Literal.createLiteral(val, f, objectPool);
return (insert(name, plit));
}
public boolean deepInsertAttr(ExprTree scopeExpr, String name, double value, NumberFactor f)
throws HyracksDataException {
ClassAd ad = privateGetDeepScope(scopeExpr);
if (ad == null) {
return (false);
}
return (ad.insertAttr(name, value, f));
}
// --- end real attribute insertion
// --- begin boolean attribute insertion
public boolean insertAttr(String name, boolean value) throws HyracksDataException {
ExprTree plit;
Value val = objectPool.valuePool.get();
val.setBooleanValue(value);
plit = Literal.createLiteral(val, objectPool);
return (insert(name, plit));
}
public boolean deepInsertAttr(ExprTree scopeExpr, String name, boolean value) throws HyracksDataException {
ClassAd ad = privateGetDeepScope(scopeExpr);
if (ad == null) {
return (false);
}
return (ad.insertAttr(name, value));
}
// --- end boolean attribute insertion
// --- begin string attribute insertion
public boolean insertAttr(String name, AMutableCharArrayString value) throws HyracksDataException {
ExprTree plit;
Value val = objectPool.valuePool.get();
val.setStringValue(value);
plit = Literal.createLiteral(val, objectPool);
return (insert(name, plit));
}
public boolean deepInsertAttr(ExprTree scopeExpr, String name, AMutableCharArrayString value)
throws HyracksDataException {
ClassAd ad = privateGetDeepScope(scopeExpr);
if (ad == null) {
return (false);
}
return (ad.insertAttr(name, value));
}
public boolean insertAttr(String name, String value) throws HyracksDataException {
ExprTree plit;
Value val = objectPool.valuePool.get();
val.setStringValue(value);
plit = Literal.createLiteral(val, objectPool);
return (insert(name, plit));
}
public boolean deepInsertAttr(ExprTree scopeExpr, String name, String value) throws HyracksDataException {
ClassAd ad = privateGetDeepScope(scopeExpr);
if (ad == null) {
return (false);
}
return (ad.insertAttr(name, value));
}
// --- end string attribute insertion
public boolean insert(String serialized_nvp) throws IOException {
boolean bRet = false;
String name, szValue;
int pos, npos, vpos;
int bpos = 0;
// comes in as "name = value" "name= value" or "name =value"
npos = pos = serialized_nvp.indexOf('=');
// only try to process if the string is valid
if (pos >= 0) {
while (npos > 0 && serialized_nvp.charAt(npos - 1) == ' ') {
npos--;
}
while (bpos < npos && serialized_nvp.charAt(bpos) == ' ') {
bpos++;
}
name = serialized_nvp.substring(bpos, npos);
vpos = pos + 1;
while (serialized_nvp.charAt(vpos) == ' ') {
vpos++;
}
szValue = serialized_nvp.substring(vpos);
if (name.charAt(0) == '\'') {
// We don't handle quoted attribute names for caching here.
// Hand the name-value-pair off to the parser as a one-attribute
// ad and merge the results into this ad.
newAd.clear();
name = "[" + serialized_nvp.toString() + "]";
if (parser.parseClassAd(name, newAd, true)) {
return update(newAd);
} else {
return false;
}
}
ExprTree newTree;
// we did not hit in the cache... parse the expression
newTree = parser.ParseExpression(szValue);
if (newTree != null) {
// if caching is enabled, and we got to here then we know that the
// cache doesn't already have an entry for this name:value, so add
// it to the cache now.
if (newTree.getKind() != NodeKind.LITERAL_NODE) {
Literal lit = objectPool.literalPool.get();
lit.getValue().setStringValue(szValue);
bRet = insert(name, lit, false);
} else {
bRet = insert(name, newTree, false);
}
}
} // end if pos >=0
return bRet;
}
public boolean insert(String attrName, ExprTree expr) throws HyracksDataException {
ExprTree tree = expr.copy();
boolean result = insert(attrName, tree.isTreeHolder() ? ((ExprTreeHolder) tree).getInnerTree() : tree, false);
return result;
}
public boolean insert(String attrName, ExprTree pRef, boolean cache) throws HyracksDataException {
boolean bRet = false;
ExprTree tree = pRef;
// sanity checks
if (attrName.isEmpty() || pRef == null) {
throw new HyracksDataException("Attribute name is empty");
}
if (tree != null) {
CaseInsensitiveString pstrAttr = objectPool.caseInsensitiveStringPool.get();
pstrAttr.set(attrName);
ExprTreeHolder mutableTree = objectPool.mutableExprPool.get();
mutableTree.copyFrom(tree);
// parent of the expression is this classad
tree.setParentScope(this);
attrList.put(pstrAttr, mutableTree);
bRet = true;
}
return (bRet);
}
public boolean deepInsert(ExprTree scopeExpr, String name, ExprTree tree) throws HyracksDataException {
ClassAd ad = privateGetDeepScope(scopeExpr);
if (ad == null) {
return (false);
}
return (ad.insert(name, tree));
}
// --- end expression insertion
// --- begin lookup methods
public ExprTree lookup(String name) {
CaseInsensitiveString aString = objectPool.caseInsensitiveStringPool.get();
aString.set(name);
ExprTree expr = lookup(aString);
return expr;
}
public ExprTree lookup(CaseInsensitiveString name) {
/*
* System.out.println("Lookup Printing all attributes with their values:");
* for (Entry<String, ExprTree> entry : attrList.entrySet()) {
* System.out.println(entry.getKey() + ":" + entry.getValue().getKind());
* }
*/
ExprTree attr = attrList.get(name);
if (attr != null) {
return attr;
} else if (chainedParentAd != null) {
return chainedParentAd.lookup(name);
} else {
return null;
}
}
public ExprTree lookupInScope(AMutableCharArrayString name, ClassAd finalScope) throws HyracksDataException {
EvalState state = objectPool.evalStatePool.get();
ExprTreeHolder tree = objectPool.mutableExprPool.get();
int rval;
state.setScopes(this);
rval = lookupInScope(name.toString(), tree, state);
if (rval == EvalResult.EVAL_OK.ordinal()) {
finalScope.setValue(state.getCurAd());
return (tree);
}
finalScope.setValue(null);
return null;
}
public int lookupInScope(String name, ExprTreeHolder expr, EvalState state) throws HyracksDataException {
ClassAd current = this;
ClassAd superScope = objectPool.classAdPool.get();
expr.setInnerTree(null);
while (expr.getInnerTree() == null && current != null) {
// lookups/eval's being done in the 'current' ad
state.getCurAd().setValue(current);
// lookup in current scope
expr.setInnerTree(current.lookup(name));
if ((expr.getInnerTree() != null)) {
return EvalResult.EVAL_OK.ordinal();
}
try {
if (state.getRootAd() == null) {
return (EvalResult.EVAL_UNDEF.ordinal());
} else if (state.getRootAd().equals(current)) {
superScope = null;
} else {
superScope = current.parentScope;
}
} catch (Throwable th) {
th.printStackTrace();
throw th;
}
if (!getSpecialAttrNames().contains(name)) {
// continue searching from the superScope ...
current = superScope;
if (current == this) { // NAC - simple loop checker
return (EvalResult.EVAL_UNDEF.ordinal());
}
} else if (name.equalsIgnoreCase(ATTR_TOPLEVEL) || name.equalsIgnoreCase(ATTR_ROOT)) {
// if the "toplevel" attribute was requested ...
expr.setInnerTree(state.getRootAd());
if (expr.getInnerTree() == null) { // NAC - circularity so no root
return EvalResult.EVAL_FAIL.ordinal(); // NAC
} // NAC
return (expr.getInnerTree() != null ? EvalResult.EVAL_OK.ordinal() : EvalResult.EVAL_UNDEF.ordinal());
} else if (name.equalsIgnoreCase(ATTR_SELF) || name.equalsIgnoreCase(ATTR_MY)) {
// if the "self" ad was requested
expr.setInnerTree(state.getCurAd());
return (expr.getInnerTree() != null ? EvalResult.EVAL_OK.ordinal() : EvalResult.EVAL_UNDEF.ordinal());
} else if (name.equalsIgnoreCase(ATTR_PARENT)) {
// the lexical parent
expr.setInnerTree(superScope);
return (expr.getInnerTree() != null ? EvalResult.EVAL_OK.ordinal() : EvalResult.EVAL_UNDEF.ordinal());
} else if (name.equalsIgnoreCase(ATTR_CURRENT_TIME)) {
// an alias for time() from old ClassAds
expr.setInnerTree(getCurrentTimeExpr());
return (expr.getInnerTree() != null ? EvalResult.EVAL_OK.ordinal() : EvalResult.EVAL_UNDEF.ordinal());
}
}
return (EvalResult.EVAL_UNDEF.ordinal());
}
// --- end lookup methods
// --- begin deletion methods
public boolean delete(String name) throws HyracksDataException {
CaseInsensitiveString aString = objectPool.caseInsensitiveStringPool.get();
aString.set(name);
boolean success = delete(aString);
return success;
}
public boolean delete(CaseInsensitiveString name) throws HyracksDataException {
boolean deleted_attribute;
deleted_attribute = false;
if (attrList.containsKey(name)) {
attrList.remove(name);
deleted_attribute = true;
}
// If the attribute is in the chained parent, we delete define it
// here as undefined, whether or not it was defined here. This is
// behavior copied from old ClassAds. It's also one reason you
// probably don't want to use this feature in the future.
if (chainedParentAd != null && chainedParentAd.lookup(name) != null) {
Value undefined_value = objectPool.valuePool.get();
undefined_value.setUndefinedValue();
deleted_attribute = true;
ExprTree plit = Literal.createLiteral(undefined_value, objectPool);
insert(name.get(), plit);
}
return deleted_attribute;
}
public boolean deepDelete(ExprTree scopeExpr, String name) throws HyracksDataException {
ClassAd ad = privateGetDeepScope(scopeExpr);
if (ad == null) {
return (false);
}
CaseInsensitiveString aString = objectPool.caseInsensitiveStringPool.get();
aString.set(name);
boolean success = ad.delete(aString);
return success;
}
// --- end deletion methods
// --- begin removal methods
public ExprTree remove(String name) throws HyracksDataException {
ExprTree tree = null;
if (attrList.containsKey(name)) {
tree = attrList.remove(name);
}
// If the attribute is in the chained parent, we delete define it
// here as undefined, whether or not it was defined here. This is
// behavior copied from old ClassAds. It's also one reason you
// probably don't want to use this feature in the future.
if (chainedParentAd != null && chainedParentAd.lookup(name) != null) {
if (tree == null) {
tree = chainedParentAd.lookup(name);
}
Value undefined_value = objectPool.valuePool.get();
undefined_value.setUndefinedValue();
ExprTree plit = Literal.createLiteral(undefined_value, objectPool);
//why??
insert(name, plit);
}
return tree;
}
public ExprTree deepRemove(ExprTree scopeExpr, String name) throws HyracksDataException {
ClassAd ad = privateGetDeepScope(scopeExpr);
if (ad == null) {
return (null);
}
return (ad.remove(name));
}
// --- end removal methods
@Override
public void privateSetParentScope(ClassAd ad) {
// already set by base class for this node; we shouldn't propagate
// the call to sub-expressions because this is a new scope
}
public void modify(ClassAd mod) throws HyracksDataException {
ClassAd ctx;
ExprTree expr;
Value val = objectPool.valuePool.get();
// Step 0: Determine Context
if ((expr = mod.lookup(Common.ATTR_CONTEXT)) != null) {
if ((ctx = privateGetDeepScope(expr)) == null) {
return;
}
} else {
ctx = this;
}
// Step 1: Process Replace attribute
if ((expr = mod.lookup(Common.ATTR_REPLACE)) != null) {
ClassAd ad = objectPool.classAdPool.get();
if (expr.publicEvaluate(val) && val.isClassAdValue(ad)) {
ctx.clear();
ctx.update(ad);
}
}
// Step 2: Process Updates attribute
if ((expr = mod.lookup(Common.ATTR_UPDATES)) != null) {
ClassAd ad = objectPool.classAdPool.get();
if (expr.publicEvaluate(val) && val.isClassAdValue(ad)) {
ctx.update(ad);
}
}
// Step 3: Process Deletes attribute
if ((expr = mod.lookup(Common.ATTR_DELETES)) != null) {
ExprList list = objectPool.exprListPool.get();
AMutableCharArrayString attrName = objectPool.strPool.get();
// make a first pass to check that it is a list of strings ...
if (!expr.publicEvaluate(val) || !val.isListValue(list)) {
return;
}
for (ExprTree aExpr : list.getExprList()) {
if (!aExpr.publicEvaluate(val) || !val.isStringValue(attrName)) {
return;
}
}
// now go through and delete all the named attributes ...
for (ExprTree aExpr : list.getExprList()) {
if (aExpr.publicEvaluate(val) && val.isStringValue(attrName)) {
ctx.delete(attrName.toString());
}
}
}
}
@Override
public ExprTree copy() throws HyracksDataException {
ClassAd newAd = objectPool.classAdPool.get();
newAd.parentScope = (parentScope == null) ? null : (ClassAd) parentScope.copy();
newAd.chainedParentAd = chainedParentAd == null ? null : (ClassAd) chainedParentAd.copy();
for (Entry<CaseInsensitiveString, ExprTree> entry : attrList.entrySet()) {
newAd.insert(entry.getKey().get(), entry.getValue(), false);
}
return newAd;
}
@Override
public boolean publicEvaluate(EvalState state, Value val) throws HyracksDataException {
val.setClassAdValue(this);
return (true);
}
@Override
public boolean privateEvaluate(EvalState state, Value val, ExprTreeHolder tree) throws HyracksDataException {
val.setClassAdValue(this);
tree.setInnerTree(copy());
return true;
}
@Override
public boolean privateFlatten(EvalState state, Value val, ExprTreeHolder tree, AMutableInt32 i)
throws HyracksDataException {
ClassAd newAd = objectPool.classAdPool.get();
Value eval = objectPool.valuePool.get();
ExprTreeHolder etree = objectPool.mutableExprPool.get();
ClassAd oldAd;
tree.setInnerTree(null); // Just to be safe... wenger 2003-12-11.
oldAd = state.getCurAd();
state.setCurAd(this);
for (Entry<CaseInsensitiveString, ExprTree> entry : attrList.entrySet()) {
// flatten expression
if (!entry.getValue().publicFlatten(state, eval, etree)) {
tree.setInnerTree(null);
eval.setUndefinedValue();
state.setCurAd(oldAd);
return false;
}
// if a value was obtained, convert it to a literal
if (etree.getInnerTree() == null) {
etree.setInnerTree(Literal.createLiteral(eval, objectPool));
if (etree.getInnerTree() == null) {
tree.setInnerTree(null);
eval.setUndefinedValue();
state.setCurAd(oldAd);
return false;
}
}
CaseInsensitiveString key = objectPool.caseInsensitiveStringPool.get();
ExprTreeHolder value = objectPool.mutableExprPool.get();
key.set(entry.getKey().get());
value.copyFrom(etree);
newAd.attrList.put(key, value);
eval.setUndefinedValue();
}
tree.setInnerTree(newAd);
state.setCurAd(oldAd);
return true;
}
public boolean evaluateAttr(String attr, Value val) throws HyracksDataException {
EvalState state = objectPool.evalStatePool.get();
ExprTreeHolder tree = objectPool.mutableExprPool.get();
state.setScopes(this);
switch (lookupInScope(attr, tree, state)) {
case ExprTree.EVAL_FAIL_Int:
return false;
case ExprTree.EVAL_OK_Int:
return (tree.publicEvaluate(state, val));
case ExprTree.EVAL_UNDEF_Int:
val.setUndefinedValue();
return (true);
case ExprTree.EVAL_ERROR_Int:
val.setErrorValue();
return (true);
default:
return false;
}
}
public boolean evaluateExpr(String buf, Value result) throws HyracksDataException {
boolean successfully_evaluated;
ExprTreeHolder tree = objectPool.mutableExprPool.get();
ClassAdParser parser = objectPool.classAdParserPool.get();
try {
if (parser.parseExpression(buf, tree)) {
successfully_evaluated = evaluateExpr(tree, result);
} else {
successfully_evaluated = false;
}
} catch (IOException e) {
throw HyracksDataException.create(e);
}
return successfully_evaluated;
}
public boolean evaluateExpr(ExprTreeHolder tree, Value val) throws HyracksDataException {
EvalState state = objectPool.evalStatePool.get();
state.setScopes(this);
return (tree.publicEvaluate(state, val));
}
public boolean evaluateExpr(ExprTreeHolder tree, Value val, ExprTreeHolder sig) throws HyracksDataException {
EvalState state = objectPool.evalStatePool.get();
state.setScopes(this);
return (tree.publicEvaluate(state, val, sig));
}
public boolean evaluateAttrInt(String attr, AMutableInt64 i) throws HyracksDataException {
Value val = objectPool.valuePool.get();
return (evaluateAttr(attr, val) && val.isIntegerValue(i));
}
public boolean evaluateAttrReal(String attr, AMutableDouble r) throws HyracksDataException {
Value val = objectPool.valuePool.get();
return (evaluateAttr(attr, val) && val.isRealValue(r));
}
public boolean evaluateAttrNumber(String attr, AMutableInt64 i) throws HyracksDataException {
Value val = objectPool.valuePool.get();
return (evaluateAttr(attr, val) && val.isNumber(i));
}
public boolean evaluateAttrNumber(String attr, AMutableDouble r) throws HyracksDataException {
Value val = objectPool.valuePool.get();
return (evaluateAttr(attr, val) && val.isNumber(r));
}
public boolean evaluateAttrString(String attr, AMutableCharArrayString buf, int len) throws HyracksDataException {
Value val = objectPool.valuePool.get();
return (evaluateAttr(attr, val) && val.isStringValue(buf, len));
}
public boolean evaluateAttrString(String attr, AMutableCharArrayString buf) throws HyracksDataException {
Value val = objectPool.valuePool.get();
return (evaluateAttr(attr, val) && val.isStringValue(buf));
}
public boolean evaluateAttrBool(String attr, MutableBoolean b) throws HyracksDataException {
Value val = objectPool.valuePool.get();
return (evaluateAttr(attr, val) && val.isBooleanValue(b));
}
public boolean evaluateAttrBoolEquiv(String attr, MutableBoolean b) throws HyracksDataException {
Value val = objectPool.valuePool.get();
return (evaluateAttr(attr, val) && val.isBooleanValueEquiv(b));
}
/*
* Reference is an ordered set of Strings <The ordering uses less than ignore case>. Example
* below
* TreeSet<String> references = new TreeSet<String>(
* new Comparator<String>(){
* public int compare(String o1, String o2) {
* return o1.compareToIgnoreCase(o2);
* }
* });
*
* // PortReferences is a Map<ClassAd,OrderedSet<Strings>>
*/
public boolean getExternalReferences(ExprTree tree, TreeSet<String> refs, boolean fullNames)
throws HyracksDataException {
EvalState state = objectPool.evalStatePool.get();
// Treat this ad as the root of the tree for reference tracking.
// If an attribute is only present in a parent scope of this ad,
// then we want to treat it as an external reference.
state.setRootAd(this);
state.setCurAd(this);
return (privateGetExternalReferences(tree, this, state, refs, fullNames));
}
public boolean privateGetExternalReferences(ExprTree expr, ClassAd ad, EvalState state, TreeSet<String> refs,
boolean fullNames) throws HyracksDataException {
if (expr.isTreeHolder()) {
expr = ((ExprTreeHolder) expr).getInnerTree();
}
switch (expr.getKind()) {
case LITERAL_NODE:
// no external references here
return (true);
case ATTRREF_NODE: {
ClassAd start = objectPool.classAdPool.get();
ExprTreeHolder tree = objectPool.mutableExprPool.get();
ExprTreeHolder result = objectPool.mutableExprPool.get();
AMutableCharArrayString attr = objectPool.strPool.get();
Value val = objectPool.valuePool.get();
MutableBoolean abs = objectPool.boolPool.get();
((AttributeReference) expr).getComponents(tree, attr, abs);
// establish starting point for attribute search
if (tree.getInnerTree() == null) {
start = abs.booleanValue() ? state.getRootAd() : state.getCurAd();
if (abs.booleanValue() && (start == null)) {// NAC - circularity so no root
return false; // NAC
} // NAC
} else {
if (!tree.publicEvaluate(state, val)) {
return (false);
}
// if the tree evals to undefined, the external references
// are in the tree part
if (val.isUndefinedValue()) {
if (fullNames) {
AMutableCharArrayString fullName = objectPool.strPool.get();
if (tree.getInnerTree() != null) {
ClassAdUnParser unparser = objectPool.prettyPrintPool.get();
unparser.unparse(fullName, tree);
fullName.appendChar('.');
}
fullName.appendString(attr);
refs.add(fullName.toString());
return true;
} else {
if (state.getDepthRemaining() <= 0) {
return false;
}
state.decrementDepth();
boolean ret = privateGetExternalReferences(tree, ad, state, refs, fullNames);
state.incrementDepth();
return ret;
}
}
// otherwise, if the tree didn't evaluate to a classad,
// we have a problem
if (!val.isClassAdValue(start)) {
return (false);
}
}
// lookup for attribute
ClassAd curAd = state.getCurAd();
switch (start.lookupInScope(attr.toString(), result, state)) {
case EVAL_ERROR_Int:
// some error
return (false);
case EVAL_UNDEF_Int:
// attr is external
refs.add(attr.toString());
state.setCurAd(curAd);
return (true);
case EVAL_OK_Int: {
// attr is internal; find external refs in result
if (state.getDepthRemaining() <= 0) {
state.setCurAd(curAd);
return false;
}
state.decrementDepth();
boolean rval = privateGetExternalReferences(result, ad, state, refs, fullNames);
state.incrementDepth();
state.setCurAd(curAd);
return (rval);
}
case EVAL_FAIL_Int:
default:
// enh??
return (false);
}
}
case OP_NODE: {
// recurse on subtrees
AMutableInt32 opKind = objectPool.int32Pool.get();
ExprTreeHolder t1 = objectPool.mutableExprPool.get();
ExprTreeHolder t2 = objectPool.mutableExprPool.get();
ExprTreeHolder t3 = objectPool.mutableExprPool.get();
((Operation) expr).getComponents(opKind, t1, t2, t3);
if (t1.getInnerTree() != null && !privateGetExternalReferences(t1, ad, state, refs, fullNames)) {
return (false);
}
if (t2.getInnerTree() != null && !privateGetExternalReferences(t2, ad, state, refs, fullNames)) {
return (false);
}
if (t3.getInnerTree() != null && !privateGetExternalReferences(t3, ad, state, refs, fullNames)) {
return (false);
}
return (true);
}
case FN_CALL_NODE: {
// recurse on subtrees
AMutableCharArrayString fnName = objectPool.strPool.get();
ExprList args = objectPool.exprListPool.get();
((FunctionCall) expr).getComponents(fnName, args);
for (ExprTree tree : args.getExprList()) {
if (!privateGetExternalReferences(tree, ad, state, refs, fullNames)) {
return (false);
}
}
return (true);
}
case CLASSAD_NODE: {
// recurse on subtrees
Map<CaseInsensitiveString, ExprTree> attrs = objectPool.strToExprPool.get();
((ClassAd) expr).getComponents(attrs, objectPool);
for (Entry<CaseInsensitiveString, ExprTree> entry : attrs.entrySet()) {
if (state.getDepthRemaining() <= 0) {
return false;
}
state.decrementDepth();
boolean ret = privateGetExternalReferences(entry.getValue(), ad, state, refs, fullNames);
state.incrementDepth();
if (!ret) {
return (false);
}
}
return (true);
}
case EXPR_LIST_NODE: {
// recurse on subtrees
ExprList exprs = objectPool.exprListPool.get();
((ExprList) expr).getComponents(exprs);
for (ExprTree exprTree : exprs.getExprList()) {
if (state.getDepthRemaining() <= 0) {
return false;
}
state.decrementDepth();
boolean ret = privateGetExternalReferences(exprTree, ad, state, refs, fullNames);
state.incrementDepth();
if (!ret) {
return (false);
}
}
return (true);
}
default:
return false;
}
}
// PortReferences is a Map<ClassAd,TreeSet<Strings>>
public boolean getExternalReferences(ExprTree tree, Map<ClassAd, TreeSet<String>> refs)
throws HyracksDataException {
EvalState state = objectPool.evalStatePool.get();
// Treat this ad as the root of the tree for reference tracking.
// If an attribute is only present in a parent scope of this ad,
// then we want to treat it as an external reference.
state.setRootAd(this);
state.setCurAd(this);
return (privateGetExternalReferences(tree, this, state, refs));
}
public boolean privateGetExternalReferences(ExprTree expr, ClassAd ad, EvalState state,
Map<ClassAd, TreeSet<String>> refs) throws HyracksDataException {
switch (expr.getKind()) {
case LITERAL_NODE:
// no external references here
return (true);
case ATTRREF_NODE: {
ClassAd start = objectPool.classAdPool.get();
ExprTreeHolder tree = objectPool.mutableExprPool.get();
ExprTreeHolder result = objectPool.mutableExprPool.get();
AMutableCharArrayString attr = objectPool.strPool.get();
Value val = objectPool.valuePool.get();
MutableBoolean abs = objectPool.boolPool.get();
((AttributeReference) expr).getComponents(tree, attr, abs);
// establish starting point for attribute search
if (tree.getInnerTree() == null) {
start = abs.booleanValue() ? state.getRootAd() : state.getCurAd();
if (abs.booleanValue() && (start == null)) {// NAC - circularity so no root
return false; // NAC
} // NAC
} else {
if (!tree.publicEvaluate(state, val)) {
return (false);
}
// if the tree evals to undefined, the external references
// are in the tree part
if (val.isUndefinedValue()) {
return (privateGetExternalReferences(tree, ad, state, refs));
}
// otherwise, if the tree didn't evaluate to a classad,
// we have a problem
if (!val.isClassAdValue(start)) {
return (false);
}
// make sure that we are starting from a "valid" scope
if (!refs.containsKey(start) && start != this) {
return (false);
}
}
// lookup for attribute
ClassAd curAd = state.getCurAd();
TreeSet<String> pitr = refs.get(start);
if (pitr == null) {
pitr = objectPool.strSetPool.get();
refs.put(start, pitr);
}
switch (start.lookupInScope(attr.toString(), result, state)) {
case EVAL_ERROR_Int:
// some error
return (false);
case EVAL_UNDEF_Int:
// attr is external
pitr.add(attr.toString());
state.setCurAd(curAd);
return (true);
case EVAL_OK_Int: {
// attr is internal; find external refs in result
boolean rval = privateGetExternalReferences(result, ad, state, refs);
state.setCurAd(curAd);
return (rval);
}
case EVAL_FAIL_Int:
default:
// enh??
return (false);
}
}
case OP_NODE: {
// recurse on subtrees
AMutableInt32 opKind = objectPool.int32Pool.get();
ExprTreeHolder t1 = objectPool.mutableExprPool.get();
ExprTreeHolder t2 = objectPool.mutableExprPool.get();
ExprTreeHolder t3 = objectPool.mutableExprPool.get();
((Operation) expr).getComponents(opKind, t1, t2, t3);
if (t1.getInnerTree() != null && !privateGetExternalReferences(t1, ad, state, refs)) {
return (false);
}
if (t2.getInnerTree() != null && !privateGetExternalReferences(t2, ad, state, refs)) {
return (false);
}
if (t3.getInnerTree() != null && !privateGetExternalReferences(t3, ad, state, refs)) {
return (false);
}
return (true);
}
case FN_CALL_NODE: {
// recurse on subtrees
AMutableCharArrayString fnName = objectPool.strPool.get();
ExprList args = objectPool.exprListPool.get();
((FunctionCall) expr).getComponents(fnName, args);
for (ExprTree exprTree : args.getExprList()) {
if (!privateGetExternalReferences(exprTree, ad, state, refs)) {
return (false);
}
}
return (true);
}
case CLASSAD_NODE: {
// recurse on subtrees
HashMap<CaseInsensitiveString, ExprTree> attrs = objectPool.strToExprPool.get();
((ClassAd) expr).getComponents(attrs, objectPool);
for (Entry<CaseInsensitiveString, ExprTree> entry : attrs.entrySet()) {
if (!privateGetExternalReferences(entry.getValue(), ad, state, refs)) {
return (false);
}
}
return (true);
}
case EXPR_LIST_NODE: {
// recurse on subtrees
ExprList exprs = objectPool.exprListPool.get();
((ExprList) expr).getComponents(exprs);
for (ExprTree exprTree : exprs.getExprList()) {
if (!privateGetExternalReferences(exprTree, ad, state, refs)) {
return (false);
}
}
return (true);
}
default:
return false;
}
}
/*
* Reference is an ordered set of Strings <The ordering uses less than ignore case>. Example
* below
* TreeSet<String> references = new TreeSet<String>(
* new Comparator<String>(){
* public int compare(String o1, String o2) {
* return o1.compareToIgnoreCase(o2);
* }
* });
*
* // PortReferences is a Map<ClassAd,OrderedSet<Strings>>
*/
public boolean getInternalReferences(ExprTree tree, TreeSet<String> refs, boolean fullNames)
throws HyracksDataException {
EvalState state = objectPool.evalStatePool.get();
// Treat this ad as the root of the tree for reference tracking.
// If an attribute is only present in a parent scope of this ad,
// then we want to treat it as an external reference.
state.setRootAd(this);
state.setCurAd(this);
return (privateGetInternalReferences(tree, this, state, refs, fullNames));
}
//this is closely modelled off of _GetExternalReferences in the new_classads.
public boolean privateGetInternalReferences(ExprTree expr, ClassAd ad, EvalState state, TreeSet<String> refs,
boolean fullNames) throws HyracksDataException {
switch (expr.getKind()) {
//nothing to be found here!
case LITERAL_NODE: {
return true;
}
case ATTRREF_NODE: {
ClassAd start = objectPool.classAdPool.get();
ExprTreeHolder tree = objectPool.mutableExprPool.get();
ExprTreeHolder result = objectPool.mutableExprPool.get();
AMutableCharArrayString attr = objectPool.strPool.get();
Value val = objectPool.valuePool.get();
MutableBoolean abs = objectPool.boolPool.get();
((AttributeReference) expr).getComponents(tree, attr, abs);
//figuring out which state to base this off of
if (tree.getInnerTree() == null) {
start = abs.booleanValue() ? state.getRootAd() : state.getCurAd();
//remove circularity
if (abs.booleanValue() && (start == null)) {
return false;
}
} else {
boolean orig_inAttrRefScope = state.isInAttrRefScope();
state.setInAttrRefScope(true);
boolean rv = privateGetInternalReferences(tree, ad, state, refs, fullNames);
state.setInAttrRefScope(orig_inAttrRefScope);
if (!rv) {
return false;
}
if (!tree.publicEvaluate(state, val)) {
return false;
}
// TODO Do we need extra handling for list values?
// Should types other than undefined, error, or list
// cause a failure?
if (val.isUndefinedValue()) {
return true;
}
//otherwise, if the tree didn't evaluate to a classad,
//we have a problemo, mon.
//TODO: but why?
if (!val.isClassAdValue(start)) {
return false;
}
}
ClassAd curAd = state.getCurAd();
switch (start.lookupInScope(attr.toString(), result, state)) {
case EVAL_ERROR_Int:
return false;
//attr is external, so let's find the internals in that
//result
//JUST KIDDING
case EVAL_UNDEF_Int: {
//boolean rval = _GetInternalReferences(result, ad, state, refs, fullNames);
//state.getCurAd() = curAd;
return true;
}
case EVAL_OK_Int: {
//whoo, it's internal.
// Check whether the attribute was found in the root
// ad for this evaluation and that the attribute isn't
// one of our special ones (self, parent, my, etc.).
// If the ad actually has an attribute with the same
// name as one of our special attributes, then count
// that as an internal reference.
// TODO LookupInScope() knows whether it's returning
// the expression of one of the special attributes
// or that of an attribute that actually appears in
// the ad. If it told us which one, then we could
// avoid the Lookup() call below.
if (state.getCurAd() == state.getRootAd() && state.getCurAd().lookup(attr.toString()) != null) {
refs.add(attr.toString());
}
if (state.getDepthRemaining() <= 0) {
state.setCurAd(curAd);
return false;
}
state.decrementDepth();
boolean rval = privateGetInternalReferences(result, ad, state, refs, fullNames);
state.incrementDepth();
//TODO: Does this actually matter?
state.setCurAd(curAd);
return rval;
}
case EVAL_FAIL_Int:
default:
// "enh??"
return false;
}
}
case OP_NODE: {
//recurse on subtrees
AMutableInt32 op = objectPool.int32Pool.get();
ExprTreeHolder t1 = objectPool.mutableExprPool.get();
ExprTreeHolder t2 = objectPool.mutableExprPool.get();
ExprTreeHolder t3 = objectPool.mutableExprPool.get();
((Operation) expr).getComponents(op, t1, t2, t3);
if (t1.getInnerTree() != null && !privateGetInternalReferences(t1, ad, state, refs, fullNames)) {
return false;
}
if (t2.getInnerTree() != null && !privateGetInternalReferences(t2, ad, state, refs, fullNames)) {
return false;
}
if (t3.getInnerTree() != null && !privateGetInternalReferences(t3, ad, state, refs, fullNames)) {
return false;
}
return true;
}
case FN_CALL_NODE: {
//recurse on the subtrees!
AMutableCharArrayString fnName = objectPool.strPool.get();
ExprList args = objectPool.exprListPool.get();
((FunctionCall) expr).getComponents(fnName, args);
for (ExprTree exprTree : args.getExprList()) {
if (!privateGetInternalReferences(exprTree, ad, state, refs, fullNames)) {
return false;
}
}
return true;
}
case CLASSAD_NODE: {
//also recurse on subtrees...
HashMap<CaseInsensitiveString, ExprTree> attrs = objectPool.strToExprPool.get();
// If this ClassAd is only being used here as the scoping
// for an attribute reference, don't recurse into all of
// its attributes.
if (state.isInAttrRefScope()) {
return true;
}
((ClassAd) expr).getComponents(attrs, objectPool);
for (Entry<CaseInsensitiveString, ExprTree> entry : attrs.entrySet()) {
if (state.getDepthRemaining() <= 0) {
return false;
}
state.decrementDepth();
boolean ret = privateGetInternalReferences(entry.getValue(), ad, state, refs, fullNames);
state.incrementDepth();
if (!ret) {
return false;
}
}
return true;
}
case EXPR_LIST_NODE: {
ExprList exprs = objectPool.exprListPool.get();
((ExprList) expr).getComponents(exprs);
for (ExprTree exprTree : exprs.getExprList()) {
if (state.getDepthRemaining() <= 0) {
return false;
}
state.decrementDepth();
boolean ret = privateGetInternalReferences(exprTree, ad, state, refs, fullNames);
state.incrementDepth();
if (!ret) {
return false;
}
}
return true;
}
default:
return false;
}
}
public boolean publicFlatten(ExprTree tree, Value val, ExprTreeHolder fexpr) throws HyracksDataException {
EvalState state = objectPool.evalStatePool.get();
state.setScopes(this);
return (tree.publicFlatten(state, val, fexpr));
}
public boolean flattenAndInline(ExprTree tree, Value val, ExprTreeHolder fexpr) throws HyracksDataException {
EvalState state = objectPool.evalStatePool.get();
state.setScopes(this);
state.setFlattenAndInline(true);
return (tree.publicFlatten(state, val, fexpr));
}
public void chainToAd(ClassAd new_chain_parent_ad) {
if (new_chain_parent_ad != null) {
chainedParentAd = new_chain_parent_ad;
}
}
public int pruneChildAd() {
int iRet = 0;
if (chainedParentAd != null) {
// loop through cleaning all expressions which are the same.
Iterator<Entry<CaseInsensitiveString, ExprTree>> it = attrList.entrySet().iterator();
while (it.hasNext()) {
Entry<CaseInsensitiveString, ExprTree> entry = it.next();
ExprTree tree = chainedParentAd.lookup(entry.getKey());
if (tree != null && tree.sameAs(entry.getValue())) {
// 1st remove from dirty list
it.remove();
iRet++;
}
}
}
return iRet;
}
public ClassAd getChainedParentAd() {
return chainedParentAd;
}
public void setValue(ClassAd value) throws HyracksDataException {
copyFrom(value);
}
@Override
public int size() {
return attrList.size();
}
public static void valStr(AMutableCharArrayString szUnparsedValue, ExprTree pTree) {
szUnparsedValue.appendString(pTree.toString());
}
public static void valStr(AMutableCharArrayString szOut, boolean tValue) {
szOut.appendString(tValue ? "true" : "false");
}
@Override
public NodeKind getKind() {
return NodeKind.CLASSAD_NODE;
}
@Override
public boolean privateEvaluate(EvalState state, Value val) throws HyracksDataException {
val.setClassAdValue(this);
return (true);
}
public void insertAttr(String name, double value) throws HyracksDataException {
insertAttr(name, value, NumberFactor.NO_FACTOR);
}
public void createParser() {
parser = objectPool.classAdParserPool.get();
}
}