001/*
002 * (C) Copyright 2007 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 * $Id: MetaValueExpression.java 28491 2008-01-04 19:04:30Z sfermigier $
018 */
019
020package org.nuxeo.ecm.platform.ui.web.binding;
021
022import java.io.IOException;
023import java.io.ObjectInput;
024import java.io.ObjectOutput;
025import java.io.Serializable;
026
027import javax.el.ELContext;
028import javax.el.ELException;
029import javax.el.ExpressionFactory;
030import javax.el.FunctionMapper;
031import javax.el.ValueExpression;
032import javax.el.VariableMapper;
033import javax.faces.application.Application;
034import javax.faces.context.FacesContext;
035
036import org.apache.commons.logging.Log;
037import org.apache.commons.logging.LogFactory;
038import org.nuxeo.ecm.platform.ui.web.util.ComponentTagUtils;
039
040/**
041 * Meta value expression used to invoke the EL expression that is already the result of a value expression.
042 *
043 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
044 */
045public class MetaValueExpression extends ValueExpression implements Serializable {
046
047    private static final long serialVersionUID = -2721042412903607760L;
048
049    private static final Log log = LogFactory.getLog(MetaValueExpression.class);
050
051    private ValueExpression originalValueExpression;
052
053    private FunctionMapper fnMapper;
054
055    private VariableMapper varMapper;
056
057    public MetaValueExpression(ValueExpression originalValueExpression) {
058        this(originalValueExpression, null, null);
059    }
060
061    public MetaValueExpression(ValueExpression originalValueExpression, FunctionMapper fnMapper,
062            VariableMapper varMapper) {
063        this.originalValueExpression = originalValueExpression;
064        this.fnMapper = fnMapper;
065        this.varMapper = varMapper;
066    }
067
068    // Expression interface
069
070    @Override
071    public boolean equals(Object obj) {
072        if (this == obj) {
073            return true;
074        }
075        if (!(obj instanceof MetaValueExpression)) {
076            return false;
077        }
078        MetaValueExpression other = (MetaValueExpression) obj;
079        return originalValueExpression.equals(other.originalValueExpression);
080    }
081
082    @Override
083    public int hashCode() {
084        return originalValueExpression.hashCode();
085    }
086
087    @Override
088    public String getExpressionString() {
089        return originalValueExpression.getExpressionString();
090    }
091
092    @Override
093    public boolean isLiteralText() {
094        // XXX should invoke first
095        return originalValueExpression.isLiteralText();
096    }
097
098    // ValueExpression interface
099
100    @Override
101    public Class<?> getExpectedType() {
102        // XXX should invoke first
103        return originalValueExpression.getExpectedType();
104    }
105
106    private ELContext getLocalContext(ELContext context) {
107        if (fnMapper == null && varMapper == null) {
108            return context;
109        }
110        return new org.nuxeo.ecm.platform.ui.web.binding.EvaluationContext(context, fnMapper, varMapper);
111    }
112
113    @Override
114    public Class<?> getType(ELContext context) {
115        ELContext nxcontext = getLocalContext(context);
116        // XXX should invoke first...
117        return originalValueExpression.getType(nxcontext);
118    }
119
120    @Override
121    public Object getValue(ELContext context) {
122        ELContext nxcontext = getLocalContext(context);
123        Object res = null;
124        if (originalValueExpression != null) {
125            res = originalValueExpression.getValue(nxcontext);
126            if (res instanceof String) {
127                String expression = (String) res;
128                if (ComponentTagUtils.isValueReference(expression)) {
129                    FacesContext faces = FacesContext.getCurrentInstance();
130                    Application app = faces.getApplication();
131                    ExpressionFactory factory = app.getExpressionFactory();
132                    ValueExpression newExpr = factory.createValueExpression(nxcontext, expression, Object.class);
133                    try {
134                        res = newExpr.getValue(nxcontext);
135                    } catch (ELException err) {
136                        log.error(String.format("Error processing expression %s: %s", expression, err));
137                        res = null;
138                    }
139                } else {
140                    res = expression;
141                }
142            }
143        }
144        return res;
145    }
146
147    @Override
148    public boolean isReadOnly(ELContext context) {
149        return true;
150    }
151
152    @Override
153    public void setValue(ELContext context, Object value) {
154        // do nothing
155    }
156
157    // Externalizable interface
158
159    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
160        originalValueExpression = (ValueExpression) in.readObject();
161    }
162
163    public void writeExternal(ObjectOutput out) throws IOException {
164        out.writeObject(originalValueExpression);
165    }
166
167}