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        return new org.nuxeo.ecm.platform.ui.web.binding.EvaluationContext(context, fnMapper, varMapper);
108    }
109
110    @Override
111    public Class<?> getType(ELContext context) {
112        ELContext nxcontext = getLocalContext(context);
113        // XXX should invoke first...
114        return originalValueExpression.getType(nxcontext);
115    }
116
117    @Override
118    public Object getValue(ELContext context) {
119        ELContext nxcontext = getLocalContext(context);
120        Object res = null;
121        if (originalValueExpression != null) {
122            res = originalValueExpression.getValue(nxcontext);
123            if (res instanceof String) {
124                String expression = (String) res;
125                if (ComponentTagUtils.isValueReference(expression)) {
126                    FacesContext faces = FacesContext.getCurrentInstance();
127                    Application app = faces.getApplication();
128                    ExpressionFactory factory = app.getExpressionFactory();
129                    ValueExpression newExpr = factory.createValueExpression(nxcontext, expression, Object.class);
130                    try {
131                        res = newExpr.getValue(nxcontext);
132                    } catch (ELException err) {
133                        log.error(String.format("Error processing expression %s: %s", expression, err));
134                        res = null;
135                    }
136                } else {
137                    res = expression;
138                }
139            }
140        }
141        return res;
142    }
143
144    @Override
145    public boolean isReadOnly(ELContext context) {
146        return true;
147    }
148
149    @Override
150    public void setValue(ELContext context, Object value) {
151        // do nothing
152    }
153
154    // Externalizable interface
155
156    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
157        originalValueExpression = (ValueExpression) in.readObject();
158    }
159
160    public void writeExternal(ObjectOutput out) throws IOException {
161        out.writeObject(originalValueExpression);
162    }
163
164}