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