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 */
018package org.nuxeo.ecm.automation.core.trace;
019
020import java.io.BufferedWriter;
021import java.io.IOException;
022import java.io.OutputStream;
023import java.io.OutputStreamWriter;
024import java.io.Writer;
025import java.util.Arrays;
026import java.util.Calendar;
027import java.util.List;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031
032/**
033 * @since 5.7.3
034 */
035public class TracePrinter {
036
037    private static final Log log = LogFactory.getLog(TracePrinter.class);
038
039    protected final BufferedWriter writer;
040
041    protected String preamble = "";
042
043    public TracePrinter(Writer writer) {
044        this.writer = new BufferedWriter(writer);
045    }
046
047    public TracePrinter(OutputStream out) {
048        this(new OutputStreamWriter(out));
049    }
050
051    protected void printLine(String line) throws IOException {
052        writer.write(preamble + line);
053    }
054
055    protected void printHeading(String heading) throws IOException {
056        printLine(System.getProperty("line.separator") + System.getProperty("line.separator") + "****** " + heading
057                + " ******");
058    }
059
060    public void print(Trace trace) throws IOException {
061        StringBuilder sb = new StringBuilder();
062        printHeading("chain");
063        if (trace.error != null) {
064            sb.append(System.getProperty("line.separator"));
065            if (trace.getParent() != null) {
066                sb.append("Parent Chain ID: ");
067                sb.append(trace.getParent().getChainId());
068                sb.append(System.getProperty("line.separator"));
069            }
070            sb.append("Name: ");
071            sb.append(trace.getChain().getId());
072            if (trace.getChain().getAliases() != null && trace.getChain().getAliases().length > 0) {
073                sb.append(System.getProperty("line.separator"));
074                sb.append("Aliases: ");
075                sb.append(Arrays.toString(trace.getChain().getAliases()));
076            }
077            sb.append(System.getProperty("line.separator"));
078            sb.append("Exception: ");
079            sb.append(trace.error.getClass().getSimpleName());
080            sb.append(System.getProperty("line.separator"));
081            sb.append("Caught error: ");
082            sb.append(trace.error.getMessage());
083            sb.append(System.getProperty("line.separator"));
084            sb.append("Caused by: ");
085            sb.append(trace.error.getCause());
086            printLine(sb.toString());
087        } else {
088            sb.append(System.getProperty("line.separator"));
089            if (trace.getParent() != null) {
090                sb.append("Parent Chain ID: ");
091                sb.append(trace.getParent().getChainId());
092                sb.append(System.getProperty("line.separator"));
093            }
094            sb.append("Name: ");
095            sb.append(trace.getChain().getId());
096            sb.append(System.getProperty("line.separator"));
097            sb.append("Produced output type: ");
098            sb.append(trace.output == null ? "Void" : trace.output.getClass().getSimpleName());
099            printLine(sb.toString());
100        }
101        StringBuilder stringBuilder = new StringBuilder();
102        stringBuilder.append(System.getProperty("line.separator"));
103        stringBuilder.append("****** Hierarchy calls ******");
104        stringBuilder.append(System.getProperty("line.separator"));
105        displayOperationTreeCalls(trace.operations, stringBuilder);
106        printLine(stringBuilder.toString());
107        print(trace.operations);
108        writer.flush();
109    }
110
111    public void print(List<Call> calls) throws IOException {
112        for (Call call : calls) {
113            print(call);
114        }
115    }
116
117    public void print(Call call) throws IOException {
118        printCall(call);
119    }
120
121    public void printCall(Call call) {
122        try {
123            StringBuilder sb = new StringBuilder();
124            sb.append(System.getProperty("line.separator"));
125            sb.append(System.getProperty("line.separator"));
126            sb.append("****** " + call.getType().getId() + " ******");
127            sb.append(System.getProperty("line.separator"));
128            sb.append("Chain ID: ");
129            sb.append(call.getChainId());
130            if (call.getAliases() != null) {
131                sb.append(System.getProperty("line.separator"));
132                sb.append("Chain Aliases: ");
133                sb.append(call.getAliases());
134            }
135            sb.append(System.getProperty("line.separator"));
136            sb.append("Class: ");
137            sb.append(call.getType().getType().getSimpleName());
138            sb.append(System.getProperty("line.separator"));
139            sb.append("Method: '");
140            sb.append(call.getMethod().getMethod().getName());
141            sb.append("' | Input Type: ");
142            sb.append(call.getMethod().getConsume());
143            sb.append(" | Output Type: ");
144            sb.append(call.getMethod().getProduce());
145            sb.append(System.getProperty("line.separator"));
146            sb.append("Input: ");
147            sb.append(call.getInput());
148            if (!call.getParmeters().isEmpty()) {
149                sb.append(System.getProperty("line.separator"));
150                sb.append("Parameters ");
151                for (String parameter : call.getParmeters().keySet()) {
152                    sb.append(" | ");
153                    sb.append("Name: ");
154                    sb.append(parameter);
155                    sb.append(", Value: ");
156                    Object value = call.getParmeters().get(parameter);
157                    if (value instanceof Call.ExpressionParameter) {
158                        value = String.format("Expr:(id=%s | value=%s)",
159                                ((Call.ExpressionParameter) call.getParmeters().get(parameter)).getParameterId(),
160                                ((Call.ExpressionParameter) call.getParmeters().get(parameter)).getParameterValue());
161                    }
162                    sb.append(value);
163                }
164            }
165            if (!call.getVariables().isEmpty()) {
166                sb.append(System.getProperty("line.separator"));
167                sb.append("Context Variables");
168                for (String keyVariable : call.getVariables().keySet()) {
169                    sb.append(" | ");
170                    sb.append("Key: ");
171                    sb.append(keyVariable);
172                    sb.append(", Value: ");
173                    Object variable = call.getVariables().get(keyVariable);
174                    if (variable instanceof Calendar) {
175                        sb.append(((Calendar) variable).getTime());
176                    } else {
177                        sb.append(variable);
178                    }
179                }
180            }
181            printLine(sb.toString());
182            sb = new StringBuilder();
183            if (!call.getNested().isEmpty()) {
184                sb.append(System.getProperty("line.separator"));
185                printHeading("start sub chain");
186                for (Trace trace : call.getNested()) {
187                    print(trace);
188                }
189                sb.append(System.getProperty("line.separator"));
190                printHeading("end sub chain");
191            }
192            printLine(sb.toString());
193        } catch (IOException e) {
194            log.error("Nuxeo TracePrinter cannot write traces output", e);
195        }
196    }
197
198    public void litePrint(Trace trace) throws IOException {
199        StringBuilder sb = new StringBuilder();
200        printHeading("chain");
201        if (trace.error != null) {
202            sb.append(System.getProperty("line.separator"));
203            if (trace.getParent() != null) {
204                sb.append("Parent Chain ID: ");
205                sb.append(trace.getParent().getChainId());
206                sb.append(System.getProperty("line.separator"));
207            }
208            sb.append("Name: ");
209            sb.append(trace.getChain().getId());
210            if (trace.getChain().getAliases() != null && trace.getChain().getAliases().length > 0) {
211                sb.append(System.getProperty("line.separator"));
212                sb.append("Aliases: ");
213                sb.append(Arrays.toString(trace.getChain().getAliases()));
214            }
215            sb.append(System.getProperty("line.separator"));
216            sb.append("Exception: ");
217            sb.append(trace.error.getClass().getSimpleName());
218            sb.append(System.getProperty("line.separator"));
219            sb.append("Caught error: ");
220            sb.append(trace.error.getMessage());
221            sb.append(System.getProperty("line.separator"));
222            sb.append("Caused by: ");
223            sb.append(trace.error.getCause());
224        }
225        sb.append(System.getProperty("line.separator"));
226        sb.append("****** Hierarchy calls ******");
227        printLine(sb.toString());
228        litePrintCall(trace.operations);
229        writer.flush();
230    }
231
232    public void litePrintCall(List<Call> calls) throws IOException {
233        StringBuilder stringBuilder = new StringBuilder();
234        stringBuilder.append(System.getProperty("line.separator"));
235        try {
236            displayOperationTreeCalls(calls, stringBuilder);
237            printLine(stringBuilder.toString());
238            stringBuilder = new StringBuilder();
239            for (Call call : calls) {
240                if (!call.getNested().isEmpty()) {
241                    stringBuilder.append(System.getProperty("line.separator"));
242                    printHeading("start sub chain");
243                    for (Trace trace : call.getNested()) {
244                        litePrint(trace);
245                    }
246                    stringBuilder.append(System.getProperty("line.separator"));
247                    printHeading("end sub chain");
248                }
249            }
250            printLine(stringBuilder.toString());
251        } catch (IOException e) {
252            log.error("Nuxeo TracePrinter cannot write traces output", e);
253        }
254    }
255
256    private void displayOperationTreeCalls(List<Call> calls, StringBuilder stringBuilder) {
257        String tabs = "\t";
258        for (Call call : calls) {
259            stringBuilder.append(tabs);
260            stringBuilder.append(call.getType().getType().getName());
261            stringBuilder.append(System.getProperty("line.separator"));
262            tabs += "\t";
263        }
264    }
265
266}