001 /*
002 *
003 * $Revision: 15201 $ $Date: 2009-05-15 16:49:11 +0200 (Fri, 15 May 2009) $
004 *
005 * This file is part of *** M y C o R e ***
006 * See http://www.mycore.de/ for details.
007 *
008 * This program is free software; you can use it, redistribute it
009 * and / or modify it under the terms of the GNU General Public License
010 * (GPL) as published by the Free Software Foundation; either version 2
011 * of the License or (at your option) any later version.
012 *
013 * This program is distributed in the hope that it will be useful, but
014 * WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program, in a file called gpl.txt or license.txt.
020 * If not, write to the Free Software Foundation Inc.,
021 * 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
022 */
023
024 package org.mycore.common.xml;
025
026 import java.io.ByteArrayInputStream;
027 import java.io.ByteArrayOutputStream;
028 import java.io.File;
029 import java.io.FileInputStream;
030 import java.io.IOException;
031 import java.io.InputStream;
032 import java.io.OutputStream;
033 import java.io.Writer;
034 import java.util.Enumeration;
035 import java.util.Hashtable;
036 import java.util.List;
037 import java.util.Map;
038 import java.util.Properties;
039 import java.util.StringTokenizer;
040
041 import javax.servlet.http.HttpServletRequest;
042 import javax.servlet.http.HttpServletResponse;
043 import javax.servlet.http.HttpSession;
044 import javax.xml.transform.ErrorListener;
045 import javax.xml.transform.Result;
046 import javax.xml.transform.Source;
047 import javax.xml.transform.SourceLocator;
048 import javax.xml.transform.Templates;
049 import javax.xml.transform.Transformer;
050 import javax.xml.transform.TransformerConfigurationException;
051 import javax.xml.transform.TransformerException;
052 import javax.xml.transform.TransformerFactory;
053 import javax.xml.transform.dom.DOMSource;
054 import javax.xml.transform.sax.SAXResult;
055 import javax.xml.transform.sax.SAXTransformerFactory;
056 import javax.xml.transform.stream.StreamResult;
057 import javax.xml.transform.stream.StreamSource;
058
059 import org.apache.avalon.framework.logger.Log4JLogger;
060 import org.apache.fop.apps.Driver;
061 import org.apache.fop.messaging.MessageHandler;
062 import org.apache.log4j.Logger;
063 import org.apache.xalan.templates.ElemTemplate;
064 import org.apache.xalan.templates.ElemTemplateElement;
065 import org.apache.xalan.trace.GenerateEvent;
066 import org.apache.xalan.trace.SelectionEvent;
067 import org.apache.xalan.trace.TraceManager;
068 import org.apache.xalan.trace.TracerEvent;
069 import org.apache.xml.utils.WrappedRuntimeException;
070 import org.jdom.Document;
071 import org.jdom.transform.JDOMResult;
072 import org.jdom.transform.JDOMSource;
073 import org.mycore.common.MCRCache;
074 import org.mycore.common.MCRConfiguration;
075 import org.mycore.common.MCRConfigurationException;
076 import org.mycore.common.MCRException;
077 import org.mycore.common.MCRSession;
078 import org.mycore.common.MCRSessionMgr;
079 import org.mycore.common.MCRUtils;
080 import org.mycore.datamodel.ifs.MCRContentInputStream;
081 import org.mycore.frontend.servlets.MCRServlet;
082 import org.mycore.frontend.servlets.MCRServletJob;
083 import org.mycore.user.MCRUser;
084 import org.mycore.user.MCRUserMgr;
085 import org.w3c.dom.Node;
086 import org.xml.sax.SAXException;
087
088 /**
089 * Does the layout for other MyCoRe servlets by transforming XML input to
090 * various output formats, using XSL stylesheets.
091 *
092 * @author Frank L�tzenkirchen
093 * @author Thomas Scheffler (yagee)
094 *
095 * @version $Revision: 15201 $ $Date: 2008-05-21 15:53:52 +0200 (Mi, 21. Mai
096 * 2008) $
097 */
098 public class MCRLayoutService implements org.apache.xalan.trace.TraceListener {
099
100 /** A cache of already compiled stylesheets */
101 private static MCRCache STYLESHEETS_CACHE = new MCRCache(MCRConfiguration.instance().getInt("MCR.LayoutService.XSLCacheSize", 100),
102 "XSLT Stylesheets");
103
104 private static MCRXMLResource XML_RESOURCE = MCRXMLResource.instance();
105
106 /** The XSL transformer factory to use */
107 private SAXTransformerFactory factory;
108
109 /** The logger */
110 private final static Logger LOGGER = Logger.getLogger(MCRLayoutService.class);
111
112 private final static org.apache.avalon.framework.logger.Logger FOPLOG = new Log4JLogger(LOGGER);
113
114 private static final MCRLayoutService singleton = new MCRLayoutService();
115
116 public static MCRLayoutService instance() {
117 return singleton;
118 }
119
120 private MCRLayoutService() {
121 // System.setProperty("javax.xml.transform.TransformerFactory",
122 // "org.apache.xalan.xsltc.trax.TransformerFactoryImpl");
123 System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
124 TransformerFactory tf = TransformerFactory.newInstance();
125 LOGGER.info("Transformerfactory: " + tf.getClass().getName());
126
127 if (!tf.getFeature(SAXTransformerFactory.FEATURE)) {
128 throw new MCRConfigurationException("Could not load a SAXTransformerFactory for use with XSLT");
129 }
130
131 factory = (SAXTransformerFactory) (tf);
132 factory.setURIResolver(MCRURIResolver.instance());
133 factory.setErrorListener(new ErrorListener() {
134 public void error(TransformerException ex) {
135 throw new MCRException("Error in transformer factory", ex);
136 }
137
138 public void fatalError(TransformerException ex) {
139 throw new MCRException("Fatal error in transformer factory", ex);
140 }
141
142 public void warning(TransformerException ex) {
143 LOGGER.warn(ex.getMessageAndLocation());
144 }
145 });
146
147 MessageHandler.setScreenLogger(FOPLOG);
148 }
149
150 public void sendXML(HttpServletRequest req, HttpServletResponse res, org.jdom.Document jdom) throws IOException {
151 res.setContentType("text/xml");
152 OutputStream out = res.getOutputStream();
153 new org.jdom.output.XMLOutputter().output(jdom, out);
154 out.close();
155 }
156
157 public void sendXML(HttpServletRequest req, HttpServletResponse res, org.w3c.dom.Document dom) throws IOException {
158 sendXML(req, res, new org.jdom.input.DOMBuilder().build(dom));
159 }
160
161 public void sendXML(HttpServletRequest req, HttpServletResponse res, InputStream in) throws IOException {
162 res.setContentType("text/xml");
163 OutputStream out = res.getOutputStream();
164 MCRUtils.copyStream(in, out);
165 out.close();
166 }
167
168 public void sendXML(HttpServletRequest req, HttpServletResponse res, File file) throws IOException {
169 FileInputStream fis = new FileInputStream(file);
170 sendXML(req, res, fis);
171 fis.close();
172 }
173
174 public void doLayout(HttpServletRequest req, HttpServletResponse res, org.jdom.Document jdom) throws IOException {
175 String docType = (jdom.getDocType() == null ? jdom.getRootElement().getName() : jdom.getDocType().getElementName());
176 Properties parameters = buildXSLParameters(req);
177 String resourceName = getResourceName(req, parameters, docType);
178 if (resourceName == null)
179 sendXML(req, res, jdom);
180 else
181 transform(res, new org.jdom.transform.JDOMSource(jdom), docType, parameters, resourceName);
182 }
183
184 /**
185 * writes the transformation result directly into the Writer uses the
186 * HttpServletResponse only for error messages
187 */
188 public void doLayout(HttpServletRequest req, HttpServletResponse res, Writer out, org.jdom.Document jdom) throws IOException {
189 String docType = (jdom.getDocType() == null ? jdom.getRootElement().getName() : jdom.getDocType().getElementName());
190 Properties parameters = buildXSLParameters(req);
191 String resourceName = getResourceName(req, parameters, docType);
192 if (resourceName == null)
193 new org.jdom.output.XMLOutputter().output(jdom, out);
194 else {
195 Templates stylesheet = buildCompiledStylesheet(resourceName);
196 Transformer transformer = buildTransformer(stylesheet);
197 setXSLParameters(transformer, parameters);
198 try {
199 transformer.transform(new org.jdom.transform.JDOMSource(jdom), new StreamResult(out));
200 } catch (TransformerException ex) {
201 String msg = "Error while transforming XML using XSL stylesheet: " + ex.getMessageAndLocation();
202 throw new MCRException(msg, ex);
203 } catch (MCRException ex) {
204 // Check if it is an error page to suppress later recursively
205 // generating an error page when there is an error in the
206 // stylesheet
207 if (!"mcr_error".equals(docType))
208 throw ex;
209 String msg = "Error while generating error page!";
210 LOGGER.warn(msg, ex);
211 res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
212 }
213 }
214 }
215
216 public void doLayout(HttpServletRequest req, HttpServletResponse res, org.w3c.dom.Document dom) throws IOException {
217 String docType = (dom.getDoctype() == null ? dom.getDocumentElement().getTagName() : dom.getDoctype().getName());
218 Properties parameters = buildXSLParameters(req);
219 String resourceName = getResourceName(req, parameters, docType);
220 if (resourceName == null)
221 sendXML(req, res, dom);
222 else
223 transform(res, new DOMSource(dom), docType, parameters, resourceName);
224 }
225
226 public void doLayout(HttpServletRequest req, HttpServletResponse res, InputStream is) throws IOException {
227 MCRContentInputStream cis = new MCRContentInputStream(is);
228 String docType = MCRUtils.parseDocumentType(new ByteArrayInputStream(cis.getHeader()));
229
230 Properties parameters = buildXSLParameters(req);
231 String resourceName = getResourceName(req, parameters, docType);
232 if (resourceName == null)
233 sendXML(req, res, cis);
234 else
235 transform(res, new StreamSource(cis), docType, parameters, resourceName);
236 }
237
238 public void doLayout(HttpServletRequest req, HttpServletResponse res, File file) throws IOException {
239 FileInputStream fis = new FileInputStream(file);
240 doLayout(req, res, fis);
241 fis.close();
242 }
243
244 public Document doLayout(Document doc, String stylesheetName, Hashtable<String, String> params) throws Exception {
245 MCRSession mcrSession = MCRSessionMgr.getCurrentSession();
246 MCRServletJob job = (MCRServletJob) mcrSession.get("MCRServletJob");
247 Templates stylesheet = buildCompiledStylesheet(stylesheetName);
248 Transformer transformer = buildTransformer(stylesheet);
249 Properties parameters = new Properties();
250 if (job != null) {
251 parameters = buildXSLParameters(job.getRequest());
252 if (null != params)
253 parameters = new Properties();
254 }
255 setXSLParameters(transformer, parameters);
256 JDOMResult out = new JDOMResult();
257 transformer.transform(new JDOMSource(doc), out);
258 return out.getDocument();
259 }
260
261 private void transform(HttpServletResponse res, Source sourceXML, String docType, Properties parameters, Templates stylesheet)
262 throws IOException {
263 Transformer transformer = buildTransformer(stylesheet);
264 setXSLParameters(transformer, parameters);
265
266 try {
267 transform(sourceXML, stylesheet, transformer, res);
268 } catch (IOException ex) {
269 LOGGER.error("IOException while XSL-transforming XML document", ex);
270 } catch (MCRException ex) {
271 // Check if it is an error page to suppress later recursively
272 // generating an error page when there is an error in the stylesheet
273 if (!"mcr_error".equals(docType))
274 throw ex;
275
276 String msg = "Error while generating error page!";
277 LOGGER.warn(msg, ex);
278 res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
279 }
280 }
281
282 private void transform(HttpServletResponse res, Source sourceXML, String docType, Properties parameters, String resourceName)
283 throws IOException {
284 Templates stylesheet = buildCompiledStylesheet(resourceName);
285 transform(res, sourceXML, docType, parameters, stylesheet);
286 }
287
288 private String getResourceName(HttpServletRequest req, Properties parameters, String docType) {
289 String style = parameters.getProperty("Style", "default");
290 LOGGER.debug("MCRLayoutService using style " + style);
291
292 String styleName = buildStylesheetName(docType, style);
293 boolean resourceExist = false;
294 try {
295 resourceExist = XML_RESOURCE.exists(styleName, this.getClass().getClassLoader());
296 if (resourceExist) {
297 return styleName;
298 }
299 } catch (Exception e) {
300 throw new MCRException("Error while loading stylesheet: " + styleName, e);
301 }
302
303 // If no stylesheet exists, forward raw xml instead
304 // You can transform raw xml code by providing a stylesheed named
305 // [doctype]-xml.xsl now
306 if (style.equals("xml") || style.equals("default"))
307 return null;
308 throw new MCRException("XSL stylesheet not found: " + styleName);
309 }
310
311 public static Properties buildXSLParameters(HttpServletRequest request) {
312 // PROPERTIES: Read all properties from system configuration
313 Properties parameters = (Properties) (MCRConfiguration.instance().getProperties().clone());
314 // added properties of MCRSession and request
315 if (request != null) {
316 parameters.putAll(mergeProperties(request));
317
318 // handle HttpSession
319 HttpSession session = request.getSession(false);
320 if (session != null) {
321 String jSessionID = MCRConfiguration.instance().getString("MCR.Session.Param", ";jsessionid=");
322 if (!request.isRequestedSessionIdFromCookie()) {
323 parameters.put("HttpSession", jSessionID + session.getId());
324 }
325 parameters.put("JSessionID", jSessionID + session.getId());
326 }
327 }
328
329 String uid = MCRSessionMgr.getCurrentSession().getCurrentUserID();
330
331 boolean setCurrentGroups = MCRConfiguration.instance().getBoolean("MCR.Users.SetCurrentGroups", true);
332 if (setCurrentGroups) { // for MyCoRe applications, always true
333 final MCRUser mcrUser = MCRUserMgr.instance().retrieveUser(uid);
334 StringBuffer groups = new StringBuffer(mcrUser.getPrimaryGroupID());
335 List<String> groupList = mcrUser.getGroupIDs();
336 for (int i = 0; i < groupList.size(); i++) {
337 if (i != 0)
338 groups.append(' ');
339 groups.append((String) groupList.get(i));
340 }
341 parameters.put("CurrentGroups", groups.toString());
342 }
343
344 MCRSession mcrSession = MCRSessionMgr.getCurrentSession();
345
346 // set parameters
347 parameters.put("CurrentUser", uid);
348 parameters.put("DefaultLang", MCRConfiguration.instance().getString("MCR.Metadata.DefaultLang", "en"));
349 parameters.put("CurrentLang", mcrSession.getCurrentLanguage());
350 parameters.put("WebApplicationBaseURL", MCRServlet.getBaseURL());
351 parameters.put("ServletsBaseURL", MCRServlet.getServletBaseURL());
352
353 if (request != null) {
354 parameters.put("RequestURL", getCompleteURL(request));
355 parameters.put("Referer", (request.getHeader("Referer") != null) ? request.getHeader("Referer") : "");
356 }
357
358 LOGGER.debug("LayoutServlet XSL.MCRSessionID=" + parameters.getProperty("MCRSessionID"));
359 LOGGER.debug("LayoutServlet XSL.CurrentUser =" + mcrSession.getCurrentUserID());
360 LOGGER.debug("LayoutServlet HttpSession =" + parameters.getProperty("HttpSession"));
361 LOGGER.debug("LayoutServlet JSessionID =" + parameters.getProperty("JSessionID"));
362 LOGGER.debug("LayoutServlet RefererURL =" + parameters.getProperty("Referer"));
363
364 return parameters;
365 }
366
367 /**
368 * returns a merged list of XSL parameters.
369 *
370 * First parameters stored in current HttpSession are used. These are
371 * overwritten by Parameters of MCRSession. Finally parameters, then
372 * attributes of HttpServletRequest overwrite the previously defined.
373 *
374 * @param request
375 * @return merged XSL.* properties of MCR|HttpSession and HttpServletRequest
376 */
377 private final static Properties mergeProperties(HttpServletRequest request) {
378 Properties props = new Properties();
379
380 HttpSession session = request.getSession(false);
381 MCRSession mcrSession = MCRSessionMgr.getCurrentSession();
382 if (session != null) {
383 for (@SuppressWarnings("unchecked")
384 Enumeration<String> e = session.getAttributeNames(); e.hasMoreElements();) {
385 String name = e.nextElement();
386 if (name.startsWith("XSL."))
387 props.put(name.substring(4), session.getAttribute(name));
388 }
389 }
390 for (Map.Entry<Object, Object> entry : mcrSession.getMapEntries()) {
391 String key = entry.getKey().toString();
392 if (key.startsWith("XSL.")) {
393 props.put(key.substring(4), entry.getValue());
394 }
395 }
396 for (@SuppressWarnings("unchecked")
397 Enumeration<String> e = request.getParameterNames(); e.hasMoreElements();) {
398 String name = e.nextElement();
399 if (name.startsWith("XSL.") && !name.endsWith(".SESSION")) {
400 props.put(name.substring(4), request.getParameter(name));
401 }
402 }
403 for (@SuppressWarnings("unchecked")
404 Enumeration<String> e = request.getAttributeNames(); e.hasMoreElements();) {
405 String name = e.nextElement();
406 if (name.startsWith("XSL.") && !name.endsWith(".SESSION")) {
407 final Object attributeValue = request.getAttribute(name);
408 if (attributeValue != null)
409 props.put(name.substring(4), attributeValue.toString());
410 }
411 }
412 return props;
413 }
414
415 private final static String getCompleteURL(HttpServletRequest request) {
416 StringBuffer buffer = request.getRequestURL();
417 String queryString = request.getQueryString();
418 if (queryString != null && queryString.length() > 0) {
419 buffer.append("?").append(queryString);
420 }
421 LOGGER.debug("Complete request URL : " + buffer.toString());
422 return buffer.toString();
423 }
424
425 /**
426 * Builds the filename of the stylesheet to use, e. g. "playlist-simple.xsl"
427 */
428 private String buildStylesheetName(String docType, String style) {
429 StringBuffer filename = new StringBuffer("xsl/").append(docType);
430
431 if (!"default".equals(style)) {
432 filename.append("-");
433 filename.append(style);
434 }
435
436 filename.append(".xsl");
437
438 return filename.toString();
439 }
440
441 private Templates buildCompiledStylesheet(String resource) {
442 Templates stylesheet = null;
443 try {
444 stylesheet = (Templates) (STYLESHEETS_CACHE.getIfUpToDate(resource, XML_RESOURCE.getLastModified(resource, this.getClass()
445 .getClassLoader())));
446 } catch (IOException e) {
447 LOGGER.warn("Could not determine last modified date of resource " + resource);
448 }
449 if (stylesheet == null) {
450 try {
451 byte[] bytes = XML_RESOURCE.getRawResource(resource, this.getClass().getClassLoader());
452 stylesheet = factory.newTemplates(new StreamSource(new ByteArrayInputStream(bytes)));
453 LOGGER.debug("MCRLayoutService compiled stylesheet resource " + resource);
454 } catch (Exception exc) {
455 reportCompileError(resource, exc);
456 }
457 STYLESHEETS_CACHE.put(resource, stylesheet);
458 } else {
459 LOGGER.debug("MCRLayoutService using cached stylesheet " + resource);
460 }
461
462 return stylesheet;
463 }
464
465 private void reportCompileError(String resource, Exception exc) {
466 StringBuffer msg = new StringBuffer("Error compiling XSL stylesheet ");
467 msg.append(resource);
468
469 while (exc != null) {
470 if (exc instanceof MCRException) {
471 MCRException mex = (MCRException) exc;
472 msg.append("\n").append(mex.getMessage());
473 exc = mex.getException();
474 } else if (exc instanceof TransformerException) {
475 TransformerException tex = (TransformerException) exc;
476 msg.append("\n").append(tex.getMessage());
477 SourceLocator sl = tex.getLocator();
478 if (sl != null)
479 msg.append(" at line ").append(sl.getLineNumber()).append(" column ").append(sl.getColumnNumber());
480
481 if (tex.getCause() instanceof Exception)
482 exc = (Exception) (tex.getCause());
483 else
484 exc = null;
485 } else if (exc instanceof WrappedRuntimeException) {
486 exc = ((WrappedRuntimeException) exc).getException();
487 } else {
488 msg.append("\n").append(exc.getMessage());
489 if (exc.getCause() instanceof Exception)
490 exc = (Exception) (exc.getCause());
491 else
492 exc = null;
493 }
494 }
495
496 LOGGER.error(msg);
497 throw new MCRConfigurationException(msg.toString(), exc);
498 }
499
500 /**
501 * Builds a XSL transformer that uses the given XSL stylesheet
502 *
503 * @param stylesheet
504 * the compiled XSL stylesheet to use
505 * @return the XSL transformer that can be used to do the XSL transformation
506 */
507 private Transformer buildTransformer(Templates stylesheet) {
508 try {
509 Transformer tf = factory.newTransformerHandler(stylesheet).getTransformer();
510
511 // In debug mode, add a TraceListener to log stylesheet execution
512 if (LOGGER.isDebugEnabled()) {
513 try {
514 TraceManager tm = ((org.apache.xalan.transformer.TransformerImpl) tf).getTraceManager();
515 tm.addTraceListener(this);
516
517 } catch (Exception ex) {
518 LOGGER.warn(ex);
519 }
520 }
521
522 return tf;
523 } catch (TransformerConfigurationException exc) {
524 String msg = "Error while building XSL transformer: " + exc.getMessageAndLocation();
525 throw new MCRConfigurationException(msg, exc);
526 }
527 }
528
529 /**
530 * Sets XSL parameters for the given transformer by taking them from the
531 * properties object provided.
532 *
533 * @param transformer
534 * the Transformer object thats parameters should be set
535 * @param parameters
536 * the XSL parameters as name-value pairs
537 */
538 private void setXSLParameters(Transformer transformer, Properties parameters) {
539 Enumeration<?> names = parameters.propertyNames();
540
541 while (names.hasMoreElements()) {
542 String name = names.nextElement().toString();
543 String value = parameters.getProperty(name);
544
545 transformer.setParameter(name, value);
546 }
547 }
548
549 /**
550 * Transforms XML input with the given XSL stylesheet and sends the output
551 * as HTTP Servlet Response to the client browser.
552 *
553 * @param xml
554 * the XML input document
555 * @param xsl
556 * the compiled XSL stylesheet
557 * @param transformer
558 * the XSL transformer to use
559 * @param response
560 * the response object to send the result to
561 */
562 private void transform(Source xml, Templates xsl, Transformer transformer, HttpServletResponse response) throws IOException,
563 MCRException {
564
565 // Set content type from "<xsl:output media-type = "...">
566 // Set char encoding from "<xsl:output encoding = "...">
567 String ct = xsl.getOutputProperties().getProperty("media-type");
568 String enc = xsl.getOutputProperties().getProperty("encoding");
569 response.setCharacterEncoding(enc);
570 response.setContentType(ct + "; charset=" + enc);
571
572 ByteArrayOutputStream out = new ByteArrayOutputStream();
573 Result result = null;
574
575 if ("application/pdf".equals(ct)) {
576 Driver driver = new Driver();
577 driver.setLogger(FOPLOG);
578 driver.setRenderer(Driver.RENDER_PDF);
579 driver.setOutputStream(out);
580 result = new SAXResult(driver.getContentHandler());
581 } else {
582 result = new StreamResult(out);
583 }
584
585 LOGGER.debug("MCRLayoutService starts to output " + response.getContentType());
586
587 try {
588 transformer.transform(xml, result);
589 } catch (TransformerException ex) {
590 String msg = "Error while transforming XML using XSL stylesheet: " + ex.getMessageAndLocation();
591 throw new MCRException(msg, ex);
592 } finally {
593 out.close();
594 }
595
596 OutputStream sos = response.getOutputStream();
597 sos.write(out.toByteArray());
598 sos.close();
599 }
600
601 /**
602 * Traces the execution of xsl stylesheet elements in debug mode. The trace
603 * is written to the log, and in parallel as comment elements to the output
604 * html.
605 */
606 public void trace(TracerEvent ev) {
607 ElemTemplateElement ete = ev.m_styleNode; // Current position in
608 // stylesheet
609
610 StringBuffer log = new StringBuffer();
611
612 // Find the name of the stylesheet file currently processed
613 try {
614 StringTokenizer st = new StringTokenizer(ete.getBaseIdentifier(), "/\\");
615 String stylesheet = null;
616 while (st.hasMoreTokens())
617 stylesheet = st.nextToken();
618 if (stylesheet != null)
619 log.append(" ").append(stylesheet);
620 } catch (Exception ignored) {
621 }
622
623 // Output current line number and column number
624 log.append(" line " + ete.getLineNumber() + " col " + ete.getColumnNumber());
625
626 // Find the name of the xsl:template currently processed
627 try {
628 ElemTemplate et = ev.m_processor.getCurrentTemplate();
629 log.append(" in <xsl:template");
630 if (et.getMatch() != null)
631 log.append(" match=\"" + et.getMatch().getPatternString() + "\"");
632 if (et.getName() != null)
633 log.append(" name=\"" + et.getName().getLocalName() + "\"");
634 if (et.getMode() != null)
635 log.append(" mode=\"" + et.getMode().getLocalName() + "\"");
636 log.append(">");
637 } catch (Exception ignored) {
638 }
639
640 // Output name of the xsl or html element currently processed
641 log.append(" " + ete.getTagName());
642 LOGGER.debug("Trace" + log.toString());
643
644 // Output xpath of current xml source node in context
645 StringBuffer path = new StringBuffer();
646 Node node = ev.m_sourceNode;
647 if (node != null) {
648 path.append(node.getLocalName());
649 while ((node = node.getParentNode()) != null) {
650 path.insert(0, node.getLocalName() + "/");
651 }
652 }
653 if (path.length() > 0) {
654 LOGGER.debug("Source " + path.toString());
655 }
656 try {
657 if ("true".equals(ev.m_processor.getParameter("DEBUG"))) {
658 ev.m_processor.getResultTreeHandler().comment(log.toString() + " ");
659 if (path.length() > 0) {
660 ev.m_processor.getResultTreeHandler().comment(" source " + path.toString() + " ");
661 }
662 }
663 } catch (Exception ignored) {
664 }
665 }
666
667 /**
668 * When a stylesheet generates characters, they will be logged in debug
669 * mode.
670 */
671 public void generated(GenerateEvent ev) {
672 if (ev.m_eventtype == 12)
673 LOGGER.debug("Output " + new String(ev.m_characters, ev.m_start, ev.m_length).trim());
674 }
675
676 /**
677 * When a stylesheet does a selection, like in <xsl:value-of /> or
678 * similar elements, the selection element and xpath is logged in debug
679 * mode.
680 */
681 public void selected(SelectionEvent ev) {
682 String log = "Selection <xsl:" + ev.m_styleNode.getTagName() + " " + ev.m_attributeName + "=\"" + ev.m_xpath.getPatternString()
683 + "\">";
684 LOGGER.debug(log);
685 try {
686 if ("true".equals(ev.m_processor.getParameter("DEBUG")))
687 ev.m_processor.getResultTreeHandler().comment(" " + log + " ");
688 } catch (SAXException ignored) {
689 }
690 }
691 }