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.util.ArrayList;
020import java.util.List;
021
022/**
023 * An abstract base class for state elements in SCXML that can be transitioned out from, such as State or Parallel.
024 */
025public abstract class TransitionalState extends EnterableState {
026
027    /**
028     * A list of outgoing Transitions from this state, by document order.
029     */
030    private List<Transition> transitions;
031
032    /**
033     * Optional property holding the data model for this state.
034     */
035    private Datamodel datamodel;
036
037    /**
038     * List of history states owned by a given state (applies to non-leaf
039     * states).
040     */
041    private List<History> history;
042
043    /**
044     * The Invoke children, each which defines an external process that should
045     * be invoked, immediately after the onentry executable content,
046     * and the transitions become candidates after the invoked
047     * process has completed its execution.
048     * May occur 0 or more times.
049     */
050    private List<Invoke> invokes;
051
052    /**
053     * The set of EnterableState children contained in this TransitionalState
054     */
055    private List<EnterableState> children;
056
057    public TransitionalState() {
058        super();
059        transitions = new ArrayList<Transition>();
060        history = new ArrayList<History>();
061        children = new ArrayList<EnterableState>();
062        invokes = new ArrayList<Invoke>();
063    }
064
065    /**
066     * Update TransitionTarget descendants their ancestors
067     */
068    protected void updateDescendantsAncestors() {
069        super.updateDescendantsAncestors();
070        for (History h : history) {
071            // reset ancestors
072            h.updateDescendantsAncestors();
073        }
074        for (TransitionTarget child : children) {
075            child.updateDescendantsAncestors();
076        }
077    }
078
079    /**
080     * Get the TransitionalState (State or Parallel) parent.
081     *
082     * @return Returns the parent.
083     */
084    @Override
085    public TransitionalState getParent() {
086        return (TransitionalState)super.getParent();
087    }
088
089    /**
090     * Set the TransitionalState parent
091     *
092     * @param parent The parent to set.
093     */
094    public final void setParent(final TransitionalState parent) {
095        super.setParent(parent);
096    }
097
098    /**
099     * Get the ancestor of this TransitionalState at specified level
100     * @param level the level of the ancestor to return, zero being top
101     * @return the ancestor at specified level
102     */
103    @Override
104    public TransitionalState getAncestor(int level) {
105        return (TransitionalState)super.getAncestor(level);
106    }
107
108    /**
109     * Get the list of all outgoing transitions from this state, that
110     * will be candidates for being fired on the given event.
111     *
112     * @param event The event
113     * @return List Returns the candidate transitions for given event
114     */
115    public final List<Transition> getTransitionsList(final String event) {
116        List<Transition> matchingTransitions = null; // since we returned null upto v0.6
117        for (Transition t : transitions) {
118            if ((event == null && t.getEvent() == null)
119                    || (event != null && event.equals(t.getEvent()))) {
120                if (matchingTransitions == null) {
121                    matchingTransitions = new ArrayList<Transition>();
122                }
123                matchingTransitions.add(t);
124            }
125        }
126        return matchingTransitions;
127    }
128
129    /**
130     * Add a transition to the map of all outgoing transitions for
131     * this state.
132     *
133     * @param transition
134     *            The transitions to set.
135     */
136    public final void addTransition(final Transition transition) {
137        transitions.add(transition);
138        transition.setParent(this);
139    }
140
141    /**
142     * Get the outgoing transitions for this state as a java.util.List.
143     *
144     * @return List Returns the transitions list.
145     */
146    public final List<Transition> getTransitionsList() {
147        return transitions;
148    }
149
150    /**
151     * Get the data model for this transition target.
152     *
153     * @return Returns the data model.
154     */
155    public final Datamodel getDatamodel() {
156        return datamodel;
157    }
158
159    /**
160     * Set the data model for this transition target.
161     *
162     * @param datamodel The Datamodel to set.
163     */
164    public final void setDatamodel(final Datamodel datamodel) {
165        this.datamodel = datamodel;
166    }
167
168    /**
169     * @param h History pseudo state
170     *
171     * @since 0.7
172     */
173    public final void addHistory(final History h) {
174        history.add(h);
175        h.setParent(this);
176    }
177
178    /**
179     * Does this state have a history pseudo state.
180     *
181     * @return boolean true if a given state contains at least one
182     *                 history pseudo state
183     *
184     * @since 0.7
185     */
186    public final boolean hasHistory() {
187        return (!history.isEmpty());
188    }
189
190    /**
191     * Get the list of history pseudo states for this state.
192     *
193     * @return a list of all history pseudo states contained by a given state
194     *         (can be empty)
195     * @see #hasHistory()
196     *
197     * @since 0.7
198     */
199    public final List<History> getHistory() {
200        return history;
201    }
202
203    /**
204     * Get the Invoke children (may be empty).
205     *
206     * @return Invoke Returns the invoke.
207     */
208    public final List<Invoke> getInvokes() {
209        return invokes;
210    }
211
212    /**
213     * Set the Invoke child.
214     *
215     * @param invoke
216     *            The invoke to set.
217     */
218    public final void addInvoke(final Invoke invoke) {
219        this.invokes.add(invoke);
220        invoke.setParentEnterableState(this);
221    }
222
223    /**
224     * Get the set of child transition targets (may be empty).
225     *
226     * @return Returns the children.
227     *
228     * @since 0.7
229     */
230    public final List<EnterableState> getChildren() {
231        return children;
232    }
233
234    /**
235     * Add a child.
236     *
237     * @param es A child enterable state.
238     *
239     * @since 0.7
240     */
241    protected void addChild(final EnterableState es) {
242        children.add(es);
243        es.setParent(this);
244    }
245}