001/*
002 * (C) Copyright 2007 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 * $Id: MetaValueExpression.java 28491 2008-01-04 19:04:30Z sfermigier $
020 */
021
022package org.nuxeo.ecm.platform.ui.web.binding;
023
024import java.io.IOException;
025import java.io.ObjectInput;
026import java.io.ObjectOutput;
027import java.io.Serializable;
028
029import javax.el.ELContext;
030import javax.el.ELException;
031import javax.el.ExpressionFactory;
032import javax.el.FunctionMapper;
033import javax.el.ValueExpression;
034import javax.el.VariableMapper;
035import javax.faces.application.Application;
036import javax.faces.context.FacesContext;
037
038import org.apache.commons.logging.Log;
039import org.apache.commons.logging.LogFactory;
040import org.nuxeo.ecm.platform.ui.web.util.ComponentTagUtils;
041
042/**
043 * Meta value expression used to invoke the EL expression that is already the result of a value expression.
044 *
045 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
046 */
047public class MetaValueExpression extends ValueExpression implements Serializable {
048
049    private static final long serialVersionUID = -2721042412903607760L;
050
051    private static final Log log = LogFactory.getLog(MetaValueExpression.class);
052
053    private ValueExpression originalValueExpression;
054
055    private FunctionMapper fnMapper;
056
057    private VariableMapper varMapper;
058
059    private Class<?> expectedType;
060
061    /**
062     * @see {@link #MetaValueExpression(ValueExpression, FunctionMapper, VariableMapper)}
063     */
064    public MetaValueExpression(ValueExpression originalValueExpression) {
065        this(originalValueExpression, null, null, Object.class);
066    }
067
068    public MetaValueExpression(ValueExpression originalValueExpression, FunctionMapper fnMapper,
069            VariableMapper varMapper) {
070        this(originalValueExpression, fnMapper, varMapper, Object.class);
071    }
072
073    public MetaValueExpression(ValueExpression originalValueExpression, FunctionMapper fnMapper,
074            VariableMapper varMapper, Class<?> expectedType) {
075        this.originalValueExpression = originalValueExpression;
076        this.fnMapper = fnMapper;
077        this.varMapper = varMapper;
078        this.expectedType = expectedType;
079    }
080
081    // Expression interface
082
083    @Override
084    public boolean equals(Object obj) {
085        if (this == obj) {
086            return true;
087        }
088        if (!(obj instanceof MetaValueExpression)) {
089            return false;
090        }
091        MetaValueExpression other = (MetaValueExpression) obj;
092        return originalValueExpression.equals(other.originalValueExpression);
093    }
094
095    @Override
096    public int hashCode() {
097        return originalValueExpression.hashCode();
098    }
099
100    @Override
101    public String getExpressionString() {
102        return originalValueExpression.getExpressionString();
103    }
104
105    @Override
106    public boolean isLiteralText() {
107        // XXX should invoke first
108        return originalValueExpression.isLiteralText();
109    }
110
111    // ValueExpression interface
112
113    @Override
114    public Class<?> getExpectedType() {
115        // XXX should invoke first
116        return originalValueExpression.getExpectedType();
117    }
118
119    private ELContext getLocalContext(ELContext context) {
120        if (fnMapper == null && varMapper == null) {
121            return context;
122        }
123        return new org.nuxeo.ecm.platform.ui.web.binding.EvaluationContext(context, fnMapper, varMapper);
124    }
125
126    @Override
127    public Class<?> getType(ELContext context) {
128        ELContext nxcontext = getLocalContext(context);
129        // XXX should invoke first...
130        return originalValueExpression.getType(nxcontext);
131    }
132
133    @Override
134    public Object getValue(ELContext context) {
135        ELContext nxcontext = getLocalContext(context);
136        Object res = null;
137        if (originalValueExpression != null) {
138            res = originalValueExpression.getValue(nxcontext);
139            if (res instanceof String) {
140                String expression = (String) res;
141                if (ComponentTagUtils.isValueReference(expression)) {
142                    FacesContext faces = FacesContext.getCurrentInstance();
143                    Application app = faces.getApplication();
144                    ExpressionFactory factory = app.getExpressionFactory();
145                    ValueExpression newExpr = factory.createValueExpression(nxcontext, expression, expectedType);
146                    try {
147                        res = newExpr.getValue(nxcontext);
148                    } catch (ELException err) {
149                        log.error("Error processing expression " + expression + ": " + err);
150                        res = null;
151                    }
152                } else {
153                    res = expression;
154                }
155            }
156        }
157        return res;
158    }
159
160    @Override
161    public boolean isReadOnly(ELContext context) {
162        return true;
163    }
164
165    @Override
166    public void setValue(ELContext context, Object value) {
167        // do nothing
168    }
169
170    // Externalizable interface
171
172    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
173        originalValueExpression = (ValueExpression) in.readObject();
174    }
175
176    public void writeExternal(ObjectOutput out) throws IOException {
177        out.writeObject(originalValueExpression);
178    }
179
180}