Package org.apache.commons.scxml.io

Source Code of org.apache.commons.scxml.io.SCXMLSerializer

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.scxml.io;

import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.logging.LogFactory;
import org.apache.commons.scxml.SCXMLHelper;
import org.apache.commons.scxml.model.Action;
import org.apache.commons.scxml.model.Assign;
import org.apache.commons.scxml.model.Cancel;
import org.apache.commons.scxml.model.Data;
import org.apache.commons.scxml.model.Datamodel;
import org.apache.commons.scxml.model.Else;
import org.apache.commons.scxml.model.ElseIf;
import org.apache.commons.scxml.model.Exit;
import org.apache.commons.scxml.model.ExternalContent;
import org.apache.commons.scxml.model.Finalize;
import org.apache.commons.scxml.model.History;
import org.apache.commons.scxml.model.If;
import org.apache.commons.scxml.model.Initial;
import org.apache.commons.scxml.model.Invoke;
import org.apache.commons.scxml.model.Log;
import org.apache.commons.scxml.model.OnEntry;
import org.apache.commons.scxml.model.OnExit;
import org.apache.commons.scxml.model.Parallel;
import org.apache.commons.scxml.model.Param;
import org.apache.commons.scxml.model.SCXML;
import org.apache.commons.scxml.model.Send;
import org.apache.commons.scxml.model.State;
import org.apache.commons.scxml.model.Transition;
import org.apache.commons.scxml.model.TransitionTarget;
import org.apache.commons.scxml.model.Var;
import org.w3c.dom.Node;

/**
* Utility class for serializing the Commons SCXML Java object
* model. Class uses the visitor pattern to trace through the
* object heirarchy. Used primarily for testing, debugging and
* visual verification.
*
*/
public class SCXMLSerializer {

    /** The indent to be used while serializing an SCXML object. */
    private static final String INDENT = " ";
    /** The JAXP transformer. */
    private static final Transformer XFORMER = getTransformer();

    /**
     * Serialize this SCXML object (primarily for debugging).
     *
     * @param scxml
     *            The SCXML to be serialized
     * @return String The serialized SCXML
     */
    public static String serialize(final SCXML scxml) {
        StringBuffer b =
            new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n").
                append("<scxml xmlns=\"").append(scxml.getXmlns()).
                append("\" version=\"").append(scxml.getVersion()).
                append("\" initialstate=\"").append(scxml.getInitialstate()).
                append("\">\n");
        if (XFORMER == null) {
            org.apache.commons.logging.Log log = LogFactory.
                getLog(SCXMLSerializer.class);
            log.warn("SCXMLSerializer: DOM serialization pertinent to"
                + " the document will be skipped since a suitable"
                + " JAXP Transformer could not be instantiated.");
        }
        Datamodel dm = scxml.getDatamodel();
        if (dm != null) {
            serializeDatamodel(b, dm, INDENT);
        }
        Map c = scxml.getChildren();
        Iterator i = c.keySet().iterator();
        while (i.hasNext()) {
            TransitionTarget tt = (TransitionTarget) c.get(i.next());
            if (tt instanceof State) {
                serializeState(b, (State) tt, INDENT);
            } else {
                serializeParallel(b, (Parallel) tt, INDENT);
            }
        }
        b.append("</scxml>\n");
        return b.toString();
    }

    /**
     * Serialize this State object.
     *
     * @param b The buffer to append the serialization to
     * @param s The State to serialize
     * @param indent The indent for this XML element
     */
    public static void serializeState(final StringBuffer b,
            final State s, final String indent) {
        b.append(indent).append("<state");
        serializeTransitionTargetAttributes(b, s);
        boolean f = s.isFinal();
        if (f) {
            b.append(" final=\"true\"");
        }
        b.append(">\n");
        Initial ini = s.getInitial();
        if (ini != null) {
            serializeInitial(b, ini, indent + INDENT);
        }
        List h = s.getHistory();
        if (h != null) {
            serializeHistory(b, h, indent + INDENT);
        }
        Datamodel dm = s.getDatamodel();
        if (dm != null) {
            serializeDatamodel(b, dm, indent + INDENT);
        }
        serializeOnEntry(b, s, indent + INDENT);
        List t = s.getTransitionsList();
        for (int i = 0; i < t.size(); i++) {
            serializeTransition(b, (Transition) t.get(i), indent + INDENT);
        }
        Parallel p = s.getParallel(); //TODO: Remove in v1.0
        Invoke inv = s.getInvoke();
        if (p != null) {
            serializeParallel(b, p, indent + INDENT);
        } else if (inv != null) {
            serializeInvoke(b , inv, indent + INDENT);
        } else {
            Map c = s.getChildren();
            Iterator j = c.keySet().iterator();
            while (j.hasNext()) {
                State cs = (State) c.get(j.next());
                serializeState(b, cs, indent + INDENT);
            }
        }
        serializeOnExit(b, s, indent + INDENT);
        b.append(indent).append("</state>\n");
    }

    /**
     * Serialize this Parallel object.
     *
     * @param b The buffer to append the serialization to
     * @param p The Parallel to serialize
     * @param indent The indent for this XML element
     */
    public static void serializeParallel(final StringBuffer b,
            final Parallel p, final String indent) {
        b.append(indent).append("<parallel");
        serializeTransitionTargetAttributes(b, p);
        b.append(">\n");
        serializeOnEntry(b, p, indent + INDENT);
        Set s = p.getChildren();
        Iterator i = s.iterator();
        while (i.hasNext()) {
            serializeState(b, (State) i.next(), indent + INDENT);
        }
        serializeOnExit(b, p, indent + INDENT);
        b.append(indent).append("</parallel>\n");
    }

    /**
     * Serialize this Invoke object.
     *
     * @param b The buffer to append the serialization to
     * @param i The Invoke to serialize
     * @param indent The indent for this XML element
     */
    public static void serializeInvoke(final StringBuffer b,
            final Invoke i, final String indent) {
        b.append(indent).append("<invoke");
        String ttype = i.getTargettype();
        String src = i.getSrc();
        String srcexpr = i.getSrcexpr();
        if (ttype != null) {
            b.append(" targettype=\"").append(ttype).append("\"");
        }
        // Prefer src
        if (src != null) {
            b.append(" src=\"").append(src).append("\"");
        } else if (srcexpr != null) {
            b.append(" srcexpr=\"").append(srcexpr).append("\"");
        }
        b.append(">\n");
        List params = i.params();
        for (Iterator iter = params.iterator(); iter.hasNext();) {
            Param p = (Param) iter.next();
            b.append(indent).append(INDENT).append("<param name=\"").
                append(p.getName()).append("\" expr=\"").
                append(p.getExpr()).append("\"/>\n");
        }
        Finalize f = i.getFinalize();
        if (f != null) {
            b.append(indent).append(INDENT).append("<finalize>\n");
            serializeActions(b, f.getActions(), indent + INDENT + INDENT);
            b.append(indent).append(INDENT).append("</finalize>\n");
        }
        b.append(indent).append("</invoke>\n");
    }

    /**
     * Serialize this Initial object.
     *
     * @param b The buffer to append the serialization to
     * @param i The Initial to serialize
     * @param indent The indent for this XML element
     */
    public static void serializeInitial(final StringBuffer b, final Initial i,
            final String indent) {
        b.append(indent).append("<initial");
        serializeTransitionTargetAttributes(b, i);
        b.append(">\n");
        serializeTransition(b, i.getTransition(), indent + INDENT);
        b.append(indent).append("</initial>\n");
    }

    /**
     * Serialize the History.
     *
     * @param b The buffer to append the serialization to
     * @param l The List of History objects to serialize
     * @param indent The indent for this XML element
     */
    public static void serializeHistory(final StringBuffer b, final List l,
            final String indent) {
        if (l.size() > 0) {
            for (int i = 0; i < l.size(); i++) {
                History h = (History) l.get(i);
                b.append(indent).append("<history");
                serializeTransitionTargetAttributes(b, h);
                 if (h.isDeep()) {
                     b.append(" type=\"deep\"");
                 } else {
                     b.append(" type=\"shallow\"");
                 }
                b.append(">\n");
                serializeTransition(b, h.getTransition(), indent + INDENT);
                b.append(indent).append("</history>\n");
            }
        }
    }

    /**
     * Serialize this Transition object.
     *
     * @param b The buffer to append the serialization to
     * @param t The Transition to serialize
     * @param indent The indent for this XML element
     */
    public static void serializeTransition(final StringBuffer b,
            final Transition t, final String indent) {
        b.append(indent).append("<transition event=\"").append(t.getEvent())
            .append("\" cond=\"").append(t.getCond()).append("\">\n");
        boolean exit = serializeActions(b, t.getActions(), indent + INDENT);
        if (!exit) {
            serializeTarget(b, t, indent + INDENT);
        }
        b.append(indent).append("</transition>\n");
    }

    /**
     * Serialize this Transition's Target.
     *
     *
     * @param b The buffer to append the serialization to
     * @param t The Transition whose Target needs to be serialized
     * @param indent The indent for this XML element
     *
     * @deprecated Inline &lt;target&gt; element has been deprecated
     *             in the SCXML WD
     */
    public static void serializeTarget(final StringBuffer b,
            final Transition t, final String indent) {
        b.append(indent).append("<target");
        String n = t.getNext();
        if (n != null) {
            b.append(" next=\"" + n + "\">\n");
        } else {
            b.append(">\n");
            if (t.getTarget() != null) {
                // The inline transition target can only be a state
                serializeState(b, (State) t.getTarget(), indent + INDENT);
            }
        }
        b.append(indent).append("</target>\n");
    }

    /**
     * Serialize this Datamodel object.
     *
     * @param b The buffer to append the serialization to
     * @param dm The Datamodel to be serialized
     * @param indent The indent for this XML element
     */
    public static void serializeDatamodel(final StringBuffer b,
            final Datamodel dm, final String indent) {
        List data = dm.getData();
        if (data != null && data.size() > 0) {
            b.append(indent).append("<datamodel>\n");
            if (XFORMER == null) {
                b.append(indent).append(INDENT).
                    append("<!-- Body content was not serialized -->\n");
                b.append(indent).append("</datamodel>\n");
                return;
            }
            for (Iterator iter = data.iterator(); iter.hasNext();) {
                Data datum = (Data) iter.next();
                Node dataNode = datum.getNode();
                if (dataNode != null) {
                    StringWriter out = new StringWriter();
                    try {
                        Source input = new DOMSource(dataNode);
                        Result output = new StreamResult(out);
                        XFORMER.transform(input, output);
                    } catch (TransformerException te) {
                        org.apache.commons.logging.Log log = LogFactory.
                            getLog(SCXMLSerializer.class);
                        log.error(te.getMessage(), te);
                        b.append(indent).append(INDENT).
                            append("<!-- Data content not serialized -->\n");
                    }
                    b.append(indent).append(INDENT).append(out.toString());
                } else {
                    b.append(indent).append(INDENT).append("<data name=\"").
                        append(datum.getName()).append("\" expr=\"").
                        append(datum.getExpr()).append("\" />\n");
                }
            }
            b.append(indent).append("</datamodel>\n");
        }
    }

    /**
     * Serialize this OnEntry object.
     *
     * @param b The buffer to append the serialization to
     * @param t The TransitionTarget whose OnEntry is to be serialized
     * @param indent The indent for this XML element
     */
    public static void serializeOnEntry(final StringBuffer b,
            final TransitionTarget t, final String indent) {
        OnEntry e = t.getOnEntry();
        if (e != null && e.getActions().size() > 0) {
            b.append(indent).append("<onentry>\n");
            serializeActions(b, e.getActions(), indent + INDENT);
            b.append(indent).append("</onentry>\n");
        }
    }

    /**
     * Serialize this OnExit object.
     *
     * @param b The buffer to append the serialization to
     * @param t The TransitionTarget whose OnExit is to be serialized
     * @param indent The indent for this XML element
     */
    public static void serializeOnExit(final StringBuffer b,
            final TransitionTarget t, final String indent) {
        OnExit x = t.getOnExit();
        if (x != null && x.getActions().size() > 0) {
            b.append(indent).append("<onexit>\n");
            serializeActions(b, x.getActions(), indent + INDENT);
            b.append(indent).append("</onexit>\n");
        }
    }

    /**
     * Serialize this List of actions.
     *
     * @param b The buffer to append the serialization to
     * @param l The List of actions to serialize
     * @param indent The indent for this XML element
     * @return boolean true if the list of actions contains an &lt;exit/&gt;
     */
    public static boolean serializeActions(final StringBuffer b, final List l,
            final String indent) {
        if (l == null) {
            return false;
        }
        boolean exit = false;
        Iterator i = l.iterator();
        while (i.hasNext()) {
            Action a = (Action) i.next();
            if (a instanceof Var) {
                Var v = (Var) a;
                b.append(indent).append("<var name=\"").append(v.getName())
                        .append("\" expr=\"").append(v.getExpr()).append(
                                "\"/>\n");
            } else if (a instanceof Assign) {
                Assign asn = (Assign) a;
                b.append(indent).append("<assign");
                if (!SCXMLHelper.isStringEmpty(asn.getLocation())) {
                    b.append(" location=\"").append(asn.getLocation());
                    if (!SCXMLHelper.isStringEmpty(asn.getSrc())) {
                        b.append("\" src=\"").append(asn.getSrc());
                    } else {
                        b.append("\" expr=\"").append(asn.getExpr());
                    }
                } else {
                    b.append(" name=\"").append(asn.getName()).
                        append("\" expr=\"").append(asn.getExpr());
                }
                b.append("\"/>\n");
            } else if (a instanceof Send) {
                serializeSend(b, (Send) a, indent);
            } else if (a instanceof Cancel) {
                Cancel c = (Cancel) a;
                b.append(indent).append("<cancel sendid=\"")
                    .append(c.getSendid()).append("\"/>\n");
            } else if (a instanceof Log) {
                Log lg = (Log) a;
                b.append(indent).append("<log expr=\"").append(lg.getExpr())
                        .append("\"/>\n");
            } else if (a instanceof Exit) {
                Exit e = (Exit) a;
                b.append(indent).append("<exit");
                String expr = e.getExpr();
                String nl = e.getNamelist();
                if (expr != null) {
                    b.append(" expr=\"" + expr + "\"");
                }
                if (nl != null) {
                    b.append(" namelist=\"" + nl + "\"");
                }
                b.append("/>\n");
                exit = true;
            } else if (a instanceof If) {
                If iff = (If) a;
                serializeIf(b, iff, indent);
            } else if (a instanceof Else) {
                b.append(indent).append("<else/>\n");
            } else if (a instanceof ElseIf) {
                ElseIf eif = (ElseIf) a;
                b.append(indent).append("<elseif cond=\"")
                        .append(eif.getCond()).append("\" />\n");
            }
        }
        return exit;
    }

    /**
     * Serialize this Send object.
     *
     * @param b The buffer to append the serialization to
     * @param send The Send object to serialize
     * @param indent The indent for this XML element
     */
    public static void serializeSend(final StringBuffer b,
            final Send send, final String indent) {
        b.append(indent).append("<send sendid=\"")
            .append(send.getSendid()).append("\" target=\"")
            .append(send.getTarget()).append("\" targetType=\"")
            .append(send.getTargettype()).append("\" namelist=\"")
            .append(send.getNamelist()).append("\" delay=\"")
            .append(send.getDelay()).append("\" events=\"")
            .append(send.getEvent()).append("\" hints=\"")
            .append(send.getHints()).append("\">\n")
            .append(getBodyContent(send))
            .append(indent).append("</send>\n");
    }

    /**
     * Return serialized body of <code>ExternalContent</code>.
     *
     * @param externalContent The model element containing the body content
     * @return String The serialized body content
     */
    public static final String getBodyContent(
            final ExternalContent externalContent) {
        StringBuffer buf = new StringBuffer();
        List externalNodes = externalContent.getExternalNodes();
        if (externalNodes.size() > 0 && XFORMER == null) {
            buf.append("<!-- Body content was not serialized -->\n");
            return buf.toString();
        }
        for (int i = 0; i < externalNodes.size(); i++) {
            Source input = new DOMSource((Node) externalNodes.get(i));
            StringWriter out = new StringWriter();
            Result output = new StreamResult(out);
            try {
                XFORMER.transform(input, output);
            } catch (TransformerException te) {
                org.apache.commons.logging.Log log = LogFactory.
                    getLog(SCXMLSerializer.class);
                log.error(te.getMessage(), te);
                buf.append("<!-- Not all body content was serialized -->");
            }
            buf.append(out.toString()).append("\n");
        }
        return buf.toString();
    }

    /**
     * Serialize this If object.
     *
     * @param b The buffer to append the serialization to
     * @param iff The If object to serialize
     * @param indent The indent for this XML element
     */
    public static void serializeIf(final StringBuffer b,
            final If iff, final String indent) {
        b.append(indent).append("<if cond=\"").append(iff.getCond()).append(
                "\">\n");
        serializeActions(b, iff.getActions(), indent + INDENT);
        b.append(indent).append("</if>\n");
    }

    /**
     * Serialize properties of TransitionTarget which are element attributes.
     *
     * @param b The buffer to append the serialization to
     * @param t The TransitionTarget
     */
    private static void serializeTransitionTargetAttributes(
            final StringBuffer b, final TransitionTarget t) {
        String id = t.getId();
        if (id != null) {
            b.append(" id=\"").append(id).append("\"");
        }
        TransitionTarget pt = t.getParent();
        if (pt != null) {
            String pid = pt.getId();
            if (pid != null) {
                b.append(" parentid=\"").append(pid).append("\"");
            }
        }
    }

    /**
     * Get a <code>Transformer</code> instance.
     *
     * @return Transformer The <code>Transformer</code> instance.
     */
    private static Transformer getTransformer() {
        Transformer transformer = null;
        Properties outputProps = new Properties();
        outputProps.put(OutputKeys.OMIT_XML_DECLARATION, "yes");
        outputProps.put(OutputKeys.STANDALONE, "no");
        outputProps.put(OutputKeys.INDENT, "yes");
        try {
            TransformerFactory tfFactory = TransformerFactory.newInstance();
            transformer = tfFactory.newTransformer();
            transformer.setOutputProperties(outputProps);
        } catch (Throwable t) {
            return null;
        }
        return transformer;
    }

    /*
     * Private methods.
     */
    /**
     * Discourage instantiation since this is a utility class.
     */
    private SCXMLSerializer() {
        super();
    }

}

TOP

Related Classes of org.apache.commons.scxml.io.SCXMLSerializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.