[x3d-public] issue with ClassCastException, X3DJSAIL: bollard.java, fix forconsistent implementation of X3DNode by Metadata* nodes; still a JSON problem

Don Brutzman brutzman at nps.edu
Mon Feb 27 09:24:01 PST 2017


[summary: sorting out MetadataSet mysteries]

On 2/27/2017 4:03 AM, yottzumm at gmail.com wrote:
> [i wrote]
> John, looks like there is still a problem in .x3d -> .json stylesheet conversion.  Output attached.  Perhaps you can spot the difficulty there?  Looks like the MetadataSet for EntityDefinition doesn't have a proper containerField setting.  Further trickiness...
>
> aha.  Each MetadataSetObject has two child-field methods
>
>    SFNode:
>
>                 setMetadata(X3DMetadataObject newValue)
>
>                 http://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/sai/Core/MetadataSet.html#setMetadata-org.web3d.x3d.sai.Core.X3DMetadataObject-
>
>    MFNode:
>
>                 setValue(X3DNode[] newValue)
>
>                 http://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/sai/Core/MetadataSet.html#setValue-org.web3d.x3d.sai.Core.X3DNode:A-

>> I believe I use the setMetadata option, even with multiple metadata objects.  But I need to confirm that.

setMetadata() is used for a single metadata node describing the MetadataSet node.

setValue() is used for the Metadata* MFNode values held by the MetadataSet node.

>>   It seems very confusing that setValue is used with MFNode, but oh well.

The field name is 'value' and so the accessor methods are named getValue() and setValue().

=================
7.4.5 MetadataSet
http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/core.html#MetadataSet

MetadataSet : X3DNode, X3DMetadataObject {
   SFNode   [in,out] metadata  NULL [X3DMetadataObject]
   SFString [in,out] name      ""
   SFString [in,out] reference ""
   MFNode   [in,out] value     [] [X3DMetadataObject]
}
=================

>>   Results of research:  I use setMetadata() with the Metadata* objects, and addValue() with the MetadataSet objects.  See Bollard.java attached.
>>   So the addValue must have superceded the containerField somehow.  Hmm.

setMetadata() replaces the SFNode in the "metadata" field in parent MetadataSet (aka containerField='metadata' for XML child nodes).

setValue() replaces the MFNode in the "value" field in parent MetadataSet (aka containerField='value' for XML child nodes).

addValue() appends to the MFNode node in the "value" field in parent MetadataSet (aka containerField='value' for XML child nodes).

=================
MetadataSetObject:addValue
http://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/sai/Core/MetadataSet.html#addValue-org.web3d.x3d.sai.Core.X3DNode:A-

addValue

     void addValue(X3DNode[] newValue)

     Add array of child value nodes to array of existing nodes (if any).

     WARNING: acceptable node types are limited to X3DMetadataObject.

     Parameters:
         newValue - is new value array to be appended the value field.
=================

>  Ah yes, I see, the are duplicate keys in my JSON object, and the addValue value overwrites setMetadata.  Hmm.  Should it be setMetadata or addValue?  I believe this is the only place that I have addValue in my map to method object.  So we can delete the method, but the question becomes, where does it come from, and would addChildren/addChild be better?

I hope the preceding summary answers these important questions.

Here is an excerpt from HelloWorldProgram.java illustrating usage for MetadataStringObject.

=================
// addChild is singleton pipeline method, avoiding return-void restrictions of SAI addChildren interface
.addChild(new ShapeObject()
	.setAppearance(new AppearanceObject(innerAppearanceNodeDEF)
		.setMaterial(new MaterialObject(innerMaterialNodeDEF)
			.setDiffuseColor(SFColorObject.LIGHTSEAGREEN))
		.addComments(innerMaterialNodeDEF + " gets overridden by subsequently added MaterialModulator ProtoInstance")
		.setMaterial(new ProtoInstanceObject("MaterialModulator").setDEF("MyMaterialModulator")))
	.setGeometry(new ConeObject()
		.setHeight(0.1f).setBottomRadius(0.05f).setBottom(false))
	.setMetadata(new MetadataStringObject("FindableMetadataStringTest") // sets DEF
		.setName(innerMetadataStringName).setValue("test case")))
.addComments("Test success: declarativeGroup.addChild() singleton pipeline method");
=================

Perhaps we should add another example there illustrating MetadataSetObject usage.

Added: TODO show another metadata/value example using MetadataSetObject

>   Anyway excellent catch!  I know I have some overriding of child object types which comes from non-discriminatory use of the Object Model (and I need to redo this with the new object model).

Hopefully non-discriminatory use means no problem, strong typing of node content and attribute values makes it very hard to create a broken scene graph.

>> Consider what addValue means and if you really
>> mean addChildren.  IDK.

or maybe "add child node(s)" since addChildren is reserved for "children" field nodes.

> I checked the original model and it appears to have the correct Metadata* containerField values.
>
>                 https://savage.nps.edu/Savage/Buildings/SecurityPerimeter/BollardIndex.html
>                 https://savage.nps.edu/Savage/Buildings/SecurityPerimeter/Bollard.html
>                 https://savage.nps.edu/Savage/Buildings/SecurityPerimeter/Bollard.x3d
> Excerpt:
>
> <MetadataSet name='SMAL' reference=' https://savage.nps.edu/Savage/Tools/SMAL/SMAL.html ' containerField='metadata'>
>                 <MetadataString containerField='value' name='version' value='"1.0"'>
>                                 <MetadataString name='appinfo' value='"This is the version of SMAL employed, not of the model."' containerField='metadata'/>
>                 </MetadataString>
>                 <MetadataSet containerField='value' name='EntityDefinition'>
>                 <!-- Identifying metadata for the current simulation of interest -->
>                                 etc.
>
> John, it appears that you must already look at containerField values when populating MetadataSet children appropriately.  Please confirm whether all this makes sense.

>> This is what I do when I hit a containerField in DOM.  Grandparent is the parent of element.  Essentially, when I find a containerField in DOM, I create a set method based on the container field value, then call the set method on the parent node, passing the child.
>>
>>        for (let a in element.attributes) {
>>
>>                 let attrs = element.attributes;
>>
>>                 try {
>>
>>                         parseInt(a);
>>
>>                         if (attrs.hasOwnProperty(a) && attrs[a].nodeType == 2) {
>>
>>                                 let attr = attrs[a].nodeName;
>>
>> [snip]
>>
>>                                 if (attr === 'containerField') {
>>
>>                                         let method = attrs[a].nodeValue;
>>
>>                                         method = "set"+method.charAt(0).toUpperCase() + method.slice(1);
>>
>>                                         str += "                "+grandparent.nodeName+gn+"."+method+"(";
>>
>>                                         str += element.nodeName+n;
>>
>>                                 } else {
>>
>> [snip]
>>
>>                                    }
>>
>>                                 str += ");\n";
>>
>>                         }
>>
>>                 } catch (e) {
>>
>>                         console.error(e);
>>
>>                 }

if I am parsing this correctly, functional description is

	// use method setSomeKindaField() for child node having containerfield='someKindaField'

... which sounds good to me too.

>> I also disable regular parent/child adding/setting if the child has a containerField.
>>
>> Not sure if that’s right or not.  Last I checked, it didn’t work with CADFace and Shape or perhaps Transform (shape container field), but something might have changed.  .  Attached is a recent set of files I worked with.

Likely your DOM is giving you containerField default values for each node element, which should work.  Typically default containerField entries are omitted when value is default, matching X3D Canonical Form.

>> I do need to upgrade and run on a recent set of java files.  Mine are dated as of 2/26.

The date on the bottom of the page is kept up to date.  Pulling down one of the .jar files is simplest.

	http://www.web3d.org/specifications/java/X3DJSAIL.html#Downloads

all the best, Don
-- 
Don Brutzman  Naval Postgraduate School, Code USW/Br       brutzman at nps.edu
Watkins 270,  MOVES Institute, Monterey CA 93943-5000 USA   +1.831.656.2149
X3D graphics, virtual worlds, navy robotics http://faculty.nps.edu/brutzman



More information about the x3d-public mailing list