blob: 8e56bd988f65535be79f142f726fccbbe0f32fd3 [file] [log] [blame]
package org.apache.tapestry.engine;
import ognl.*;
import ognl.enhance.ExpressionAccessor;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.tapestry.ApplicationRuntimeException;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.enhance.IEnhancedClassFactory;
import org.apache.tapestry.enhance.javassist.OGNLExpressionCompiler;
import org.apache.tapestry.spec.IApplicationSpecification;
import java.beans.Introspector;
import java.util.Map;
/**
* @since 4.0
*/
public class ExpressionEvaluatorImpl implements ExpressionEvaluator {
private static final long POOL_MIN_IDLE_TIME = 1000 * 60 * 50;
private static final long POOL_SLEEP_TIME = 1000 * 60 * 4;
// Uses Thread's context class loader
private final ClassResolver _ognlResolver;
private ExpressionCache _expressionCache;
private IApplicationSpecification _applicationSpecification;
private TypeConverter _typeConverter;
// Context, with a root of null, used when evaluating an expression
// to see if it is a constant.
private Map _defaultContext;
private IEnhancedClassFactory _classFactory;
private GenericObjectPool _contextPool;
private final boolean _cachingDisabled = Boolean.getBoolean("org.apache.tapestry.disable-caching");
private final boolean _compileDisabled = Boolean.getBoolean("org.apache.tapestry.disable-expression-compile");
public ExpressionEvaluatorImpl(ClassResolver resolver, IEnhancedClassFactory classFactory,
ExpressionCache expressionCache, IApplicationSpecification spec)
{
_ognlResolver = resolver;
_classFactory = classFactory;
_expressionCache = expressionCache;
_applicationSpecification = spec;
initializeService();
}
void initializeService()
{
if (_applicationSpecification.checkExtension(Tapestry.OGNL_TYPE_CONVERTER))
_typeConverter = (TypeConverter) _applicationSpecification.getExtension(Tapestry.OGNL_TYPE_CONVERTER, TypeConverter.class);
_defaultContext = Ognl.createDefaultContext(null, _ognlResolver, _typeConverter);
OgnlRuntime.setCompiler(new OGNLExpressionCompiler(_classFactory));
_contextPool = new GenericObjectPool(new PoolableOgnlContextFactory(_ognlResolver, _typeConverter));
_contextPool.setMaxActive(-1);
_contextPool.setMaxIdle(-1);
_contextPool.setMinEvictableIdleTimeMillis(POOL_MIN_IDLE_TIME);
_contextPool.setTimeBetweenEvictionRunsMillis(POOL_SLEEP_TIME);
}
public Node parse(Object target, String expression)
{
Node node = (Node)_expressionCache.get(target, expression);
if (node == null)
{
try
{
node = (Node)Ognl.parseExpression(expression);
_expressionCache.cache(target, expression, node);
} catch (OgnlException ex)
{
throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex), target, null, ex);
}
}
return node;
}
public Object read(Object target, String expression)
{
Node node = parse(target, expression);
if (node.getAccessor() != null)
return read(target, node.getAccessor());
return readCompiled(target, node);
}
public Object readCompiled(Object target, Object expression)
{
OgnlContext context = null;
try
{
context = (OgnlContext)_contextPool.borrowObject();
context.setRoot(target);
return Ognl.getValue(expression, context, target);
}
catch (Exception ex)
{
throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex), target, null, ex);
} finally {
try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
}
}
public Object read(Object target, ExpressionAccessor expression)
{
OgnlContext context = null;
try
{
context = (OgnlContext)_contextPool.borrowObject();
return expression.get(context, target);
}
catch (Exception ex)
{
throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex), target, null, ex);
} finally {
try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
}
}
public void write(Object target, String expression, Object value)
{
writeCompiled(target, parse(target, expression), value);
}
public void write(Object target, ExpressionAccessor expression, Object value)
{
OgnlContext context = null;
try
{
context = (OgnlContext)_contextPool.borrowObject();
// set up context
context.setRoot(target);
expression.set(context, target, value);
}
catch (Exception ex)
{
throw new ApplicationRuntimeException(Tapestry.format("unable-to-write-expression",
new Object[] {expression, target, value, ex}),
target, null, ex);
} finally {
try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
}
}
public void writeCompiled(Object target, Object expression, Object value)
{
OgnlContext context = null;
try
{
context = (OgnlContext)_contextPool.borrowObject();
Ognl.setValue(expression, context, target, value);
}
catch (Exception ex)
{
throw new ApplicationRuntimeException(Tapestry.format("unable-to-write-expression",
new Object[] {expression, target, value, ex}),
target, null, ex);
} finally {
try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
}
}
public boolean isConstant(Object target, String expression)
{
Node node = parse(target, expression);
try
{
return Ognl.isConstant(node, _defaultContext);
}
catch (Exception ex)
{
throw new ApplicationRuntimeException(Tapestry.format("is-constant-expression-error", expression, ex), ex);
}
}
public boolean isCompileEnabled()
{
return !_cachingDisabled && !_compileDisabled;
}
public void compileExpression(Object target, Node node, String expression)
{
OgnlContext context = null;
try
{
context = (OgnlContext)_contextPool.borrowObject();
// set up context
context.setRoot(target);
OgnlRuntime.compileExpression(context, node, target);
_expressionCache.cache(target, expression, node);
} catch (Exception ex)
{
throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex), target, null, ex);
} finally {
try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
}
}
public void reset()
{
try
{
_contextPool.clear();
OgnlRuntime.clearCache();
Introspector.flushCaches();
} catch (Exception et) {
// ignore
}
}
}