blob: 785f5fbfaca8515762ceb59a6eb7f359c8865fb6 [file] [log] [blame]
// Copyright 2008 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.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
}
}
}