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