001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 */
012package org.nuxeo.ecm.automation.core.scripting;
013
014import java.io.Serializable;
015import java.util.HashMap;
016import java.util.Map;
017
018import org.mvel2.MVEL;
019import org.mvel2.compiler.BlankLiteral;
020import org.nuxeo.ecm.automation.OperationContext;
021import org.nuxeo.ecm.automation.core.Constants;
022import org.nuxeo.ecm.automation.core.trace.TracerFactory;
023import org.nuxeo.runtime.api.Framework;
024
025/**
026 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
027 */
028public class MvelExpression implements Expression {
029
030    private static final long serialVersionUID = 1L;
031
032    protected transient volatile Serializable compiled;
033
034    protected final String expr;
035
036    public MvelExpression(String expr) {
037        this.expr = expr;
038    }
039
040    @Override
041    public Object eval(OperationContext ctx) {
042        if (compiled == null) {
043            compiled = MVEL.compileExpression(expr);
044        }
045        Object result;
046
047        // Get and/or Store mvel results in operation context in case when trace mode enabled
048        TracerFactory factory = Framework.getService(TracerFactory.class);
049        if (factory.getRecordingState()) {
050            HashMap<String, Object> mvelResults = (HashMap<String, Object>) ctx.get(Constants.MVEL_RESULTS);
051            if (mvelResults == null) {
052                mvelResults = new HashMap<>();
053            }
054            if (mvelResults.get(expr) != null) {
055                result = mvelResults.get(expr);
056            } else {
057                result = MVEL.executeExpression(compiled, getBindings(ctx));
058                mvelResults.put(expr, result);
059                ctx.put(Constants.MVEL_RESULTS, mvelResults);
060            }
061        } else {
062            result = MVEL.executeExpression(compiled, getBindings(ctx));
063        }
064
065        return result != null && result.getClass().isAssignableFrom(BlankLiteral.class) ? "" : result;
066    }
067
068    /**
069     * @since 5.9.3
070     */
071    protected Map<String, Object> getBindings(OperationContext ctx) {
072        return Scripting.initBindings(ctx);
073    }
074}