- Timestamp:
- 2012-05-15T18:37:43+12:00 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/XMLTransformer.java
r25602 r25603 58 58 import org.apache.log4j.*; 59 59 60 /** XMLTransformer - utility class for greenstone 61 * 60 /** 61 * XMLTransformer - utility class for greenstone 62 * 62 63 * transforms xml using xslt 63 * 64 * 64 65 * @author <a href="mailto:[email protected]">Katherine Don</a> 65 66 * @version $Revision$ 66 67 */ 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 { 68 public 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); 204 169 // Use the TransformerFactory to process the stylesheet Source and generate a Transformer. 205 170 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 { 208 173 Set params = parameters.entrySet(); 209 174 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()); 213 179 } 214 180 } 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"); 216 252 // When we transform the DOMResult, we need to make sure the result of 217 253 // the transformation has a DocType. For that to happen, we need to create … … 220 256 // that does not contain any doctype (like we use to do before). 221 257 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); 224 261 } 225 262 DOMSource domSource = new DOMSource(source); 263 System.err.println("2"); 226 264 transformer.setErrorListener(new TransformErrorListener(stylesheet, domSource)); 265 System.err.println("4"); 227 266 transformer.transform(domSource, result); 267 System.err.println("5"); 228 268 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 271 315 // Given a heading string on the sort of transformation error that occurred and the exception object itself, 272 316 // this method prints the exception to the tomcat window (system.err) and the greenstone log and then returns 273 317 // 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 { 275 320 String message = heading + "\n" + e.getMessage(); 276 321 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 { 280 326 logger.error(location); 281 327 message = message + "\n" + location; … … 284 330 return constructErrorXHTMLPage(message); 285 331 } 286 332 287 333 // Given an error message, splits it into separate lines based on any newlines present and generates an xhtml page 288 334 // (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 { 291 339 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 { 320 369 Node pNode = xhtmlDoc.createElement("p"); 321 370 Node textNode = xhtmlDoc.createTextNode(lines[i]); … … 323 372 bodyNode.appendChild(pNode); 324 373 } 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 } 325 618 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 } 495 657 } 496 658 }
Note:
See TracChangeset
for help on using the changeset viewer.