Changeset 25603 for main/trunk


Ignore:
Timestamp:
2012-05-15T18:37:43+12:00 (12 years ago)
Author:
sjm84
Message:
  1. Sam discoverd that the TransformerFactory used by XMLConverter could also have XMLConverter's TransformerErrorHandler attached and that this can help point out the line numbers and errors that occur when a TransformerFactory fails to create a new instance of a Transformer object. The code has been adjusted to allow a TransformerErrorListener object to be set on a TransformerFactory, which on detection of error then writes the XSLT stylesheet used to instantiate a Transformer object out to a file. Thereafter, the errorhandler then tries to use the TransformerFactory to reinstantiate a Transformer object with the file version of the XSLT which at least appears to show an error that can be understood now. 2. Sadly more whitespace formatting changes introduced by Eclipse and Notepad.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/XMLTransformer.java

    r25602 r25603  
    5858import org.apache.log4j.*;
    5959
    60 /** XMLTransformer - utility class for greenstone
    61  *
     60/**
     61 * XMLTransformer - utility class for greenstone
     62 *
    6263 * transforms xml using xslt
    63  *
     64 * 
    6465 * @author <a href="mailto:[email protected]">Katherine Don</a>
    6566 * @version $Revision$
    6667 */
    67 public class XMLTransformer {
    68     private static int debugFileCount = 0; // for unique filenames when debugging XML transformations with physical files
    69 
    70     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.XMLTransformer.class.getName());
    71    
    72   /** The transformer factory we're using */
    73     TransformerFactory t_factory=null;
    74  
    75   /**
    76    * The no-arguments constructor.
    77    *
    78    * Any exceptions thrown are caught internally
    79    *
    80    * @see javax.xml.transform.TransformerFactory
    81    */
    82     public XMLTransformer() {
    83     // http://download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/api/index.html?javax/xml/transform/TransformerFactory.html states that
    84     // TransformerFactory.newInstance() looks in jar files for a Factory specified in META-INF/services/javax.xml.transform.TransformerFactory,
    85     // else it will use the "platform default"
    86     // In this case: xalan.jar's META-INF/services/javax.xml.transform.TransformerFactory contains org.apache.xalan.processor.TransformerFactoryImpl
    87     // as required.
    88 
    89     // This means we no longer have to do a System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
    90     // followed by a this.t_factory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
    91     // The System.setProperty step to force the TransformerFactory implementation that gets used, conflicts with
    92     // Fedora (visiting the Greenstone server pages breaks the Greenstone-tomcat hosted Fedora pages) as Fedora
    93     // does not include the xalan.jar and therefore can't then find the xalan TransformerFactory explicitly set.
    94 
    95     // Gone back to forcing use of xalan transformer, since other jars like crimson.jar, which may be on some
    96     // classpaths, could be be chosen as the TransformerFactory implementation over xalan. This is what used to
    97     // give problems before. Instead, have placed copies of the jars that Fedora needs (xalan.jar and serializer.jar
    98     // and the related xsltc.jar which it may need) into packages/tomcat/lib so that it's on the server's classpath
    99     // and will be found by Fedora.
    100 
    101     // make sure we are using the xalan transformer
    102     System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
    103     try {
    104         this.t_factory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
    105         //this.t_factory = TransformerFactory.newInstance();
    106     } catch (Exception e) {
    107         logger.error("exception creating t_factory "+e.getMessage());
    108     }
    109     }
    110 
    111  
    112    
    113   /**
    114    * Transform an XML document using a XSLT stylesheet
    115    *
    116    * @param stylesheet a filename for an XSLT stylesheet
    117    * @param xml_in the XML to be transformed
    118    * @return the transformed XML
    119    */
    120     public String transform(String stylesheet, String xml_in) {
    121    
    122     try {
    123         // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
    124         Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
    125 
    126         // Use the Transformer to transform an XML Source and send the output to a Result object.
    127         StringWriter output = new StringWriter();
    128         StreamSource streamSource = new StreamSource(new StringReader(xml_in));
    129         transformer.setErrorListener(new TransformErrorListener(stylesheet, streamSource));
    130         transformer.transform(streamSource, new StreamResult(output));
    131         return output.toString();
    132     } catch (TransformerConfigurationException e) {
    133         logger.error("couldn't create transformer object: "+e.getMessageAndLocation());
    134         logger.error(e.getLocationAsString()); 
    135         return "";
    136     } catch (TransformerException e) {
    137         logger.error("couldn't transform the source: " + e.getMessageAndLocation());
    138         return "";
    139     }   
    140     }
    141 
    142     public String transformToString(Document stylesheet, Document source) {
    143     return transformToString(stylesheet, source, null);
    144     }
    145    
    146 
    147     public String transformToString(Document stylesheet, Document source, HashMap parameters) {
    148    
    149     try {
    150         // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
    151         Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));
    152         if (parameters != null) {
    153         Set params = parameters.entrySet();
    154         Iterator i = params.iterator();
    155         while (i.hasNext()) {
    156             Map.Entry m = (Map.Entry)i.next();
    157             transformer.setParameter((String)m.getKey(), m.getValue());
    158         }
    159         }
    160         //transformer.setParameter("page_lang", source.getDocumentElement().getAttribute(GSXML.LANG_ATT));
    161 
    162        
    163         // Use the Transformer to transform an XML Source and send the output to a Result object.
    164         StringWriter output = new StringWriter();
    165         DOMSource domSource = new DOMSource(source);
    166 
    167         transformer.setErrorListener(new TransformErrorListener(stylesheet, domSource));
    168         transformer.transform(domSource, new StreamResult(output));
    169         return output.toString();
    170     } catch (TransformerConfigurationException e) {
    171         logger.error("couldn't create transformer object: "+e.getMessageAndLocation());
    172         logger.error(e.getLocationAsString()); 
    173         return "";
    174     } catch (TransformerException e) {
    175         logger.error("couldn't transform the source: " + e.getMessageAndLocation());
    176         return "";
    177     }
    178     }
    179 
    180    
    181 
    182     /**
    183      * Transform an XML document using a XSLT stylesheet,
    184      * but using a DOMResult whose node should be set to the Document donated by resultNode
    185      */
    186     public Node transform_withResultNode(Document stylesheet, Document source, Document resultNode) {
    187         return transform(stylesheet, source, null, null, resultNode);
    188     }
    189 
    190     public Node transform(Document stylesheet, Document source) {
    191         return transform(stylesheet, source, null, null, null);
    192     }
    193    
    194     public Node transform(Document stylesheet, Document source, HashMap parameters) {
    195         return transform(stylesheet, source, parameters, null, null);
    196     }
    197 
    198     public Node transform(Document stylesheet, Document source, HashMap parameters, Document docDocType) {
    199     return transform(stylesheet, source, parameters, docDocType, null);
    200     }
    201 
    202     protected Node transform(Document stylesheet, Document source, HashMap parameters, Document docDocType, Document resultNode) {
    203         try {
     68public class XMLTransformer
     69{
     70    private static int debugFileCount = 0; // for unique filenames when debugging XML transformations with physical files
     71
     72    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.XMLTransformer.class.getName());
     73
     74    /** The transformer factory we're using */
     75    TransformerFactory t_factory = null;
     76
     77    /**
     78     * The no-arguments constructor.
     79     *
     80     * Any exceptions thrown are caught internally
     81     *
     82     * @see javax.xml.transform.TransformerFactory
     83     */
     84    public XMLTransformer()
     85    {
     86        // http://download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/api/index.html?javax/xml/transform/TransformerFactory.html states that
     87        // TransformerFactory.newInstance() looks in jar files for a Factory specified in META-INF/services/javax.xml.transform.TransformerFactory,
     88        // else it will use the "platform default"
     89        // In this case: xalan.jar's META-INF/services/javax.xml.transform.TransformerFactory contains org.apache.xalan.processor.TransformerFactoryImpl
     90        // as required.
     91
     92        // This means we no longer have to do a System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
     93        // followed by a this.t_factory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
     94        // The System.setProperty step to force the TransformerFactory implementation that gets used, conflicts with
     95        // Fedora (visiting the Greenstone server pages breaks the Greenstone-tomcat hosted Fedora pages) as Fedora
     96        // does not include the xalan.jar and therefore can't then find the xalan TransformerFactory explicitly set.
     97
     98        // Gone back to forcing use of xalan transformer, since other jars like crimson.jar, which may be on some
     99        // classpaths, could be be chosen as the TransformerFactory implementation over xalan. This is what used to
     100        // give problems before. Instead, have placed copies of the jars that Fedora needs (xalan.jar and serializer.jar
     101        // and the related xsltc.jar which it may need) into packages/tomcat/lib so that it's on the server's classpath
     102        // and will be found by Fedora.
     103
     104        // make sure we are using the xalan transformer
     105        System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
     106        try
     107        {
     108            this.t_factory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
     109            //this.t_factory = TransformerFactory.newInstance();
     110            this.t_factory.setErrorListener(new TransformErrorListener()); // handle errors in the xml Source used to instantiate transformers
     111        }
     112        catch (Exception e)
     113        {
     114            logger.error("exception creating t_factory " + e.getMessage());
     115        }
     116    }
     117
     118    /**
     119     * Transform an XML document using a XSLT stylesheet
     120     *
     121     * @param stylesheet
     122     *            a filename for an XSLT stylesheet
     123     * @param xml_in
     124     *            the XML to be transformed
     125     * @return the transformed XML
     126     */
     127    public String transform(String stylesheet, String xml_in)
     128    {
     129
     130        try
     131        {
     132            TransformErrorListener transformerErrorListener = (TransformErrorListener)this.t_factory.getErrorListener();
     133            transformerErrorListener.setStylesheet(stylesheet);         
     134            // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
     135            Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
     136
     137            // Use the Transformer to transform an XML Source and send the output to a Result object.
     138            StringWriter output = new StringWriter();
     139            StreamSource streamSource = new StreamSource(new StringReader(xml_in));
     140            transformer.setErrorListener(new TransformErrorListener(stylesheet, streamSource));
     141            transformer.transform(streamSource, new StreamResult(output));
     142            return output.toString();
     143        }
     144        catch (TransformerConfigurationException e)
     145        {
     146            logger.error("couldn't create transformer object: " + e.getMessageAndLocation());
     147            logger.error(e.getLocationAsString());
     148            return "";
     149        }
     150        catch (TransformerException e)
     151        {
     152            logger.error("couldn't transform the source: " + e.getMessageAndLocation());
     153            return "";
     154        }
     155    }
     156
     157    public String transformToString(Document stylesheet, Document source)
     158    {
     159        return transformToString(stylesheet, source, null);
     160    }
     161
     162    public String transformToString(Document stylesheet, Document source, HashMap parameters)
     163    {
     164
     165        try
     166        {
     167            TransformErrorListener transformerErrorListener = (TransformErrorListener)this.t_factory.getErrorListener();
     168            transformerErrorListener.setStylesheet(stylesheet);
    204169            // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
    205170            Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));
    206             logger.info("XMLTransformer transformer is " + transformer);
    207             if (parameters != null) {
     171            if (parameters != null)
     172            {
    208173                Set params = parameters.entrySet();
    209174                Iterator i = params.iterator();
    210                 while (i.hasNext()) {
    211                     Map.Entry m = (Map.Entry)i.next();
    212                     transformer.setParameter((String)m.getKey(), m.getValue());
     175                while (i.hasNext())
     176                {
     177                    Map.Entry m = (Map.Entry) i.next();
     178                    transformer.setParameter((String) m.getKey(), m.getValue());
    213179                }
    214180            }
    215 
     181            //transformer.setParameter("page_lang", source.getDocumentElement().getAttribute(GSXML.LANG_ATT));
     182
     183            // Use the Transformer to transform an XML Source and send the output to a Result object.
     184            StringWriter output = new StringWriter();
     185            DOMSource domSource = new DOMSource(source);
     186
     187            transformer.setErrorListener(new TransformErrorListener(stylesheet, domSource));
     188            transformer.transform(domSource, new StreamResult(output));
     189            return output.toString();
     190        }
     191        catch (TransformerConfigurationException e)
     192        {
     193            logger.error("couldn't create transformer object: " + e.getMessageAndLocation());
     194            logger.error(e.getLocationAsString());
     195            return "";
     196        }
     197        catch (TransformerException e)
     198        {
     199            logger.error("couldn't transform the source: " + e.getMessageAndLocation());
     200            return "";
     201        }
     202    }
     203
     204    /**
     205     * Transform an XML document using a XSLT stylesheet, but using a DOMResult
     206     * whose node should be set to the Document donated by resultNode
     207     */
     208    public Node transform_withResultNode(Document stylesheet, Document source, Document resultNode)
     209    {
     210        return transform(stylesheet, source, null, null, resultNode);
     211    }
     212
     213    public Node transform(Document stylesheet, Document source)
     214    {
     215        return transform(stylesheet, source, null, null, null);
     216    }
     217
     218    public Node transform(Document stylesheet, Document source, HashMap parameters)
     219    {
     220        return transform(stylesheet, source, parameters, null, null);
     221    }
     222
     223    public Node transform(Document stylesheet, Document source, HashMap parameters, Document docDocType)
     224    {
     225        System.err.println("1");
     226        return transform(stylesheet, source, parameters, docDocType, null);
     227    }
     228
     229    protected Node transform(Document stylesheet, Document source, HashMap parameters, Document docDocType, Document resultNode)
     230    {
     231        try
     232        {
     233            System.err.println("1.1");
     234            // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
     235            TransformErrorListener transformerErrorListener = (TransformErrorListener)this.t_factory.getErrorListener();
     236            transformerErrorListener.setStylesheet(stylesheet);
     237            Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));         
     238
     239            System.err.println("1.2");
     240            //logger.info("XMLTransformer transformer is " + transformer); //done in ErrorListener
     241            if (parameters != null)
     242            {
     243                Set params = parameters.entrySet();
     244                Iterator i = params.iterator();
     245                while (i.hasNext())
     246                {
     247                    Map.Entry m = (Map.Entry) i.next();
     248                    transformer.setParameter((String) m.getKey(), m.getValue());
     249                }
     250            }
     251            System.err.println("1.3");
    216252            // When we transform the DOMResult, we need to make sure the result of
    217253            // the transformation has a DocType. For that to happen, we need to create
     
    220256            // that does not contain any doctype (like we use to do before).
    221257            DOMResult result = docDocType == null ? new DOMResult() : new DOMResult(docDocType);
    222             if(resultNode != null) {
    223                 result.setNode(resultNode);
     258            if (resultNode != null)
     259            {
     260                result.setNode(resultNode);
    224261            }
    225262            DOMSource domSource = new DOMSource(source);
     263            System.err.println("2");
    226264            transformer.setErrorListener(new TransformErrorListener(stylesheet, domSource));
     265            System.err.println("4");
    227266            transformer.transform(domSource, result);
     267            System.err.println("5");
    228268            return result.getNode(); // pass the entire document
    229         }
    230         catch (TransformerConfigurationException e) {
    231             return transformError("XMLTransformer.transform(Doc, Doc, HashMap, Doc)"
    232                 + "\ncouldn't create transformer object", e);
    233         }
    234         catch (TransformerException e) {
    235             return transformError("XMLTransformer.transform(Doc, Doc, HashMap, Doc)"
    236                 + "\ncouldn't transform the source", e);
    237         }
    238     }
    239 
    240     public Node transform(File stylesheet, File source) {
    241     return transform(stylesheet, source, null);
    242     }
    243 
    244     // debugAsFile is only to be set to true when either the stylesheet or source parameters
    245     // are not objects of type File. The debugAsFile variable is passed into the
    246     // TransformErrorListener. When set to true, the TransformErrorListener will itself create
    247     // two files containing the stylesheet and source XML, and try to transform the new source
    248     // file with the stylesheet file for debugging purposes.
    249     protected Node transform(File stylesheet, File source, Document docDocType) {
    250     try {
    251         Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
    252         DOMResult result = (docDocType == null) ? new DOMResult() : new DOMResult(docDocType);
    253         StreamSource streamSource = new StreamSource(source);
    254 
    255         transformer.setErrorListener(new TransformErrorListener(stylesheet, streamSource));
    256 
    257         transformer.transform(streamSource, result);
    258         return result.getNode().getFirstChild();
    259     } catch (TransformerConfigurationException e) {
    260             return transformError("XMLTransformer.transform(File, File)"
    261                 + "\ncouldn't create transformer object for files\n"
    262                 + stylesheet + "\n" + source, e);
    263     }
    264     catch (TransformerException e) {
    265         return transformError("XMLTransformer.transform(File, File)"
    266                 + "\ncouldn't transform the source for files\n"
    267                 + stylesheet + "\n" + source, e);
    268     }   
    269     }
    270      
     269        }
     270        catch (TransformerConfigurationException e)
     271        {
     272            return transformError("XMLTransformer.transform(Doc, Doc, HashMap, Doc)" + "\ncouldn't create transformer object", e);
     273        }
     274        catch (TransformerException e)
     275        {
     276            return transformError("XMLTransformer.transform(Doc, Doc, HashMap, Doc)" + "\ncouldn't transform the source", e);
     277        }
     278    }
     279
     280    public Node transform(File stylesheet, File source)
     281    {
     282        return transform(stylesheet, source, null);
     283    }
     284
     285    // debugAsFile is only to be set to true when either the stylesheet or source parameters
     286    // are not objects of type File. The debugAsFile variable is passed into the
     287    // TransformErrorListener. When set to true, the TransformErrorListener will itself create
     288    // two files containing the stylesheet and source XML, and try to transform the new source
     289    // file with the stylesheet file for debugging purposes.
     290    protected Node transform(File stylesheet, File source, Document docDocType)
     291    {
     292        try
     293        {
     294            TransformErrorListener transformerErrorListener = (TransformErrorListener)this.t_factory.getErrorListener();
     295            transformerErrorListener.setStylesheet(stylesheet);
     296            Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
     297            DOMResult result = (docDocType == null) ? new DOMResult() : new DOMResult(docDocType);
     298            StreamSource streamSource = new StreamSource(source);
     299
     300            transformer.setErrorListener(new TransformErrorListener(stylesheet, streamSource));
     301
     302            transformer.transform(streamSource, result);
     303            return result.getNode().getFirstChild();
     304        }
     305        catch (TransformerConfigurationException e)
     306        {
     307            return transformError("XMLTransformer.transform(File, File)" + "\ncouldn't create transformer object for files\n" + stylesheet + "\n" + source, e);
     308        }
     309        catch (TransformerException e)
     310        {
     311            return transformError("XMLTransformer.transform(File, File)" + "\ncouldn't transform the source for files\n" + stylesheet + "\n" + source, e);
     312        }
     313    }
     314
    271315    // Given a heading string on the sort of transformation error that occurred and the exception object itself,
    272316    // this method prints the exception to the tomcat window (system.err) and the greenstone log and then returns
    273317    // an xhtml error page that is constructed from it.
    274     protected Node transformError(String heading, TransformerException e) {
     318    protected Node transformError(String heading, TransformerException e)
     319    {
    275320        String message = heading + "\n" + e.getMessage();
    276321        logger.error(heading + ": " + e.getMessage());
    277        
    278         String location = e.getLocationAsString();     
    279         if(location != null) {
     322
     323        String location = e.getLocationAsString();
     324        if (location != null)
     325        {
    280326            logger.error(location);
    281327            message = message + "\n" + location;
     
    284330        return constructErrorXHTMLPage(message);
    285331    }
    286    
     332
    287333    // Given an error message, splits it into separate lines based on any newlines present and generates an xhtml page
    288334    // (xml Element)  with paragraphs for each line. This is then returned so that it can be displayed in the browser.
    289     public static Element constructErrorXHTMLPage(String message) {
    290         try{
     335    public static Element constructErrorXHTMLPage(String message)
     336    {
     337        try
     338        {
    291339            String[] lines = message.split("\n");
    292        
    293             Document xhtmlDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
    294             // <html></html>
    295             Node htmlNode = xhtmlDoc.createElement("html");
    296             xhtmlDoc.appendChild(htmlNode);
    297             // <head></head>
    298             Node headNode = xhtmlDoc.createElement("head");
    299             htmlNode.appendChild(headNode);
    300             // <title></title>
    301             Node titleNode = xhtmlDoc.createElement("title");
    302             headNode.appendChild(titleNode);
    303             Node titleString = xhtmlDoc.createTextNode("Error occurred");
    304             titleNode.appendChild(titleString);
    305            
    306             // <body></body>
    307             Node bodyNode = xhtmlDoc.createElement("body");
    308             htmlNode.appendChild(bodyNode);
    309            
    310             // finally put the message in the body
    311             Node h1Node = xhtmlDoc.createElement("h1");
    312             bodyNode.appendChild(h1Node);
    313             Node headingString = xhtmlDoc.createTextNode("The following error occurred:");
    314             h1Node.appendChild(headingString);
    315            
    316             //Node textNode = xhtmlDoc.createTextNode(message);
    317             //bodyNode.appendChild(textNode);
    318            
    319             for (int i = 0; i < lines.length; i++) {
     340
     341            Document xhtmlDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
     342            // <html></html>
     343            Node htmlNode = xhtmlDoc.createElement("html");
     344            xhtmlDoc.appendChild(htmlNode);
     345            // <head></head>
     346            Node headNode = xhtmlDoc.createElement("head");
     347            htmlNode.appendChild(headNode);
     348            // <title></title>
     349            Node titleNode = xhtmlDoc.createElement("title");
     350            headNode.appendChild(titleNode);
     351            Node titleString = xhtmlDoc.createTextNode("Error occurred");
     352            titleNode.appendChild(titleString);
     353
     354            // <body></body>
     355            Node bodyNode = xhtmlDoc.createElement("body");
     356            htmlNode.appendChild(bodyNode);
     357
     358            // finally put the message in the body
     359            Node h1Node = xhtmlDoc.createElement("h1");
     360            bodyNode.appendChild(h1Node);
     361            Node headingString = xhtmlDoc.createTextNode("The following error occurred:");
     362            h1Node.appendChild(headingString);
     363
     364            //Node textNode = xhtmlDoc.createTextNode(message);
     365            //bodyNode.appendChild(textNode);
     366
     367            for (int i = 0; i < lines.length; i++)
     368            {
    320369                Node pNode = xhtmlDoc.createElement("p");
    321370                Node textNode = xhtmlDoc.createTextNode(lines[i]);
     
    323372                bodyNode.appendChild(pNode);
    324373            }
     374
     375            return xhtmlDoc.getDocumentElement();
     376
     377        }
     378        catch (Exception e)
     379        {
     380            String errmsg = "Exception trying to construct error xhtml page from message: " + message + "\n" + e.getMessage();
     381            System.err.println(errmsg);
     382            logger.error(errmsg);
     383            return null;
     384        }
     385    }
     386
     387    // ErrorListener class for both Transformer objects and TransformerFactory objects.
     388    // This class can be used to register a handler for any fatal errors, errors and warnings that
     389    // may occur when either transforming an xml file with an xslt stylesheet using the XMLTransformer,
     390    // or when instantiating a Transformer object using the XMLTransformer's TransformerFactory member var.
     391    // The latter case occurs when the xml Source used to instantiate a Transformer from a TransformerFactory
     392    // is invalid in some manner, which results in a null Transformer object. However, as no
     393    // TransformerConfigurationException or TransformerException are thrown in this case, the errors
     394    // would have not been noticed until things go wrong later when trying to use the (null) Transformer.
     395    //
     396    // The errors caught by this ErrorListener class are printed both to the greenstone.log and to the
     397    // tomcat console (System.err), and the error message is stored in the errorMessage variable so that
     398    // it can be retrieved and be used to generate an xhtml error page.
     399    public class TransformErrorListener implements ErrorListener
     400    {
     401        protected String errorMessage = null;
     402        protected String stylesheet = null;
     403        protected Source source = null; // can be DOMSource or StreamSource
     404        protected boolean debugAsFile = true; // true if xslt or source are not real physical files
     405       
     406        // *********** METHODS TO BE CALLED WHEN SETTING AN ERROR LISTENER ON TRANSFORMERFACTORY OBJECTS
     407        // The default constructor is only for when setting an ErrorListener on TransformerFactory objects
     408        public TransformErrorListener() {
     409            this.stylesheet = null;
     410            this.source = null;
     411            XMLTransformer.debugFileCount++;
     412        }
     413       
     414        public void setStylesheet(Document xslt)
     415        {
     416            this.debugAsFile = true;
     417            this.stylesheet = GSXML.elementToString(xslt.getDocumentElement(), true);
     418            this.source = null;
     419        }
     420       
     421        public void setStylesheet(String xslt)
     422        {
     423            this.debugAsFile = true;
     424            this.stylesheet = xslt;
     425            this.source = null;
     426        }
     427       
     428        public void setStylesheet(File xslt)
     429        {
     430            this.debugAsFile = false; // if this constructor is called, we're dealing with physical files for both xslt and source         
     431            this.stylesheet = xslt.getAbsolutePath();
     432            this.source = null;
     433        }
     434
     435        // *********** METHODS TO BE CALLED WHEN SETTING AN ERROR LISTENER ON TRANSFORMERFACTORY OBJECTS
     436        // When setting an ErrorListener on Transformer object, the ErrorListener takes a Stylesheet xslt and a Source
     437        public TransformErrorListener(String xslt, Source source)
     438        {
     439            this.stylesheet = xslt;
     440            this.source = source;
     441            XMLTransformer.debugFileCount++;
     442        }
     443
     444        public TransformErrorListener(Document xslt, Source source)
     445        {
     446            this.stylesheet = GSXML.elementToString(xslt.getDocumentElement(), true);
     447            this.source = source;
     448            XMLTransformer.debugFileCount++;
     449        }
     450
     451        public TransformErrorListener(File xslt, Source source)
     452        {
     453            this.debugAsFile = false; // if this constructor is called, we're dealing with physical files for both xslt and source
     454            this.source = source;
     455            this.stylesheet = xslt.getAbsolutePath(); // not necessary to get the string from the file
     456            // all we were going to do with it *on error* was write it out to a file anyway     
     457        }
     458
     459        // *********** METHODS CALLED AUTOMATICALLY ON ERROR
     460       
     461        //  Receive notification of a recoverable error.
     462        public void error(TransformerException exception)
     463        {
     464            handleError("Error:\n", exception);
     465        }
     466
     467        // Receive notification of a non-recoverable error.
     468        public void fatalError(TransformerException exception)
     469        {
     470            handleError("Fatal Error:\n", exception);
     471        }
     472
     473        // Receive notification of a warning.
     474        public void warning(TransformerException exception)
     475        {
     476            handleError("Warning:\n", exception);
     477        }
     478
     479        public String toString(TransformerException e)
     480        {
     481            String msg = "Exception encountered was:\n\t";
     482            String location = e.getLocationAsString();
     483            if (location != null)
     484            {
     485                msg = msg + "Location: " + location + "\n\t";
     486            }
     487
     488            return msg + "Message: " + e.getMessage();
     489        }
     490
     491        // clears the errorPage variable after the first call to this method
     492        public String getErrorMessage()
     493        {
     494            String errMsg = this.errorMessage;
     495            if (this.errorMessage != null)
     496            {
     497                this.errorMessage = null;
     498            }
     499            return errMsg;
     500        }
     501
     502        // sets the errorMessage member variable to the data stored in the exception
     503        // and writes the errorMessage to the logger and tomcat's System.err
     504        protected void handleError(String errorType, TransformerException exception)
     505        {
     506
     507            this.errorMessage = errorType + toString(exception);
     508
     509            // If either the stylesheet or the source to be transformed with it were not files,
     510            // so that the transformation was performed in-memory, then the "location" information
     511            // during the error handling (if any) wouldn't have been helpful.
     512            // To allow proper debugging, we write both stylesheet and source out as physical files
     513            // and perform the same transformation again, so that when a transformation error does
     514            // occur, the files are not in-memory but can be viewed, and any location information
     515            // for the error given by the ErrorListener will be sensible (instead of the unhelpful
     516            // "line#0 column#0 in file://somewhere/dummy.xsl").
     517            // Note that if the stylesheet and the source it is to transform were both physical
     518            // files to start off with, we will not need to perform the same transformation again
     519            // since the error reporting would have provided accurate locations for those.
     520            if (debugAsFile)
     521            {
     522
     523                performTransformWithPhysicalFiles(); // will give accurate line numbers
     524
     525                // No need to print out the current error message (seen in the Else statement below),
     526                // as the recursive call to XMLTransformer.transform(File, File, false) in method
     527                // performTransformWithPhysicalFiles() will do this for us.
     528            }
     529            else
     530            {
     531                // printing out the error message
     532                // since !debugAsFile, we are dealing with physical files,
     533                // variable stylesheet would have stored the filename instead of contents
     534                this.errorMessage = this.errorMessage + "\nstylesheet filename: " + stylesheet;             
     535               
     536                this.errorMessage += "\nException CAUSE:\n" + exception.getCause();
     537                System.err.println("\n****Error transforming xml:\n" + this.errorMessage + "\n****\n");
     538                //System.err.println("Stylesheet was:\n + this.stylesheet + "************END STYLESHEET***********\n\n");           
     539
     540                logger.error(this.errorMessage);
     541
     542                // now print out the source to a file, and run the stylesheet on it using a transform()
     543                // then any error will be referring to one of these two input files.
     544            }
     545        }
     546       
     547        // This method will redo the transformation that went wrong with *real* files:
     548        // it writes out the stylesheet and source XML to files first, then performs the transformation
     549        // to get the actual line location of where things went wrong (instead of "line#0 column#0 in dummy.xsl")
     550        protected void performTransformWithPhysicalFiles()
     551        {
     552            File webLogsTmpFolder = new File(GlobalProperties.getGSDL3Home() + File.separator + "logs" + File.separator + "tmp");
     553            if (!webLogsTmpFolder.exists())
     554            {
     555                webLogsTmpFolder.mkdirs(); // create any necessary folders
     556            }
     557            File styleFile = new File(webLogsTmpFolder + File.separator + "stylesheet" + XMLTransformer.debugFileCount + ".xml");
     558            File sourceFile = new File(webLogsTmpFolder + File.separator + "source" + XMLTransformer.debugFileCount + ".xml");
     559               
     560
     561            try
     562            {
     563                // write stylesheet to a file called stylesheet_systemID in tmp
     564                FileWriter styleSheetWriter = new FileWriter(styleFile);
     565                styleSheetWriter.write(stylesheet, 0, stylesheet.length());
     566                styleSheetWriter.flush();
     567                styleSheetWriter.close();
     568            }
     569            catch (Exception e)
     570            {
     571                System.err.println("*** Exception when trying to write out stylesheet to " + styleFile.getAbsolutePath());
     572            }
     573
     574            if(this.source != null) { // ErrorListener was set on a Transformer object
     575                try
     576                {
     577                    FileWriter srcWriter = new FileWriter(sourceFile);
     578                    String contents = "";
     579                    if (source instanceof DOMSource)
     580                    {
     581                        DOMSource domSource = (DOMSource) source;
     582                        Document doc = (Document) domSource.getNode();
     583                        contents = GSXML.elementToString(doc.getDocumentElement(), true);
     584                        //contents = GSXML.xmlNodeToXMLString(domSource.getNode());
     585                    }
     586                    else if (source instanceof StreamSource)
     587                    {
     588                        StreamSource streamSource = (StreamSource) source;
     589                        BufferedReader reader = new BufferedReader(streamSource.getReader());
     590                        String line = "";
     591                        while ((line = reader.readLine()) != null)
     592                        {
     593                            contents = contents + line + "\n";
     594                        }
     595                    }
     596                    srcWriter.write(contents, 0, contents.length());
     597                    srcWriter.flush();
     598                    srcWriter.close();
     599                }
     600                catch (Exception e)
     601                {
     602                    System.err.println("*** Exception when trying to write out stylesheet to " + sourceFile.getAbsolutePath());
     603                }
     604            }
     605
     606            System.err.println("*****************************************");
     607            System.err.println("Look for stylesheet in: " + styleFile.getAbsolutePath());
     608            if(this.source != null) { // ErrorListener was set on a Transformer object
     609                System.err.println("Look for source XML in: " + sourceFile.getAbsolutePath());
     610            }   
     611
     612            // now perform the transform again, which will assign another TransformErrorListener
     613            // but since debuggingAsFile is turned off, we won't recurse into this section of
     614            // handling the error again
     615            if(this.source != null) { // ErrorListener was set on a Transformer object
     616                XMLTransformer.this.transform(styleFile, sourceFile); // calls the File, File version, so debugAsFile will be false
     617            }
    325618           
    326             return xhtmlDoc.getDocumentElement();
    327            
    328         }catch(Exception e) {
    329             String errmsg = "Exception trying to construct error xhtml page from message: " + message
    330                 + "\n" + e.getMessage();
    331             System.err.println(errmsg);
    332             logger.error(errmsg);
    333             return null;
    334         }
    335     }
    336    
    337     // ErrorListener class that can be used to register a handler for any fatal errors, errors and warnings
    338     // that may occur when transforming an xml file with an xslt stylesheet using the XMLTransformer.
    339         // The errors are printed both to the greenstone.log and to the tomcat console (System.err), and the
    340     // error message is stored in the errorMessage variable so that it can be retrieved and be used to
    341     // generate an xhtml error page.
    342     public class TransformErrorListener implements ErrorListener {
    343         protected String errorMessage = null;
    344         protected String stylesheet = null;
    345         protected Source source = null; // can be DOMSource or StreamSource
    346         protected boolean debugAsFile = true; // true if xslt or source are not real physical files
    347        
    348         public TransformErrorListener(String xslt, Source source) {
    349         this.stylesheet = xslt;
    350         this.source = source;
    351         XMLTransformer.debugFileCount++;
    352         }
    353 
    354         public TransformErrorListener(Document xslt, Source source) {       
    355         this.stylesheet = GSXML.elementToString(xslt.getDocumentElement(), true);
    356         this.source = source;
    357         XMLTransformer.debugFileCount++;
    358         }
    359 
    360         public TransformErrorListener(File xslt, Source source) {
    361         this.debugAsFile = false; // if this constructor is called, we're dealing with physical files for both xslt and source
    362         this.source = source;
    363         this.stylesheet = xslt.getAbsolutePath(); // not necessary to get the string from the file
    364                    // all we were going to do with it *on error* was write it out to a file anyway     
    365         }
    366 
    367         //  Receive notification of a recoverable error.
    368         public void error(TransformerException exception) {
    369         handleError("Error:\n", exception);
    370         }
    371         // Receive notification of a non-recoverable error.
    372         public void fatalError(TransformerException exception) {
    373         handleError("Fatal Error:\n", exception);
    374         }
    375         // Receive notification of a warning.
    376         public void warning(TransformerException exception) {
    377         handleError("Warning:\n", exception);
    378         }
    379        
    380         public String toString(TransformerException e) {
    381         String msg = "Exception encountered was:\n\t";
    382         String location = e.getLocationAsString();
    383         if(location != null) {         
    384             msg = msg + "Location: " + location + "\n\t";
    385         }
    386 
    387         return msg + "Message: " + e.getMessage();
    388         }
    389        
    390         // clears the errorPage variable after the first call to this method
    391         public String getErrorMessage() {
    392         String errMsg = this.errorMessage;
    393         if(this.errorMessage != null) {
    394             this.errorMessage = null;
    395         }
    396         return errMsg;
    397         }
    398        
    399         // sets the errorMessage member variable to the data stored in the exception
    400         // and writes the errorMessage to the logger and tomcat's System.err
    401         protected void handleError(String errorType, TransformerException exception) {
    402 
    403         this.errorMessage = errorType + toString(exception);
    404 
    405         // If either the stylesheet or the source to be transformed with it were not files,
    406         // so that the transformation was performed in-memory, then the "location" information
    407         // during the error handling (if any) wouldn't have been helpful.
    408         // To allow proper debugging, we write both stylesheet and source out as physical files
    409         // and perform the same transformation again, so that when a transformation error does
    410         // occur, the files are not in-memory but can be viewed, and any location information
    411         // for the error given by the ErrorListener will be sensible (instead of the unhelpful
    412         // "line#0 column#0 in file://somewhere/dummy.xsl").
    413         // Note that if the stylesheet and the source it is to transform were both physical
    414         // files to start off with, we will not need to perform the same transformation again
    415         // since the error reporting would have provided accurate locations for those.
    416         if(debugAsFile) {
    417            
    418             performTransformWithPhysicalFiles(); // will give accurate line numbers
    419        
    420             // No need to print out the current error message (seen in the Else statement below),
    421             // as the recursive call to XMLTransformer.transform(File, File, false) in method
    422             // performTransformWithPhysicalFiles() will do this for us.
    423         }
    424         else {
    425             // printing out the error message
    426             // since !debugAsFile, we are dealing with physical files,
    427             // variable stylesheet would have stored the filename instead of contents
    428             this.errorMessage = this.errorMessage + "\nstylesheet filename: " + stylesheet;
    429            
    430             this.errorMessage += "\nException CAUSE:\n" + exception.getCause();
    431             System.err.println("\n****Error transforming xml:\n" + this.errorMessage + "\n****\n");
    432             //System.err.println("Stylesheet was:\n + this.stylesheet + "************END STYLESHEET***********\n\n");           
    433            
    434             logger.error(this.errorMessage);
    435            
    436             // now print out the source to a file, and run the stylesheet on it using a transform()
    437             // then any error will be referring to one of these two input files.
    438         }
    439         }
    440 
    441         // This method will redo the transformation that went wrong with *real* files:
    442         // it writes out the stylesheet and source XML to files first, then performs the transformation
    443         // to get the actual line location of where things went wrong (instead of "line#0 column#0 in dummy.xsl")
    444         protected void performTransformWithPhysicalFiles() {
    445         File webLogsTmpFolder = new File(GlobalProperties.getGSDL3Home() + File.separator + "logs" + File.separator + "tmp");
    446         if(!webLogsTmpFolder.exists()) {
    447             webLogsTmpFolder.mkdirs(); // create any necessary folders
    448         }
    449         File styleFile = new File(webLogsTmpFolder + File.separator + "stylesheet" + XMLTransformer.debugFileCount + ".xml");
    450         File sourceFile = new File(webLogsTmpFolder + File.separator + "source" + XMLTransformer.debugFileCount + ".xml");
    451        
    452         try {
    453             // write stylesheet to a file called stylesheet_systemID in tmp
    454             FileWriter styleSheetWriter = new FileWriter(styleFile);
    455             styleSheetWriter.write(stylesheet, 0, stylesheet.length());
    456             styleSheetWriter.flush();
    457             styleSheetWriter.close();
    458         } catch(Exception e) {
    459             System.err.println("*** Exception when trying to write out stylesheet to " + styleFile.getAbsolutePath());
    460         }       
    461        
    462         try {
    463             FileWriter srcWriter = new FileWriter(sourceFile);
    464             String contents = "";
    465             if(source instanceof DOMSource) {
    466             DOMSource domSource = (DOMSource)source;
    467             Document doc = (Document)domSource.getNode();
    468             contents = GSXML.elementToString(doc.getDocumentElement(), true);
    469             //contents = GSXML.xmlNodeToXMLString(domSource.getNode());
    470             } else if (source instanceof StreamSource) {
    471             StreamSource streamSource = (StreamSource)source;
    472             BufferedReader reader = new BufferedReader(streamSource.getReader());
    473             String line = "";
    474             while((line = reader.readLine()) != null) {
    475                 contents = contents + line + "\n";
    476             }           
    477             }
    478             srcWriter.write(contents, 0, contents.length());
    479             srcWriter.flush();
    480             srcWriter.close();     
    481         } catch(Exception e) {
    482             System.err.println("*** Exception when trying to write out stylesheet to " + sourceFile.getAbsolutePath());
    483         }
    484        
    485         System.err.println("*****************************************");
    486         System.err.println("Look for stylesheet in: " + styleFile.getAbsolutePath());
    487         System.err.println("Look for source XML in: " + sourceFile.getAbsolutePath());
    488        
    489         // now perform the transform again, which will assign another TransformErrorListener
    490         // but since debuggingAsFile is turned off, we won't recurse into this section of
    491         // handling the error again
    492         XMLTransformer.this.transform(styleFile, sourceFile); // calls the File, File version, so debugAsFile will be false     
    493        
    494         }
     619            else { // ErrorListener was set on a TransformerFactory object
     620               
     621                // The recursive step in this case is to perform the instantiation
     622                // of the Transformer object again.
     623                // Only one TransformerFactory object per XMLTransformer,
     624                // and only one TransformerHandler object set on any TransformerFactory
     625                // But the stylesheet used to create a Transformer from that TransformerFactory
     626                // object changes each time, by calls to setStylesheet(),
     627                // Therefore, the debugAsFile state for the single TransformerFactory's
     628                // TransformerHandler changes each time also.
     629               
     630                try {
     631                    debugAsFile = false;
     632                    this.stylesheet = styleFile.getAbsolutePath();                 
     633                    //TransformErrorListener transformerErrorListener = (TransformErrorListener)XMLTransformer.this.t_factory.getErrorListener();
     634                    //transformerErrorListener.setStylesheet(styleFile);
     635                    Transformer transformer = XMLTransformer.this.t_factory.newTransformer(new StreamSource(styleFile));
     636                    if(transformer == null) {
     637                        String msg = "XMLTransformer transformer is " + transformer;
     638                        logger.info(msg);
     639                        System.out.println(msg + "\n****\n");
     640                    }
     641                } catch (TransformerConfigurationException e)
     642                {
     643                    String message = "Couldn't create transformer object: " + e.getMessageAndLocation();                   
     644                    logger.error(message);
     645                    logger.error(e.getLocationAsString());
     646                    System.out.println(message);
     647                }
     648                catch (TransformerException e)
     649                {
     650                    String message = "Couldn't transform the source: " + e.getMessageAndLocation();
     651                    logger.error(message);
     652                    System.out.println(message);
     653                }
     654            }
     655
     656        }
    495657    }
    496658}
Note: See TracChangeset for help on using the changeset viewer.