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     */
017    package org.apache.commons.scxml.model;
018    
019    import java.io.Serializable;
020    import java.util.ArrayList;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    /**
026     * An abstract base class for elements in SCXML that can serve as a
027     * <target> for a <transition>, such as State or Parallel.
028     *
029     */
030    public abstract class TransitionTarget implements Serializable {
031    
032        /**
033         * Identifier for this transition target. Other parts of the SCXML
034         * document may refer to this <state> using this ID.
035         */
036        private String id;
037    
038        /**
039         * Optional property holding executable content to be run upon
040         * entering this transition target.
041         */
042        private OnEntry onEntry;
043    
044        /**
045         * Optional property holding executable content to be run upon
046         * exiting this transition target.
047         */
048        private OnExit onExit;
049    
050        /**
051         * Optional property holding the data model for this transition target.
052         */
053        private Datamodel datamodel;
054    
055        /**
056         * The parent of this transition target (may be null, if the parent
057         * is the SCXML document root).
058         */
059        private TransitionTarget parent;
060    
061        /**
062         * A list of outgoing Transitions from this target, by document order.
063         */
064        private List transitions;
065    
066        /**
067         * List of history states owned by a given state (applies to non-leaf
068         * states).
069         */
070        private List history;
071    
072        /**
073         * Constructor.
074         */
075        public TransitionTarget() {
076            super();
077            onEntry = new OnEntry(); //empty defaults
078            onEntry.setParent(this);
079            onExit = new OnExit();   //empty defaults
080            onExit.setParent(this);
081            parent = null;
082            transitions = new ArrayList();
083            history = new ArrayList();
084        }
085    
086        /**
087         * Get the identifier for this transition target (may be null).
088         *
089         * @return Returns the id.
090         */
091        public final String getId() {
092            return id;
093        }
094    
095        /**
096         * Set the identifier for this transition target.
097         *
098         * @param id The id to set.
099         */
100        public final void setId(final String id) {
101            this.id = id;
102        }
103    
104        /**
105         * Get the onentry property.
106         *
107         * @return Returns the onEntry.
108         */
109        public final OnEntry getOnEntry() {
110            return onEntry;
111        }
112    
113        /**
114         * Set the onentry property.
115         *
116         * @param onEntry The onEntry to set.
117         */
118        public final void setOnEntry(final OnEntry onEntry) {
119            this.onEntry = onEntry;
120            this.onEntry.setParent(this);
121        }
122    
123        /**
124         * Get the onexit property.
125         *
126         * @return Returns the onExit.
127         */
128        public final OnExit getOnExit() {
129            return onExit;
130        }
131    
132        /**
133         * Set the onexit property.
134         *
135         * @param onExit The onExit to set.
136         */
137        public final void setOnExit(final OnExit onExit) {
138            this.onExit = onExit;
139            this.onExit.setParent(this);
140        }
141    
142        /**
143         * Get the data model for this transition target.
144         *
145         * @return Returns the data model.
146         */
147        public final Datamodel getDatamodel() {
148            return datamodel;
149        }
150    
151        /**
152         * Set the data model for this transition target.
153         *
154         * @param datamodel The Datamodel to set.
155         */
156        public final void setDatamodel(final Datamodel datamodel) {
157            this.datamodel = datamodel;
158        }
159    
160        /**
161         * Get the parent TransitionTarget.
162         *
163         * @return Returns the parent state
164         * (null if parent is <scxml> element)
165         */
166        public final TransitionTarget getParent() {
167            return parent;
168        }
169    
170        /**
171         * Set the parent TransitionTarget.
172         *
173         * @param parent The parent state to set
174         */
175        public final void setParent(final TransitionTarget parent) {
176            this.parent = parent;
177        }
178    
179        /**
180         * Get the parent State.
181         *
182         * @return The parent State
183         * @deprecated Will be removed in v1.0
184         */
185        public final State getParentState() {
186            TransitionTarget tt = this.getParent();
187            if (tt == null) {
188                return null;
189            } else {
190                if (tt instanceof State) {
191                    return (State) tt;
192                } else { //tt is Parallel
193                    return tt.getParentState();
194                }
195            }
196        }
197    
198        /**
199         * Get the map of all outgoing transitions from this state.
200         *
201         * @return Map Returns the transitions Map.
202         * @deprecated Use {@link #getTransitionsList()} instead
203         */
204        public final Map getTransitions() {
205            Map transitionsMap = new HashMap();
206            for (int i = 0; i < transitions.size(); i++) {
207                Transition transition = (Transition) transitions.get(i);
208                String event = transition.getEvent();
209                if (!transitionsMap.containsKey(event)) {
210                    List eventTransitions = new ArrayList();
211                    eventTransitions.add(transition);
212                    transitionsMap.put(event, eventTransitions);
213                } else {
214                    ((List) transitionsMap.get(event)).add(transition);
215                }
216            }
217            return transitionsMap;
218        }
219    
220        /**
221         * Get the list of all outgoing transitions from this target, that
222         * will be candidates for being fired on the given event.
223         *
224         * @param event The event
225         * @return List Returns the candidate transitions for given event
226         */
227        public final List getTransitionsList(final String event) {
228            List matchingTransitions = null; // TODO v1.0 we returned null <= v0.6
229            for (int i = 0; i < transitions.size(); i++) {
230                Transition t = (Transition) transitions.get(i);
231                if ((event == null && t.getEvent() == null)
232                        || (event != null && event.equals(t.getEvent()))) {
233                    if (matchingTransitions == null) {
234                        matchingTransitions = new ArrayList();
235                    }
236                    matchingTransitions.add(t);
237                }
238            }
239            return matchingTransitions;
240        }
241    
242        /**
243         * Add a transition to the map of all outgoing transitions for
244         * this transition target.
245         *
246         * @param transition
247         *            The transitions to set.
248         */
249        public final void addTransition(final Transition transition) {
250            transitions.add(transition);
251            transition.setParent(this);
252        }
253    
254        /**
255         * Get the outgoing transitions for this target as a java.util.List.
256         *
257         * @return List Returns the transitions list.
258         */
259        public final List getTransitionsList() {
260            return transitions;
261        }
262    
263        /**
264         * This method is used by XML digester.
265         *
266         * @param h
267         *            History pseudo state
268         *
269         * @since 0.7
270         */
271        public final void addHistory(final History h) {
272            history.add(h);
273            h.setParent(this);
274        }
275    
276        /**
277         * Does this state have a history pseudo state.
278         *
279         * @return boolean true if a given state contains at least one
280         *                 history pseudo state
281         *
282         * @since 0.7
283         */
284        public final boolean hasHistory() {
285            return (!history.isEmpty());
286        }
287    
288        /**
289         * Get the list of history pseudo states for this state.
290         *
291         * @return a list of all history pseudo states contained by a given state
292         *         (can be empty)
293         * @see #hasHistory()
294         *
295         * @since 0.7
296         */
297        public final List getHistory() {
298            return history;
299        }
300    
301    }
302