001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: TraceManager.java 468644 2006-10-28 06:56:42Z minchau $
020     */
021    package org.apache.xalan.trace;
022    
023    import java.lang.reflect.Method;
024    import java.util.TooManyListenersException;
025    import java.util.Vector;
026    
027    import org.apache.xalan.templates.ElemTemplateElement;
028    import org.apache.xalan.transformer.TransformerImpl;
029    import org.apache.xpath.XPath;
030    import org.apache.xpath.objects.XObject;
031    import org.w3c.dom.Node;
032    
033    /**
034     * This class manages trace listeners, and acts as an
035     * interface for the tracing functionality in Xalan.
036     */
037    public class TraceManager
038    {
039    
040      /** A transformer instance */
041      private TransformerImpl m_transformer;
042    
043      /**
044       * Constructor for the trace manager.
045       *
046       * @param transformer a non-null instance of a transformer
047       */
048      public TraceManager(TransformerImpl transformer)
049      {
050        m_transformer = transformer;
051      }
052    
053      /**
054       * List of listeners who are interested in tracing what's
055       * being generated.
056       */
057      private Vector m_traceListeners = null;
058    
059      /**
060       * Add a trace listener for the purposes of debugging and diagnosis.
061       * @param tl Trace listener to be added.
062       *
063       * @throws TooManyListenersException
064       */
065      public void addTraceListener(TraceListener tl)
066              throws TooManyListenersException
067      {
068    
069        m_transformer.setDebug(true);
070    
071        if (null == m_traceListeners)
072          m_traceListeners = new Vector();
073    
074        m_traceListeners.addElement(tl);
075      }
076    
077      /**
078       * Remove a trace listener.
079       * @param tl Trace listener to be removed.
080       */
081      public void removeTraceListener(TraceListener tl)
082      {
083    
084        if (null != m_traceListeners)
085        {
086          m_traceListeners.removeElement(tl);
087          
088          // The following line added to fix the bug#5140: hasTraceListeners() returns true
089          // after adding and removing a listener.
090          // Check: if m_traceListeners is empty, then set it to NULL.
091          if (0 == m_traceListeners.size()) m_traceListeners = null;
092        }
093      }
094    
095      /**
096       * Fire a generate event.
097       *
098       * @param te Generate Event to fire
099       */
100      public void fireGenerateEvent(GenerateEvent te)
101      {
102    
103        if (null != m_traceListeners)
104        {
105          int nListeners = m_traceListeners.size();
106    
107          for (int i = 0; i < nListeners; i++)
108          {
109            TraceListener tl = (TraceListener) m_traceListeners.elementAt(i);
110    
111            tl.generated(te);
112          }
113        }
114      }
115    
116      /**
117       * Tell if trace listeners are present.
118       *
119       * @return True if there are trace listeners
120       */
121      public boolean hasTraceListeners()
122      {
123        return (null != m_traceListeners);
124      }
125    
126      /**
127       * Fire a trace event.
128       *
129       * @param styleNode Stylesheet template node
130       */
131      public void fireTraceEvent(ElemTemplateElement styleNode)
132      {
133    
134        if (hasTraceListeners())
135        {
136          int sourceNode = m_transformer.getXPathContext().getCurrentNode();
137          Node source = getDOMNodeFromDTM(sourceNode);
138    
139          fireTraceEvent(new TracerEvent(m_transformer, source, 
140                         m_transformer.getMode(),  /*sourceNode, mode,*/
141                                         styleNode));
142        }
143      }
144    
145      /**
146       * Fire a end trace event, after all children of an element have been
147       * executed.
148       *
149       * @param styleNode Stylesheet template node
150       */
151      public void fireTraceEndEvent(ElemTemplateElement styleNode)
152      {
153    
154        if (hasTraceListeners())
155        {
156          int sourceNode = m_transformer.getXPathContext().getCurrentNode();
157          Node source = getDOMNodeFromDTM(sourceNode);
158    
159          fireTraceEndEvent(new TracerEvent(m_transformer, source,
160                         m_transformer.getMode(),  /*sourceNode, mode,*/
161                                         styleNode));
162        }
163      }
164    
165      /**
166       * Fire a trace event.
167       *
168       * @param te Trace event to fire
169       */
170      public void fireTraceEndEvent(TracerEvent te)
171      {
172    
173        if (hasTraceListeners())
174        {
175          int nListeners = m_traceListeners.size();
176    
177          for (int i = 0; i < nListeners; i++)
178          {
179            TraceListener tl = (TraceListener) m_traceListeners.elementAt(i);
180            if(tl instanceof TraceListenerEx2)
181            {
182              ((TraceListenerEx2)tl).traceEnd(te);
183            }
184          }
185        }
186      }
187    
188    
189    
190      /**
191       * Fire a trace event.
192       *
193       * @param te Trace event to fire
194       */
195      public void fireTraceEvent(TracerEvent te)
196      {
197    
198        if (hasTraceListeners())
199        {
200          int nListeners = m_traceListeners.size();
201    
202          for (int i = 0; i < nListeners; i++)
203          {
204            TraceListener tl = (TraceListener) m_traceListeners.elementAt(i);
205    
206            tl.trace(te);
207          }
208        }
209      }
210    
211      /**
212       * Fire a selection event.
213       *
214       * @param sourceNode Current source node
215       * @param styleNode node in the style tree reference for the event.
216       * @param attributeName The attribute name from which the selection is made.
217       * @param xpath The XPath that executed the selection.
218       * @param selection The result of the selection.
219       *
220       * @throws javax.xml.transform.TransformerException
221       */
222      public void fireSelectedEvent(
223              int sourceNode, ElemTemplateElement styleNode, String attributeName, 
224              XPath xpath, XObject selection)
225                throws javax.xml.transform.TransformerException
226      {
227    
228        if (hasTraceListeners())
229        {
230          Node source = getDOMNodeFromDTM(sourceNode);
231            
232          fireSelectedEvent(new SelectionEvent(m_transformer, source, styleNode,
233                                               attributeName, xpath, selection));
234        }
235      }
236      
237      /**
238       * Fire a selection event.
239       *
240       * @param sourceNode Current source node
241       * @param styleNode node in the style tree reference for the event.
242       * @param attributeName The attribute name from which the selection is made.
243       * @param xpath The XPath that executed the selection.
244       * @param selection The result of the selection.
245       *
246       * @throws javax.xml.transform.TransformerException
247       */
248      public void fireSelectedEndEvent(
249              int sourceNode, ElemTemplateElement styleNode, String attributeName, 
250              XPath xpath, XObject selection)
251                throws javax.xml.transform.TransformerException
252      {
253    
254        if (hasTraceListeners())
255        {
256          Node source = getDOMNodeFromDTM(sourceNode);
257            
258          fireSelectedEndEvent(new EndSelectionEvent(m_transformer, source, styleNode,
259                                               attributeName, xpath, selection));
260        }
261      }
262      
263      /**
264       * Fire a selection event.
265       *
266       * @param se Selection event to fire
267       *
268       * @throws javax.xml.transform.TransformerException
269       */
270      public void fireSelectedEndEvent(EndSelectionEvent se)
271              throws javax.xml.transform.TransformerException
272      {
273    
274        if (hasTraceListeners())
275        {
276          int nListeners = m_traceListeners.size();
277    
278          for (int i = 0; i < nListeners; i++)
279          {
280            TraceListener tl = (TraceListener) m_traceListeners.elementAt(i);
281    
282            if(tl instanceof TraceListenerEx)
283              ((TraceListenerEx)tl).selectEnd(se);
284          }
285        }
286      }
287    
288      /**
289       * Fire a selection event.
290       *
291       * @param se Selection event to fire
292       *
293       * @throws javax.xml.transform.TransformerException
294       */
295      public void fireSelectedEvent(SelectionEvent se)
296              throws javax.xml.transform.TransformerException
297      {
298    
299        if (hasTraceListeners())
300        {
301          int nListeners = m_traceListeners.size();
302    
303          for (int i = 0; i < nListeners; i++)
304          {
305            TraceListener tl = (TraceListener) m_traceListeners.elementAt(i);
306    
307            tl.selected(se);
308          }
309        }
310      }
311      
312    
313      /**
314       * Fire an end extension event.
315       *
316       * @see java.lang.reflect.Method#invoke
317       * 
318       * @param method The java method about to be executed
319       * @param instance The instance the method will be executed on
320       * @param arguments Parameters passed to the method.
321       */
322      public void fireExtensionEndEvent(Method method, Object instance, Object[] arguments)
323      {
324          ExtensionEvent ee = new ExtensionEvent(m_transformer, method, instance, arguments);
325    
326        if (hasTraceListeners())
327        {
328          int nListeners = m_traceListeners.size();
329    
330          for (int i = 0; i < nListeners; i++)
331          {
332            TraceListener tl = (TraceListener) m_traceListeners.elementAt(i);
333            if(tl instanceof TraceListenerEx3)
334            {
335              ((TraceListenerEx3)tl).extensionEnd(ee);
336            }
337          }
338        }
339      }
340    
341      /**
342       * Fire an end extension event.
343       *
344       * @see java.lang.reflect.Method#invoke
345       * 
346       * @param method The java method about to be executed
347       * @param instance The instance the method will be executed on
348       * @param arguments Parameters passed to the method.
349       */
350      public void fireExtensionEvent(Method method, Object instance, Object[] arguments)
351      {
352        ExtensionEvent ee = new ExtensionEvent(m_transformer, method, instance, arguments);
353    
354        if (hasTraceListeners())
355        {
356          int nListeners = m_traceListeners.size();
357    
358          for (int i = 0; i < nListeners; i++)
359          {
360            TraceListener tl = (TraceListener) m_traceListeners.elementAt(i);
361            if(tl instanceof TraceListenerEx3)
362            {
363              ((TraceListenerEx3)tl).extension(ee);
364            }
365          }
366        }
367      }
368    
369      /**
370       * Fire an end extension event.
371       *
372       * @see java.lang.reflect.Method#invoke
373       * 
374       * @param ee the ExtensionEvent to fire
375       */
376      public void fireExtensionEndEvent(ExtensionEvent ee)
377      {
378        if (hasTraceListeners())
379        {
380          int nListeners = m_traceListeners.size();
381    
382          for (int i = 0; i < nListeners; i++)
383          {
384            TraceListener tl = (TraceListener) m_traceListeners.elementAt(i);
385            if(tl instanceof TraceListenerEx3)
386            {
387              ((TraceListenerEx3)tl).extensionEnd(ee);
388            }
389          }
390        }
391      }
392    
393      /**
394       * Fire an end extension event.
395       *
396       * @see java.lang.reflect.Method#invoke
397       * 
398       * @param ee the ExtensionEvent to fire
399       */
400      public void fireExtensionEvent(ExtensionEvent ee)
401      {    
402          
403        if (hasTraceListeners())
404        {
405          int nListeners = m_traceListeners.size();
406    
407          for (int i = 0; i < nListeners; i++)
408          {
409            TraceListener tl = (TraceListener) m_traceListeners.elementAt(i);
410            if(tl instanceof TraceListenerEx3)
411            {
412              ((TraceListenerEx3)tl).extension(ee);
413            }
414          }
415        }
416      }
417      
418      /**
419       * Get the DOM Node of the current XPath context, which is possibly null.
420       * @param sourceNode the handle on the node used by a DTM.
421       */
422      private Node getDOMNodeFromDTM(int sourceNode) {
423        org.apache.xml.dtm.DTM dtm = m_transformer.getXPathContext().getDTM(sourceNode);
424        final Node source = (dtm == null) ? null : dtm.getNode(sourceNode);
425        return source;
426      }
427    }