blob: e45c0b7506b8f4a829fed5afaff4adec726d7881 [file] [log] [blame]
// Copyright 2004, 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.tapestry.services.impl;
import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
import ognl.ClassCacheInspector;
import ognl.Node;
import ognl.Ognl;
import ognl.OgnlRuntime;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.tapestry.AbstractComponent;
import org.apache.tapestry.event.ReportStatusEvent;
import org.apache.tapestry.event.ReportStatusListener;
import org.apache.tapestry.event.ResetEventListener;
import org.apache.tapestry.services.ExpressionCache;
import org.apache.tapestry.services.ExpressionEvaluator;
import java.beans.Introspector;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
/**
* @author Howard M. Lewis Ship
* @since 4.0
*/
public class ExpressionCacheImpl implements ExpressionCache, ResetEventListener, ReportStatusListener, ClassCacheInspector {
private final ReentrantLock _lock = new ReentrantLock();
private String _serviceId;
private Map _cache = new WeakHashMap();
private Map _objectCache = new WeakHashMap();
private ExpressionEvaluator _evaluator;
private final boolean _cachingDisabled = Boolean.getBoolean("org.apache.tapestry.disable-caching");
public void initializeService()
{
if (_cachingDisabled)
{
OgnlRuntime.setClassCacheInspector(this);
}
}
public void resetEventDidOccur()
{
try {
_lock.lock();
_cache.clear();
_objectCache.clear();
Introspector.flushCaches();
} finally {
_lock.unlock();
}
}
public boolean shouldCache(Class type)
{
if (!_cachingDisabled || type == null
|| AbstractComponent.class.isAssignableFrom(type))
return false;
return true;
}
public void reportStatus(ReportStatusEvent event)
{
event.title(_serviceId);
event.property("cached expression count", _cache.size());
event.collection("cached expressions", _cache.keySet());
event.property("cached object expression count", _objectCache.size());
}
public Object getCompiledExpression(Object target, String expression)
{
try {
_lock.lock();
Map cached = (Map)_objectCache.get(target.getClass());
if (cached == null)
{
cached = new HashMap();
_objectCache.put(target.getClass(), cached);
}
Node result = (Node)cached.get(expression);
if (result == null || result.getAccessor() == null)
{
result = parse(target, expression);
cached.put(expression, result);
}
return result;
} finally {
_lock.unlock();
}
}
public Object getCompiledExpression(String expression)
{
try {
_lock.lock();
Object result = _cache.get(expression);
if (result == null)
{
result = parse(expression);
_cache.put(expression, result);
}
return result;
} finally {
_lock.unlock();
}
}
private Node parse(Object target, String expression)
{
try
{
return Ognl.compileExpression(_evaluator.createContext(target), target, expression);
}
catch (Exception ex)
{
throw new ApplicationRuntimeException(ImplMessages.unableToParseExpression(expression,ex), ex);
}
}
private Object parse(String expression)
{
try
{
return Ognl.parseExpression(expression);
}
catch (Exception ex)
{
throw new ApplicationRuntimeException(ImplMessages.unableToParseExpression(expression, ex), ex);
}
}
public void setServiceId(String serviceId)
{
_serviceId = serviceId;
}
public void setEvaluator(ExpressionEvaluator evaluator)
{
_evaluator = evaluator;
}
}