Changeset 25445 for main


Ignore:
Timestamp:
2012-04-19T22:09:50+12:00 (12 years ago)
Author:
ak19
Message:

Error reporting is now improved again, much better than in previous commit: no longer just writes out the XSLT stylesheet to the log file, but follows Dr Bainbridge and Sam's suggestion of performing the transformation that failed again with physical files instead of in-memory as before. This points out the exact line location of errors.

Location:
main/trunk/greenstone3/src/java/org/greenstone/gsdl3
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone3/src/java/org/greenstone/gsdl3/core/TransformingReceptionist.java

    r25423 r25445  
    593593        Document skinAndLibraryXsl = null;
    594594        Document skinAndLibraryDoc = converter.newDOM();
    595         try
     595       
     596        // Applying the preprocessing XSLT - in its own block {} to allow use of non-unique variable names
    596597        {
    597598
     
    615616            //In other words, apply the preProcess.xsl to 'skinAndLibraryXsl' in order to
    616617            //expand all GS-Lib statements into complete XSL statements and also to create
    617             //a valid  xsl style sheet document.
    618 
    619             Transformer preProcessor = transformerFactory.newTransformer(new DOMSource(preprocessingXsl));
    620             preProcessor.setErrorListener(new XMLTransformer.TransformErrorListener(preprocessingXsl));
    621             DOMResult result = new DOMResult();
    622             result.setNode(skinAndLibraryDoc);
    623             preProcessor.transform(new DOMSource(skinAndLibraryXsl), result);
    624             //System.out.println("GS-Lib statements are now expanded") ;       
    625 
    626         }
    627         catch (TransformerException e)
    628         {
    629             e.printStackTrace();
    630             System.out.println("TransformerException while preprocessing the skin xslt");
    631             return XMLTransformer.constructErrorXHTMLPage(e.getMessage());
    632         }
    633         catch (Exception e)
    634         {
    635             e.printStackTrace();
    636             System.out.println("Error while preprocessing the skin xslt");
    637             return XMLTransformer.constructErrorXHTMLPage(e.getMessage());
    638         }
     618            //a valid xsl style sheet document.
     619
     620            XMLTransformer preProcessor = new XMLTransformer();
     621            // Perform the transformation, by passing in:
     622            // preprocess-stylesheet, source-xsl (skinAndLibraryXsl), and the node that should
     623            // be in the result (skinAndLibraryDoc)
     624            preProcessor.transform_withResultNode(preprocessingXsl, skinAndLibraryXsl, skinAndLibraryDoc);
     625            //System.out.println("GS-Lib statements are now expanded") ;
     626        }
     627   
    639628
    640629        //The following code is to be uncommented if we need to append the extracted GSF statements
  • main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSXML.java

    r25423 r25445  
    12441244    public static String elementToString(Element e, boolean indent)
    12451245    {
    1246         String str = "**********START*************\n";
    12471246        try {
    12481247        TransformerFactory tf = TransformerFactory.newInstance();
     
    12611260        }
    12621261        finally {
    1263         str += "\n***********************\n";
    12641262        return str;
    12651263        }
  • main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/XMLTransformer.java

    r25423 r25445  
    1919package org.greenstone.gsdl3.util;
    2020
     21import org.greenstone.util.GlobalProperties;
     22
    2123// XML classes
    2224import javax.xml.transform.Transformer;
     
    2830import javax.xml.transform.stream.StreamSource;
    2931import javax.xml.transform.dom.DOMSource;
     32import javax.xml.transform.Source;
    3033import javax.xml.transform.stream.StreamResult;
    3134import javax.xml.transform.dom.DOMResult;
     
    4447import java.io.BufferedReader;
    4548import java.io.FileReader;
     49import java.io.FileWriter;
    4650import java.io.File;
    4751import java.util.HashMap;
     
    6266 */
    6367public class XMLTransformer {
     68    private static int debugFileCount = 0; // for unique filenames when debugging XML transformations with physical files
    6469
    6570    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.XMLTransformer.class.getName());
     
    118123        // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
    119124        Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
    120         transformer.setErrorListener(new TransformErrorListener(stylesheet));
    121125
    122126        // Use the Transformer to transform an XML Source and send the output to a Result object.
    123127        StringWriter output = new StringWriter();
    124 
    125         transformer.transform(new StreamSource(new StringReader(xml_in)), new StreamResult(output));
     128        StreamSource streamSource = new StreamSource(new StringReader(xml_in));
     129        transformer.setErrorListener(new TransformErrorListener(stylesheet, streamSource));
     130        transformer.transform(streamSource, new StreamResult(output));
    126131        return output.toString();
    127132    } catch (TransformerConfigurationException e) {
     
    139144    }
    140145   
     146
    141147    public String transformToString(Document stylesheet, Document source, HashMap parameters) {
    142148   
     
    144150        // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
    145151        Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));
    146         transformer.setErrorListener(new TransformErrorListener(stylesheet));
    147152        if (parameters != null) {
    148153        Set params = parameters.entrySet();
     
    158163        // Use the Transformer to transform an XML Source and send the output to a Result object.
    159164        StringWriter output = new StringWriter();
    160        
    161         transformer.transform(new DOMSource(source), new StreamResult(output));
     165        DOMSource domSource = new DOMSource(source);
     166
     167        transformer.setErrorListener(new TransformErrorListener(stylesheet, domSource));
     168        transformer.transform(domSource, new StreamResult(output));
    162169        return output.toString();
    163170    } catch (TransformerConfigurationException e) {
     
    171178    }
    172179
     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
    173190    public Node transform(Document stylesheet, Document source) {
    174         return transform(stylesheet, source, null, null);
     191        return transform(stylesheet, source, null, null, null);
    175192    }
    176193   
    177194    public Node transform(Document stylesheet, Document source, HashMap parameters) {
    178         return transform(stylesheet, source, parameters, null);
     195        return transform(stylesheet, source, parameters, null, null);
    179196    }
    180197
    181198    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) {
    182203        try {
    183204            // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
    184205            Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));
    185206            logger.info("XMLTransformer transformer is " + transformer);
    186             transformer.setErrorListener(new TransformErrorListener(stylesheet));
    187207            if (parameters != null) {
    188208                Set params = parameters.entrySet();
     
    200220            // that does not contain any doctype (like we use to do before).
    201221            DOMResult result = docDocType == null ? new DOMResult() : new DOMResult(docDocType);
    202             transformer.transform(new DOMSource(source), result);
     222            if(resultNode != null) {
     223                result.setNode(resultNode);
     224            }
     225            DOMSource domSource = new DOMSource(source);
     226            transformer.setErrorListener(new TransformErrorListener(stylesheet, domSource));
     227            transformer.transform(domSource, result);
    203228            return result.getNode(); // pass the entire document
    204229        }
     
    214239
    215240    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) {
    216250    try {
    217251        Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
    218         transformer.setErrorListener(new TransformErrorListener(stylesheet));
    219         DOMResult result = new DOMResult();
    220         transformer.transform(new StreamSource(source), result);
     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);
    221258        return result.getNode().getFirstChild();
    222259    } catch (TransformerConfigurationException e) {
     
    230267                + stylesheet + "\n" + source, e);
    231268    }   
    232  }
    233  
    234     public Node transform(File stylesheet, File source, Document docDocType) {
    235         try {
    236             Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
    237             transformer.setErrorListener(new TransformErrorListener(stylesheet));
    238             DOMResult result = new DOMResult(docDocType);
    239             transformer.transform(new StreamSource(source), result);
    240             return result.getNode().getFirstChild();
    241         } catch (TransformerConfigurationException e) {
    242             return transformError("XMLTransformer.transform(File, File, Doc)"
    243                 + "\ncouldn't create transformer object for files\n"
    244                 + stylesheet + "\n" + source, e);
    245         }
    246         catch (TransformerException e) {
    247             return transformError("XMLTransformer.transform(File, File, Doc)"
    248                 + "\ncouldn't transform the source for files\n"
    249                 + stylesheet + "\n" + source, e);
    250         }   
    251     }
    252    
     269    }
     270     
    253271    // Given a heading string on the sort of transformation error that occurred and the exception object itself,
    254272    // this method prints the exception to the tomcat window (system.err) and the greenstone log and then returns
     
    317335    }
    318336   
    319     // ErrorListener class that can be used to register a handler for any fatal errors, errors and warnings that may
    320     // occur when transforming an xml file with an xslt stylesheet. The errors are printed both to the greenstone.log and
    321     // to the tomcat console (System.err), and the error message is stored in the errorMessage variable so that it can
    322     // be retrieved and be used to generate an xhtml error page.
    323     static public class TransformErrorListener implements ErrorListener {
     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 {
    324343        protected String errorMessage = null;
    325344        protected String stylesheet = null;
    326         protected String file = 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
    327347       
    328         public TransformErrorListener(String xslt) {
     348        public TransformErrorListener(String xslt, Source source) {
    329349        this.stylesheet = xslt;
    330         }
    331 
    332         public TransformErrorListener(Document xslt) {
    333         //this.stylesheet = GSXML.xmlNodeToString(xslt);
     350        this.source = source;
     351        XMLTransformer.debugFileCount++;
     352        }
     353
     354        public TransformErrorListener(Document xslt, Source source) {       
    334355        this.stylesheet = GSXML.elementToString(xslt.getDocumentElement(), true);
    335         }
    336 
    337         public TransformErrorListener(File xslt) {
    338         stylesheet = "";       
    339         file = xslt.getAbsolutePath();
    340         String error = "Can't locate stylesheet file: " + xslt;
    341 
    342         if(!xslt.exists()) {
    343             stylesheet = error;
    344             System.err.println("@@@@@@@ " + error);
    345             return;
    346         }
    347         try {
    348             BufferedReader in = new BufferedReader(new FileReader(xslt));
    349             String line = "";
    350             while((line = in.readLine()) != null) {
    351             stylesheet = stylesheet + line + "\n";
    352             }
    353             in.close();
    354             in = null;
    355         } catch(Exception e) {
    356             stylesheet = error;
    357             System.err.println("Exception reading file: " + xslt.getAbsolutePath());
    358             e.printStackTrace();
    359         }
     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     
    360365        }
    361366
     
    383388        }
    384389       
    385         // clears the errorPage variable after first call to this method
     390        // clears the errorPage variable after the first call to this method
    386391        public String getErrorMessage() {
    387392        String errMsg = this.errorMessage;
     
    395400        // and writes the errorMessage to the logger and tomcat's System.err
    396401        protected void handleError(String errorType, TransformerException exception) {
    397         this.errorMessage = errorType + toString(exception);
    398         if(file != null) {
    399             this.errorMessage = this.errorMessage + "\nfilename: " + file;
    400         }
    401         this.errorMessage += "\nException CAUSE:\n" + exception.getCause();
    402         System.err.println("\n****Error transforming xml:\n" + this.errorMessage + "\n****\n");
    403         System.err.println("Stylesheet was:\n" + this.stylesheet + "\n\n");
    404         logger.error(this.errorMessage);
     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        File styleFile = new File(webLogsTmpFolder + File.separator + "stylesheet" + XMLTransformer.debugFileCount + ".xml");
     447        File sourceFile = new File(webLogsTmpFolder + File.separator + "source" + XMLTransformer.debugFileCount + ".xml");
     448       
     449        try {
     450            // write stylesheet to a file called stylesheet_systemID in tmp
     451            FileWriter styleSheetWriter = new FileWriter(styleFile);
     452            styleSheetWriter.write(stylesheet, 0, stylesheet.length());
     453            styleSheetWriter.flush();
     454            styleSheetWriter.close();
     455        } catch(Exception e) {
     456            System.err.println("*** Exception when trying to write out stylesheet to " + styleFile.getAbsolutePath());
     457        }       
     458       
     459        try {
     460            FileWriter srcWriter = new FileWriter(sourceFile);
     461            String contents = "";
     462            if(source instanceof DOMSource) {
     463            DOMSource domSource = (DOMSource)source;
     464            Document doc = (Document)domSource.getNode();
     465            contents = GSXML.elementToString(doc.getDocumentElement(), true);
     466            //contents = GSXML.xmlNodeToXMLString(domSource.getNode());
     467            } else if (source instanceof StreamSource) {
     468            StreamSource streamSource = (StreamSource)source;
     469            BufferedReader reader = new BufferedReader(streamSource.getReader());
     470            String line = "";
     471            while((line = reader.readLine()) != null) {
     472                contents = contents + line + "\n";
     473            }           
     474            }
     475            srcWriter.write(contents, 0, contents.length());
     476            srcWriter.flush();
     477            srcWriter.close();     
     478        } catch(Exception e) {
     479            System.err.println("*** Exception when trying to write out stylesheet to " + sourceFile.getAbsolutePath());
     480        }
     481       
     482        System.err.println("*****************************************");
     483        System.err.println("Look for stylesheet in: " + styleFile.getAbsolutePath());
     484        System.err.println("Look for source XML in: " + sourceFile.getAbsolutePath());
     485       
     486        // now perform the transform again, which will assign another TransformErrorListener
     487        // but since debuggingAsFile is turned off, we won't recurse into this section of
     488        // handling the error again
     489        XMLTransformer.this.transform(styleFile, sourceFile); // calls the File, File version, so debugAsFile will be false     
     490       
    405491        }
    406492    }
Note: See TracChangeset for help on using the changeset viewer.