1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 #include <Inventor/scxml/ScXML.h>
34
35 /*!
36 \class ScXML ScXML.h Inventor/scxml/ScXML.h
37 \brief namespace for static ScXML-related functions.
38
39 This is a static namespace class for ScXML-related functions.
40
41 \since Coin 3.0
42 \ingroup scxml
43 */
44
45 #ifdef _MSC_VER
46 #pragma warning(disable:4786) // symbol truncated
47 #endif // _MSC_VER
48
49 #include <Inventor/SbName.h>
50 #include <Inventor/errors/SoDebugError.h>
51
52 #include <Inventor/misc/CoinResources.h>
53
54 #include <Inventor/scxml/ScXML.h>
55 #include <Inventor/scxml/ScXMLObject.h>
56 #include <Inventor/scxml/ScXMLEvent.h>
57 #include <Inventor/scxml/ScXMLEventTarget.h>
58 #include <Inventor/scxml/ScXMLDocument.h>
59
60 #include <Inventor/scxml/ScXMLElt.h>
61 #include <Inventor/scxml/ScXMLScxmlElt.h>
62 #include <Inventor/scxml/ScXMLInitialElt.h>
63 #include <Inventor/scxml/ScXMLAbstractStateElt.h>
64 #include <Inventor/scxml/ScXMLStateElt.h>
65 #include <Inventor/scxml/ScXMLParallelElt.h>
66 #include <Inventor/scxml/ScXMLFinalElt.h>
67 #include <Inventor/scxml/ScXMLOnEntryElt.h>
68 #include <Inventor/scxml/ScXMLOnExitElt.h>
69 #include <Inventor/scxml/ScXMLTransitionElt.h>
70 #include <Inventor/scxml/ScXMLHistoryElt.h>
71
72 #include <Inventor/scxml/ScXMLExecutableElt.h>
73 #include <Inventor/scxml/ScXMLEventElt.h>
74 #include <Inventor/scxml/ScXMLIfElt.h>
75 #include <Inventor/scxml/ScXMLElseIfElt.h>
76 #include <Inventor/scxml/ScXMLElseElt.h>
77 #include <Inventor/scxml/ScXMLLogElt.h>
78
79 #include <Inventor/scxml/ScXMLDataModelElt.h>
80 #include <Inventor/scxml/ScXMLDataElt.h>
81 #include <Inventor/scxml/ScXMLAssignElt.h>
82 #include <Inventor/scxml/ScXMLValidateElt.h>
83
84 #include <Inventor/scxml/ScXMLSendElt.h>
85 #include <Inventor/scxml/ScXMLInvokeElt.h>
86 #include <Inventor/scxml/ScXMLParamElt.h>
87 #include <Inventor/scxml/ScXMLFinalizeElt.h>
88 #include <Inventor/scxml/ScXMLContentElt.h>
89
90 #include <Inventor/scxml/ScXMLAnchorElt.h>
91
92 #include <Inventor/scxml/ScXMLEvaluator.h>
93 #include <Inventor/scxml/ScXMLMinimumEvaluator.h>
94 #include <Inventor/scxml/ScXMLXPathEvaluator.h>
95 #include <Inventor/scxml/ScXMLECMAScriptEvaluator.h>
96 #include <Inventor/scxml/ScXMLCoinEvaluator.h>
97
98 #include <Inventor/scxml/SoScXMLEvent.h>
99 #include <Inventor/scxml/SoScXMLStateMachine.h>
100
101 #include "tidbitsp.h"
102
103 #include "scxml/ScXMLP.h"
104
105 // *************************************************************************
106
107 /*!
108 \page scxml State Chart XML
109
110 The ScXML part of Coin is a basic, non-conformant, partial
111 implementation of State Chart XML, based on the W3C Working Draft
112 16 May 2008 of SCXML <http://www.w3.org/TR/2008/WD-scxml-20080516/>.
113 The latest version should be at <http://www.w3.org/TR/scxml/>.
114 Read that document for a basic understanding how SCXML documents
115 should be constructed.
116
117 Coin uses SCXML for setting up its navigation systems, to be able to
118 remove hardcoded logic for user navigation and externalize it into XML
119 files. This makes it easy for users to customize the navigation
120 system for their own purposes.
121
122 Unsupported Items:
123
124 - The <parallel> element is not supported as intended with
125 parallel states. Coin will just treat it as an ordinary
126 <state> element for now. Parallel states is not high up on
127 the priority list, so expect this to be handled after a lot of
128 other functionality is in place.
129
130 - The <datamodel>-related part of the specification is not
131 fully supported.
132
133 - The 'target' attribute in the <transition> element can only
134 identify a single state currently, not multiple as you would have
135 to when having support for <parallel> elements (which we
136 don't have).
137
138 - The virtual state elements like <history> and <anchor>
139 are just implemented as dummy states for now and do not do
140 anything in relation to what they should actually do.
141
142 For learning more about how ScXML is implemented and used in Coin,
143 take a look at $COINDIR/scxml/navigation/examiner.xml (or in the
144 Coin source directory, data/scxml/navigation/examiner.xml) for an
145 example of how an SCXML system for camera navigation looks,
146 and look at the source files in src/navigation/ for the C++ counterparts
147 to the same SCXML navigation system.
148
149 \ingroup scxml
150 \since Coin 3.0
151 */
152
153 // *************************************************************************
154
155 extern "C" {
156 static void scxml_cleanup(void);
157 }
158
159 /*!
160 Initializes the basic ScXML classes.
161 */
162 void
initClasses(void)163 ScXML::initClasses(void)
164 {
165 ScXMLP::init();
166 ScXMLObject::initClass();
167 ScXMLEvent::initClass();
168 ScXMLEventTarget::initClass();
169 ScXMLStateMachine::initClass();
170 ScXMLDocument::initClass();
171
172 ScXMLElt::initClass();
173 ScXMLScxmlElt::initClass();
174 ScXMLInitialElt::initClass();
175 ScXMLAbstractStateElt::initClass();
176 ScXMLStateElt::initClass();
177 ScXMLParallelElt::initClass();
178 ScXMLFinalElt::initClass();
179 ScXMLOnEntryElt::initClass();
180 ScXMLOnExitElt::initClass();
181 ScXMLTransitionElt::initClass();
182 ScXMLHistoryElt::initClass();
183
184 ScXMLExecutableElt::initClass();
185 ScXMLEventElt::initClass();
186 ScXMLIfElt::initClass();
187 ScXMLElseIfElt::initClass();
188 ScXMLElseElt::initClass();
189 ScXMLLogElt::initClass();
190
191 ScXMLDataModelElt::initClass();
192 ScXMLDataElt::initClass();
193 ScXMLAssignElt::initClass();
194 ScXMLValidateElt::initClass();
195
196 ScXMLSendElt::initClass();
197 ScXMLInvokeElt::initClass();
198 ScXMLParamElt::initClass();
199 ScXMLFinalizeElt::initClass();
200 ScXMLContentElt::initClass();
201
202 ScXMLAnchorElt::initClass();
203
204 // evaluators also inits data-objs
205 ScXMLEvaluator::initClass();
206 ScXMLMinimumEvaluator::initClass();
207 ScXMLXPathEvaluator::initClass();
208 ScXMLECMAScriptEvaluator::initClass();
209 ScXMLCoinEvaluator::initClass();
210
211 SoScXMLEvent::initClass();
212 SoScXMLStateMachine::initClass();
213
214 coin_atexit(scxml_cleanup, CC_ATEXIT_NORMAL);
215 }
216
217 void
scxml_cleanup(void)218 scxml_cleanup(void)
219 {
220 ScXML::cleanClasses();
221 }
222
223 void
cleanClasses(void)224 ScXML::cleanClasses(void)
225 {
226 SoScXMLStateMachine::cleanClass();
227 SoScXMLEvent::cleanClass();
228
229 ScXMLCoinEvaluator::cleanClass();
230 ScXMLECMAScriptEvaluator::cleanClass();
231 ScXMLXPathEvaluator::cleanClass();
232 ScXMLMinimumEvaluator::cleanClass();
233 ScXMLEvaluator::cleanClass();
234
235 ScXMLAnchorElt::cleanClass();
236
237 ScXMLContentElt::cleanClass();
238 ScXMLFinalizeElt::cleanClass();
239 ScXMLParamElt::cleanClass();
240 ScXMLInvokeElt::cleanClass();
241 ScXMLSendElt::cleanClass();
242
243 ScXMLValidateElt::cleanClass();
244 ScXMLAssignElt::cleanClass();
245 ScXMLDataElt::cleanClass();
246 ScXMLDataModelElt::cleanClass();
247
248 ScXMLLogElt::cleanClass();
249 ScXMLElseElt::cleanClass();
250 ScXMLElseIfElt::cleanClass();
251 ScXMLIfElt::cleanClass();
252 ScXMLEventElt::cleanClass();
253 ScXMLExecutableElt::cleanClass();
254
255 ScXMLHistoryElt::cleanClass();
256 ScXMLTransitionElt::cleanClass();
257 ScXMLOnExitElt::cleanClass();
258 ScXMLOnEntryElt::cleanClass();
259 ScXMLFinalElt::cleanClass();
260 ScXMLParallelElt::cleanClass();
261 ScXMLStateElt::cleanClass();
262 ScXMLAbstractStateElt::cleanClass();
263 ScXMLInitialElt::cleanClass();
264 ScXMLScxmlElt::cleanClass();
265 ScXMLElt::cleanClass();
266
267 ScXMLDocument::cleanClass();
268 ScXMLStateMachine::cleanClass();
269 ScXMLEventTarget::cleanClass();
270 ScXMLEvent::cleanClass();
271 ScXMLObject::cleanClass();
272 ScXMLP::cleanup();
273 }
274
275 // *************************************************************************
276
277 SbBool
registerEvaluatorType(SbName profilename,SoType evaluatortype)278 ScXML::registerEvaluatorType(SbName profilename, SoType evaluatortype)
279 {
280 assert(!evaluatortype.isBad());
281 assert(ScXMLP::profileevaluators);
282 if (!evaluatortype.isDerivedFrom(ScXMLEvaluator::getClassTypeId())) {
283 SoDebugError::post("ScXMLStateMachine::registerEvaluator",
284 "Evaluator type must be derived from ScXMLEvaluator");
285 return FALSE;
286 }
287 ScXMLP::TypeDict::iterator it = ScXMLP::profileevaluators->find(profilename.getString());
288 if (it != ScXMLP::profileevaluators->end()) {
289 SoDebugError::post("ScXML::registerEvaluatorType",
290 "Evaluator for profile '%s' already registered.\n",
291 profilename.getString());
292 return FALSE;
293 }
294 ScXMLP::TypeEntry entry(profilename.getString(), evaluatortype);
295 ScXMLP::profileevaluators->insert(entry);
296 return TRUE;
297 }
298
299 SbBool
unregisterEvaluatorType(SbName profilename,SoType evaluatortype)300 ScXML::unregisterEvaluatorType(SbName profilename, SoType evaluatortype)
301 {
302 assert(!evaluatortype.isBad());
303 assert(ScXMLP::profileevaluators);
304
305 ScXMLP::TypeDict::iterator it = ScXMLP::profileevaluators->find(profilename.getString());
306 if (it == ScXMLP::profileevaluators->end()) {
307 SoDebugError::post("ScXML::unregisterEvaluatorType",
308 "No evaluator type is registered for profile '%s'.\n",
309 profilename.getString());
310 return FALSE;
311 }
312 if (it->second != evaluatortype) {
313 SoDebugError::post("ScXML::unregisterEvaluatorType",
314 "Different evaluator type registered for profile '%s'.\n",
315 profilename.getString());
316 return FALSE;
317 }
318 ScXMLP::profileevaluators->erase(it);
319 return TRUE;
320 }
321
322 SoType
getEvaluatorTypeForProfile(SbName profilename)323 ScXML::getEvaluatorTypeForProfile(SbName profilename)
324 {
325 assert(ScXMLP::profileevaluators);
326
327 ScXMLP::TypeDict::iterator it = ScXMLP::profileevaluators->find(profilename.getString());
328 if (it == ScXMLP::profileevaluators->end()) {
329 // no type registered for profile
330 return SoType::badType();
331 }
332 return it->second;
333 }
334
335 // *************************************************************************
336 // SCXML FILE INPUT
337 // *************************************************************************
338
339 /*!
340 This function reads in an SCXML document from a file.
341
342 \returns an ScXMLDocument-derived statemachine object hierarchy.
343 */
344 ScXMLStateMachine *
readFile(const char * filename)345 ScXML::readFile(const char * filename)
346 {
347 ScXMLDocument * doc = ScXMLDocument::readFile(filename);
348 if (!doc) {
349 return NULL;
350 }
351
352 ScXMLStateMachine * statemachine = new SoScXMLStateMachine;
353 statemachine->setDescription(doc);
354 statemachine->setName(filename);
355
356 return statemachine;
357 }
358
359 /*!
360 This function reads in an SCXML document residing in memory.
361
362 \returns an ScXMLDocument-derived statemachine object hierarchy.
363 */
364 ScXMLStateMachine *
readBuffer(const SbByteBuffer & bufferdata)365 ScXML::readBuffer(const SbByteBuffer & bufferdata)
366 {
367 ScXMLDocument * doc = ScXMLDocument::readBuffer(bufferdata);
368 if (!doc) {
369 return NULL;
370 }
371
372 ScXMLStateMachine * statemachine = new SoScXMLStateMachine;
373 statemachine->setDescription(doc);
374 statemachine->setName("<memory buffer>");
375
376 return statemachine;
377 }
378
379 // *************************************************************************
380