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