| /* |
| * 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 org.apache.asterix.external.classad.object.pool.ClassAdObjectPool; |
| import org.apache.asterix.om.base.AMutableInt32; |
| import org.apache.commons.lang3.mutable.MutableBoolean; |
| import org.apache.hyracks.api.exceptions.HyracksDataException; |
| |
| public class AttributeReference extends ExprTree { |
| |
| private final ExprTreeHolder expr; |
| private boolean absolute; |
| private final AMutableCharArrayString attributeStr; |
| private final ExprList adList; |
| private final Value val; |
| private AttributeReference tempAttrRef; |
| private final EvalState tstate; |
| private MutableBoolean rVal = new MutableBoolean(false); |
| private ClassAd current; |
| |
| public ExprTree getExpr() { |
| return expr; |
| } |
| |
| public void setExpr(ExprTree expr) { |
| this.expr.setInnerTree(expr.self()); |
| } |
| |
| public AttributeReference(ClassAdObjectPool objectPool) { |
| super(objectPool); |
| this.val = new Value(objectPool); |
| this.current = new ClassAd(this.objectPool); |
| this.tstate = new EvalState(this.objectPool); |
| this.adList = new ExprList(this.objectPool); |
| this.attributeStr = new AMutableCharArrayString(); |
| this.expr = new ExprTreeHolder(objectPool); |
| absolute = false; |
| } |
| |
| /// Assignment operator |
| @Override |
| public boolean equals(Object o) { |
| if (o instanceof AttributeReference) { |
| AttributeReference ref = (AttributeReference) o; |
| return sameAs(ref); |
| } |
| return false; |
| } |
| |
| /// node type |
| @Override |
| public NodeKind getKind() { |
| return NodeKind.ATTRREF_NODE; |
| } |
| |
| public static AttributeReference createAttributeReference(ExprTree expr, AMutableCharArrayString attrName, |
| ClassAdObjectPool objectPool) { |
| return createAttributeReference(expr, attrName, false, objectPool); |
| } |
| |
| /** |
| * Return a copy of this attribute reference. |
| * |
| * @throws HyracksDataException |
| */ |
| @Override |
| public ExprTree copy() throws HyracksDataException { |
| AttributeReference newTree = objectPool.attrRefPool.get(); |
| newTree.copyFrom(this); |
| return newTree; |
| } |
| |
| /** |
| * Copy from the given reference into this reference. |
| * |
| * @param ref |
| * The reference to copy from. |
| * @return true if the copy succeeded, false otherwise. |
| * @throws HyracksDataException |
| */ |
| public boolean copyFrom(AttributeReference ref) throws HyracksDataException { |
| attributeStr.setValue(ref.attributeStr); |
| expr.setInnerTree(ref.expr); |
| super.copyFrom(ref); |
| this.absolute = ref.absolute; |
| return true; |
| } |
| |
| /** |
| * Is this attribute reference the same as another? |
| * |
| * @param tree |
| * The reference to compare with |
| * @return true if they are the same, false otherwise. |
| */ |
| @Override |
| public boolean sameAs(ExprTree tree) { |
| boolean is_same; |
| ExprTree pSelfTree = tree.self(); |
| if (this == pSelfTree) { |
| is_same = true; |
| } else if (pSelfTree.getKind() != NodeKind.ATTRREF_NODE) { |
| is_same = false; |
| } else { |
| AttributeReference other_ref = (AttributeReference) pSelfTree; |
| if (absolute != other_ref.absolute || !attributeStr.equals(other_ref.attributeStr)) { |
| is_same = false; |
| } else if ((expr == null && other_ref.expr == null) || (expr.equals(other_ref.expr)) |
| || (expr != null && other_ref.expr != null && expr.sameAs(other_ref.expr))) { |
| // Will this check result in infinite recursion? How do I stop it? |
| is_same = true; |
| } else { |
| is_same = false; |
| } |
| } |
| return is_same; |
| } |
| |
| @Override |
| public void privateSetParentScope(ClassAd parent) { |
| expr.setParentScope(parent); |
| } |
| |
| public void getComponents(ExprTreeHolder tree, AMutableCharArrayString attr, MutableBoolean abs) |
| throws HyracksDataException { |
| tree.copyFrom(expr); |
| attr.setValue(attributeStr); |
| abs.setValue(absolute); |
| } |
| |
| public EvalResult findExpr(EvalState state, ExprTreeHolder tree, ExprTreeHolder sig, boolean wantSig) |
| throws HyracksDataException { |
| // establish starting point for search |
| if (expr.getTree() == null) { |
| // "attr" and ".attr" |
| current = absolute ? state.getRootAd() : state.getCurAd(); |
| if (absolute && (current == null)) { // NAC - circularity so no root |
| return EvalResult.EVAL_FAIL; // NAC |
| } // NAC |
| } else { |
| // "expr.attr" |
| rVal.setValue(wantSig ? expr.publicEvaluate(state, val, sig) : expr.publicEvaluate(state, val)); |
| if (!rVal.booleanValue()) { |
| return (EvalResult.EVAL_FAIL); |
| } |
| |
| if (val.isUndefinedValue()) { |
| return (EvalResult.EVAL_UNDEF); |
| } else if (val.isErrorValue()) { |
| return (EvalResult.EVAL_ERROR); |
| } |
| |
| if (!val.isClassAdValue(current) && !val.isListValue(adList)) { |
| return (EvalResult.EVAL_ERROR); |
| } |
| } |
| |
| if (val.isListValue()) { |
| ExprList eList = objectPool.exprListPool.get(); |
| // |
| // iterate through exprList and apply attribute reference |
| // to each exprTree |
| for (ExprTree currExpr : adList.getExprList()) { |
| if (currExpr == null) { |
| return (EvalResult.EVAL_FAIL); |
| } else { |
| if (tempAttrRef == null) { |
| tempAttrRef = objectPool.attrRefPool.get(); |
| } else { |
| tempAttrRef.reset(); |
| } |
| createAttributeReference(currExpr.copy(), attributeStr, false, tempAttrRef); |
| val.setUndefinedValue(); |
| // Create new EvalState, within this scope, because |
| // attrRef is only temporary, so we do not want to |
| // cache the evaluated result in the outer state object. |
| tstate.reset(); |
| tstate.setScopes(state.getCurAd()); |
| rVal.setValue(wantSig ? tempAttrRef.publicEvaluate(tstate, val, sig) |
| : tempAttrRef.publicEvaluate(tstate, val)); |
| if (!rVal.booleanValue()) { |
| return (EvalResult.EVAL_FAIL); |
| } |
| |
| ClassAd evaledAd = objectPool.classAdPool.get(); |
| ExprList evaledList = objectPool.exprListPool.get(); |
| if (val.isClassAdValue(evaledAd)) { |
| eList.add(evaledAd); |
| continue; |
| } else if (val.isListValue(evaledList)) { |
| eList.add(evaledList.copy()); |
| continue; |
| } else { |
| eList.add(Literal.createLiteral(val, objectPool)); |
| } |
| } |
| } |
| |
| tree.setInnerTree(ExprList.createExprList(eList, objectPool)); |
| ClassAd newRoot = objectPool.classAdPool.get(); |
| tree.setParentScope(newRoot); |
| return EvalResult.EVAL_OK; |
| } |
| // lookup with scope; this may side-affect state |
| |
| /* ClassAd::alternateScope is intended for transitioning Condor from |
| * old to new ClassAds. It allows unscoped attribute references |
| * in expressions that can't be found in the local scope to be |
| * looked for in an alternate scope. In Condor, the alternate |
| * scope is the Target ad in matchmaking. |
| * Expect alternateScope to be removed from a future release. |
| */ |
| if (current == null) { |
| return EvalResult.EVAL_UNDEF; |
| } |
| int rc = 0; |
| try { |
| rc = current.lookupInScope(attributeStr.toString(), tree, state); |
| } catch (Throwable th) { |
| th.printStackTrace(); |
| throw th; |
| } |
| if (expr.getTree() == null && !absolute && rc == EvalResult.EVAL_UNDEF.ordinal() |
| && current.getAlternateScope() != null) { |
| rc = current.getAlternateScope().lookupInScope(attributeStr.toString(), tree, state); |
| } |
| return EvalResult.values()[rc]; |
| } |
| |
| @Override |
| public boolean publicEvaluate(EvalState state, Value val) throws HyracksDataException { |
| ExprTreeHolder tree = objectPool.mutableExprPool.get(); |
| ExprTreeHolder dummy = objectPool.mutableExprPool.get(); |
| ClassAd curAd = objectPool.classAdPool.get(); |
| curAd.copyFrom(state.getCurAd()); |
| boolean rval; |
| // find the expression and the evalstate |
| switch (findExpr(state, tree, dummy, false)) { |
| case EVAL_FAIL: |
| return false; |
| case EVAL_ERROR: |
| val.setErrorValue(); |
| state.setCurAd(curAd); |
| return true; |
| case EVAL_UNDEF: |
| val.setUndefinedValue(); |
| state.setCurAd(curAd); |
| return true; |
| case EVAL_OK: { |
| if (state.getDepthRemaining() <= 0) { |
| val.setErrorValue(); |
| state.setCurAd(curAd); |
| return false; |
| } |
| state.decrementDepth(); |
| rval = tree.publicEvaluate(state, val); |
| state.incrementDepth(); |
| state.getCurAd().setValue(curAd); |
| return rval; |
| } |
| default: |
| throw new HyracksDataException("ClassAd: Should not reach here"); |
| } |
| } |
| |
| @Override |
| public boolean privateEvaluate(EvalState state, Value val, ExprTreeHolder sig) throws HyracksDataException { |
| ExprTreeHolder tree = objectPool.mutableExprPool.get(); |
| ExprTreeHolder exprSig = objectPool.mutableExprPool.get(); |
| ClassAd curAd = objectPool.classAdPool.get(); |
| curAd.copyFrom(state.getCurAd()); |
| MutableBoolean rval = objectPool.boolPool.get(); |
| rval.setValue(true); |
| |
| switch (findExpr(state, tree, exprSig, true)) { |
| case EVAL_FAIL: |
| rval.setValue(false); |
| break; |
| case EVAL_ERROR: |
| val.setErrorValue(); |
| break; |
| case EVAL_UNDEF: |
| val.setUndefinedValue(); |
| break; |
| case EVAL_OK: { |
| if (state.getDepthRemaining() <= 0) { |
| val.setErrorValue(); |
| state.getCurAd().setValue(curAd); |
| return false; |
| } |
| state.decrementDepth(); |
| rval.setValue(tree.publicEvaluate(state, val)); |
| state.incrementDepth(); |
| break; |
| } |
| default: |
| throw new HyracksDataException("ClassAd: Should not reach here"); |
| } |
| AttributeReference newAttrRef = objectPool.attrRefPool.get(); |
| newAttrRef.setValue(exprSig, attributeStr, absolute); |
| sig.setInnerTree(newAttrRef); |
| state.getCurAd().setValue(curAd); |
| return rval.booleanValue(); |
| } |
| |
| @Override |
| public boolean privateFlatten(EvalState state, Value val, ExprTreeHolder ntree, AMutableInt32 op) |
| throws HyracksDataException { |
| ExprTreeHolder tree = objectPool.mutableExprPool.get(); |
| ExprTreeHolder dummy = objectPool.mutableExprPool.get(); |
| ClassAd curAd; |
| boolean rval; |
| ntree.setInnerTree(null); // Just to be safe... wenger 2003-12-11. |
| // find the expression and the evalstate |
| curAd = state.getCurAd(); |
| switch (findExpr(state, tree, dummy, false)) { |
| case EVAL_FAIL: |
| return false; |
| case EVAL_ERROR: |
| val.setErrorValue(); |
| state.getCurAd().setValue(curAd); |
| return true; |
| case EVAL_UNDEF: |
| if (expr != null && state.isFlattenAndInline()) { |
| ExprTreeHolder expr_ntree = objectPool.mutableExprPool.get(); |
| Value expr_val = objectPool.valuePool.get(); |
| if (state.getDepthRemaining() <= 0) { |
| val.setErrorValue(); |
| state.getCurAd().setValue(curAd); |
| return false; |
| } |
| state.decrementDepth(); |
| rval = expr.publicFlatten(state, expr_val, expr_ntree); |
| state.incrementDepth(); |
| if (rval && expr_ntree.getInnerTree() != null) { |
| ntree.setInnerTree(createAttributeReference(expr_ntree, attributeStr, objectPool)); |
| if (ntree.getInnerTree() != null) { |
| state.getCurAd().setValue(curAd); |
| return true; |
| } |
| } |
| } |
| ntree.setInnerTree(copy()); |
| state.getCurAd().setValue(curAd); |
| return true; |
| case EVAL_OK: { |
| // Don't flatten or inline a classad that's referred to |
| // by an attribute. |
| if (tree.getKind() == NodeKind.CLASSAD_NODE) { |
| ntree.setInnerTree(copy()); |
| val.setUndefinedValue(); |
| return true; |
| } |
| |
| if (state.getDepthRemaining() <= 0) { |
| val.setErrorValue(); |
| state.getCurAd().setValue(curAd); |
| return false; |
| } |
| state.decrementDepth(); |
| |
| rval = tree.publicFlatten(state, val, ntree); |
| state.incrementDepth(); |
| |
| // don't inline if it didn't flatten to a value, and clear cache |
| // do inline if FlattenAndInline was called |
| if (ntree.getInnerTree() != null) { |
| if (state.isFlattenAndInline()) { // NAC |
| return true; // NAC |
| } // NAC |
| ntree.setInnerTree(copy()); |
| val.setUndefinedValue(); |
| } |
| |
| state.getCurAd().setValue(curAd); |
| return rval; |
| } |
| default: |
| throw new HyracksDataException("ClassAd: Should not reach here"); |
| } |
| } |
| |
| /** |
| * Factory method to create attribute reference nodes. |
| * |
| * @param expr |
| * The expression part of the reference (i.e., in |
| * case of expr.attr). This parameter is NULL if the reference |
| * is absolute (i.e., .attr) or simple (i.e., attr). |
| * @param attrName |
| * The name of the reference. This string is |
| * duplicated internally. |
| * @param absolute |
| * True if the reference is an absolute reference |
| * (i.e., in case of .attr). This parameter cannot be true if |
| * expr is not NULL, default value is false; |
| */ |
| public static AttributeReference createAttributeReference(ExprTree tree, AMutableCharArrayString attrStr, |
| boolean absolut, ClassAdObjectPool objectPool) { |
| AttributeReference attrRef = objectPool.attrRefPool.get(); |
| attrRef.setValue(tree, attrStr, absolut); |
| return attrRef; |
| } |
| |
| public void setValue(ExprTree tree, AMutableCharArrayString attrStr, boolean absolut) { |
| this.absolute = absolut; |
| this.attributeStr.copyValue(attrStr.getValue(), attrStr.size()); |
| this.expr.setInnerTree(tree == null ? null : tree.self()); |
| } |
| |
| public static void createAttributeReference(ExprTree tree, AMutableCharArrayString attrStr, boolean absolut, |
| AttributeReference ref) { |
| ref.setValue(tree, attrStr, absolut); |
| } |
| |
| @Override |
| public boolean privateEvaluate(EvalState state, Value val) throws HyracksDataException { |
| ExprTreeHolder tree = objectPool.mutableExprPool.get(); |
| ExprTreeHolder dummy = objectPool.mutableExprPool.get(); |
| ClassAd curAd; |
| boolean rval; |
| |
| // find the expression and the evalstate |
| curAd = state.getCurAd(); |
| switch (findExpr(state, tree, dummy, false)) { |
| case EVAL_FAIL: |
| return false; |
| case EVAL_ERROR: |
| val.setErrorValue(); |
| state.getCurAd().setValue(curAd); |
| return true; |
| case EVAL_UNDEF: |
| val.setUndefinedValue(); |
| state.getCurAd().setValue(curAd); |
| return true; |
| |
| case EVAL_OK: { |
| if (state.getDepthRemaining() <= 0) { |
| val.setErrorValue(); |
| state.getCurAd().setValue(curAd); |
| return false; |
| } |
| state.decrementDepth(); |
| rval = tree.publicEvaluate(state, val); |
| state.incrementDepth(); |
| state.getCurAd().setValue(curAd); |
| return rval; |
| } |
| default: |
| throw new HyracksDataException("ClassAd: Should not reach here"); |
| } |
| } |
| |
| @Override |
| public void reset() { |
| expr.reset(); |
| val.reset(); |
| current.reset(); |
| tstate.reset(); |
| adList.reset(); |
| attributeStr.reset(); |
| absolute = false; |
| } |
| } |