View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  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  package org.apache.commons.scxml2.model;
18  
19  import java.io.IOException;
20  
21  import javax.xml.parsers.DocumentBuilderFactory;
22  import javax.xml.parsers.FactoryConfigurationError;
23  import javax.xml.parsers.ParserConfigurationException;
24  
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.commons.scxml2.ActionExecutionContext;
27  import org.apache.commons.scxml2.Context;
28  import org.apache.commons.scxml2.Evaluator;
29  import org.apache.commons.scxml2.PathResolver;
30  import org.apache.commons.scxml2.SCXMLExpressionException;
31  import org.w3c.dom.*;
32  import org.xml.sax.SAXException;
33  
34  /**
35   * The class in this SCXML object model that corresponds to the
36   * <assign> SCXML element.
37   *
38   */
39  public class Assign extends Action implements PathResolverHolder {
40  
41      /**
42       * Serial version UID.
43       */
44      private static final long serialVersionUID = 1L;
45  
46      /**
47       * Left hand side expression evaluating to a location within
48       * a previously defined XML data tree.
49       */
50      private String location;
51  
52      /**
53       * The source where the new XML instance for this location exists.
54       */
55      private String src;
56  
57      /**
58       * Expression evaluating to the new value of the variable.
59       */
60      private String expr;
61  
62      /**
63       * Defines the nature of the insertion to be performed, default {@link Evaluator.AssignType#REPLACE_CHILDREN}
64       */
65      private Evaluator.AssignType type;
66  
67      /**
68       * The attribute name to add at the specified location when using {@link Evaluator.AssignType#ADD_ATTRIBUTE}
69       */
70      private String attr;
71  
72      /**
73       * {@link PathResolver} for resolving the "src" result.
74       */
75      private PathResolver pathResolver;
76  
77      /**
78       * Constructor.
79       */
80      public Assign() {
81          super();
82      }
83  
84      /**
85       * Get the expr that will evaluate to the new value.
86       *
87       * @return Returns the expr.
88       */
89      public String getExpr() {
90          return expr;
91      }
92  
93      /**
94       * Set the expr that will evaluate to the new value.
95       *
96       * @param expr The expr to set.
97       */
98      public void setExpr(final String expr) {
99          this.expr = expr;
100     }
101 
102     /**
103      * Get the location for a previously defined XML data tree.
104      *
105      * @return Returns the location.
106      */
107     public String getLocation() {
108         return location;
109     }
110 
111     /**
112      * Set the location for a previously defined XML data tree.
113      *
114      * @param location The location.
115      */
116     public void setLocation(final String location) {
117         this.location = location;
118     }
119 
120     /**
121      * Get the source where the new XML instance for this location exists.
122      *
123      * @return Returns the source.
124      */
125     public String getSrc() {
126         return src;
127     }
128 
129     /**
130      * Set the source where the new XML instance for this location exists.
131      *
132      * @param src The source.
133      */
134     public void setSrc(final String src) {
135         this.src = src;
136     }
137 
138     /**
139      * Get the {@link PathResolver}.
140      *
141      * @return Returns the pathResolver.
142      */
143     public PathResolver getPathResolver() {
144         return pathResolver;
145     }
146 
147     /**
148      * Set the {@link PathResolver}.
149      *
150      * @param pathResolver The pathResolver to set.
151      */
152     public void setPathResolver(final PathResolver pathResolver) {
153         this.pathResolver = pathResolver;
154     }
155 
156     public Evaluator.AssignType getType() {
157         return type;
158     }
159 
160     public void setType(final Evaluator.AssignType type) {
161         this.type = type;
162     }
163 
164     public String getAttr() {
165         return attr;
166     }
167 
168     public void setAttr(final String attr) {
169         this.attr = attr;
170     }
171 
172     /**
173      * {@inheritDoc}
174      */
175     @Override
176     public void execute(ActionExecutionContext exctx) throws ModelException, SCXMLExpressionException {
177         EnterableState parentState = getParentEnterableState();
178         Context ctx = exctx.getContext(parentState);
179         Evaluator evaluator = exctx.getEvaluator();
180         ctx.setLocal(getNamespacesKey(), getNamespaces());
181         Object data;
182         if (src != null && src.trim().length() > 0) {
183             data = getSrcNode();
184         } else {
185             data = evaluator.eval(ctx, expr);
186         }
187 
188         evaluator.evalAssign(ctx, location, data, type, attr);
189         if (exctx.getAppLog().isDebugEnabled()) {
190             exctx.getAppLog().debug("<assign>: '" + location + "' updated");
191         }
192         // TODO: introduce a optional 'trace.change' setting or something alike to enable .change events,
193        //        but don't do this by default as it can interfere with transitions not expecting such events
194         /*
195         if ((Evaluator.XPATH_DATA_MODEL.equals(evaluator.getSupportedDatamodel()) && location.startsWith("$") && ctx.has(location.substring(1))
196                 || ctx.has(location))) {
197             TriggerEvent ev = new TriggerEvent(location + ".change", TriggerEvent.CHANGE_EVENT);
198             exctx.getInternalIOProcessor().addEvent(ev);
199         }
200         */
201         ctx.setLocal(getNamespacesKey(), null);
202     }
203 
204     /**
205      * Get the {@link Node} the "src" attribute points to.
206      *
207      * @return The node the "src" attribute points to.
208      */
209     private Node getSrcNode() {
210         String resolvedSrc = src;
211         if (pathResolver != null) {
212             resolvedSrc = pathResolver.resolvePath(src);
213         }
214         Document doc = null;
215         try {
216             doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(resolvedSrc);
217         } catch (FactoryConfigurationError t) {
218             logError(t);
219         } catch (SAXException e) {
220             logError(e);
221         } catch (IOException e) {
222             logError(e);
223         } catch (ParserConfigurationException e) {
224             logError(e);
225         }
226         if (doc == null) {
227             return null;
228         }
229         return doc.getDocumentElement();
230     }
231 
232     /**
233      * @param throwable The throwable to log about
234      */
235     private void logError(Throwable throwable) {
236         org.apache.commons.logging.Log log = LogFactory.
237             getLog(Assign.class);
238         log.error(throwable.getMessage(), throwable);
239     }
240 }