View Javadoc

1   /*
2    *
3    *   Copyright 2005 The Apache Software Foundation.
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   *
17   */
18  package org.apache.commons.scxml.model;
19  
20  import java.util.Collection;
21  
22  import javax.xml.parsers.DocumentBuilderFactory;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.commons.scxml.Context;
27  import org.apache.commons.scxml.ErrorReporter;
28  import org.apache.commons.scxml.Evaluator;
29  import org.apache.commons.scxml.EventDispatcher;
30  import org.apache.commons.scxml.PathResolver;
31  import org.apache.commons.scxml.SCInstance;
32  import org.apache.commons.scxml.SCXMLExpressionException;
33  import org.apache.commons.scxml.SCXMLHelper;
34  import org.apache.commons.scxml.TriggerEvent;
35  import org.w3c.dom.Document;
36  import org.w3c.dom.Node;
37  
38  /***
39   * The class in this SCXML object model that corresponds to the
40   * <assign> SCXML element.
41   *
42   */
43  public final class Assign extends Action implements PathResolverHolder {
44  
45      /***
46       * Left hand side expression evaluating to a previously
47       * defined variable.
48       */
49      private String name;
50  
51      /***
52       * Left hand side expression evaluating to a location within
53       * a previously defined XML data tree.
54       */
55      private String location;
56  
57      /***
58       * The source where the new XML instance for this location exists.
59       */
60      private String src;
61  
62      /***
63       * Expression evaluating to the new value of the variable.
64       */
65      private String expr;
66  
67      /***
68       * {@link PathResolver} for resolving the "src" result.
69       */
70      private PathResolver pathResolver;
71  
72      /***
73       * Constructor.
74       */
75      public Assign() {
76          super();
77      }
78  
79      /***
80       * Get the variable to be assigned a new value.
81       *
82       * @return Returns the name.
83       */
84      public String getName() {
85          return name;
86      }
87  
88      /***
89       * Get the variable to be assigned a new value.
90       *
91       * @param name The name to set.
92       */
93      public void setName(final String name) {
94          this.name = name;
95      }
96  
97      /***
98       * Get the expr that will evaluate to the new value.
99       *
100      * @return Returns the expr.
101      */
102     public String getExpr() {
103         return expr;
104     }
105 
106     /***
107      * Set the expr that will evaluate to the new value.
108      *
109      * @param expr The expr to set.
110      */
111     public void setExpr(final String expr) {
112         this.expr = expr;
113     }
114 
115     /***
116      * Get the location for a previously defined XML data tree.
117      *
118      * @return Returns the location.
119      */
120     public String getLocation() {
121         return location;
122     }
123 
124     /***
125      * Set the location for a previously defined XML data tree.
126      *
127      * @param location The location.
128      */
129     public void setLocation(final String location) {
130         this.location = location;
131     }
132 
133     /***
134      * Get the source where the new XML instance for this location exists.
135      *
136      * @return Returns the source.
137      */
138     public String getSrc() {
139         return src;
140     }
141 
142     /***
143      * Set the source where the new XML instance for this location exists.
144      *
145      * @param src The source.
146      */
147     public void setSrc(final String src) {
148         this.src = src;
149     }
150 
151     /***
152      * Get the {@link PathResolver}.
153      *
154      * @return Returns the pathResolver.
155      */
156     public PathResolver getPathResolver() {
157         return pathResolver;
158     }
159 
160     /***
161      * Set the {@link PathResolver}.
162      *
163      * @param pathResolver The pathResolver to set.
164      */
165     public void setPathResolver(final PathResolver pathResolver) {
166         this.pathResolver = pathResolver;
167     }
168 
169     /***
170      * {@inheritDoc}
171      */
172     public void execute(final EventDispatcher evtDispatcher,
173             final ErrorReporter errRep, final SCInstance scInstance,
174             final Log appLog, final Collection derivedEvents)
175     throws ModelException, SCXMLExpressionException {
176         State parentState = getParentState();
177         Context ctx = scInstance.getContext(parentState);
178         Evaluator eval = scInstance.getEvaluator();
179         // "location" gets preference over "name"
180         if (!SCXMLHelper.isStringEmpty(location)) {
181             Node oldNode = eval.evalLocation(ctx, location);
182             if (oldNode != null) {
183                 //// rvalue may be ...
184                 // a Node, if so, import it at location
185                 Node newNode = null;
186                 try {
187                     if (src != null && src.trim().length() > 0) {
188                         newNode = getSrcNode();
189                     } else {
190                         newNode = eval.evalLocation(ctx, expr);
191                     }
192                     if (newNode != null) {
193                         // adopt children, possible spec clarification needed
194                         for (Node child = newNode.getFirstChild();
195                                 child != null;
196                                 child = child.getNextSibling()) {
197                             Node importedNode = oldNode.getOwnerDocument().
198                                 importNode(child, true);
199                             oldNode.appendChild(importedNode);
200                         }
201                     }
202                 } catch (SCXMLExpressionException see) {
203                     // or something else, stuff toString() into lvalue
204                     Object valueObject = eval.eval(ctx, expr);
205                     SCXMLHelper.setNodeValue(oldNode, valueObject.toString());
206                 }
207                 TriggerEvent ev = new TriggerEvent(name + ".change",
208                     TriggerEvent.CHANGE_EVENT);
209                 derivedEvents.add(ev);
210             } else {
211                 appLog.error("<assign>: location does not point to"
212                     + " a <data> node");
213             }
214         } else {
215             // lets try "name" (usage as in Sep '05 WD, useful with <var>)
216             if (!ctx.has(name)) {
217                 errRep.onError(ErrorReporter.UNDEFINED_VARIABLE, name
218                     + " = null", parentState);
219             } else {
220                 Object varObj = null;
221                 if (src != null && src.trim().length() > 0) {
222                     varObj = getSrcNode();
223                 } else {
224                     varObj = eval.eval(ctx, expr);
225                 }
226                 ctx.set(name, varObj);
227                 TriggerEvent ev = new TriggerEvent(name + ".change",
228                     TriggerEvent.CHANGE_EVENT);
229                 derivedEvents.add(ev);
230             }
231         }
232     }
233 
234     /***
235      * Get the {@link Node} the "src" attribute points to.
236      *
237      * @return The node the "src" attribute points to.
238      */
239     private Node getSrcNode() {
240         String resolvedSrc = src;
241         if (pathResolver != null) {
242             resolvedSrc = pathResolver.resolvePath(src);
243         }
244         Document doc = null;
245         try {
246             doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().
247                 parse(resolvedSrc);
248         } catch (Throwable t) {
249             org.apache.commons.logging.Log log = LogFactory.
250                 getLog(Assign.class);
251             log.error(t.getMessage(), t);
252         }
253         if (doc == null) {
254             return null;
255         }
256         return doc.getDocumentElement();
257     }
258 
259 }