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
015package org.apache.tapestry.services.impl;
016
017import java.util.Iterator;
018import java.util.List;
019import java.util.Map;
020
021import ognl.ClassResolver;
022import ognl.Ognl;
023import ognl.OgnlRuntime;
024import ognl.TypeConverter;
025
026import org.apache.hivemind.ApplicationRuntimeException;
027import org.apache.tapestry.Tapestry;
028import org.apache.tapestry.services.ExpressionCache;
029import org.apache.tapestry.services.ExpressionEvaluator;
030import org.apache.tapestry.spec.IApplicationSpecification;
031
032/**
033 * @author Howard M. Lewis Ship
034 * @since 4.0
035 */
036public class ExpressionEvaluatorImpl implements ExpressionEvaluator
037{
038    // Uses Thread's context class loader
039
040    private final ClassResolver _ognlResolver = new OgnlClassResolver();
041
042    private ExpressionCache _expressionCache;
043
044    private IApplicationSpecification _applicationSpecification;
045
046    private TypeConverter _typeConverter;
047
048    private List _contributions;
049
050    // Context, with a root of null, used when evaluating an expression
051    // to see if it is a constant.
052
053    private Map _defaultContext;
054
055    public void setApplicationSpecification(IApplicationSpecification applicationSpecification)
056    {
057        _applicationSpecification = applicationSpecification;
058    }
059
060    public void initializeService()
061    {
062        if (_applicationSpecification.checkExtension(Tapestry.OGNL_TYPE_CONVERTER))
063            _typeConverter = (TypeConverter) _applicationSpecification.getExtension(
064                    Tapestry.OGNL_TYPE_CONVERTER,
065                    TypeConverter.class);
066
067        Iterator i = _contributions.iterator();
068
069        while (i.hasNext())
070        {
071            PropertyAccessorContribution c = (PropertyAccessorContribution) i.next();
072
073            OgnlRuntime.setPropertyAccessor(c.getSubjectClass(), c.getAccessor());
074        }
075
076        _defaultContext = Ognl.createDefaultContext(null, _ognlResolver, _typeConverter);
077
078    }
079
080    public Object read(Object target, String expression)
081    {
082        return readCompiled(target, _expressionCache.getCompiledExpression(expression));
083    }
084
085    public Object readCompiled(Object target, Object expression)
086    {
087        try
088        {
089            Map context = createContext(target);
090
091            return Ognl.getValue(expression, context, target);
092        }
093        catch (Exception ex)
094        {
095            throw new ApplicationRuntimeException(ImplMessages.unableToReadExpression(ImplMessages
096                    .parsedExpression(), target, ex), target, null, ex);
097        }
098    }
099
100    private Map createContext(Object target)
101    {
102        Map result = Ognl.createDefaultContext(target, _ognlResolver);
103
104        if (_typeConverter != null)
105            Ognl.setTypeConverter(result, _typeConverter);
106
107        return result;
108    }
109
110    public void write(Object target, String expression, Object value)
111    {
112        writeCompiled(target, _expressionCache.getCompiledExpression(expression), value);
113    }
114
115    public void writeCompiled(Object target, Object expression, Object value)
116    {
117        try
118        {
119            Map context = createContext(target);
120
121            Ognl.setValue(expression, context, target, value);
122        }
123        catch (Exception ex)
124        {
125            throw new ApplicationRuntimeException(ImplMessages.unableToWriteExpression(ImplMessages
126                    .parsedExpression(), target, value, ex), target, null, ex);
127        }
128
129    }
130
131    public boolean isConstant(String expression)
132    {
133        Object compiled = _expressionCache.getCompiledExpression(expression);
134
135        try
136        {
137            return Ognl.isConstant(compiled, _defaultContext);
138        }
139        catch (Exception ex)
140        {
141            throw new ApplicationRuntimeException(ImplMessages.isConstantExpressionError(
142                    expression,
143                    ex), ex);
144        }
145    }
146
147    public void setExpressionCache(ExpressionCache expressionCache)
148    {
149        _expressionCache = expressionCache;
150    }
151
152    public void setContributions(List contributions)
153    {
154        _contributions = contributions;
155    }
156}