001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry.services.impl;
016
017 import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
018 import ognl.ClassCacheInspector;
019 import ognl.Node;
020 import ognl.Ognl;
021 import ognl.OgnlRuntime;
022 import org.apache.hivemind.ApplicationRuntimeException;
023 import org.apache.tapestry.AbstractComponent;
024 import org.apache.tapestry.event.ReportStatusEvent;
025 import org.apache.tapestry.event.ReportStatusListener;
026 import org.apache.tapestry.event.ResetEventListener;
027 import org.apache.tapestry.services.ExpressionCache;
028 import org.apache.tapestry.services.ExpressionEvaluator;
029
030 import java.beans.Introspector;
031 import java.util.HashMap;
032 import java.util.Map;
033 import java.util.WeakHashMap;
034
035 /**
036 * @author Howard M. Lewis Ship
037 * @since 4.0
038 */
039 public class ExpressionCacheImpl implements ExpressionCache, ResetEventListener, ReportStatusListener, ClassCacheInspector {
040
041 private final ReentrantLock _lock = new ReentrantLock();
042
043 private String _serviceId;
044
045 private Map _cache = new WeakHashMap();
046
047 private Map _objectCache = new WeakHashMap();
048
049 private ExpressionEvaluator _evaluator;
050
051 private final boolean _cachingDisabled = Boolean.getBoolean("org.apache.tapestry.disable-caching");
052
053 public void initializeService()
054 {
055 if (_cachingDisabled)
056 {
057 OgnlRuntime.setClassCacheInspector(this);
058 }
059 }
060
061 public void resetEventDidOccur()
062 {
063 try {
064
065 _lock.lock();
066
067 _cache.clear();
068 _objectCache.clear();
069
070 Introspector.flushCaches();
071
072 } finally {
073
074 _lock.unlock();
075 }
076 }
077
078 public boolean shouldCache(Class type)
079 {
080 if (!_cachingDisabled || type == null
081 || AbstractComponent.class.isAssignableFrom(type))
082 return false;
083
084 return true;
085 }
086
087 public void reportStatus(ReportStatusEvent event)
088 {
089 event.title(_serviceId);
090
091 event.property("cached expression count", _cache.size());
092 event.collection("cached expressions", _cache.keySet());
093
094 event.property("cached object expression count", _objectCache.size());
095 }
096
097 public Object getCompiledExpression(Object target, String expression)
098 {
099 try {
100
101 _lock.lock();
102
103 Map cached = (Map)_objectCache.get(target.getClass());
104
105 if (cached == null)
106 {
107 cached = new HashMap();
108 _objectCache.put(target.getClass(), cached);
109 }
110
111 Node result = (Node)cached.get(expression);
112
113 if (result == null || result.getAccessor() == null)
114 {
115 result = parse(target, expression);
116 cached.put(expression, result);
117 }
118
119 return result;
120
121 } finally {
122
123 _lock.unlock();
124 }
125 }
126
127 public Object getCompiledExpression(String expression)
128 {
129 try {
130
131 _lock.lock();
132
133 Object result = _cache.get(expression);
134
135 if (result == null)
136 {
137 result = parse(expression);
138 _cache.put(expression, result);
139 }
140
141 return result;
142 } finally {
143
144 _lock.unlock();
145 }
146 }
147
148 private Node parse(Object target, String expression)
149 {
150 try
151 {
152 return Ognl.compileExpression(_evaluator.createContext(target), target, expression);
153 }
154 catch (Exception ex)
155 {
156 throw new ApplicationRuntimeException(ImplMessages.unableToParseExpression(expression,ex), ex);
157 }
158 }
159
160 private Object parse(String expression)
161 {
162 try
163 {
164 return Ognl.parseExpression(expression);
165 }
166 catch (Exception ex)
167 {
168 throw new ApplicationRuntimeException(ImplMessages.unableToParseExpression(expression, ex), ex);
169 }
170 }
171
172 public void setServiceId(String serviceId)
173 {
174 _serviceId = serviceId;
175 }
176
177 public void setEvaluator(ExpressionEvaluator evaluator)
178 {
179 _evaluator = evaluator;
180 }
181
182 }