/*
*
* Copyright 2005 The Apache Software Foundation.
*
* Licensed 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.util.Collection;
import javax.xml.parsers.DocumentBuilderFactory;
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.w3c.dom.Document;
import org.w3c.dom.Node;
/**
* The class in this SCXML object model that corresponds to the
* <assign> SCXML element.
*
*/
public final class Assign extends Action implements PathResolverHolder {
/**
* 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.
*/
public PathResolver getPathResolver() {
return pathResolver;
}
/**
* Set the {@link PathResolver}.
*
* @param pathResolver The pathResolver to set.
*/
public void setPathResolver(final PathResolver pathResolver) {
this.pathResolver = pathResolver;
}
/**
* {@inheritDoc}
*/
public void execute(final EventDispatcher evtDispatcher,
final ErrorReporter errRep, final SCInstance scInstance,
final Log appLog, final Collection derivedEvents)
throws ModelException, SCXMLExpressionException {
State parentState = getParentState();
Context ctx = scInstance.getContext(parentState);
Evaluator eval = scInstance.getEvaluator();
// "location" gets preference over "name"
if (!SCXMLHelper.isStringEmpty(location)) {
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);
}
if (newNode != null) {
// adopt children, possible spec clarification needed
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());
}
TriggerEvent ev = new TriggerEvent(name + ".change",
TriggerEvent.CHANGE_EVENT);
derivedEvents.add(ev);
} 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 (!ctx.has(name)) {
errRep.onError(ErrorReporter.UNDEFINED_VARIABLE, name
+ " = null", parentState);
} else {
Object varObj = null;
if (src != null && src.trim().length() > 0) {
varObj = getSrcNode();
} else {
varObj = eval.eval(ctx, expr);
}
ctx.set(name, varObj);
TriggerEvent ev = new TriggerEvent(name + ".change",
TriggerEvent.CHANGE_EVENT);
derivedEvents.add(ev);
}
}
}
/**
* 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 (Throwable t) {
org.apache.commons.logging.Log log = LogFactory.
getLog(Assign.class);
log.error(t.getMessage(), t);
}
if (doc == null) {
return null;
}
return doc.getDocumentElement();
}
}