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.ArrayList;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025/**
026 * The class in this SCXML object model that corresponds to the
027 * <scxml> root element, and serves as the "document
028 * root".
029 *
030 */
031public class SCXML implements Serializable, Observable,
032                              NamespacePrefixesHolder {
033
034    /**
035     * Serial version UID.
036     */
037    private static final long serialVersionUID = 2L;
038
039    /**
040     * The SCXML XMLNS.
041     */
042    @SuppressWarnings("unused")
043    public static final String XMLNS = "http://www.w3.org/2005/07/scxml";
044
045    /**
046     * Reserved prefix for auto generated TransitionTarget id values
047     */
048    public static final String GENERATED_TT_ID_PREFIX = "_generated_tt_id_";
049
050    /**
051     * The predefined observableId with value 0 (zero) for this SCXML state machine
052     */
053    private static final Integer SCXML_OBSERVABLE_ID = 0;
054
055    /**
056     * The xmlns attribute on the root <smxml> element.
057     * This must match XMLNS above.
058     */
059    private String xmlns;
060
061    /**
062     * The SCXML version of this document.
063     */
064    private String version;
065
066    /**
067     * The initial Transition for the SCXML executor.
068     */
069    private SimpleTransition initialTransition;
070
071    /**
072     * The initial transition target ID
073     */
074    private String initial;
075
076    /**
077     * The name for this state machine.
078     */
079    private String name;
080
081    /**
082     * The profile in use.
083     */
084    private String profile;
085
086    /**
087     * The exmode for this document.
088     */
089    private String exmode;
090
091
092    /**
093     * The datamodel name as specified as "datamodel" attribute on this document
094     */
095    private String datamodelName;
096
097    /**
098     * Optional property holding the data model for this SCXML document.
099     * This gets merged with the root context and potentially hides any
100     * (namesake) variables in the root context.
101     */
102    private Datamodel datamodel;
103
104    /**
105     * Optional property holding the initial script for this SCXML document.
106     */
107    private Script globalScript;
108
109    /**
110     * The immediate child targets of this SCXML document root.
111     */
112    private List<EnterableState> children;
113
114    /**
115     * A global map of all States and Parallels associated with this
116     * state machine, keyed by their id.
117     */
118    private Map<String, TransitionTarget> targets;
119
120    /**
121     * The XML namespaces defined on the SCXML document root node,
122     * preserved primarily for serialization.
123     */
124    private Map<String, String> namespaces;
125
126    /**
127     * The next auto-generated transition target unique id value
128     * @see #generateTransitionTargetId()
129     */
130    private long ttNextId;
131
132    /**
133     * Constructor.
134     */
135    public SCXML() {
136        this.children = new ArrayList<EnterableState>();
137        this.targets = new HashMap<String, TransitionTarget>();
138    }
139
140    /**
141     * {@inheritDoc}
142     */
143    public final Integer getObservableId() {
144        return SCXML_OBSERVABLE_ID;
145    }
146
147    /**
148     * Simple unique TransitionTarget id value generation
149     * @return a unique TransitionTarget id for this SCXML instance
150     */
151    public final String generateTransitionTargetId() {
152        return GENERATED_TT_ID_PREFIX +ttNextId++;
153    }
154
155    public final Script getGlobalScript() {
156        return globalScript;
157    }
158
159    public final void setGlobalScript(Script script) {
160        this.globalScript = script;
161    }
162
163    /**
164     * Get the initial Transition.
165     *
166     * @return Returns the initial transition for this state machine.
167     *
168     * @since 2.0
169     */
170    public final SimpleTransition getInitialTransition() {
171        return initialTransition;
172    }
173
174    /**
175     * Set the initial Transition.
176     * <p>Note: the initial transition can/may not have executable content!</p>
177     *
178     * @param initialTransition The initial transition to set.
179     *
180     * @since 2.0
181     */
182    public final void setInitialTransition(final SimpleTransition initialTransition) {
183        this.initialTransition = initialTransition;
184    }
185
186    /**
187     * Get the data model placed at document root.
188     *
189     * @return Returns the data model.
190     */
191    public final Datamodel getDatamodel() {
192        return datamodel;
193    }
194
195    /**
196     * Set the data model at document root.
197     *
198     * @param datamodel The Datamodel to set.
199     */
200    public final void setDatamodel(final Datamodel datamodel) {
201        this.datamodel = datamodel;
202    }
203
204    /**
205     * Get the immediate child targets of the SCXML root.
206     *
207     * @return List Returns list of the child targets.
208     *
209     * @since 0.7
210     */
211    public final List<EnterableState> getChildren() {
212        return children;
213    }
214
215    /**
216     * Get the first immediate child of the SCXML root. Return null if there's no child.
217     *
218     * @return Returns the first immediate child of the SCXML root. Return null if there's no child.
219     *
220     * @since 2.0
221     */
222    public final EnterableState getFirstChild() {
223        if (!children.isEmpty()) {
224            return children.get(0);
225        }
226        return null;
227    }
228
229    /**
230     * Add an immediate child of the SCXML root.
231     *
232     * @param es The child to be added.
233     *
234     * @since 0.7
235     */
236    public final void addChild(final EnterableState es) {
237        children.add(es);
238    }
239
240    /**
241     * Get the targets map, which is a Map of all States and Parallels
242     * associated with this state machine, keyed by their id.
243     *
244     * @return Map Returns the targets.
245     */
246    public final Map<String, TransitionTarget> getTargets() {
247        return targets;
248    }
249
250    /**
251     * Add a target to this SCXML document.
252     *
253     * @param target The target to be added to the targets Map.
254     */
255    public final void addTarget(final TransitionTarget target) {
256        targets.put(target.getId(), target);
257    }
258
259    /**
260     * Get the SCXML document version.
261     *
262     * @return Returns the version.
263     */
264    public final String getVersion() {
265        return version;
266    }
267
268    /**
269     * Set the SCXML document version.
270     *
271     * @param version The version to set.
272     */
273    public final void setVersion(final String version) {
274        this.version = version;
275    }
276
277    /**
278     * Get the xmlns of this SCXML document.
279     *
280     * @return Returns the xmlns.
281     */
282    public final String getXmlns() {
283        return xmlns;
284    }
285
286    /**
287     * Set the xmlns of this SCXML document.
288     *
289     * @param xmlns The xmlns to set.
290     */
291    public final void setXmlns(final String xmlns) {
292        this.xmlns = xmlns;
293    }
294
295    /**
296     * Get the namespace definitions specified on the SCXML element.
297     * May be <code>null</code>.
298     *
299     * @return The namespace definitions specified on the SCXML element,
300     *         may be <code>null</code>.
301     */
302    public final Map<String, String> getNamespaces() {
303        return namespaces;
304    }
305
306    /**
307     * Set the namespace definitions specified on the SCXML element.
308     *
309     * @param namespaces The namespace definitions specified on the
310     *                   SCXML element.
311     */
312    public final void setNamespaces(final Map<String, String> namespaces) {
313        this.namespaces = namespaces;
314    }
315
316    /**
317     * Get the the initial transition target.
318     *
319     * @return String Returns the initial transition target ID
320     * @see #getInitialTransition()
321     */
322    public final String getInitial() {
323        return initial;
324    }
325
326    /**
327     * Set the initial transition target.
328     *
329     * @param initial The initial transition target
330     * @see #setInitialTransition(SimpleTransition)
331     */
332    public final void setInitial(final String initial) {
333        this.initial = initial;
334    }
335
336    /**
337     * Get the name for this state machine.
338     *
339     * @return The name for this state machine.
340     */
341        public String getName() {
342                return name;
343        }
344
345        /**
346         * Set the name for this state machine.
347         *
348         * @param name The name for this state machine.
349         */
350        public void setName(String name) {
351                this.name = name;
352        }
353
354        /**
355         * Get the profile in use for this state machine.
356         *
357         * @return The profile in use.
358         */
359        public String getProfile() {
360                return profile;
361        }
362
363        /**
364         * Set the profile in use for this state machine.
365         *
366         * @param profile The profile to be used.
367         */
368        public void setProfile(String profile) {
369                this.profile = profile;
370        }
371
372        /**
373         * Get the exmode in use for this state machine.
374         *
375         * @return The exmode in use.
376         */
377        public String getExmode() {
378                return exmode;
379        }
380
381        /**
382         * Set the exmode to be used for this state machine.
383         *
384         * @param exmode The exmode to be used.
385         */
386        public void setExmode(String exmode) {
387                this.exmode = exmode;
388        }
389
390    /**
391     * Get the datamodel name as specified as attribute on this document
392     * @return The datamodel name of this document
393     */
394    public String getDatamodelName() {
395        return datamodelName;
396    }
397
398    /**
399     * Sets the datamodel name as specified as attribute on this document
400     * @param datamodelName The datamodel name
401     */
402    public void setDatamodelName(final String datamodelName) {
403        this.datamodelName = datamodelName;
404    }
405}
406