org.apache.commons.scxml.model.Assign.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.commons.scxml.model.Assign.java

Source

/*
 * 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.model;

import java.io.IOException;
import java.util.Collection;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.scxml.Context;
import org.apache.commons.scxml.ErrorReporter;
import org.apache.commons.scxml.Evaluator;
import org.apache.commons.scxml.EventDispatcher;
import org.apache.commons.scxml.PathResolver;
import org.apache.commons.scxml.SCInstance;
import org.apache.commons.scxml.SCXMLExpressionException;
import org.apache.commons.scxml.SCXMLHelper;
import org.apache.commons.scxml.TriggerEvent;
import org.apache.commons.scxml.semantics.ErrorConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

/**
 * The class in this SCXML object model that corresponds to the <assign>
 * SCXML element.
 * 
 */
public class Assign extends Action implements PathResolverHolder {

    /**
     * Serial version UID.
     */
    private static final long serialVersionUID = 1L;

    /**
     * Left hand side expression evaluating to a previously defined variable.
     */
    private String name;

    /**
     * Left hand side expression evaluating to a location within a previously
     * defined XML data tree.
     */
    private String location;

    /**
     * The source where the new XML instance for this location exists.
     */
    private String src;

    /**
     * Expression evaluating to the new value of the variable.
     */
    private String expr;

    /**
     * {@link PathResolver} for resolving the "src" result.
     */
    private PathResolver pathResolver;

    /**
     * Constructor.
     */
    public Assign() {
        super();
    }

    /**
     * Get the variable to be assigned a new value.
     * 
     * @return Returns the name.
     */
    public String getName() {
        return name;
    }

    /**
     * Get the variable to be assigned a new value.
     * 
     * @param name
     *            The name to set.
     */
    public void setName(final String name) {
        this.name = name;
    }

    /**
     * Get the expr that will evaluate to the new value.
     * 
     * @return Returns the expr.
     */
    public String getExpr() {
        return expr;
    }

    /**
     * Set the expr that will evaluate to the new value.
     * 
     * @param expr
     *            The expr to set.
     */
    public void setExpr(final String expr) {
        this.expr = expr;
    }

    /**
     * Get the location for a previously defined XML data tree.
     * 
     * @return Returns the location.
     */
    public String getLocation() {
        return location;
    }

    /**
     * Set the location for a previously defined XML data tree.
     * 
     * @param location
     *            The location.
     */
    public void setLocation(final String location) {
        this.location = location;
    }

    /**
     * Get the source where the new XML instance for this location exists.
     * 
     * @return Returns the source.
     */
    public String getSrc() {
        return src;
    }

    /**
     * Set the source where the new XML instance for this location exists.
     * 
     * @param src
     *            The source.
     */
    public void setSrc(final String src) {
        this.src = src;
    }

    /**
     * Get the {@link PathResolver}.
     * 
     * @return Returns the pathResolver.
     */
    @Override
    public PathResolver getPathResolver() {
        return pathResolver;
    }

    /**
     * Set the {@link PathResolver}.
     * 
     * @param pathResolver
     *            The pathResolver to set.
     */
    @Override
    public void setPathResolver(final PathResolver pathResolver) {
        this.pathResolver = pathResolver;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void execute(final EventDispatcher evtDispatcher, final ErrorReporter errRep,
            final SCInstance scInstance, final Log appLog, final Collection<TriggerEvent> derivedEvents)
            throws ModelException, SCXMLExpressionException {
        TransitionTarget parentTarget = getParentTransitionTarget();
        Context ctx = scInstance.getContext(parentTarget);
        Evaluator eval = scInstance.getEvaluator();
        ctx.setLocal(getNamespacesKey(), getNamespaces());
        // "location" gets preference over "name"
        Node oldNode = null;

        // @CUSTOM [
        try {
            oldNode = eval.evalLocation(ctx, location);
        } catch (SCXMLExpressionException e) {
            if (name == null) {
                name = location;
            }
        }
        // ]

        if (!SCXMLHelper.isStringEmpty(location) && oldNode != null) {
            // @CUSTOM [
            // Node oldNode = eval.evalLocation(ctx, location);
            // if (oldNode != null) {
            // ]
            // // rvalue may be ...
            // a Node, if so, import it at location
            Node newNode = null;
            try {
                if (src != null && src.trim().length() > 0) {
                    newNode = getSrcNode();
                } else {
                    newNode = eval.evalLocation(ctx, expr);
                }
                // Remove all children
                Node removeChild = oldNode.getFirstChild();
                while (removeChild != null) {
                    Node nextChild = removeChild.getNextSibling();
                    oldNode.removeChild(removeChild);
                    removeChild = nextChild;
                }
                if (newNode != null) {
                    // Adopt new children
                    for (Node child = newNode.getFirstChild(); child != null; child = child.getNextSibling()) {
                        Node importedNode = oldNode.getOwnerDocument().importNode(child, true);
                        oldNode.appendChild(importedNode);
                    }
                }
            } catch (SCXMLExpressionException see) {
                // or something else, stuff toString() into lvalue
                Object valueObject = eval.eval(ctx, expr);
                SCXMLHelper.setNodeValue(oldNode, valueObject.toString());
            }
            if (appLog.isDebugEnabled()) {
                appLog.debug("<assign>: data node '" + oldNode.getNodeName() + "' updated");
            }
            TriggerEvent ev = new TriggerEvent(name + ".change", TriggerEvent.CHANGE_EVENT);
            derivedEvents.add(ev);
            // @CUSTOM [
            // } else {
            // appLog.error("<assign>: location does not point to"
            // + " a <data> node");
            // }
            // ]
        } else {
            // lets try "name" (usage as in Sep '05 WD, useful with <var>)
            if (name != null && !name.isEmpty() && !ctx.has(name)) {
                errRep.onError(ErrorConstants.UNDEFINED_VARIABLE, name + " = null", parentTarget);
            } else {
                Object varObj = null;
                if (src != null && src.trim().length() > 0) {
                    varObj = getSrcNode();
                } else {
                    varObj = eval.eval(ctx, expr);
                }
                if (name != null && !name.isEmpty()) {
                    ctx.set(name, varObj);
                    if (appLog.isDebugEnabled()) {
                        appLog.debug("<assign>: Set variable '" + name + "' to '" + String.valueOf(varObj) + "'");
                    }
                    TriggerEvent ev = new TriggerEvent(name + ".change", TriggerEvent.CHANGE_EVENT);
                    derivedEvents.add(ev);
                }
            }
        }
        ctx.setLocal(getNamespacesKey(), null);
    }

    /**
     * Get the {@link Node} the "src" attribute points to.
     * 
     * @return The node the "src" attribute points to.
     */
    private Node getSrcNode() {
        String resolvedSrc = src;
        if (pathResolver != null) {
            resolvedSrc = pathResolver.resolvePath(src);
        }
        Document doc = null;
        try {
            doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(resolvedSrc);
        } catch (FactoryConfigurationError t) {
            logError(t);
        } catch (SAXException e) {
            logError(e);
        } catch (IOException e) {
            logError(e);
        } catch (ParserConfigurationException e) {
            logError(e);
        }
        if (doc == null)
            return null;
        return doc.getDocumentElement();
    }

    /**
     * @param throwable
     */
    private void logError(Throwable throwable) {
        org.apache.commons.logging.Log log = LogFactory.getLog(Assign.class);
        log.error(throwable.getMessage(), throwable);
    }

}