001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.scxml2.model; 018 019import java.io.Serializable; 020import java.util.Map; 021 022import org.apache.commons.scxml2.ActionExecutionContext; 023import org.apache.commons.scxml2.Context; 024import org.apache.commons.scxml2.SCXMLExpressionException; 025import org.w3c.dom.Node; 026 027/** 028 * An abstract base class for executable elements in SCXML, 029 * such as <assign>, <log> etc. 030 * 031 */ 032public abstract class Action implements NamespacePrefixesHolder, 033 Serializable { 034 035 /** 036 * Link to its parent or container. 037 */ 038 private Executable parent; 039 040 /** 041 * The current XML namespaces in the SCXML document for this action node, 042 * preserved for deferred XPath evaluation. 043 */ 044 private Map<String, String> namespaces; 045 046 /** 047 * Constructor. 048 */ 049 public Action() { 050 super(); 051 this.parent = null; 052 this.namespaces = null; 053 } 054 055 /** 056 * Get the Executable parent. 057 * 058 * @return Returns the parent. 059 */ 060 public final Executable getParent() { 061 return parent; 062 } 063 064 /** 065 * Set the Executable parent. 066 * 067 * @param parent The parent to set. 068 */ 069 public final void setParent(final Executable parent) { 070 this.parent = parent; 071 } 072 073 /** 074 * Get the XML namespaces at this action node in the SCXML document. 075 * 076 * @return Returns the map of namespaces. 077 */ 078 public final Map<String, String> getNamespaces() { 079 return namespaces; 080 } 081 082 /** 083 * Set the XML namespaces at this action node in the SCXML document. 084 * 085 * @param namespaces The document namespaces. 086 */ 087 public final void setNamespaces(final Map<String, String> namespaces) { 088 this.namespaces = namespaces; 089 } 090 091 /** 092 * Return the {@link EnterableState} whose {@link org.apache.commons.scxml2.Context} this action 093 * executes in. 094 * 095 * @return The parent {@link EnterableState} 096 * @throws ModelException For an unknown EnterableState subclass 097 * 098 * @since 0.9 099 */ 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