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;
025
026/**
027 * An abstract base class for executable elements in SCXML,
028 * such as <assign>, <log> etc.
029 *
030 */
031public abstract class Action implements NamespacePrefixesHolder,
032        Serializable {
033
034    /**
035     * Link to its parent or container.
036     */
037    private Executable parent;
038
039    /**
040     * The current XML namespaces in the SCXML document for this action node,
041     * preserved for deferred XPath evaluation.
042     */
043    private Map<String, String> namespaces;
044
045    /**
046     * Constructor.
047     */
048    public Action() {
049        super();
050        this.parent = null;
051        this.namespaces = null;
052    }
053
054    /**
055     * Get the Executable parent.
056     *
057     * @return Returns the parent.
058     */
059    public final Executable getParent() {
060        return parent;
061    }
062
063    /**
064     * Set the Executable parent.
065     *
066     * @param parent The parent to set.
067     */
068    public final void setParent(final Executable parent) {
069        this.parent = parent;
070    }
071
072    /**
073     * Get the XML namespaces at this action node in the SCXML document.
074     *
075     * @return Returns the map of namespaces.
076     */
077    public final Map<String, String> getNamespaces() {
078        return namespaces;
079    }
080
081    /**
082     * Set the XML namespaces at this action node in the SCXML document.
083     *
084     * @param namespaces The document namespaces.
085     */
086    public final void setNamespaces(final Map<String, String> namespaces) {
087        this.namespaces = namespaces;
088    }
089
090    /**
091     * Return the {@link EnterableState} whose {@link org.apache.commons.scxml2.Context} this action
092     * executes in.
093     *
094     * @return The parent {@link EnterableState}
095     * @throws ModelException For an unknown EnterableState subclass
096     *
097     * @since 0.9
098     */
099    public final EnterableState getParentEnterableState()
100    throws ModelException {
101        if (parent == null && this instanceof Script && ((Script)this).isGlobalScript()) {
102            // global script doesn't have a EnterableState
103            return null;
104        }
105        TransitionTarget tt = parent.getParent();
106        if (tt instanceof EnterableState) {
107            return (EnterableState)tt;
108        } else if (tt instanceof History) {
109            return ((History)tt).getParent();
110        } else {
111            throw new ModelException("Unknown TransitionTarget subclass:"
112                    + tt.getClass().getName());
113        }
114    }
115
116    /**
117     * Execute this action instance.
118     *
119     * @param exctx The ActionExecutionContext for this execution instance
120     *
121     * @throws ModelException If the execution causes the model to enter
122     *                        a non-deterministic state.
123     * @throws SCXMLExpressionException If the execution involves trying
124     *                        to evaluate an expression which is malformed.
125     */
126    public abstract void execute(ActionExecutionContext exctx) throws ModelException, SCXMLExpressionException;
127
128    /**
129     * Return the key under which the current document namespaces are saved
130     * in the parent state's context.
131     *
132     * @return The namespaces key
133     */
134    protected static String getNamespacesKey() {
135        return Context.NAMESPACES_KEY;
136    }
137
138}
139