001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.scxml.io; 018 019 import java.io.StringWriter; 020 import java.util.Iterator; 021 import java.util.List; 022 import java.util.Map; 023 import java.util.Properties; 024 import java.util.Set; 025 026 import javax.xml.transform.OutputKeys; 027 import javax.xml.transform.Result; 028 import javax.xml.transform.Source; 029 import javax.xml.transform.Transformer; 030 import javax.xml.transform.TransformerException; 031 import javax.xml.transform.TransformerFactory; 032 import javax.xml.transform.dom.DOMSource; 033 import javax.xml.transform.stream.StreamResult; 034 035 import org.apache.commons.logging.LogFactory; 036 import org.apache.commons.scxml.SCXMLHelper; 037 import org.apache.commons.scxml.model.Action; 038 import org.apache.commons.scxml.model.Assign; 039 import org.apache.commons.scxml.model.Cancel; 040 import org.apache.commons.scxml.model.Data; 041 import org.apache.commons.scxml.model.Datamodel; 042 import org.apache.commons.scxml.model.Else; 043 import org.apache.commons.scxml.model.ElseIf; 044 import org.apache.commons.scxml.model.Exit; 045 import org.apache.commons.scxml.model.ExternalContent; 046 import org.apache.commons.scxml.model.Finalize; 047 import org.apache.commons.scxml.model.History; 048 import org.apache.commons.scxml.model.If; 049 import org.apache.commons.scxml.model.Initial; 050 import org.apache.commons.scxml.model.Invoke; 051 import org.apache.commons.scxml.model.Log; 052 import org.apache.commons.scxml.model.NamespacePrefixesHolder; 053 import org.apache.commons.scxml.model.OnEntry; 054 import org.apache.commons.scxml.model.OnExit; 055 import org.apache.commons.scxml.model.Parallel; 056 import org.apache.commons.scxml.model.Param; 057 import org.apache.commons.scxml.model.SCXML; 058 import org.apache.commons.scxml.model.Send; 059 import org.apache.commons.scxml.model.State; 060 import org.apache.commons.scxml.model.Transition; 061 import org.apache.commons.scxml.model.TransitionTarget; 062 import org.apache.commons.scxml.model.Var; 063 import org.w3c.dom.Node; 064 065 /** 066 * <p>Utility class for serializing the Commons SCXML Java object 067 * model. Class uses the visitor pattern to trace through the 068 * object heirarchy. Used primarily for testing, debugging and 069 * visual verification.</p> 070 * 071 * <b>NOTE:</b> This serializer makes the following assumptions about the 072 * original SCXML document(s) parsed to create the object model: 073 * <ul> 074 * <li>The default document namespace is the SCXML namespace: 075 * <i>http://www.w3.org/2005/07/scxml</i></li> 076 * <li>The Commons SCXML namespace 077 * ( <i>http://commons.apache.org/scxml</i> ), if needed, uses the 078 * "<i>cs</i>" prefix</li> 079 * <li>All namespace prefixes needed throughout the document are 080 * declared on the document root element (<scxml>)</li> 081 * </ul> 082 */ 083 public class SCXMLSerializer { 084 085 /** The indent to be used while serializing an SCXML object. */ 086 private static final String INDENT = " "; 087 /** The JAXP transformer. */ 088 private static final Transformer XFORMER = getTransformer(); 089 /** The SCXML namespace. */ 090 private static final String NAMESPACE_SCXML = 091 "http://www.w3.org/2005/07/scxml"; 092 /** The Commons SCXML namespace. */ 093 private static final String NAMESPACE_COMMONS_SCXML = 094 "http://commons.apache.org/scxml"; 095 096 /** 097 * Serialize this SCXML object (primarily for debugging). 098 * 099 * @param scxml 100 * The SCXML to be serialized 101 * @return String The serialized SCXML 102 */ 103 public static String serialize(final SCXML scxml) { 104 StringBuffer b = 105 new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"). 106 append("<scxml xmlns=\"").append(NAMESPACE_SCXML). 107 append("\"").append(serializeNamespaceDeclarations(scxml)). 108 append(" version=\"").append(scxml.getVersion()). 109 append("\" initial=\"").append(scxml.getInitial()). 110 append("\">\n"); 111 if (XFORMER == null) { 112 org.apache.commons.logging.Log log = LogFactory. 113 getLog(SCXMLSerializer.class); 114 log.warn("SCXMLSerializer: DOM serialization pertinent to" 115 + " the document will be skipped since a suitable" 116 + " JAXP Transformer could not be instantiated."); 117 } 118 b.append(INDENT).append("<!-- http://commons.apache.org/scxml -->\n"); 119 Datamodel dm = scxml.getDatamodel(); 120 if (dm != null) { 121 serializeDatamodel(b, dm, INDENT); 122 } 123 Map c = scxml.getChildren(); 124 Iterator i = c.keySet().iterator(); 125 while (i.hasNext()) { 126 TransitionTarget tt = (TransitionTarget) c.get(i.next()); 127 if (tt instanceof State) { 128 serializeState(b, (State) tt, INDENT); 129 } else { 130 serializeParallel(b, (Parallel) tt, INDENT); 131 } 132 } 133 b.append("</scxml>\n"); 134 return b.toString(); 135 } 136 137 /** 138 * Serialize this State object. 139 * 140 * @param b The buffer to append the serialization to 141 * @param s The State to serialize 142 * @param indent The indent for this XML element 143 */ 144 public static void serializeState(final StringBuffer b, 145 final State s, final String indent) { 146 b.append(indent).append("<state"); 147 serializeTransitionTargetAttributes(b, s); 148 boolean f = s.isFinal(); 149 if (f) { 150 b.append(" final=\"true\""); 151 } 152 b.append(">\n"); 153 Initial ini = s.getInitial(); 154 if (ini != null) { 155 serializeInitial(b, ini, indent + INDENT); 156 } 157 List h = s.getHistory(); 158 if (h != null) { 159 serializeHistory(b, h, indent + INDENT); 160 } 161 Datamodel dm = s.getDatamodel(); 162 if (dm != null) { 163 serializeDatamodel(b, dm, indent + INDENT); 164 } 165 serializeOnEntry(b, s, indent + INDENT); 166 List t = s.getTransitionsList(); 167 for (int i = 0; i < t.size(); i++) { 168 serializeTransition(b, (Transition) t.get(i), indent + INDENT); 169 } 170 Parallel p = s.getParallel(); //TODO: Remove in v1.0 171 Invoke inv = s.getInvoke(); 172 if (p != null) { 173 serializeParallel(b, p, indent + INDENT); 174 } else if (inv != null) { 175 serializeInvoke(b , inv, indent + INDENT); 176 } else { 177 Map c = s.getChildren(); 178 Iterator j = c.keySet().iterator(); 179 while (j.hasNext()) { 180 TransitionTarget tt = (TransitionTarget) c.get(j.next()); 181 if (tt instanceof State) { 182 serializeState(b, (State) tt, indent + INDENT); 183 } else if (tt instanceof Parallel) { 184 serializeParallel(b, (Parallel) tt, indent + INDENT); 185 } 186 } 187 } 188 serializeOnExit(b, s, indent + INDENT); 189 b.append(indent).append("</state>\n"); 190 } 191 192 /** 193 * Serialize this Parallel object. 194 * 195 * @param b The buffer to append the serialization to 196 * @param p The Parallel to serialize 197 * @param indent The indent for this XML element 198 */ 199 public static void serializeParallel(final StringBuffer b, 200 final Parallel p, final String indent) { 201 b.append(indent).append("<parallel"); 202 serializeTransitionTargetAttributes(b, p); 203 b.append(">\n"); 204 serializeOnEntry(b, p, indent + INDENT); 205 Set s = p.getChildren(); 206 Iterator i = s.iterator(); 207 while (i.hasNext()) { 208 serializeState(b, (State) i.next(), indent + INDENT); 209 } 210 serializeOnExit(b, p, indent + INDENT); 211 b.append(indent).append("</parallel>\n"); 212 } 213 214 /** 215 * Serialize this Invoke object. 216 * 217 * @param b The buffer to append the serialization to 218 * @param i The Invoke to serialize 219 * @param indent The indent for this XML element 220 */ 221 public static void serializeInvoke(final StringBuffer b, 222 final Invoke i, final String indent) { 223 b.append(indent).append("<invoke"); 224 String ttype = i.getTargettype(); 225 String src = i.getSrc(); 226 String srcexpr = i.getSrcexpr(); 227 if (ttype != null) { 228 b.append(" targettype=\"").append(ttype).append("\""); 229 } 230 // Prefer src 231 if (src != null) { 232 b.append(" src=\"").append(src).append("\""); 233 } else if (srcexpr != null) { 234 b.append(" srcexpr=\"").append(srcexpr).append("\""); 235 } 236 b.append(">\n"); 237 List params = i.params(); 238 for (Iterator iter = params.iterator(); iter.hasNext();) { 239 Param p = (Param) iter.next(); 240 b.append(indent).append(INDENT).append("<param name=\""). 241 append(p.getName()).append("\" expr=\""). 242 append(SCXMLHelper.escapeXML(p.getExpr())).append("\"/>\n"); 243 } 244 Finalize f = i.getFinalize(); 245 if (f != null) { 246 b.append(indent).append(INDENT).append("<finalize>\n"); 247 serializeActions(b, f.getActions(), indent + INDENT + INDENT); 248 b.append(indent).append(INDENT).append("</finalize>\n"); 249 } 250 b.append(indent).append("</invoke>\n"); 251 } 252 253 /** 254 * Serialize this Initial object. 255 * 256 * @param b The buffer to append the serialization to 257 * @param i The Initial to serialize 258 * @param indent The indent for this XML element 259 */ 260 public static void serializeInitial(final StringBuffer b, final Initial i, 261 final String indent) { 262 b.append(indent).append("<initial"); 263 serializeTransitionTargetAttributes(b, i); 264 b.append(">\n"); 265 serializeTransition(b, i.getTransition(), indent + INDENT); 266 b.append(indent).append("</initial>\n"); 267 } 268 269 /** 270 * Serialize the History. 271 * 272 * @param b The buffer to append the serialization to 273 * @param l The List of History objects to serialize 274 * @param indent The indent for this XML element 275 */ 276 public static void serializeHistory(final StringBuffer b, final List l, 277 final String indent) { 278 if (l.size() > 0) { 279 for (int i = 0; i < l.size(); i++) { 280 History h = (History) l.get(i); 281 b.append(indent).append("<history"); 282 serializeTransitionTargetAttributes(b, h); 283 if (h.isDeep()) { 284 b.append(" type=\"deep\""); 285 } else { 286 b.append(" type=\"shallow\""); 287 } 288 b.append(">\n"); 289 serializeTransition(b, h.getTransition(), indent + INDENT); 290 b.append(indent).append("</history>\n"); 291 } 292 } 293 } 294 295 /** 296 * Serialize this Transition object. 297 * 298 * @param b The buffer to append the serialization to 299 * @param t The Transition to serialize 300 * @param indent The indent for this XML element 301 */ 302 public static void serializeTransition(final StringBuffer b, 303 final Transition t, final String indent) { 304 b.append(indent).append("<transition"); 305 if (!SCXMLHelper.isStringEmpty(t.getEvent())) { 306 b.append(" event=\"").append(t.getEvent()).append("\""); 307 } 308 if (!SCXMLHelper.isStringEmpty(t.getCond())) { 309 b.append(" cond=\"").append(SCXMLHelper.escapeXML(t.getCond())). 310 append("\""); 311 } 312 boolean next = !SCXMLHelper.isStringEmpty(t.getNext()); 313 if (next) { 314 b.append(" target=\"" + t.getNext() + "\""); 315 } 316 b.append(">\n"); 317 boolean exit = serializeActions(b, t.getActions(), indent + INDENT); 318 if (!next && !exit) { 319 serializeTarget(b, t, indent + INDENT); 320 } 321 b.append(indent).append("</transition>\n"); 322 } 323 324 /** 325 * Serialize this Transition's Target. 326 * 327 * 328 * @param b The buffer to append the serialization to 329 * @param t The Transition whose Target needs to be serialized 330 * @param indent The indent for this XML element 331 * 332 * @deprecated Inline <target> element has been deprecated 333 * in the SCXML WD 334 */ 335 public static void serializeTarget(final StringBuffer b, 336 final Transition t, final String indent) { 337 if (t.getTarget() != null) { 338 b.append(indent).append("<target>"); 339 // The inline transition target can only be a state 340 serializeState(b, (State) t.getTarget(), indent + INDENT); 341 b.append(indent).append("</target>"); 342 } 343 } 344 345 /** 346 * Serialize this Datamodel object. 347 * 348 * @param b The buffer to append the serialization to 349 * @param dm The Datamodel to be serialized 350 * @param indent The indent for this XML element 351 */ 352 public static void serializeDatamodel(final StringBuffer b, 353 final Datamodel dm, final String indent) { 354 List data = dm.getData(); 355 if (data != null && data.size() > 0) { 356 b.append(indent).append("<datamodel>\n"); 357 if (XFORMER == null) { 358 b.append(indent).append(INDENT). 359 append("<!-- Body content was not serialized -->\n"); 360 b.append(indent).append("</datamodel>\n"); 361 return; 362 } 363 for (Iterator iter = data.iterator(); iter.hasNext();) { 364 Data datum = (Data) iter.next(); 365 Node dataNode = datum.getNode(); 366 if (dataNode != null) { 367 StringWriter out = new StringWriter(); 368 try { 369 Source input = new DOMSource(dataNode); 370 Result output = new StreamResult(out); 371 XFORMER.transform(input, output); 372 } catch (TransformerException te) { 373 org.apache.commons.logging.Log log = LogFactory. 374 getLog(SCXMLSerializer.class); 375 log.error(te.getMessage(), te); 376 b.append(indent).append(INDENT). 377 append("<!-- Data content not serialized -->\n"); 378 } 379 b.append(indent).append(INDENT).append(out.toString()); 380 } else { 381 b.append(indent).append(INDENT).append("<data id=\""). 382 append(datum.getId()).append("\" expr=\""). 383 append(SCXMLHelper.escapeXML(datum.getExpr())). 384 append("\" />\n"); 385 } 386 } 387 b.append(indent).append("</datamodel>\n"); 388 } 389 } 390 391 /** 392 * Serialize this OnEntry object. 393 * 394 * @param b The buffer to append the serialization to 395 * @param t The TransitionTarget whose OnEntry is to be serialized 396 * @param indent The indent for this XML element 397 */ 398 public static void serializeOnEntry(final StringBuffer b, 399 final TransitionTarget t, final String indent) { 400 OnEntry e = t.getOnEntry(); 401 if (e != null && e.getActions().size() > 0) { 402 b.append(indent).append("<onentry>\n"); 403 serializeActions(b, e.getActions(), indent + INDENT); 404 b.append(indent).append("</onentry>\n"); 405 } 406 } 407 408 /** 409 * Serialize this OnExit object. 410 * 411 * @param b The buffer to append the serialization to 412 * @param t The TransitionTarget whose OnExit is to be serialized 413 * @param indent The indent for this XML element 414 */ 415 public static void serializeOnExit(final StringBuffer b, 416 final TransitionTarget t, final String indent) { 417 OnExit x = t.getOnExit(); 418 if (x != null && x.getActions().size() > 0) { 419 b.append(indent).append("<onexit>\n"); 420 serializeActions(b, x.getActions(), indent + INDENT); 421 b.append(indent).append("</onexit>\n"); 422 } 423 } 424 425 /** 426 * Serialize this List of actions. 427 * 428 * @param b The buffer to append the serialization to 429 * @param l The List of actions to serialize 430 * @param indent The indent for this XML element 431 * @return boolean true if the list of actions contains an <exit/> 432 */ 433 public static boolean serializeActions(final StringBuffer b, final List l, 434 final String indent) { 435 if (l == null) { 436 return false; 437 } 438 boolean exit = false; 439 Iterator i = l.iterator(); 440 while (i.hasNext()) { 441 Action a = (Action) i.next(); 442 if (a instanceof Var) { 443 Var v = (Var) a; 444 b.append(indent).append("<cs:var name=\"").append(v.getName()) 445 .append("\" expr=\"") 446 .append(SCXMLHelper.escapeXML(v.getExpr())) 447 .append("\"/>\n"); 448 } else if (a instanceof Assign) { 449 Assign asn = (Assign) a; 450 b.append(indent).append("<assign"); 451 if (!SCXMLHelper.isStringEmpty(asn.getLocation())) { 452 b.append(" location=\"").append(asn.getLocation()); 453 if (!SCXMLHelper.isStringEmpty(asn.getSrc())) { 454 b.append("\" src=\"").append(asn.getSrc()); 455 } else { 456 b.append("\" expr=\""). 457 append(SCXMLHelper.escapeXML(asn.getExpr())); 458 } 459 } else { 460 b.append(" name=\"").append(asn.getName()). 461 append("\" expr=\""). 462 append(SCXMLHelper.escapeXML(asn.getExpr())); 463 } 464 b.append("\"/>\n"); 465 } else if (a instanceof Send) { 466 serializeSend(b, (Send) a, indent); 467 } else if (a instanceof Cancel) { 468 Cancel c = (Cancel) a; 469 b.append(indent).append("<cancel sendid=\"") 470 .append(c.getSendid()).append("\"/>\n"); 471 } else if (a instanceof Log) { 472 Log lg = (Log) a; 473 b.append(indent).append("<log expr=\""). 474 append(SCXMLHelper.escapeXML(lg.getExpr())). 475 append("\"/>\n"); 476 } else if (a instanceof Exit) { 477 Exit e = (Exit) a; 478 b.append(indent).append("<cs:exit"); 479 String expr = SCXMLHelper.escapeXML(e.getExpr()); 480 String nl = e.getNamelist(); 481 if (expr != null) { 482 b.append(" expr=\"" + expr + "\""); 483 } 484 if (nl != null) { 485 b.append(" namelist=\"" + nl + "\""); 486 } 487 b.append("/>\n"); 488 exit = true; 489 } else if (a instanceof If) { 490 If iff = (If) a; 491 serializeIf(b, iff, indent); 492 } else if (a instanceof Else) { 493 b.append(indent).append("<else/>\n"); 494 } else if (a instanceof ElseIf) { 495 ElseIf eif = (ElseIf) a; 496 b.append(indent).append("<elseif cond=\"") 497 .append(SCXMLHelper.escapeXML(eif.getCond())) 498 .append("\" />\n"); 499 } 500 } 501 return exit; 502 } 503 504 /** 505 * Serialize this Send object. 506 * 507 * @param b The buffer to append the serialization to 508 * @param send The Send object to serialize 509 * @param indent The indent for this XML element 510 */ 511 public static void serializeSend(final StringBuffer b, 512 final Send send, final String indent) { 513 b.append(indent).append("<send"); 514 if (send.getSendid() != null) { 515 b.append(" sendid=\"").append(send.getSendid()).append("\""); 516 } 517 if (send.getTarget() != null) { 518 b.append(" target=\"").append(send.getTarget()).append("\""); 519 } 520 if (send.getTargettype() != null) { 521 b.append(" targetType=\"").append(send.getTargettype()).append("\""); 522 } 523 if (send.getNamelist() != null) { 524 b.append(" namelist=\"").append(send.getNamelist()).append("\""); 525 } 526 if (send.getDelay() != null) { 527 b.append(" delay=\"").append(send.getDelay()).append("\""); 528 } 529 if (send.getEvent() != null) { 530 b.append(" event=\"").append(send.getEvent()).append("\""); 531 } 532 if (send.getHints() != null) { 533 b.append(" hints=\"").append(send.getHints()).append("\""); 534 } 535 b.append(">\n"); 536 b.append(getBodyContent(send)); 537 b.append(indent).append("</send>\n"); 538 } 539 540 /** 541 * Return serialized body of <code>ExternalContent</code>. 542 * 543 * @param externalContent The model element containing the body content 544 * @return String The serialized body content 545 */ 546 public static final String getBodyContent( 547 final ExternalContent externalContent) { 548 StringBuffer buf = new StringBuffer(); 549 List externalNodes = externalContent.getExternalNodes(); 550 if (externalNodes.size() > 0 && XFORMER == null) { 551 buf.append("<!-- Body content was not serialized -->\n"); 552 return buf.toString(); 553 } 554 for (int i = 0; i < externalNodes.size(); i++) { 555 Source input = new DOMSource((Node) externalNodes.get(i)); 556 StringWriter out = new StringWriter(); 557 Result output = new StreamResult(out); 558 try { 559 XFORMER.transform(input, output); 560 } catch (TransformerException te) { 561 org.apache.commons.logging.Log log = LogFactory. 562 getLog(SCXMLSerializer.class); 563 log.error(te.getMessage(), te); 564 buf.append("<!-- Not all body content was serialized -->"); 565 } 566 buf.append(out.toString()).append("\n"); 567 } 568 return buf.toString(); 569 } 570 571 /** 572 * Serialize this If object. 573 * 574 * @param b The buffer to append the serialization to 575 * @param iff The If object to serialize 576 * @param indent The indent for this XML element 577 */ 578 public static void serializeIf(final StringBuffer b, 579 final If iff, final String indent) { 580 b.append(indent).append("<if cond=\"").append(SCXMLHelper. 581 escapeXML(iff.getCond())).append("\">\n"); 582 serializeActions(b, iff.getActions(), indent + INDENT); 583 b.append(indent).append("</if>\n"); 584 } 585 586 /** 587 * Serialize properties of TransitionTarget which are element attributes. 588 * 589 * @param b The buffer to append the serialization to 590 * @param t The TransitionTarget 591 */ 592 private static void serializeTransitionTargetAttributes( 593 final StringBuffer b, final TransitionTarget t) { 594 String id = t.getId(); 595 if (id != null) { 596 b.append(" id=\"").append(id).append("\""); 597 } 598 } 599 600 /** 601 * Serialize namespace declarations for the root SCXML element. 602 * 603 * @param holder The {@link NamespacePrefixesHolder} object 604 * @return The serialized namespace declarations 605 */ 606 private static String serializeNamespaceDeclarations( 607 final NamespacePrefixesHolder holder) { 608 Map ns = holder.getNamespaces(); 609 StringBuffer b = new StringBuffer(); 610 if (ns != null) { 611 Iterator iter = ns.entrySet().iterator(); 612 while (iter.hasNext()) { 613 Map.Entry entry = (Map.Entry) iter.next(); 614 String prefix = (String) entry.getKey(); 615 String nsURI = (String) entry.getValue(); 616 if (prefix.length() == 0 && !nsURI.equals(NAMESPACE_SCXML)) { 617 org.apache.commons.logging.Log log = LogFactory. 618 getLog(SCXMLSerializer.class); 619 log.warn("When using the SCXMLSerializer, the default " 620 + "namespace must be the SCXML namespace:" 621 + NAMESPACE_SCXML); 622 } if (prefix.equals("cs") 623 && !nsURI.equals(NAMESPACE_COMMONS_SCXML)) { 624 org.apache.commons.logging.Log log = LogFactory. 625 getLog(SCXMLSerializer.class); 626 log.warn("When using the SCXMLSerializer, the namespace" 627 + "prefix \"cs\" must bind to the Commons SCXML " 628 + "namespace:" + NAMESPACE_COMMONS_SCXML); 629 } else if (prefix.length() > 0) { 630 b.append(" xmlns:").append(prefix).append("=\""). 631 append(nsURI).append("\""); 632 } 633 } 634 } 635 return b.toString(); 636 } 637 638 /** 639 * Get a <code>Transformer</code> instance. 640 * 641 * @return Transformer The <code>Transformer</code> instance. 642 */ 643 private static Transformer getTransformer() { 644 Transformer transformer = null; 645 Properties outputProps = new Properties(); 646 outputProps.put(OutputKeys.OMIT_XML_DECLARATION, "yes"); 647 outputProps.put(OutputKeys.STANDALONE, "no"); 648 outputProps.put(OutputKeys.INDENT, "yes"); 649 try { 650 TransformerFactory tfFactory = TransformerFactory.newInstance(); 651 transformer = tfFactory.newTransformer(); 652 transformer.setOutputProperties(outputProps); 653 } catch (Throwable t) { 654 return null; 655 } 656 return transformer; 657 } 658 659 /* 660 * Private methods. 661 */ 662 /** 663 * Discourage instantiation since this is a utility class. 664 */ 665 private SCXMLSerializer() { 666 super(); 667 } 668 669 } 670