[x3d-public] Building an X3D Object Model - Progress Review after Step 3

Roy Walmsley roy.walmsley at ntlworld.com
Sun Oct 22 07:10:16 PDT 2017


Hi,

 

So today we will take a break from defining new stuff, and instead look at
what we have got, and the implications for language bindings. I want to look
in particular at one language binding, namely Java. The Java language has
object oriented capabilities, so we should be able to map to it without too
many issues.

 

Let's start by listing all the definitions.

 

enum SAIFieldAccess {

    initializeOnly,

    inputOnly,

    outputOnly,

    inputOutput

};

 

enum SAIFieldType {

    SFBool,

    MFBool,

    SFColor,

   .

};

 

X3DField {

    enum SAIFieldType type;

    enum SAIFieldAccess accessType;

    SAIFieldName name;

 

    enum SAIFieldAccess getAccessType (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_DISPOSED;

    enum SAIFieldType getType (void) throws SAI_CONNECTION_ERROR,
SAI_DISPOSED;

    SAIFieldName getName (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;

    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;

    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;

    void dispose void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING;

 

    X3DField (SAIFieldName fieldName, enum SAIFieldAccess accessType);

};

 

SFInt32 : X3DField {

    int32 value = 0;

 

    int32 getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void setValue (int32 newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

 

    SFInt32 (SAIFieldName fieldName, enum SAIFieldAccess accessType, int32
defaultValue);

};

 

SFNode : X3DField {

    SAINode value = NULL;

 

    SAINode getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void setValue (SAINode newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

 

    SFNode (SAIFieldName fieldName, enum SAIFieldAccess accessType, SAINode
defaultValue);

};

 

SFString : X3DField {

    SAIString value = "";

 

    SAIString getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void setValue (SAIString newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

 

    SFString (SAIFieldName fieldName, enum SAIFieldAccess accessType,
SAIString defaultValue);

};

 

X3DArrayField : X3DField {

    int getNum (void) throws throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void removeAllValues (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

    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;

 

    X3DArrayField (void);

};

 

MFInt32 : X3DArrayField {

    int32 value[];

 

    int32[] getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    int32 get1Value (int index) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

    void appendValue (int32 newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

    void insertValue (int index, int32 newValue) throws
SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

    void setValue (int32 newValue[]) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

    void set1Value (int index, int32 newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

 

    MFInt32 (SAIFieldName fieldName, enum SAIFieldAccess accessType, int32
defaultValue[]);

};

 

enum SAINodeType {

    Anchor,

    Appearance,

    Arc2D,

    ..

};

 

X3DNode {

    enum SAINodeType  type;

    SAIString DEFname;

    SAIString typeName;

    SFNode metadata ("metadata", inputOutput, NULL);

 

    SAIString getTypeName (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;

    enum SAINodeType getType (void) throws SAI_CONNECTION_ERROR,
SAI_DISPOSED;

    SAIField getField (SAIFieldName fieldname) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_NAME, SAI_DISPOSED;

    static SAIField[] getFieldDefinitions (enum SAINodeType nodeType) throws
SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_NAME,
SAI_DISPOSED;

    void dispose (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING;

 

    protected X3DNode (void);

};

 

X3DMetadataObject {

    SFString name ("name", inputOutput, "");

    SFString reference ("reference", inputOutput, "");

 

    protected X3DMetadataObject (void);

};

 

MetadataInteger : X3DNode, X3DMetadataObject {

    MFInt32 value ("value, inputOutput, int32[]);

 

    MetadataInteger (void);

};

 

Now, the Java language binding is specified at ISO/IEC 19777-2:2006.
However, this is for version 3.0 of X3D. There is a draft of version 3.3,
but this is not yet publicly shared. However, there is the X3D Java Scene
Access Interface Library (X3DJSAIL) which is publicly available. In
particular, we can look at the Javadoc for this library.

Reference:
http://www.web3d.org/specifications/java/X3dJavaSceneAuthoringInterface.html

Reference: http://www.web3d.org/specifications/java/javadoc/index.html

 

Referring to our list of definitions presented above, the first two are the
enumerations SAIFieldAccess and SAIFieldType. What do we have in the Java
library. We have X3DFieldTypes. This interface definition merges the two
enumerations we defined into a single set. That's OK. X3D does not define
the implementation, only that a mapping be provided. So a good start.

 

The next item on our list is X3DField, the abstract interface which is
inherited by all field objects. In the Java library we also have an X3DField
interface. I've reproduced the definition below (in blue, to highlight that
this is the Java language, and not the Object Model).

 

public interface X3DField

{

X3DFieldDefinition getDefinition();

boolean isReadable();

boolean isWritable();

void addX3DEventListener(X3DFieldEventListener listener);

void removeX3DEventListener(X3DFieldEventListener listener);

}

 

Does it have the required services? At first glance, it seems not. There are
no methods corresponding to the services getAccessType, getType, getName, or
dispose. The methods addX3DEventListener and removeX3DEventListener map to
the addInterest and removeInterest services that we defined, so that's OK.
However, there are two additional methods, isReadable and isWritable, which
are a substitute for the getAccessType service. There is also an additional
method getDefinition, which is not formally specified by the SAI. So
getType, getName, and dispose are missing. Let's not report this yet, since
they might be in the inherited definitions.

 

Let's move on to the first field object SFInt32. Here is the Java library
definition:

 

public interface SFInt32 extends X3DField

{

public int getValue();

public void setValue(int newValue);

}

 

This looks great. We have the getValue and setValue methods. Although we
note we still don't have methods corresponding to the getType, getName, or
dispose services. In view of this let's see what the V3.3 draft has to say
about the mappings to the SAI. These are listed in Table 4.9 for Field
services. I've reproduced the table next.

 


Abstract name

Java bound name


getName

String getName()


getType

int getType()


getAccessType

boolean isWritable()
boolean isReadable() 


getValue

type getValue()
void getValue(type)
type get1Value(int)


setValue

void setValue(type)
void get1Value(int, type)


registerFieldInterest

void addFieldEventListener(X3DFieldEventListener)
void removeFieldEventListener(X3DFieldEventListener)


dispose

void dispose()

 

So the Java library has agrees with the draft Java language binding, but has
missing functionality. Now we can report this. But there is one other point
to notice. What about the exceptions list. So far we haven't seen any. Let's
also report this.

 

Problem 7: The X3DJSAIL library is missing functions for the field services
getName, getType, and dispose.

Problem 8: The X3DJSAIL library is missing exceptions on the interface
definitions.

 

Let's also check the SFNode and SFString definitions in the X3DJSAIL
library.

 

public interface SFNode extends X3DField

{

public X3DNode getValue();

public void setValue(X3DNode newValue) throws InvalidNodeException;

}

 

public interface SFString extends X3DField

{

public String getValue();

public void setValue(String newValue);

}

 

There are no additional issues, so let's move on to the multivalued field
definitions. The first is the abstract X3DArrayField definition. We find
that the corresponding interface in X3DJSAIL is called MField. Here is the
definition:

 

public interface MField extends X3DField

{

public int size();

public void clear();

public void remove(int index);

}

 

We have the methods here that map  directly to our Object Model methods. The
method "size" maps to "getNum". The method "clear" maps to "removeAll", and
the method "remove" maps to "remove". Great. Now we can look at the MFInt32
interface. The X3DJSAIL interface is:

 

public interface MFInt32 extends MField

{

public void getValue(int[] valueDestination);

public int get1Value(int index) throws ArrayIndexOutOfBoundsException;

public void setValue(int size, int[] newValue);

public void set1Value(int imageIndex, int newValue) throws
ArrayIndexOutOfBoundsException;

public void append(int newValue);

public void insertValue(int index, int newValue);

}

 

Comparing with our Object Model definition, the six methods in the X3DJSAIL
interface map directly to the  Object Model, although we still note the lack
of exceptions, except that an ArrayIndexOutOfBoundsException has been
defined to correspond to the SAI_INVALID_ARRAY_INDEX error that we defined
previously.

 

That completes the review of fields. Now let's turn our attention to nodes.
The X3DNode definition is the abstract definition that all node interfaces
are derived from. We find it in the X3DJSAIL library with that name. Here is
the X3DNode interface definition.

 

public interface X3DNode

{

                public X3DMetadataObject getMetadata(); // acceptable node
types: X3DMetadataObject

                public X3DNode setMetadata(X3DMetadataObject newValue); //
acceptable node types: X3DMetadataObject

                public X3DNode setDEF(String newValue);

                public X3DNode setUSE(String newValue);

                public X3DNode setCssClass(String newValue);

}

 

How does this correspond to our Object Model? It doesn't look anything like
it. So, let's look at what is defined for node services in the draft X3D
Java language binding. This is in Table 4.8. I've reproduced it below.

 


Abstract name

Java bound name


getTypeName

String getName()


getType

int[] getType()


getField

X3DField getField(java.lang.String)


getFieldDefinitions

X3DFieldDefinition getFieldDefinitions()


dispose

void dispose()

 

No, X3DJSAIL doesn't match. What is going on? X3DJSAIL is missing all the
services defined by the SAI and the draft Java language binding
specification. We'll report that in a moment. Let's just review what is
there, though. There are methods "getMetadata" and "setMetadata". These
relate to getting/setting the value of the metadata field. In our Object
Model we defined the SFNode field metadata as a property of the interface.
X3DJSAIL has not done that. Instead, it has get and set methods defined on a
field by field basis. Obviously there is nothing inherently wrong about
this. However, it doesn't match the draft Java language binding
specification, or the SAI. We'll report that in a moment.

 

The X3DJSAIL library has some additional methods. The "setDEF" and "setUSE"
methods relate to namedNodeHandling. We didn't address that yet in our
Object Model. The "setCssClass" method relates to the planned integration of
X3D into HTML, to be specified in V4.0 of X3D.

 

Problem 9: The X3DJSAIL library does not have the required node services.

 

Its time to move on to the concrete node type. But we need one more abstract
object first. That is X3DMetadataObject. Here is the X3DJSAIL library
definition.

 

public interface X3DMetadataObject

{

public String getName();

public X3DMetadataObject setName(String newValue);

public String getReference();

public X3DMetadataObject setReference(String newValue);

}

 

It has the same issues as X3DNode. All field oriented operations are
implemented on a field by field basis. Note that the "getName" method, which
here refers to getting the value of the "name" field, would be confused with
the node service "getName", which returns the name of the node.

 

Finally, we look at the MetadataInteger node definition in X3DJSAIL.

 

public interface MetadataInteger extends X3DMetadataObject, X3DNode

{

public X3DMetadataObject getMetadata(); // acceptable node types:
X3DMetadataObject

public MetadataInteger setMetadata(X3DMetadataObject newValue); //
acceptable node types: X3DMetadataObject

public String getName();

public MetadataInteger setName(String newValue);

public String getReference();

public MetadataInteger setReference(String newValue);

public int[] getValue();

public MetadataInteger setValue(int[] newValue);

public MetadataInteger setDEF(String newValue);

public MetadataInteger setUSE(String newValue);

public MetadataInteger setCssClass(String newValue);

}

 

Ahh, this is even worse. Why are the methods inherited from the
X3DMetadataObject and X3DNode definitions redefined? And what about all
those methods for setting multivalued fields that were defined in the MField
class? Since this library is implementing methods within a node on a field
by field basis, these methods also need to be added. And even then there is
no set1Value method or append methods, which the SAI requires.

 

Problem 10: The X3DJSAIL library fails to provide all the correct
functionality as  required by a) the abstract SAI specification and b) the
draft Java language binding for version 3.3.

 

Finally, let's review what is in Appendix C of the draft Java language
binding, for the MetadataInteger node. This is at clause C.3.128
MetadataInteger. I've reproduced it below, in green to highlight it is from
the draft specification.

 

public interface MetadataInteger extends X3DMetadataObject

{

  /** Return MFInt32 result [] from MFInt32 inputOutput field named "value"
*/

  public MFInt32 getValue ();

 

  /** Return number of primitive values in "value" array */

  public int getNumValue ();

 

  /** Assign MFInt32 value [] to MFInt32 inputOutput field named "value" */

  public void setValue (MFInt32 values) throws InvalidFieldValueException;

 

  /** Assign single SFInt32 value [] as the MFInt32 array for inputOutput
field named "value" */

  public void setValue (SFInt32 value) throws InvalidFieldValueException;

 

  // ===== methods for fields inherited from parent interfaces =====

 

  /** Return String result [] from SFString inputOutput field named "name"
*/

  public String getName ();

 

  /** Assign String value [] to SFString inputOutput field named "name" */

  public void setName (String value);

 

  /** Return String result [] from SFString inputOutput field named
"reference" */

  public String getReference ();

 

  /** Assign String value [] to SFString inputOutput field named "reference"
*/

  public void setReference (String value);

 

  /** Return X3DMetadataObject result (using a properly typed node or
X3DPrototypeInstance) from SFNode inputOutput field named "metadata" */

  public void getMetadata (X3DNode result);

 

  /** Assign X3DMetadataObject value (using a properly typed node) to SFNode
inputOutput field named "metadata" */

  public void setMetadata (X3DMetadataObject node) throws
InvalidFieldValueException;

 

  /** Assign X3DMetadataObject value (using a properly typed protoInstance)
*/

  public void setMetadata (X3DPrototypeInstance protoInstance) throws
InvalidFieldValueException;

}

 

Here we see similar problems. There are the same missing node services that
we have noted for X3DJSAIL. And there is also a completely different method
for handling individual fields that is not described in the Concepts clause
of the draft specification.

 

Problem 11: In the draft Java language binding specification for X3D V3.3
the node definitions in Annex C do not meet the requirements described in
clauses 3 to 6, in turn failing to meet the requirements of the abstract SAI
specification ISO/IEC 19775-2:2015.

 

Well, we appear to have uncovered some serious failings. So let's pause and
wait for comment. Perhaps we have misunderstood things. Anyway, let's get
other opinions before we move on to filling in some of the gaps we
intentionally set aside, and then generalizing our approach to all the other
nodes.

 

All the best,

 

Roy

 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://web3d.org/pipermail/x3d-public_web3d.org/attachments/20171022/53122245/attachment-0001.html>


More information about the x3d-public mailing list