<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=us-ascii"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;
        mso-fareast-language:EN-US;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:#0563C1;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:#954F72;
        text-decoration:underline;}
p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
        {mso-style-priority:34;
        margin-top:0cm;
        margin-right:0cm;
        margin-bottom:0cm;
        margin-left:36.0pt;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;
        mso-fareast-language:EN-US;}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        mso-fareast-language:EN-US;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
/* List Definitions */
@list l0
        {mso-list-id:519703121;
        mso-list-type:hybrid;
        mso-list-template-ids:1405118518 134807569 134807577 134807579 134807567 134807577 134807579 134807567 134807577 134807579;}
@list l0:level1
        {mso-level-text:"%1\)";
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level2
        {mso-level-number-format:alpha-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level3
        {mso-level-number-format:roman-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:right;
        text-indent:-9.0pt;}
@list l0:level4
        {mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level5
        {mso-level-number-format:alpha-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level6
        {mso-level-number-format:roman-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:right;
        text-indent:-9.0pt;}
@list l0:level7
        {mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level8
        {mso-level-number-format:alpha-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level9
        {mso-level-number-format:roman-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:right;
        text-indent:-9.0pt;}
ol
        {margin-bottom:0cm;}
ul
        {margin-bottom:0cm;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=EN-GB link="#0563C1" vlink="#954F72"><div class=WordSection1><p class=MsoNormal>Hi,<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>We’re nearly ready to move on to nodes, we just need to extend our list of fields that we have defined. Before we do that, we’ll  start with a reminder of where we got to last time, by listing the things we have defined.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>enum SAIFieldAccess {<o:p></o:p></p><p class=MsoNormal>    initializeOnly,<o:p></o:p></p><p class=MsoNormal>    inputOnly,<o:p></o:p></p><p class=MsoNormal>    outputOnly,<o:p></o:p></p><p class=MsoNormal>    inputOutput<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>enum SAIFieldType {<o:p></o:p></p><p class=MsoNormal>    SFBool,<o:p></o:p></p><p class=MsoNormal>    MFBool,<o:p></o:p></p><p class=MsoNormal>    SFColor,<o:p></o:p></p><p class=MsoNormal>   …<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DField {<o:p></o:p></p><p class=MsoNormal>    enum SAIFieldType type;<o:p></o:p></p><p class=MsoNormal>    enum SAIFieldAccess accessType;<o:p></o:p></p><p class=MsoNormal>    SAIFieldName name;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    enum SAIFieldAccess getAccessType (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    enum SAIFieldType getType (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    SAIFieldName getName (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void addInterest (SAIRequester requester) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INSUFFICIENT_CAPABILITIES, SAI_NODE_IN_USE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void removeInterest (SAIRequester requester) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INSUFFICIENT_CAPABILITIES, SAI_NODE_IN_USE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void dispose void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING;<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DArrayField : X3DField {<o:p></o:p></p><p class=MsoNormal>    int getNum (void) throws throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void removeAllValues (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void removeValue (int index) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>SFInt32 : X3DField {<o:p></o:p></p><p class=MsoNormal>    int32 value = 0;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    int32 getValue (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void setValue (int32 newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>MFInt32 : X3DArrayField {<o:p></o:p></p><p class=MsoNormal>    int32 value[];<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    int32[] getValue (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    int32 get1Value (int index) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void appendValue (int32 newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void insertValue (int index, int32 newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void setValue (int32 newValue[]) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void set1Value (int index, int32 newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>We need to define some additional field types. We need SFNode, and SFString. These can be done analogously to SFInt32, with a change to the data type. For SFNode the data type is SAINode. This is defined in ISO/IEC 19775-2:2015 clause 5.2.22 as “an identifier for a node.”. The data type for string, as we have already seen is SAIString.<o:p></o:p></p><p class=MsoNormal>Reference: <a href="http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/dataRef.html#SAINode">http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/dataRef.html#SAINode</a><o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>For our object model definitions for  SFNode and SFString we also need to modify the default values. These are listed in ISO/IEC 19775-1:2013 clause 5 Field type reference. Clause 5.3.12 SFNode and MFNode details the default value of an uninitialized SFNode field to be NULL, while clause 5.3.14 SFString and MFString specifies that the default value of an uninitialized SFString field is the empty string.<o:p></o:p></p><p class=MsoNormal>Reference: <a href="http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/fieldsDef.html#SFNodeAndMFNode">http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/fieldsDef.html#SFNodeAndMFNode</a><o:p></o:p></p><p class=MsoNormal>Reference: <a href="http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/fieldsDef.html#SFStringAndMFString">http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/fieldsDef.html#SFStringAndMFString</a><o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>So our two additional field type definitions become:<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>SFNode : X3DField {<o:p></o:p></p><p class=MsoNormal>    SAINode value = NULL;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    SAINode getValue (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void setValue (SAINode newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>SFString : X3DField {<o:p></o:p></p><p class=MsoNormal>    SAIString value = “”;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    SAIString getValue (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void setValue (SAIString newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Now we can move on to nodes! We’ll use the same processes that we did for fields. We started that with reviewing the characteristics listed in ISO/IEC 19775-1:2013 clause 4.4.2.1 Overview.<o:p></o:p></p><p class=MsoNormal>Reference: <a href="http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/concepts.html#ObjectmodelOverview">http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/concepts.html#ObjectmodelOverview</a><o:p></o:p></p><p class=MsoNormal>Listing these characteristics we have:<o:p></o:p></p><ol style='margin-top:0cm' start=1 type=1><li class=MsoListParagraph style='margin-left:0cm;mso-list:l0 level1 lfo1'>A type name<o:p></o:p></li><li class=MsoListParagraph style='margin-left:0cm;mso-list:l0 level1 lfo1'>Zero or more field values<o:p></o:p></li><li class=MsoListParagraph style='margin-left:0cm;mso-list:l0 level1 lfo1'>Zero or more events it can receive and send<o:p></o:p></li><li class=MsoListParagraph style='margin-left:0cm;mso-list:l0 level1 lfo1'>A name<o:p></o:p></li></ol><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Considering 3) more carefully, we see that actually events are sent and received from the fields within a node, and not the nodes themselves. So we’ll save that for later.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Referring back to the second paragraph in clause 4.4.2.1 we note that “… <i>nodes</i> and are derived from the <i><a href="http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/core.html#X3DNode">X3DNode</a></i> object.”. So that is the base object that we must define. We have two characteristics, type name and node, that are common to all nodes. So our starter definition is:<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DNode {<o:p></o:p></p><p class=MsoNormal>    type;<o:p></o:p></p><p class=MsoNormal>    name;<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Now we need to look at the node signature for X3DNode. This is found at ISO/IEC 19775-1:2013 clause 7.3.5 X3DNode. We see that it has a single SFNode field, named “metadata”. That field has an access type of “inputOutput”, and a default value of “NULL”. Furthermore, the “metadata” field only accepts nodes that inherit the X3DMetadataObject interface. However, again we’ll save this last requirement about acceptable node types for later.<o:p></o:p></p><p class=MsoNormal>Reference: <a href="http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/core.html#X3DNode">http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/core.html#X3DNode</a><o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Now we can expand the definition of X3DNode to include the “metadata” field. It becomes:<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DNode {<o:p></o:p></p><p class=MsoNormal>    type;<o:p></o:p></p><p class=MsoNormal>    name;<o:p></o:p></p><p class=MsoNormal>    SFNode metadata (“metadata”, inputOutput, NULL);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Notice that we have used “metadata” twice. The first occurrence provides a property name that software engineers can use to refer to this particular field within the codes. The second occurrence is there to provide the name for the name property in the field. Similarly, the “inputOutput” specifies the access type, and the “NULL” the default value. You’ll notice that this looks remarkably like a constructor. And we have not defined any constructors in our field definitions. We need to fix that. However, since these constructors have default values, they need to go into the individual classes. So, we’ll extend our four specific field types to include a constructor.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>SFInt32 : X3DField {<o:p></o:p></p><p class=MsoNormal>    int32 value = 0;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    int32 getValue (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void setValue (int32 newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    SFInt32 (SAIFieldName fieldName, enum SAIFieldAccess accessType, int32 defaultValue);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>MFInt32 : X3DArrayField {<o:p></o:p></p><p class=MsoNormal>    int32 value[];<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    int32[] getValue (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    int32 get1Value (int index) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void appendValue (int32 newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void insertValue (int index, int32 newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void setValue (int32 newValue[]) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void set1Value (int index, int32 newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    MFInt32 (SAIFieldName fieldName, enum SAIFieldAccess accessType, int32 defaultValue[]);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>SFNode : X3DField {<o:p></o:p></p><p class=MsoNormal>    SAINode value = NULL;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    SAINode getValue (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void setValue (SAINode newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    SFNode (SAIFieldName fieldName, enum SAIFieldAccess accessType, SAINode defaultValue);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>SFString : X3DField {<o:p></o:p></p><p class=MsoNormal>    SAIString value = “”;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    SAIString getValue (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void setValue (SAIString newValue) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    SFString (SAIFieldName fieldName, enum SAIFieldAccess accessType, SAIString defaultValue);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Of course, our base abstract types X3DField and X3DArrayField will also need constructors, so we could add those too.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DField {<o:p></o:p></p><p class=MsoNormal>    enum SAIFieldType type;<o:p></o:p></p><p class=MsoNormal>    enum SAIFieldAccess accessType;<o:p></o:p></p><p class=MsoNormal>    SAIFieldName name;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    enum SAIFieldAccess getAccessType (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    enum SAIFieldType getType (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    SAIFieldName getName (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void addInterest (SAIRequester requester) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INSUFFICIENT_CAPABILITIES, SAI_NODE_IN_USE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void removeInterest (SAIRequester requester) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_INSUFFICIENT_CAPABILITIES, SAI_NODE_IN_USE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void dispose void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    X3DField (SAIFieldName fieldName, enum SAIFieldAccess accessType);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DArrayField : X3DField {<o:p></o:p></p><p class=MsoNormal>    int getNum (void) throws throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void removeAllValues (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void removeValue (int index) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE, SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    X3DArrayField (void);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Now we can go back to our X3DNode definition. We need to review the requirements of the SAI from ISO/IEC 19775-2:2015. Looking at clause 5 Data type reference we are going to need one additional data type, namely SAINodeType. This is defined in clause 5.2.23 SAINodeType. It represents the type of the node. We can proceed like we did for SAIFieldType, and define an enumeration. Here’s how it will look:<o:p></o:p></p><p class=MsoNormal>Reference: <a href="http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/dataRef.html#SAINodeType">http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/dataRef.html#SAINodeType</a><o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>enum SAINodeType {<o:p></o:p></p><p class=MsoNormal>    Anchor,<o:p></o:p></p><p class=MsoNormal>    Appearance,<o:p></o:p></p><p class=MsoNormal>    Arc2D,<o:p></o:p></p><p class=MsoNormal>    ….<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>With all the data types known we can add these to our X3DNode definition.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DNode {<o:p></o:p></p><p class=MsoNormal>    enum SAINodeType  type;<o:p></o:p></p><p class=MsoNormal>    ??? name;<o:p></o:p></p><p class=MsoNormal>    SFNode metadata (“metadata”, inputOutput, NULL);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>And suddenly we come across our next problem. There is no data type for the node name. We had one for the field, namely SAIFieldName. But then the names of nodes are handled differently, as it is the “DEF” name. And so the node name has the standard SAIString data type, as can be seen from reviewing clause 6.4.10 namedNodeHandling. So the X3DNode definition becomes:<o:p></o:p></p><p class=MsoNormal>Reference: <a href="http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/servRef.html#NamedNodeHandling">http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/servRef.html#NamedNodeHandling</a><o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DNode {<o:p></o:p></p><p class=MsoNormal>    enum SAINodeType  type;<o:p></o:p></p><p class=MsoNormal>    SAIString name;<o:p></o:p></p><p class=MsoNormal>    SFNode metadata (“metadata”, inputOutput, NULL);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Now we need to look at the node services defined in clause 6.6 Node services, just like we did for Field services. With the benefit of that experience, we can skip all the workings, and jump straight to the results. And now we see we have confused ourselves. We need to “names”. One is a “type name”, and the other is the “DEF name”. Both have the data type SAIString. So, when we fix that, and add our services in, plus a constructor, our X3DNode definition becomes:<o:p></o:p></p><p class=MsoNormal>Reference: <a href="http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/servRef.html#NodeServices">http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/servRef.html#NodeServices</a><o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DNode {<o:p></o:p></p><p class=MsoNormal>    enum SAINodeType  type;<o:p></o:p></p><p class=MsoNormal>    SAIString DEFname;<o:p></o:p></p><p class=MsoNormal>    SAIString typeName;<o:p></o:p></p><p class=MsoNormal>    SFNode metadata (“metadata”, inputOutput, NULL);<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    SAIString getTypeName (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    enum SAINodeType getType (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    SAIField getField (SAIFieldName fieldname) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_NAME, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    static SAIField[] getFieldDefinitions (enum SAINodeType nodeType) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_NAME, SAI_DISPOSED;<o:p></o:p></p><p class=MsoNormal>    void dispose (void) throws SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING;<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    protected X3DNode (void);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>You will note that I have prepended the getFieldDefinitions method with the qualifier “static”. This indicates that this method has no dependence on any particular instance, but is a generic function that can be called even in the absence of any instances. However, this also raises the question about the validity of some of the error exceptions that can be thrown. I have also added the qualifier “protected” to the constructor for X3DNode. This indicates that this constructor can only be called by interfaces that inherit this definition, and not by other code. This prevents the instantiation of an abstract object type.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><b>Problem 6</b>: Since the node service “getFieldDefinitions” is independent of any instances, the exceptions “SAI_INVALID_OPERATION_TIMING” and “SAI_DISPOSED” are inappropriate, and should be removed.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Finally, we can define a concrete node. Let’s choose MetadataInteger, since we have the fields for that. First, though, we have to define the interface “X3DMetadataObject”. This just contains two fields. Again, for the time being we’ll ignore the fact that the “name” field is required, saving it for later. The definition then becomes:<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>X3DMetadataObject {<o:p></o:p></p><p class=MsoNormal>    SFString name (“name”, inputOutput, “”);<o:p></o:p></p><p class=MsoNormal>    SFString reference (“reference”, inputOutput, “”);<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    protected X3DMetadataObject (void);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Finally, we can define MetadataInteger, as follows:<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>MetadataInteger : X3DNode, X3DMetadataObject {<o:p></o:p></p><p class=MsoNormal>    MFInt32 value (“value, inputOutput, int32[]);<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    MetadataInteger (void);<o:p></o:p></p><p class=MsoNormal>};<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>That’s it for this session. Tomorrow, we’ll take a step back, and look at the implications of what we have defined so far, reviewing it from the perspective of different language bindings, and automatic code generation.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>All the best,<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Roy<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p></div></body></html>