1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 /*
19 * $Id$
20 */
21 package org.apache.xalan.trace;
22
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.Method;
25
26 import javax.xml.transform.SourceLocator;
27
28 import org.apache.xalan.templates.Constants;
29 import org.apache.xalan.templates.ElemTemplate;
30 import org.apache.xalan.templates.ElemTemplateElement;
31 import org.apache.xalan.templates.ElemTextLiteral;
32 import org.apache.xml.dtm.DTM;
33 import org.apache.xml.dtm.ref.DTMNodeProxy;
34 import org.apache.xml.serializer.SerializerTrace;
35
36 import org.w3c.dom.Node;
37
38 /**
39 * Implementation of the TraceListener interface that
40 * prints each event to standard out as it occurs.
41 *
42 * @see org.apache.xalan.trace.TracerEvent
43 * @xsl.usage advanced
44 */
45 public class PrintTraceListener implements TraceListenerEx3
46 {
47
48 /**
49 * Construct a trace listener.
50 *
51 * @param pw PrintWriter to use for tracing events
52 */
PrintTraceListener(java.io.PrintWriter pw)53 public PrintTraceListener(java.io.PrintWriter pw)
54 {
55 m_pw = pw;
56 }
57
58 /**
59 * The print writer where the events should be written.
60 */
61 java.io.PrintWriter m_pw;
62
63 /**
64 * This needs to be set to true if the listener is to print an event whenever a template is invoked.
65 */
66 public boolean m_traceTemplates = false;
67
68 /**
69 * Set to true if the listener is to print events that occur as each node is 'executed' in the stylesheet.
70 */
71 public boolean m_traceElements = false;
72
73 /**
74 * Set to true if the listener is to print information after each result-tree generation event.
75 */
76 public boolean m_traceGeneration = false;
77
78 /**
79 * Set to true if the listener is to print information after each selection event.
80 */
81 public boolean m_traceSelection = false;
82
83 /**
84 * Set to true if the listener is to print information after each extension event.
85 */
86 public boolean m_traceExtension = false;
87
88 /**
89 * Print information about a TracerEvent.
90 *
91 * @param ev the trace event.
92 */
_trace(TracerEvent ev)93 public void _trace(TracerEvent ev)
94 {
95
96 switch (ev.m_styleNode.getXSLToken())
97 {
98 case Constants.ELEMNAME_TEXTLITERALRESULT :
99 if (m_traceElements)
100 {
101 m_pw.print(ev.m_styleNode.getSystemId()+ " Line #" + ev.m_styleNode.getLineNumber() + ", "
102 + "Column #" + ev.m_styleNode.getColumnNumber() + " -- "
103 + ev.m_styleNode.getNodeName() + ": ");
104
105 ElemTextLiteral etl = (ElemTextLiteral) ev.m_styleNode;
106 String chars = new String(etl.getChars(), 0, etl.getChars().length);
107
108 m_pw.println(" " + chars.trim());
109 }
110 break;
111 case Constants.ELEMNAME_TEMPLATE :
112 if (m_traceTemplates || m_traceElements)
113 {
114 ElemTemplate et = (ElemTemplate) ev.m_styleNode;
115
116 m_pw.print(et.getSystemId()+ " Line #" + et.getLineNumber() + ", " + "Column #"
117 + et.getColumnNumber() + ": " + et.getNodeName() + " ");
118
119 if (null != et.getMatch())
120 {
121 m_pw.print("match='" + et.getMatch().getPatternString() + "' ");
122 }
123
124 if (null != et.getName())
125 {
126 m_pw.print("name='" + et.getName() + "' ");
127 }
128
129 m_pw.println();
130 }
131 break;
132 default :
133 if (m_traceElements)
134 {
135 m_pw.println(ev.m_styleNode.getSystemId()+ " Line #" + ev.m_styleNode.getLineNumber() + ", "
136 + "Column #" + ev.m_styleNode.getColumnNumber() + ": "
137 + ev.m_styleNode.getNodeName());
138 }
139 }
140 }
141
142 int m_indent = 0;
143
144 /**
145 * Print information about a TracerEvent.
146 *
147 * @param ev the trace event.
148 */
trace(TracerEvent ev)149 public void trace(TracerEvent ev)
150 {
151 // m_traceElements = true;
152 // m_traceTemplates = true;
153 //
154 // for(int i = 0; i < m_indent; i++)
155 // m_pw.print(" ");
156 // m_indent = m_indent+2;
157 // m_pw.print("trace: ");
158 _trace(ev);
159 }
160
161 /**
162 * Method that is called when the end of a trace event occurs.
163 * The method is blocking. It must return before processing continues.
164 *
165 * @param ev the trace event.
166 */
traceEnd(TracerEvent ev)167 public void traceEnd(TracerEvent ev)
168 {
169 // m_traceElements = true;
170 // m_traceTemplates = true;
171 //
172 // m_indent = m_indent-2;
173 // for(int i = 0; i < m_indent; i++)
174 // m_pw.print(" ");
175 // m_pw.print("etrac: ");
176 // _trace(ev);
177 }
178
179
180 /**
181 * Method that is called just after a select attribute has been evaluated.
182 *
183 * @param ev the generate event.
184 *
185 * @throws javax.xml.transform.TransformerException
186 */
selected(SelectionEvent ev)187 public void selected(SelectionEvent ev)
188 throws javax.xml.transform.TransformerException {
189
190 if (m_traceSelection) {
191 ElemTemplateElement ete = (ElemTemplateElement) ev.m_styleNode;
192 Node sourceNode = ev.m_sourceNode;
193
194 SourceLocator locator = null;
195 if (sourceNode instanceof DTMNodeProxy) {
196 int nodeHandler = ((DTMNodeProxy) sourceNode).getDTMNodeNumber();
197 locator =
198 ((DTMNodeProxy) sourceNode).getDTM().getSourceLocatorFor(
199 nodeHandler);
200 }
201
202 if (locator != null)
203 m_pw.println(
204 "Selected source node '"
205 + sourceNode.getNodeName()
206 + "', at "
207 + locator);
208 else
209 m_pw.println(
210 "Selected source node '" + sourceNode.getNodeName() + "'");
211
212 if (ev.m_styleNode.getLineNumber() == 0) {
213
214 // You may not have line numbers if the selection is occuring from a
215 // default template.
216 ElemTemplateElement parent =
217 (ElemTemplateElement) ete.getParentElem();
218
219 if (parent == ete.getStylesheetRoot().getDefaultRootRule()) {
220 m_pw.print("(default root rule) ");
221 } else if (
222 parent == ete.getStylesheetRoot().getDefaultTextRule()) {
223 m_pw.print("(default text rule) ");
224 } else if (parent == ete.getStylesheetRoot().getDefaultRule()) {
225 m_pw.print("(default rule) ");
226 }
227
228 m_pw.print(
229 ete.getNodeName()
230 + ", "
231 + ev.m_attributeName
232 + "='"
233 + ev.m_xpath.getPatternString()
234 + "': ");
235 } else {
236 m_pw.print(
237 ev.m_styleNode.getSystemId()
238 + " Line #"
239 + ev.m_styleNode.getLineNumber()
240 + ", "
241 + "Column #"
242 + ev.m_styleNode.getColumnNumber()
243 + ": "
244 + ete.getNodeName()
245 + ", "
246 + ev.m_attributeName
247 + "='"
248 + ev.m_xpath.getPatternString()
249 + "': ");
250 }
251
252 if (ev.m_selection.getType() == ev.m_selection.CLASS_NODESET) {
253 m_pw.println();
254
255 org.apache.xml.dtm.DTMIterator nl = ev.m_selection.iter();
256
257 // The following lines are added to fix bug#16222.
258 // The main cause is that the following loop change the state of iterator, which is shared
259 // with the transformer. The fix is that we record the initial state before looping, then
260 // restore the state when we finish it, which is done in the following lines added.
261 int currentPos = DTM.NULL;
262 currentPos = nl.getCurrentPos();
263 nl.setShouldCacheNodes(true); // This MUST be done before we clone the iterator!
264 org.apache.xml.dtm.DTMIterator clone = null;
265 // End of block
266
267 try {
268 clone = nl.cloneWithReset();
269 } catch (CloneNotSupportedException cnse) {
270 m_pw.println(
271 " [Can't trace nodelist because it it threw a CloneNotSupportedException]");
272 return;
273 }
274 int pos = clone.nextNode();
275
276 if (DTM.NULL == pos) {
277 m_pw.println(" [empty node list]");
278 } else {
279 while (DTM.NULL != pos) {
280 // m_pw.println(" " + ev.m_processor.getXPathContext().getDTM(pos).getNode(pos));
281 DTM dtm = ev.m_processor.getXPathContext().getDTM(pos);
282 m_pw.print(" ");
283 m_pw.print(Integer.toHexString(pos));
284 m_pw.print(": ");
285 m_pw.println(dtm.getNodeName(pos));
286 pos = clone.nextNode();
287 }
288 }
289
290 // Restore the initial state of the iterator, part of fix for bug#16222.
291 nl.runTo(-1);
292 nl.setCurrentPos(currentPos);
293 // End of fix for bug#16222
294
295 } else {
296 m_pw.println(ev.m_selection.str());
297 }
298 }
299 }
300 /**
301 * Method that is called after an xsl:apply-templates or xsl:for-each
302 * selection occurs.
303 *
304 * @param ev the generate event.
305 *
306 * @throws javax.xml.transform.TransformerException
307 */
selectEnd(EndSelectionEvent ev)308 public void selectEnd(EndSelectionEvent ev)
309 throws javax.xml.transform.TransformerException
310 {
311 // Nothing for right now.
312 }
313
314
315 /**
316 * Print information about a Generate event.
317 *
318 * @param ev the trace event.
319 */
generated(GenerateEvent ev)320 public void generated(GenerateEvent ev)
321 {
322
323 if (m_traceGeneration)
324 {
325 switch (ev.m_eventtype)
326 {
327 case SerializerTrace.EVENTTYPE_STARTDOCUMENT :
328 m_pw.println("STARTDOCUMENT");
329 break;
330 case SerializerTrace.EVENTTYPE_ENDDOCUMENT :
331 m_pw.println("ENDDOCUMENT");
332 break;
333 case SerializerTrace.EVENTTYPE_STARTELEMENT :
334 m_pw.println("STARTELEMENT: " + ev.m_name);
335 break;
336 case SerializerTrace.EVENTTYPE_ENDELEMENT :
337 m_pw.println("ENDELEMENT: " + ev.m_name);
338 break;
339 case SerializerTrace.EVENTTYPE_CHARACTERS :
340 {
341 String chars = new String(ev.m_characters, ev.m_start, ev.m_length);
342
343 m_pw.println("CHARACTERS: " + chars);
344 }
345 break;
346 case SerializerTrace.EVENTTYPE_CDATA :
347 {
348 String chars = new String(ev.m_characters, ev.m_start, ev.m_length);
349
350 m_pw.println("CDATA: " + chars);
351 }
352 break;
353 case SerializerTrace.EVENTTYPE_COMMENT :
354 m_pw.println("COMMENT: " + ev.m_data);
355 break;
356 case SerializerTrace.EVENTTYPE_PI :
357 m_pw.println("PI: " + ev.m_name + ", " + ev.m_data);
358 break;
359 case SerializerTrace.EVENTTYPE_ENTITYREF :
360 m_pw.println("ENTITYREF: " + ev.m_name);
361 break;
362 case SerializerTrace.EVENTTYPE_IGNORABLEWHITESPACE :
363 m_pw.println("IGNORABLEWHITESPACE");
364 break;
365 }
366 }
367 }
368
369 /**
370 * Print information about an extension event.
371 *
372 * @param ev the extension event to print information about
373 */
extension(ExtensionEvent ev)374 public void extension(ExtensionEvent ev) {
375 if (m_traceExtension) {
376 switch (ev.m_callType) {
377 case ExtensionEvent.DEFAULT_CONSTRUCTOR:
378 m_pw.println("EXTENSION: " + ((Class)ev.m_method).getName() + "#<init>");
379 break;
380 case ExtensionEvent.METHOD:
381 m_pw.println("EXTENSION: " + ((Method)ev.m_method).getDeclaringClass().getName() + "#" + ((Method)ev.m_method).getName());
382 break;
383 case ExtensionEvent.CONSTRUCTOR:
384 m_pw.println("EXTENSION: " + ((Constructor)ev.m_method).getDeclaringClass().getName() + "#<init>");
385 break;
386 }
387 }
388 }
389
390
391 /**
392 * Print information about an extension event.
393 *
394 * @param ev the extension event to print information about
395 */
extensionEnd(ExtensionEvent ev)396 public void extensionEnd(ExtensionEvent ev) {
397 // do nothing
398 }
399
400 }
401