//--------------------------------------------------------------------------
// Copyright (c) 1998-2004, Drew Davidson and Luke Blanshard
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// Neither the name of the Drew Davidson nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
//--------------------------------------------------------------------------
package ariba.util.expr;
import java.util.*;
import ariba.util.fieldtype.TypeInfo;
/**
* This class defines the execution context for an AribaExpr expression
* @author Luke Blanshard (blanshlu@netscape.net)
* @author Drew Davidson (drew@ognl.org)
*/
public class ExprContext extends Object implements Map
{
//--------------------------------------------------------------------------
// constants
public static final String CONTEXT_CONTEXT_KEY = "context";
public static final String ROOT_CONTEXT_KEY = "this";
public static final String THIS_CONTEXT_KEY = "it";
public static final String LOGIN_USER_CONTEXT_KEY = "loginUser";
public static final String TRACE_EVALUATIONS_CONTEXT_KEY = "_traceEvaluations";
public static final String LAST_EVALUATION_CONTEXT_KEY = "_lastEvaluation";
public static final String KEEP_LAST_EVALUATION_CONTEXT_KEY = "_keepLastEvaluation";
public static final String CLASS_RESOLVER_CONTEXT_KEY = "_classResolver";
public static final String TYPE_CONVERTER_CONTEXT_KEY = "_typeConverter";
public static final String MEMBER_ACCESS_CONTEXT_KEY = "_memberAccess";
private static final String PROPERTY_KEY_PREFIX = "aribaExpr";
private static boolean DEFAULT_TRACE_EVALUATIONS = false;
private static boolean DEFAULT_KEEP_LAST_EVALUATION = false;
public static final ClassResolver DEFAULT_CLASS_RESOLVER = new DefaultClassResolver();
public static final TypeConverter DEFAULT_TYPE_CONVERTER = new DefaultTypeConverter();
public static final MemberAccess DEFAULT_MEMBER_ACCESS = new DefaultMemberAccess(false);
//--------------------------------------------------------------------------
// nested class
/**
@aribaapi ariba
*/
public static interface ExtensibleContext
{
/**
@aribaapi ariba
*/
public String getLoginUserTypeName ();
/**
@aribaapi ariba
*/
public Object getLoginUser ();
}
//--------------------------------------------------------------------------
// public static methods
/**
@aribaapi ariba
*/
public static ExtensibleContext getExtensibleContext ()
{
return EXTENSIBLE_CONTEXT;
}
/**
@aribaapi ariba
*/
public static void setExtensibleContext (ExtensibleContext context)
{
EXTENSIBLE_CONTEXT = context;
}
//--------------------------------------------------------------------------
// data members
private static Map RESERVED_KEYS = new HashMap(11);
private static ExtensibleContext EXTENSIBLE_CONTEXT = null;
private Object root;
private Object currentObject;
private Node currentNode;
private boolean traceEvaluations = DEFAULT_TRACE_EVALUATIONS;
private Evaluation rootEvaluation;
private Evaluation currentEvaluation;
private Evaluation lastEvaluation;
private boolean keepLastEvaluation = DEFAULT_KEEP_LAST_EVALUATION;
private Map values = new HashMap(23);
private ClassResolver classResolver = DEFAULT_CLASS_RESOLVER;
private TypeConverter typeConverter = DEFAULT_TYPE_CONVERTER;
private MemberAccess memberAccess = DEFAULT_MEMBER_ACCESS;
private SymbolTable symbolTable;
static
{
String s;
RESERVED_KEYS.put(CONTEXT_CONTEXT_KEY, null);
RESERVED_KEYS.put(ROOT_CONTEXT_KEY, null);
RESERVED_KEYS.put(THIS_CONTEXT_KEY, null);
RESERVED_KEYS.put(TRACE_EVALUATIONS_CONTEXT_KEY, null);
RESERVED_KEYS.put(LAST_EVALUATION_CONTEXT_KEY, null);
RESERVED_KEYS.put(KEEP_LAST_EVALUATION_CONTEXT_KEY, null);
RESERVED_KEYS.put(CLASS_RESOLVER_CONTEXT_KEY, null);
RESERVED_KEYS.put(TYPE_CONVERTER_CONTEXT_KEY, null);
RESERVED_KEYS.put(MEMBER_ACCESS_CONTEXT_KEY, null);
try {
if ((s = System.getProperty(PROPERTY_KEY_PREFIX + ".traceEvaluations")) != null) {
DEFAULT_TRACE_EVALUATIONS = Boolean.valueOf(s.trim()).booleanValue();
}
if ((s = System.getProperty(PROPERTY_KEY_PREFIX + ".keepLastEvaluation")) != null) {
DEFAULT_KEEP_LAST_EVALUATION = Boolean.valueOf(s.trim()).booleanValue();
}
} catch (SecurityException ex) {
// restricted access environment, just keep defaults
}
}
/**
Constructs a new ExprContext with the default class resolver, type converter and
member access.
*/
public ExprContext()
{
super();
}
/**
Constructs a new ExprContext with the given class resolver, type converter and
member access. If any of these parameters is null the default will be used.
*/
public ExprContext(ClassResolver classResolver, TypeConverter typeConverter, MemberAccess memberAccess)
{
this();
if (classResolver != null) {
this.classResolver = classResolver;
}
if (typeConverter != null) {
this.typeConverter = typeConverter;
}
if (memberAccess != null) {
this.memberAccess = memberAccess;
}
}
public ExprContext(Map values)
{
super();
this.values = values;
}
public ExprContext (
ClassResolver classResolver,
TypeConverter typeConverter,
MemberAccess memberAccess,
Map values
)
{
this(classResolver, typeConverter, memberAccess);
this.values = values;
}
public ExprContext (SymbolTable symbolTable)
{
this();
this.symbolTable = symbolTable;
}
public void setValues (Map value)
{
for (Iterator it = value.keySet().iterator(); it.hasNext();) {
Object k = it.next();
values.put(k, value.get(k));
}
}
public Map getValues ()
{
return values;
}
public void setClassResolver (ClassResolver value)
{
if (value == null) {
throw new IllegalArgumentException("cannot set ClassResolver to null");
}
classResolver = value;
}
public ClassResolver getClassResolver ()
{
return classResolver;
}
public void setTypeConverter (TypeConverter value)
{
if (value == null) {
throw new IllegalArgumentException("cannot set TypeConverter to null");
}
typeConverter = value;
}
public TypeConverter getTypeConverter ()
{
return typeConverter;
}
public void setMemberAccess (MemberAccess value)
{
if (value == null) {
throw new IllegalArgumentException("cannot set MemberAccess to null");
}
memberAccess = value;
}
public MemberAccess getMemberAccess ()
{
return memberAccess;
}
public SymbolTable getSymbolTable ()
{
return symbolTable;
}
public void setRoot (Object value)
{
root = value;
}
public Object getRoot ()
{
return root;
}
public boolean getTraceEvaluations ()
{
return traceEvaluations;
}
public void setTraceEvaluations (boolean value)
{
traceEvaluations = value;
}
public Evaluation getLastEvaluation ()
{
return lastEvaluation;
}
public void setLastEvaluation (Evaluation value)
{
lastEvaluation = value;
}
/**
This method can be called when the last evaluation has been used
and can be returned for reuse in the free pool maintained by the
runtime. This is not a necessary step, but is useful for keeping
memory usage down. This will recycle the last evaluation and then
set the last evaluation to null.
*/
public void recycleLastEvaluation ()
{
ExprRuntime.getEvaluationPool().recycleAll(lastEvaluation);
lastEvaluation = null;
}
/**
Returns true if the last evaluation that was done on this
context is retained and available through <code>getLastEvaluation()</code>.
The default is true.
*/
public boolean getKeepLastEvaluation ()
{
return keepLastEvaluation;
}
/**
Sets whether the last evaluation that was done on this
context is retained and available through <code>getLastEvaluation()</code>.
The default is true.
*/
public void setKeepLastEvaluation (boolean value)
{
keepLastEvaluation = value;
}
public void setCurrentObject (Object value)
{
currentObject = value;
}
public Object getCurrentObject ()
{
return currentObject;
}
public void setCurrentNode (Node value)
{
currentNode = value;
}
public Node getCurrentNode ()
{
return currentNode;
}
/**
Gets the current Evaluation from the top of the stack.
This is the Evaluation that is in process of evaluating.
*/
public Evaluation getCurrentEvaluation ()
{
return currentEvaluation;
}
public void setCurrentEvaluation (Evaluation value)
{
currentEvaluation = value;
}
/**
Gets the root of the evaluation stack.
This Evaluation contains the node representing
the root expression and the source is the root
source object.
*/
public Evaluation getRootEvaluation ()
{
return rootEvaluation;
}
public void setRootEvaluation (Evaluation value)
{
rootEvaluation = value;
}
/**
Returns the Evaluation at the relative index given. This should be
zero or a negative number as a relative reference back up the evaluation
stack. Therefore getEvaluation(0) returns the current Evaluation.
*/
public Evaluation getEvaluation (int relativeIndex)
{
Evaluation result = null;
if (relativeIndex <= 0) {
result = currentEvaluation;
while ((++relativeIndex < 0) && (result != null)) {
result = result.getParent();
}
}
return result;
}
/**
Pushes a new Evaluation onto the stack. This is done
before a node evaluates. When evaluation is complete
it should be popped from the stack via <code>popEvaluation()</code>.
*/
public void pushEvaluation (Evaluation value)
{
if (currentEvaluation != null) {
currentEvaluation.addChild(value);
} else {
setRootEvaluation(value);
}
setCurrentEvaluation(value);
}
/**
Pops the current Evaluation off of the top of the stack.
This is done after a node has completed its evaluation.
*/
public Evaluation popEvaluation ()
{
Evaluation result;
result = currentEvaluation;
setCurrentEvaluation(result.getParent());
if (currentEvaluation == null) {
setLastEvaluation(getKeepLastEvaluation() ? result : null);
setRootEvaluation(null);
setCurrentNode(null);
}
return result;
}
/*================= Map interface =================*/
public int size ()
{
return values.size();
}
public boolean isEmpty ()
{
return values.isEmpty();
}
public boolean containsKey (Object key)
{
return values.containsKey(key);
}
public boolean containsValue (Object value)
{
return values.containsValue(value);
}
public Object get (Object key)
{
if (RESERVED_KEYS.containsKey(key)) {
if (key.equals(ExprContext.THIS_CONTEXT_KEY)) {
return getCurrentObject();
}
if (key.equals(ExprContext.ROOT_CONTEXT_KEY)) {
return getRoot();
}
if (key.equals(ExprContext.CONTEXT_CONTEXT_KEY)) {
return this;
}
if (key.equals(ExprContext.TRACE_EVALUATIONS_CONTEXT_KEY)) {
return getTraceEvaluations() ? Boolean.TRUE : Boolean.FALSE;
}
if (key.equals(ExprContext.LAST_EVALUATION_CONTEXT_KEY)) {
return getLastEvaluation();
}
if (key.equals(ExprContext.KEEP_LAST_EVALUATION_CONTEXT_KEY)) {
return getKeepLastEvaluation() ? Boolean.TRUE : Boolean.FALSE;
}
if (key.equals(ExprContext.CLASS_RESOLVER_CONTEXT_KEY)) {
return getClassResolver();
}
if (key.equals(ExprContext.TYPE_CONVERTER_CONTEXT_KEY)) {
return getTypeConverter();
}
if (key.equals(ExprContext.MEMBER_ACCESS_CONTEXT_KEY)) {
return getMemberAccess();
}
if (key.equals(ExprContext.LOGIN_USER_CONTEXT_KEY)) {
return getMemberAccess();
}
throw new IllegalArgumentException("unknown reserved key '" + key + "'");
}
return values.get(key);
}
public Object put (Object key, Object value)
{
Object result;
if (RESERVED_KEYS.containsKey(key)) {
if (key.equals(ExprContext.THIS_CONTEXT_KEY)) {
result = getCurrentObject();
setCurrentObject(value);
}
else if (key.equals(ExprContext.ROOT_CONTEXT_KEY)) {
result = getRoot();
setRoot(value);
}
else if (key.equals(ExprContext.CONTEXT_CONTEXT_KEY)) {
throw new IllegalArgumentException("can't change " +
ExprContext.CONTEXT_CONTEXT_KEY +
" in context");
}
else if (key.equals(ExprContext.TRACE_EVALUATIONS_CONTEXT_KEY)) {
result = getTraceEvaluations() ? Boolean.TRUE : Boolean.FALSE;
setTraceEvaluations(ExprOps.booleanValue(value));
}
else if (key.equals(ExprContext.LAST_EVALUATION_CONTEXT_KEY)) {
result = getLastEvaluation();
lastEvaluation = (Evaluation)value;
}
else if (key.equals(ExprContext.KEEP_LAST_EVALUATION_CONTEXT_KEY)) {
result = getKeepLastEvaluation() ? Boolean.TRUE : Boolean.FALSE;
setKeepLastEvaluation(ExprOps.booleanValue(value));
}
else if (key.equals(ExprContext.CLASS_RESOLVER_CONTEXT_KEY)) {
result = getClassResolver();
setClassResolver((ClassResolver)value);
}
else if (key.equals(ExprContext.TYPE_CONVERTER_CONTEXT_KEY)) {
result = getTypeConverter();
setTypeConverter((TypeConverter)value);
}
else if (key.equals(ExprContext.MEMBER_ACCESS_CONTEXT_KEY)) {
result = getMemberAccess();
setMemberAccess((MemberAccess)value);
}
else if (key.equals(ExprContext.LOGIN_USER_CONTEXT_KEY)) {
throw new IllegalArgumentException("can't change " +
ExprContext.LOGIN_USER_CONTEXT_KEY +
" in context");
}
else {
throw new IllegalArgumentException("unknown reserved key '" + key + "'");
}
} else {
result = values.put(key, value);
}
return result;
}
public Object remove (Object key)
{
Object result;
if (RESERVED_KEYS.containsKey(key)) {
if (key.equals(ExprContext.THIS_CONTEXT_KEY)) {
result = getCurrentObject();
setCurrentObject(null);
}
else if (key.equals(ExprContext.ROOT_CONTEXT_KEY)) {
result = getRoot();
setRoot(null);
}
else if (key.equals(ExprContext.CONTEXT_CONTEXT_KEY)) {
throw new IllegalArgumentException("can't remove " +
ExprContext.CONTEXT_CONTEXT_KEY +
" from context");
}
else if (key.equals(ExprContext.TRACE_EVALUATIONS_CONTEXT_KEY)) {
throw new IllegalArgumentException("can't remove " +
ExprContext.TRACE_EVALUATIONS_CONTEXT_KEY +
" from context");
}
else if (key.equals(ExprContext.LAST_EVALUATION_CONTEXT_KEY)) {
result = lastEvaluation;
setLastEvaluation(null);
}
else if (key.equals(ExprContext.KEEP_LAST_EVALUATION_CONTEXT_KEY)) {
throw new IllegalArgumentException("can't remove " +
ExprContext.KEEP_LAST_EVALUATION_CONTEXT_KEY +
" from context");
}
else if (key.equals(ExprContext.CLASS_RESOLVER_CONTEXT_KEY)) {
result = getClassResolver();
setClassResolver(null);
}
else if (key.equals(ExprContext.TYPE_CONVERTER_CONTEXT_KEY)) {
result = getTypeConverter();
setTypeConverter(null);
}
else if (key.equals(ExprContext.MEMBER_ACCESS_CONTEXT_KEY)) {
result = getMemberAccess();
setMemberAccess(null);
}
else if (key.equals(ExprContext.LOGIN_USER_CONTEXT_KEY)) {
throw new IllegalArgumentException("can't remove " +
ExprContext.LOGIN_USER_CONTEXT_KEY +
" from context");
}
else {
throw new IllegalArgumentException("unknown reserved key '" + key + "'");
}
} else {
result = values.remove(key);
}
return result;
}
public void putAll (Map t)
{
for (Iterator it = t.keySet().iterator(); it.hasNext();) {
Object k = it.next();
put(k, t.get(k));
}
}
public void clear ()
{
values.clear();
setRoot(null);
setCurrentObject(null);
setRootEvaluation(null);
setCurrentEvaluation(null);
setLastEvaluation(null);
setCurrentNode(null);
setClassResolver(DEFAULT_CLASS_RESOLVER);
setTypeConverter(DEFAULT_TYPE_CONVERTER);
setMemberAccess(DEFAULT_MEMBER_ACCESS);
}
public Set keySet ()
{
/* Should root, currentObject, classResolver, typeConverter & memberAccess be included here? */
return values.keySet();
}
public Collection values ()
{
/* Should root, currentObject, classResolver, typeConverter & memberAccess be included here? */
return values.values();
}
public Set entrySet ()
{
/* Should root, currentObject, classResolver, typeConverter & memberAccess be included here? */
return values.entrySet();
}
public boolean equals (Object o)
{
return values.equals(o);
}
public int hashCode ()
{
return values.hashCode();
}
public Integer getSymbolKind (Symbol symbol)
{
Integer symbolKind = null;
SymbolTable symbolTable = getSymbolTable();
if (symbolTable != null) {
SemanticRecord record = symbolTable.getSymbolRecord(symbol);
if (record != null) {
symbolKind = record.getSymbolKind();
}
}
return symbolKind;
}
public TypeInfo getSymbolType (Symbol symbol)
{
TypeInfo type = null;
SymbolTable symbolTable = getSymbolTable();
if (symbolTable != null) {
SemanticRecord record = symbolTable.getSymbolRecord(symbol);
if (record != null) {
type = record.getTypeInfo();
}
}
return type;
}
/**
@aribaapi ariba
*/
public static String getLoginUserTypeName ()
{
return EXTENSIBLE_CONTEXT != null
? EXTENSIBLE_CONTEXT.getLoginUserTypeName() : null;
}
/**
@aribaapi ariba
*/
public static Object getLoginUser ()
{
return EXTENSIBLE_CONTEXT != null ? EXTENSIBLE_CONTEXT.getLoginUser() : null;
}
}