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 */
020
021package org.nuxeo.ecm.automation.core.trace;
022
023import java.util.LinkedList;
024import java.util.Stack;
025
026import org.nuxeo.ecm.automation.OperationCallback;
027import org.nuxeo.ecm.automation.OperationException;
028import org.nuxeo.ecm.automation.OperationType;
029
030/**
031 * Automation Abstract tracer recording all automation execution traces.
032 *
033 * @since 5.9.1
034 */
035public abstract class BasedTracer implements OperationCallback {
036
037    protected final TracerFactory factory;
038
039    protected final LinkedList<Call> calls = new LinkedList<Call>();
040
041    protected Stack<Trace> callingStacks = new Stack<Trace>();
042
043    protected Call parent;
044
045    protected OperationType chain;
046
047    protected Trace trace;
048
049    protected Boolean printable;
050
051    protected BasedTracer(TracerFactory factory, Boolean printable) {
052        this.factory = factory;
053        this.printable = printable;
054    }
055
056    protected void pushContext(OperationType newChain) {
057        if (chain != null) {
058            callingStacks.push(new Trace(parent, chain, calls));
059            parent = calls.isEmpty() ? null : calls.getLast();
060            calls.clear();
061        }
062        chain = newChain;
063    }
064
065    protected void popContext() {
066        calls.clear();
067        if (callingStacks.isEmpty()) {
068            parent = null;
069            chain = null;
070            return;
071        }
072        Trace trace = callingStacks.pop();
073        parent = trace.parent;
074        chain = trace.chain;
075        calls.addAll(trace.operations);
076    }
077
078    protected void saveTrace(Trace popped) {
079        if (parent == null) {
080            trace = popped;
081            chain = null;
082            calls.clear();
083            factory.onTrace(popped);
084        } else {
085            parent.nested.add(popped);
086            popContext();
087        }
088    }
089
090    @Override
091    public void onChain(OperationType chain) {
092        pushContext(chain);
093    }
094
095    @Override
096    public void onOutput(Object output) {
097        saveTrace(new Trace(parent, chain, calls, output));
098    }
099
100    @Override
101    public void onError(OperationException error) {
102        saveTrace(new Trace(parent, chain, calls, error));
103    }
104
105    @Override
106    public Trace getTrace() {
107        return trace;
108    }
109
110    @Override
111    public String getFormattedText() {
112        return printable ? trace.getFormattedText() : "";
113    }
114}