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.Serializable;
20  import java.util.Map;
21  
22  import org.apache.commons.scxml2.ActionExecutionContext;
23  import org.apache.commons.scxml2.Context;
24  import org.apache.commons.scxml2.SCXMLExpressionException;
25  import org.w3c.dom.Node;
26  
27  /**
28   * An abstract base class for executable elements in SCXML,
29   * such as <assign>, <log> etc.
30   *
31   */
32  public abstract class Action implements NamespacePrefixesHolder,
33          Serializable {
34  
35      /**
36       * Link to its parent or container.
37       */
38      private Executable parent;
39  
40      /**
41       * The current XML namespaces in the SCXML document for this action node,
42       * preserved for deferred XPath evaluation.
43       */
44      private Map<String, String> namespaces;
45  
46      /**
47       * Constructor.
48       */
49      public Action() {
50          super();
51          this.parent = null;
52          this.namespaces = null;
53      }
54  
55      /**
56       * Get the Executable parent.
57       *
58       * @return Returns the parent.
59       */
60      public final Executable getParent() {
61          return parent;
62      }
63  
64      /**
65       * Set the Executable parent.
66       *
67       * @param parent The parent to set.
68       */
69      public final void setParent(final Executable parent) {
70          this.parent = parent;
71      }
72  
73      /**
74       * Get the XML namespaces at this action node in the SCXML document.
75       *
76       * @return Returns the map of namespaces.
77       */
78      public final Map<String, String> getNamespaces() {
79          return namespaces;
80      }
81  
82      /**
83       * Set the XML namespaces at this action node in the SCXML document.
84       *
85       * @param namespaces The document namespaces.
86       */
87      public final void setNamespaces(final Map<String, String> namespaces) {
88          this.namespaces = namespaces;
89      }
90  
91      /**
92       * Return the {@link EnterableState} whose {@link org.apache.commons.scxml2.Context} this action
93       * executes in.
94       *
95       * @return The parent {@link EnterableState}
96       * @throws ModelException For an unknown EnterableState subclass
97       *
98       * @since 0.9
99       */
100     public EnterableState getParentEnterableState()
101     throws ModelException {
102         if (parent == null && this instanceof Script && ((Script)this).isGlobalScript()) {
103             // global script doesn't have a EnterableState
104             return null;
105         }
106         else if (parent == null) {
107             throw new ModelException("Action "
108                     + this.getClass().getName() + " instance missing required parent TransitionTarget");
109         }
110         TransitionTarget tt = parent.getParent();
111         if (tt instanceof EnterableState) {
112             return (EnterableState)tt;
113         } else if (tt instanceof History) {
114             return ((History)tt).getParent();
115         } else {
116             throw new ModelException("Unknown TransitionTarget subclass:"
117                     + (tt != null ? tt.getClass().getName() : "(null)"));
118         }
119     }
120 
121     /**
122      * Execute this action instance.
123      *
124      * @param exctx The ActionExecutionContext for this execution instance
125      *
126      * @throws ModelException If the execution causes the model to enter
127      *                        a non-deterministic state.
128      * @throws SCXMLExpressionException If the execution involves trying
129      *                        to evaluate an expression which is malformed.
130      */
131     public abstract void execute(ActionExecutionContext exctx) throws ModelException, SCXMLExpressionException;
132 
133     /**
134      * Return the key under which the current document namespaces are saved
135      * in the parent state's context.
136      *
137      * @return The namespaces key
138      */
139     protected static String getNamespacesKey() {
140         return Context.NAMESPACES_KEY;
141     }
142 
143     /**
144      * Convenient method to convert a possible {@link Node} result from an expression evaluation to a String
145      * using its {@link Node#getTextContent()} method.
146      * @param result the result to convert
147      * @return its text content if the result is a {@link Node} otherwise the unmodified result itself
148      */
149     protected Object getTextContentIfNodeResult(final Object result) {
150         if (result instanceof Node) {
151             return ((Node)result).getTextContent();
152         }
153         return result;
154     }
155 }
156