001/*
002 * (C) Copyright 2013 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 *     vpasquier <vpasquier@nuxeo.com>
018 *     slacoin <slacoin@nuxeo.com>
019 */
020package org.nuxeo.ecm.automation.core.trace;
021
022import java.util.Arrays;
023import java.util.HashMap;
024import java.util.LinkedList;
025import java.util.List;
026import java.util.Map;
027
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030import org.nuxeo.ecm.automation.OperationContext;
031import org.nuxeo.ecm.automation.OperationType;
032import org.nuxeo.ecm.automation.core.impl.InvokableMethod;
033import org.nuxeo.ecm.automation.core.scripting.Expression;
034
035/**
036 * @since 5.7.3
037 */
038public class Call {
039
040    private static final Log log = LogFactory.getLog(Call.class);
041
042    /**
043     * Black listing of mvel expressions which should not be evaluated by the Automation traces for debugging purpose
044     *
045     * @since 8.1
046     */
047    public static final String[] MVEL_BLACK_LIST_EXPR = new String[] { "getNextId" };
048
049    protected final String chainId;
050
051    protected final String aliases;
052
053    protected final OperationType type;
054
055    protected final List<Trace> nested = new LinkedList<Trace>();
056
057    protected final Details details;
058
059
060    protected Call(OperationType chain, OperationType op, Details details) {
061        type = op;
062        chainId = chain.getId();
063        aliases = Arrays.toString(chain.getAliases());
064        this.details = details;
065    }
066
067    public Call(OperationType chain, OperationType op) {
068        this(chain, op, new Details());
069    }
070
071    public Call(OperationType chain, OperationContext context, OperationType type, InvokableMethod method,
072            Map<String, Object> parms) {
073        this(chain, type, new Details(context, method, parms));
074    }
075
076    protected static class Details {
077
078        protected final Map<String, Object> parameters = new HashMap<>();
079
080        protected final Map<String, Object> variables = new HashMap<>();
081
082        protected final InvokableMethod method;
083
084        protected final Object input;
085
086        protected Object output;
087
088        protected Details() {
089            method = null;
090            input = null;
091        }
092
093        protected Details(OperationContext context, InvokableMethod method,  Map<String, Object> parms) {
094            this.method = method;
095            input = context.getInput();
096            variables.putAll(context);
097            parms.forEach(new Evaluator(context)::inject);
098        }
099
100        protected class Evaluator {
101
102            protected final OperationContext context;
103
104            protected Evaluator(OperationContext context) {
105                this.context = context;
106            }
107
108            protected void inject(String key, Object value) {
109                if (!(value instanceof Expression)) {
110                    parameters.put(key, value);
111                    return;
112                }
113                Expression exp = (Expression) value;
114                for (String mvelExpr : MVEL_BLACK_LIST_EXPR) {
115                    if (exp.getExpr().contains(mvelExpr)) {
116                        parameters.put(key, new ExpressionParameter(key,
117                                String.format("Cannot be evaluated in traces when using '%s' expression", mvelExpr)));
118                        return;
119                    }
120                }
121                try {
122                    parameters.put(key, new ExpressionParameter(key, exp.eval(context)));
123                    return;
124                } catch (RuntimeException e) {
125                    log.warn("Cannot evaluate mvel expression for parameter: " + key, e);
126                }
127            }
128        }
129
130
131    }
132
133    /**
134     * @since 7.1
135     */
136    public static class ExpressionParameter {
137
138        protected final String parameterId;
139
140        protected final Object parameterValue;
141
142        public ExpressionParameter(String parameterId, Object parameterValue) {
143            this.parameterId = parameterId;
144            this.parameterValue = parameterValue;
145        }
146
147        public Object getParameterValue() {
148            return parameterValue;
149        }
150
151        public String getParameterId() {
152
153            return parameterId;
154        }
155    }
156
157    public OperationType getType() {
158        return type;
159    }
160
161    public InvokableMethod getMethod() {
162        return details.method;
163    }
164
165    public Map<String, Object> getParameters() {
166        return details.parameters;
167    }
168
169    public Map<String, Object> getVariables() {
170        return details.variables;
171    }
172
173    public Object getInput() {
174        return details.input;
175    }
176
177    public Object getOutput() {
178        return details.output;
179    }
180
181    public List<Trace> getNested() {
182        return nested;
183    }
184
185    public String getChainId() {
186        return chainId;
187    }
188
189    public String getAliases() {
190        return aliases;
191    }
192
193}