blob: 6b0ef583b4bf34f37ec543b0cb9aabfacba725d0 [file] [log] [blame]
/*
* Copyright 2005 The Apache Software Foundation
*
* Licensed 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.osgi.framework.util.ldap;
import java.util.Stack;
import java.util.Vector;
public class Evaluator {
Object[] program = null;
Stack operands = new Stack();
Mapper mapper = null;
public Evaluator()
{
reset();
}
public Evaluator(Object[] prog)
{
reset(prog);
}
public void reset()
{
program = null;
mapper = null;
operands.clear();
}
public void reset(Object[] prog)
{
reset();
setProgram(prog);
}
public void setProgram(Object[] prog)
{
program = prog;
}
public void setMapper(Mapper mapper)
{
this.mapper = mapper;
}
public Stack getOperands()
{
return operands;
}
public boolean evaluate(Mapper mapper) throws EvaluationException
{
try
{
// The following code is a little complicated because it
// is trying to deal with evaluating a given filter expression
// when it contains an attribute that does not exist in the
// supplied mapper. In such a situation the code below
// catches the "attribute not found" exception and inserts
// an instance of Unknown, which is used as a marker for
// non-existent attributes. The Unknown instance forces the
// operator to throw an "unsupported type" exception, which
// the code below converts into a FALSE and this has the effect
// of evaluating the subexpression that contained the
// non-existent attribute to FALSE. The rest of the filter
// expression evaluates normally. Any other exceptions are
// rethrown.
setMapper(mapper);
for (int i = 0; i < program.length; i++)
{
try
{
Operator op = (Operator) program[i];
op.execute(operands, mapper);
// printAction(op); // for debug output
}
catch (AttributeNotFoundException ex)
{
operands.push(new Unknown());
}
catch (EvaluationException ex)
{
// If the exception is for an unsupported type of
// type Unknown, then just push FALSE onto the
// operand stack because this type will only appear
// if an attribute was not found.
if (ex.isUnsupportedType() &&
(ex.getUnsupportedType() == Unknown.class))
{
operands.push(Boolean.FALSE);
}
// Otherwise, rethrow the exception.
else
{
throw ex;
}
}
}
if (operands.empty())
{
throw new EvaluationException(
"Evaluation.evalute: final stack is empty");
}
Object result = operands.pop();
if (!operands.empty())
{
throw new EvaluationException(
"Evaluation.evalute: final stack has more than one result");
}
if (!(result instanceof Boolean))
{
throw new EvaluationException(
"Evaluation.evalute: final result is not Boolean");
}
return ((Boolean) result).booleanValue();
}
finally
{
// Clear the operands just in case an exception was thrown,
// otherwise stuff will be left in the stack.
operands.clear();
}
}
// For debugging; Dump the operator and stack
void printAction(Operator op)
{
System.err.println("Operator:"+op.toString());
System.err.print("Stack After:");
// recast operands as Vector to make interior access easier
Vector v = operands;
int len = v.size();
for (int i = 0; i < len; i++)
System.err.print(" " + v.elementAt(i));
System.err.println();
}
public String toString()
{
StringBuffer buf = new StringBuffer();
for (int i = 0; i < program.length; i++)
{
buf.append((i==0) ? "{" : ";");
buf.append(((Operator) program[i]).toString());
}
buf.append("}");
return buf.toString();
}
public String toStringInfix()
{
// First, we "evaluate" the program
// but for the purpose of re-constructing
// a parsetree.
operands.clear();
for (int i = 0; i < program.length; i++)
{
((Operator) program[i]).buildTree(operands);
}
StringBuffer b = new StringBuffer();
Object result = operands.pop();
((Operator)result).toStringInfix(b);
operands.clear();
return b.toString();
}
}