Annex B
(normative)
Java language binding
B.1 Table of contents and introduction
B.1.1 Introduction
This annex provides a detailed description of the Java language binding to the services defined in this standard. Note that support for the Java platform is not required by this standard but any access of the Java platform as an external application to a VRML browser shall conform with the requirements specified in this annex.
The Javatm platform is an object-oriented, hardware and operating system independent, multi-threaded, general-purpose application environment developed by Sun Microsystems, Inc. The Java platform consists of the language, the virtual machine, and a set of core class libraries. A conforming Java platform implements all three components according to their specifications. See 2.[JAVA] for a description of the language, the virtual machine, and the three core classes java.lang, java.util, and java.io. The other core class libraries, which are not used in this annex, are described in ISO/IEC 14772-1 E.[JAPI].
For historical reasons, the Java language binding to the EAI does not implement the full set of capabilities defined in the main specification. It implements the minimum requirements (see 7.3 Minimum Support Requirements). Restrictions imposed by this implementation on the services specification are noted individually in B.5 Services Binding.
B.1.2 Table of contents
See Table B.1 for the contents of this annex.
B.1.3 Conventions
The following type-setting conventions are used to indicate a particular meaning to the text in this document.
name | Words written in monospaced font are direct description of a particular Java class, field or property. This text may also provide a link to the specific documentation (provided in javadoc style documentation) to provide greater definition of the information |
methodName() | Indicates a particular java method call. This may be representative of the general method name (where there are overloaded versions of the method) or just the method. No arguments definitions are provided unless needed in context to define the particular method specifically. The capitalization of the method name exactly follows the name of the method |
ClassName.methodName() | The first word indicates the name of the class and is qualified with the method name. The capitalization of the class name follows the exact naming of the class. The method argument presentation is the same as that for the plain method name. |
package.name.ClassName | All words up to the class name represent the package definition that the class belongs to. Referred to as the fully qualified class name. The last word is the name of the class. Capitalization follows the exact definition of the class and package. |
B.2 Concepts
B.2.1 The Browser script interface
As with scripts within the VRML scene, the EAI allows access to the full functionality of the Browser script interface. Browser state can be queried, routes can be added and deleted, and new nodes can be created. The EAI extends the basic browser interface with a number of extra capabilities such as retrieving node references and registering interest in browser events. This annex provides an implementation in the Java language.
B.2.2 Relationship to ISO/IEC 14772-1 Annex B Java platform scripting reference
Annex B Java platform scripting reference of 2.VRML defines a Java specification to the script interface. Due to the differing capabilities of the EAI and scripting interface, the browser interfaces are not interchangeable between the two environments. This applies to all of the classes defined in ISO/IEC 14772-1 B Java platform scripting reference.
B.2.3 Scope of specification
The Java platform provides an implementation of the EAI specification. It provides a complete binding to the specification within the restrictions and implementation specific capabilities as defined in this standard. The specification provides a browser implementation independent way of accessing the browser capabilities through the Java language.
B.2.4 Conformance
Java support is not required for a conforming implementation of the EAI. If a browser supports a Java language interface from an external environment, it shall conform with all of the requirements specified in this annex.
An implementation shall not modify the classes defined in this specification with their own specific methods or additional methods. The Java reflection APIs shall be used to test this aspect of conformance.
B.2.5 Types of Java browsers
A VRML browser that can be accessed through a Java API can take one of two forms. The first form is as a plugin to a web browser. The Java code exists as an applet and accesses the plugin. The second form is a component that is available to be directly embedded in the Java framework. This form will subclass the Java Component class found in java.awt.Component.
B.2.6 Implementation dependencies
Implementation dependent for the scope of this annex is defined to be the browser writer implementation of the Java classes and how they interact with the environment and the VRML browser.
This specification does not implement the full capabilities of the EAI specification. Additional capabilities may be provided by individual implementations but shall not form part of the standard vrml.eai package hierarchy and classes as defined in this specification. Any implementation dependent provision of these capabilities shall be provided under a non-VRML package such as the vendor's own hierarchy. The listing of the implementation of all Java classes used for binding to the services is provided in B.6 Java Class Hierarchy.
B.3 Data Type Implementation
B.3.1 Data type Definitions
B.3.1.1 EAIAction
The action type is dependent on the method used. Table B.2 defines the mapping between each service, the valid action types for that service and the Java implementation of that action. Actions are mapped as method names describing the action rather than strict primitive types.
Table B.2 — EAIAction to Java implementation mapping
Service | Action Type | Java Implementation |
Dynamic Route Handling | Add Route | Browser.addRoute() |
Delete Route | Browser.deleteRoute() | |
Update Control | Begin Update | Browser.beginUpdate() |
| End Update | Browser.endUpdate() |
Register Browser Interest | Add | Browser.addBrowserListener() |
| Remove | Browser.removeBrowserListener() |
Register Event Interest | Add | EventOut.addVrmlEventListener() |
| Remove | EventOut.removeVrmlEventListener() |
B.3.1.2 EAIBrowserApp
The data type is implemented as the class vrml.eai.VrmlComponent. The capability to obtain a EAIBrowserRef is implemented in the getBrowser() method which returns an instance of the vrml.eai.Browser class.
B.3.1.3 EAIBrowserName
The data type is implemented as a java.lang.String.
B.3.1.4 EAIBrowserRef
The browser reference type is defined to be an instance of the vrml.eai.Browser class. The Browser class is defined as an implementation independent Java interface which is then subclassed to provide vendor specific
B.3.1.5 EAIBrowserVersion
The data type is implemented as a java.lang.String. The NULL value is defined as the Java null primitive type.
B.3.1.6 EAIFieldAccess
Field access is defined by the hierarchy of inheritance of classes used to represent the EAIFieldID. The base class vrml.eai.field.BaseField defines the basic field properties which are then subclassed. These subclasses vrml.eai.field.EventIn and vrml.eai.field.EventOut provide representations of the access types.
There is a distinct difference between the access type of the underlying field that was retrieved from the node and how it is represented by the subclasses. A request is made of the node to access any field to be viewed as either an eventIn (see Node.getEventIn()) or and eventOut (see Node.getEventOut()). The node implementation then either returns the type or generates an error condition. The acceptable conditions for successful completion of the request are defined in Table B.3
Table B.3 — Rules for mapping VRML Field types to Java field classes
| | Java Classes | |
|
| EventIn | EventOut |
VRML Field Types | field | Error | Error |
eventIn | yes | Error | |
eventOut | Error | yes | |
exposedField | yes | yes |
B.3.1.7 EAIFieldID
The field identifier is represented as an instance of the class vrml.eai.field.BaseField. Note that since the Java class hierarchy design allows two representations of a field using the EventIn and EventOut classes, it is possible to have two disparate references to the same field. The only time that this occurs is when referencing an exposedField of a node. The class implementation shall override the equals() method such that checking for equality in the above case shall return a result of true.
The following example illustrates the correct behaviour associated with this. The node reference has been obtained to a transform node.
Node transform; // value has been assign previously
EventIn set_translation = transform.getEventIn("set_translation");
EventOut translation_changed = transform.getEventOut("translation_changed");
Boolean same_event_in;
same_event_in = set_translation.equals(translation_changed);
System.out.println("Checking set translation equals " +
"translation changed: " +
same_event_in);
// now check the reverse case
same_event_in = translation_changed.equals(set_translation);
System.out.println("Checking translation changed equals " +
"set translation: " +
same_event_in);
The resulting execution of this code segment should produce on standard output
Checking set translation equals translation changed: true
Checking translation changed equals set translation: true
B.3.1.8 EAIFieldName
The name of the field is implemented as a java.lang.String.
B.3.1.9 EAIFieldType
The field type may be represented in two alternative fashions.
The first alternative is provided through getType() method provided in the BaseField class. This returns an int which has one of the values defined by the constant types also defined in that class as shown in Table B.4.
Table B.4 — Mapping of VRML Field type to Java representation
VRML Field type | Java representation |
MFColor | static final int MFColor |
MFFloat | static final int MFFloat |
MFInt32 | static final int MFInt32 |
MFNode | static final int MFNode |
MFRotation | static final int MFRotation |
MFString | static final int MFString |
MFTime | static final int MFTime |
MFVec2f | static final int MFVec2f |
MFVec3f | static final int MFVec3f |
SFBool | static final int SFBool |
SFColor | static final int SFColor |
SFFloat | static final int SFFloat |
SFImage | static final int SFImage |
SFInt32 | static final int SFInt32 |
SFNode | static final int SFNode |
SFRotation | static final int SFRotation |
SFString | static final int SFString |
SFTime | static final int SFTime |
SFVec2f | static final int SFVec2f |
SFVec3f | static final int SFVec3f |
The second alternative is provided by the class hierarchy. The EventIn and EventOut classes are further derived to provide implementations of the exact field type. These classes are defined in the vrml.eai.field package. A list of all the classes for each field type and access type is provided in B.5.4 Field Services.
B.3.1.10 EAIFieldValue
The field value is defined on a per class and per field type instance. See the definitions of the classes in the vrml.eai.field package for the exact definition of each type.
B.3.1.11 EAIFrameRate
The data type is implemented as the Java primitive type float. A null value is defined as the value 0.0f.
B.3.1.12 EAINavSpeed
The data type is implemented as the Java primitive type float. A null value is defined as the value 0.0f.
B.3.1.13 EAINodeID
The node identifier is represented as an instance of vrml.eai.Node.
B.3.1.14 EAINodeType
The node type is represented as a java.lang.String.
B.3.1.15 EAIParameterList
The data type is represented by the values in the Table B.5. The table defines the services that use the data type, the method of the BrowserFactory class and the lists of argument types that method takes.
Table B.5 — Mapping of EAIParameterList to Java parameter lists
Service | method | Java Parameters |
getBrowser | getBrowser() | java.applet.Applet |
getBrowser() | java.applet.Applet, String, int | |
getBrowser() | java.net.InetAddress, int | |
createBrowser | createVrmlComponent() | None |
B.3.1.16 EAIPropertyList
The data type is implemented as an array of java.lang.String. Key/Value pairs are declared in a single string in the following format with the '=' character as the separator. Whitespace surrounding the key and value are ignored although whitespace inside the key and value are legal.
The following are considered valid values (as well as permutations of the given examples):
"key=value"
"key = value "
" key = value"
"a key= some value"
"a key =some value"
B.3.1.17 EAIRequesterID
The requestor ID is represented as an instance of one of two classes depending on what information is being requested.
The requestor ID is an instance of the class implementing the interface vrml.eai.event.BrowserListener when the service request is browser_event_interest.
The requestor ID is an instance of the class implementing the interface vrml.eai.event.VrmlEventListener when the service request is field_event_interest.
B.3.1.18 EAIURL
The URL is implemented as a java.lang.String.
B.3.1.19 EAIString
The string is implemented as a java.lang.String.
B.3.2 Error data types
B.3.2.1 EAIError
Java implementations of the errors rely on a set of derived classes based on the EAIError type.
The error type is implemented as the class vrml.eai.VrmlException. This exception is in turn derived from the standard Java error type of java.lang.RuntimeException. All exceptions(errors) defined in this specification shall be derived from VrmlException.
B.3.2.2 EAI_BROWSER_UNAVAILABLE
The error type is implemented as the class vrml.eai.NoSuchBrowserException.
B.3.2.3 EAI_CONNECTION_ERROR
The error type is implemented as the class vrml.eai.ConnectionException.
B.3.2.4 EAI_DISPOSED
The error type is implemented as two separate dual purpose exception classes depending on their scope.
vrml.eai.InvalidBrowserException is used to indicate an EAIBrowserRef has been disposed of.
vrml.eai.InvalidNodeException is used to indicate an EAINodeID has been disposed of.
B.3.2.5 EAI_INVALID_ACCESS_TYPE
The error type is implemented as two separate exceptions based on the implementation of EAINodeID and the rules defined in Table B.2. These classes also derive from vrml.eai.field.InvalidFieldException.
vrml.eai.field.InvalidEventInException is used to indicate the named field is not accessible as an eventIn from the Node.getEventIn() method.
vrml.eai.field.InvalidEventOutException is used to indicate the named field is not accessible as an eventOut from the Node.getEventOut() method.
B.3.2.6 EAI_INVALID_BROWSER
The error type is implemented as the class vrml.eai.InvalidBrowserException.
B.3.2.7 EAI_INVALID_NAME
The error type is expressed as different exceptions dependent on the situation. The Browser.getNode() method uses the InvalidNodeException. The Node class getEventIn() and getEventOut() methods use the InvalidEventInException and InvalidEventOutException types respectively.
B.3.2.8 EAI_INVALID_NODE
The error type is implemented as the class vrml.eai.InvalidNodeException.
B.3.2.9 EAI_INVALID_FIELD
The error type is implemented as the class vrml.eai.field.InvalidFieldException. Note that there are two derived classes from this class (InvalidEventInException and InvalidEventOutException) that may be used at times where this error may be generated.
B.3.2.10 EAI_INVALID_URL
The error type is implemented as the class vrml.eai.InvalidURLException.
B.3.2.11 EAI_INVALID_VRML
The error type is implemented as the class vrml.eai.InvalidVrmlException.
B.3.2.12 EAI_URL_UNAVAILABLE
The error type is implemented as the class vrml.eai.URLUnavailableException.
B.3.3 Event Types
B.3.3.1 Concepts
The Java implementation of the event handling and types is based around the Java 1.1 AWT event listener model. A single event class is used to encapsulate the type of event and then parameters defining the actual event item that occurred.
B.3.3.2 EAIBrowserEvent
vrml.eai.event.BrowserEvent
The event type is implemented in the class vrml.eai.event.BrowserEvent. Each of the individual events are expressed as actions that the event then passes to the registered listeners. The action type of the individual event is available through the getID() method.
B.3.3.3 EAI_B_Initialized
The event type is implemented as the INITIALIZED value for the browser event ID.
B.3.3.4 EAI_B_Shutdown
The event type is implemented as the SHUTDOWN value for the browser event ID.
B.3.3.5 EAI_B_ConnectionError
The event type is implemented as the CONNECTION_ERROR value for the browser event ID.
B.3.3.6 EAI_B_URLError
The event type is implemented as the URL_ERROR value for the browser event ID.
B.3.3.7 EAIFieldEvent
The event type is implemented as the class vrml.eai.event.VrmlEvent. This class contains methods for obtaining the source of the event, the time (in VRML time) and any user defined data that occurred with the event.
B.4 Language specific concepts
B.4.1 Class implementation
B.4.1.1 Introduction
This specification provides a set of implementation independent base classes that represent the possible interactions with the VRML scene through the External Authoring Interface. Browser specific implementation dependencies shall to remain hidden to the general user. Where classes are declared to be abstract, it is expected that the browser specific implementation shall derive from these classes as required.
An implementation shall not modify these base classes with their own specific methods or additional methods.
The difference between the two forms of the browser is limited to how to initially obtain the browser reference. Once this has been obtained, the services provided shall not differ. The term application is used to describe the Java code that wishes to access the VRML browser, regardless of how the initial reference to the browser was obtained.
B.4.1.2 Provision of Classes
A browser that supports the EAI Java implementation may supply the base classes as part of the distribution. The design of the classes is such that only one copy of the classes defined by this application needs to be placed on the machine although multiple copies are permitted. Implementation dependent classes need only to be supplied with the browser and accessed by setting the CLASSPATH to point to the appropriate implementation dependent classes.
It is recommended that the implementation of the classes defined by this specification are placed in either a zip file or Java Archive (JAR file) under the <JAVAHOME>/lib directory.
B.4.1.3 Required Java version
Where a VRML browser is supplied as a standalone application, the minimum required version of Java Virtual Machine support is version 1.1.
VRML Browsers that operate as a plugin to general purpose web browsers may support whatever version of Java that the web browser supports. In the case where the web browser does not support any Java, or multiple versions, the minimum of version 1.1 shall be required.
B.4.1.4 Package Structure
The Java bindings to the EAI shall be provided under the vrml.eai top level package structure and are organized in the following manner.
vrml.eai | The basic working classes for the interface to the browser and nodes. |
vrml.eai.event | Event classes and listener interfaces |
vrml.eai.field | Classes for accessing fields |
B.4.2 Sessions
B.4.2.1 Introduction
A session for Java based communications is dependent on the type of handle established: applet or component.
The difference between the two forms of the browser is limited to how to initially obtain the browser reference. Once this has been obtained, the services provided shall not differ. The term application is used to describe the Java code that wishes to access the VRML browser, regardless of how the initial reference to the browser was obtained.
B.4.2.2 Component
A VRML browser established by creating a new instance of the vrml component class. This instance may then be inserted into the Java GUI framework following any Java restrictions that may be imposed on the class as a result of adding it to an AWT Container.
At the point where the browser object is instantiated, it contains no scene graph. To load the initial scene the loadURL() method is called. If the application has registered as a listener for browser events, it shall receive the initialize event as specified in the EAI specification.
Components follow the normal rules for any class derived from java.awt.Component. It may be freely added to any container and have extra components added that may partially or completely obscure the area of the window that is being used to render the VRML world. At no time shall the actions of other components that partially or complete obscure the VRML browser cause execution of the VRML event model to suspend or complete.
Note that this allows application code to draw over the top of the VRML window and attach any Java.awt.event listener as it requires without modifying the functionality of the VRML browser and vice versa.
B.4.2.3 Web Browser Plugin
When the VRML browser exists as an element embedded in a HTML page to which a Java applet has access, it must use the underlying web browser APIs to access the plugin. The session is defined to last as long as that particular plugin instance is associated with a currently active page. A factory class shall be provided to obtain a reference to a VRML browser plugin in an implementation independent manner.
The browser shall also provide notification to the listening applications of when the world is no longer displayed on the page. When the browser is removed from visibility it shall generate a shutdown event to all registered listeners. If the browser becomes visible again an initialized event shall be generated. If a new page is loaded with a VRML browser as part of it, it will contain a different Browser reference and hence the applet will not receive any such notification of its presence.
B.4.3 Identifiers
B.4.3.1 Identifier equivalence
Due to the nature of Java to native code interaction, it is possible that two instances of a Java class may refer to the same node or field inside the vrml scene (that is, using the == comparison will be false). For this reason, an identifier of a node or field cannot be implied to mean the same instance reference of the class representation. The representation of an Identifier in Java classes is implementation dependent. However, class instances may be checked for equivalence by calling the equals() method of the appropriate class. Implementations of the classes shall override the equals() method so that comparing two nodes, fields or other classes that require an identifier will return the correct result.
B.4.3.2 Data Storage
In the class structure, it is possible to associate user definable data references with each field of a node and with the node itself. If one reference to a node has data associated with it,, this information shall be available to all references to that node at all times. For example, if a field has data associated with it, is then disposed and a later application references that node, the data shall still remain (if that other application is Java based). There is no requirement to store this information if the node/field is no longer referenced by external applications or the internal scene graph, or if the external application is not Java based.
B.4.4 Serialization
Java serialization may be used to either store the state of the scene graph (for example in a database or file) or communicate between two applications/applets interfacing with the same browser. Because serialization does not maintain the same Java reference, calls to the equals() method shall produce the correct result. The specification has not defined classes to be serializable. This is implementation dependent.
B.4.5 Relative URLs
B.4.5.1 Introduction
Due to the different environments that a Java based VRML may find itself in, this binding defines the following additional behaviour for Java implementations.
B.4.5.2 Java applications
For standalone Java applications, the current working directory is determined by using the user.dir system property of the application. If a RURL is passed to the browser, it shall be resolved in equivalent terms to the following statements:
String url_base = System.getProperty("user.dir");
String complete_url = "file://" + url_base + <relative_url> ;
java.net.URL url = new URL(complete_url);
B.4.5.3 Applets
The base document of the browser is considered to be the web page in which the browser is embedded if the VRML Browser does not have a VRML world loaded.
If the applet also creates a component-based VRML browser, the base document determination shall be treated in exactly the same manner as B.4.5.2 Java applications if there is not a base world already loaded. Note that this normally will produce different base documents if an applet accesses both a plugin and a component-based browser simultaneously.
B.4.5.4 Remote applications
If a browser is located remotely to the application using it (for example using an RMI implementation), the base url is considered to be the base URL of the world. If no world URL has yet been set, the appropriate action shall be either of the previous two sections depending on how the browser was started.
B.4.6 Field access
B.4.6.1 NULL nodes
The Java null reference to an object shall be treated as the equivalent of the VRML NULL value. Where an SFNode field has its value set to null, this shall clear the field of the node reference causing the default behaviour defined by the parent node to be used for that field. When reading a value of an SFNode field where it is empty, the return value shall be null.
B.4.6.2 Setting MFNode fields
MFNodes are represented as an array of Node instances. It is possible that during the creation of the array some or all of contents may contain null references. How the browser treats a null reference is implementation dependent. That is, it is permissible to read back the field value and have it not contain the null node references, or to maintain them in the order they were sent.
B.4.6.3 Array representations
In MF fields, arrays are used to represent the data contained in the VRML field. Setting the value of that field with an array of length 0 shall result in the contents of the field being cleared and is the equivalent of the VRML text file declaration of
SomeNode {
MFField []
}
An empty MF field shall return an array of length zero if queried about its value. The size() method of the MFField base class shall return a value of 0.
Attempting to set the value of the field with null shall generate an IllegalArgumentException.
B.4.6.4 set1Value
MFField classes contain a set1Value() method for setting an individual value in the field.
If beginUpdate() has been called and multiple set1Value() methods have been called on that field, the result when endUpdate() is called shall be a single event with all of the individual values set. If two calls are made to set a particular array index, the last value written shall be used.
If beginUpdate()has not been called, the result shall be an event that contains the entire field value with the individual value changed. Multiple set1Value() calls to the field shall result in the equivalent number of events being generated inside the VRML browser.
B.4.7 Disposing of Resources
Of particular concern to Java implementations is the disposal of resources used by the Java environment. The garbage collection environment creates problems when dealing with native code implementations of the VRML browser. An explicit dispose() method is provided with all classes representing VRML entities so that the application can explicitly dispose of the resources used by the browser implementation.
For safety purposes, where a class defines a dispose() method, it shall also override the default finalize() method provided by java.lang.Object and call the dispose() method. This shall ensure that even if the user has not explicitly called dispose on objects, when the object reference goes out of scope, all resources shall be freed regardless avoiding potential memory leaks.
Once a node has had the dispose method of, method calls on the node shall generate an InvalidNodeException.
B.5 Services Binding
B.5.1 Establishing browser connections
B.5.1.1 BrowserFactory
vrml.eai.BrowserFactory
Creating a reference to a VRML browser must deal with a number of different scenarios: Java applet to VRML plugin in a web browser, server application talking to a browser on a separate machine or a component in a standalone Java application. Each of these requires a separate solution in order to maintain implementation dependence.
The method of access a VRML browser shall be through a single factory style class. This class contains methods for each type of access. To provide implementation independence the vrml.eai.BrowserFactoryImpl interface for the implementation dependent parts is defined. Browsers shall subclass this interface to provide the necessary dependent code. This interface is loaded by the vrml browser factory using dynamic methods or by having the code explicitly set.
A properties file called vrml.properties, if resident in the user's CLASSPATH shall be used to determine the name of the class to be loaded. The name of the property in the properties file shall be
vrml.eai.factory.class
which shall be set to the fully qualified name of the browser factory class implementation to be loaded. The implementation of this class shall not reside within the vrml.* class hierarchy but shall reside in the browser writer's own class hierarchy. The browser factory shall also contain a setBrowserFactoryImpl() method to allow an explicit setting of the factory implementation. If this method is the first method called of all the factory methods, it shall be used as the factory implementation. If any other method is called prior to calling this method, the name of the factory implementation shall be drawn from the properties file and loaded. Any attempt to call the set implementation method shall result in a vrml.eai.VrmlException being generated.
The factory implementation shall return the appropriate subclasses for each of the methods. If the implementation does not support the particular connection requested, it shall generate a vrml.eai.NotSupportedException. If it is supported, it shall return the appropriate subclass of the object for that method.
B.5.1.2 getBrowser
B.5.1.2.1 Web Plugin browser
Browser BrowserFactory.getBrowser(Applet)
Browser BrowserFactory.getBrowser(Applet, String, int)
A browser that operates as part of a web browser requires a number of different parameters for correct determination of the plugin to access. Due to the nature of web pages, it is possible that an applet on one page may access either more that one VRML plugin or that the plugin exists in another HTML frame. The applet form of the getBrowser() method requires a reference to the accessing applet, the name of the frame and the index of the frame in the nominated frame. The frame name is a string representing the name of the frame. The index is the number of the VRML browser in the page (where there might be more than one) starting from 0.
B.5.1.2.2 Remote browser
Browser BrowserFactory.getBrowser(InetAddress, int)
An application server may wish to access browsers on client machines. The third variant of the getBrowser request requires an IP address (or machine name) and a port number. The server application requests the browser reference of the remote machine. Once the browser reference is returned, the server application may manipulate the browser contents like any other EAI using application.
The port number of the protocol may be any port number. There is no defined default port to which a browser will listen. The protocol between the application and the browser is also not defined.
B.5.1.3 createBrowser
B.5.1.3.1 AWT Component browser
VrmlComponent BrowserFactory.createVrmlComponent(String[])
The component browser is required to fit into the standard java.awt.Component model and is implemented as a subclass of vrml.eai.VrmlComponent. It shall derive from java.awt.Component and also provide a getBrowser() method that returns a reference to a standard vrml.eai.Browser object. The component implementation may implement the component in any manner it requires. Both lightweight components (all rendering performed in Java) and heavyweight components (with peer interfaces extending from java.awt.peer.ComponentPeer) are permitted. These details shall be hidden within the implementation specific classes and not accessible to the general API user.
The factory class shall include a method that generates an instance of this component class. Each call to the component shall result in a new independent instance of a VRML browser capable of running as a component. The browser shall be capable of running either within a web browser environment (e.g., Java applet window with a VRML browser in it) or in standalone applications with the restrictions appropriate to the underlying environment. It shall also use whatever hints are supported in the parameter argument passed to it. These hints are in the same form as those passed to loadURL.
B.5.2 Browser services
B.5.2.1 getName
String Browser.getName()
The name returned is a String representing the name of the browser. If this is not supported, null shall be returned.
B.5.2.2 getVersion
String Browser.getVersion()
The version returned is a String representing the version number of the browser. If this is not supported, null shall be returned.
B.5.2.3 getCurrentSpeed
float Browser.getCurrentSpeed()
The speed value returned shall be a floating point number or 0.0 if is not supported.
B.5.2.4 getCurrentFrameRate
float Browser.getCurrentFrameRate()
The frame rate value shall be a floating point number or 0.0 if it is not supported.
B.5.2.5 getWorldURL
String Browser.getWorldURL()
The world URL shall be a string indicating the complete world URL as defined in 6.3.11 getWorldURL.
B.5.2.6 replaceWorld
void Browser.replaceWorld(Node[])
The parameter shall be an array of Node instances which shall be used to replace the currently loaded world. If one or more of the node instances have been disposed of, an IllegalArgumentException shall be generated.
B.5.2.7 loadURL
void Browser.loadURL(String[], String[])
The parameters shall be an array of strings for the URL list and an array of Strings for the parameters. If the browser determines that it cannot load any of the URLs passed, the browser event listener shall receive an event notifying it of an error.
If the parameters list is a zero length array or is null, the action is to replace the world in the current browser. The properties defined in Table B.6 are standard values that shall be supported.
Table B.6 — Property list for loadURL
Key | Value | Description of Function |
replace | true | Replaces the entire page that browser is embedded in. If the browser is a standalone browser this shall have no effect. |
false | The browser shall replace the contents of the currently loaded world with the new world specified by the URL argument. The same effect as providing no value to the parameters argument. | |
target | <frameName> | The name of the frame shall be used to load the browser as the contents of the named HTML frame. |
Individual browser implementations may support extra property definitions.
B.5.2.8 setDescription
void Browser.setDescription(String)
This service sets the description string of the browser. If the browser is running as a plugin, this shall set the title of the page (if the containing web browser supports this). For component browsers the result shall be implementation dependent.
B.5.2.9 createVrmlFromString
Node[] Browser.createVrmlFromString(String)
The parameter shall be a string that contains legal syntax as defined in ISO/IEC 14772-1. The only difference is that the file header #VRML V2.0 utf8 need not be present as the first line in the string. If the string does not contain legal VRML97 syntax, an InvalidVrmlException shall be generated. Returned is an array of the top level Nodes in the order that they are declared in the string parameter.
B.5.2.10 createVrmlFromURL
void Browser.createVrmlFromURL(String[], Node, String)
The parameter list shall consist of an array of Strings describing the list of URLs, a reference to a destination Node and a String which is the name of the eventIn to send the loaded URL nodes to. If the browser determines that it cannot load any of the URLs passed, the browser event listener shall receive an event notifying it of an error.
B.5.2.11 Dynamic Route Handling
void Browser.addRoute(Node, String, Node, String)
void Browser.deleteRoute(Node, String, Node, String)
This service is split into two separate methods: addRoute and deleteRoute. They both take the same argument list. The first parameter is a Node reference that the event will leave from. The second is a String describing the name of the eventOut. Third and forth parameters are the destination node reference and the eventIn as a String. If either of the Node references have been disposed of, an InvalidNodeException shall be generated. If either of the nodes do not contain the nominated eventIn/eventOut, an InvalidEventIn/EventOutException shall be generated appropriately.
B.5.2.12 Update Control
void Browser.beginUpdate()
void Browser.endUpdate()
This service is split into two separate methods beginUpdate and endUpdate. The functionality remains as described in 6.3.16 Update Control.
B.5.2.13 Register Browser Interest
void Browser.addBrowserListener(BrowserListener)
void Browser.removeBrowserListener(BrowserListener)
Registering interest in browser events is through a browser event listener. The listener is an interface which is passed browser events when the state of the browser changes or asynchronous error messages must be sent (for example, inability to load any of the requested URLs). Methods shall be provided to allow listeners to be added and removed dynamically. A separate event class shall be used to indicate the event information. This class has a predefined number of events although specific browser implementations may send more events than the defined values. The toString() method shall be overridden in this case to provide more information to the user in determining the extra event types to deal with them. Any extra event types must not have values below the figure defined by LAST_IDENTIFIER.
B.5.2.14 getNode
Node Browser.getNode(String)
The return value is a Node reference. The parameter is a String defining the DEF name of the required node. If the browser cannot find the node name, an InvalidNodeException shall be generated.
B.5.2.15 Dispose
void Browser.dispose()
Dispose shall notify the browser that the Java implementation is no longer interested in the VRML browser. Any further requests to methods of this instance of the browser interface shall generate an InvalidBrowserException.
B.5.3 Node services
B.5.3.1 Node Representation
vrml.eai.Node
The ability to list all of the fields of a node reference and their values is not available as part of the standard implementation. It is not possible to get the name of the node. The implementation of the node services is implemented as the class vrml.eai.Node.
B.5.3.2 getName/getType
String Node.getType()
The 6.4.5 getType and 6.4.4 getName services are combined into a single method request getType() that returns the name of the node as a String.
B.5.3.3 getField
EventIn Node.getEventIn(String)
EventOut Node.getEventOut(String)
6.4.3 getField service is implemented as two separate methods getEventIn() and getEventOut() which allows access to eventIns and eventOuts but not to fields. An exposedField may be accessed as either the eventIn or eventOut portion separately through these two methods. The normal field name or with the set_ modifier may be used with the getEventIn method. The normal field name or the _changed modifier may be used with the getEventOut method.
B.5.3.4 Dispose
void Node.dispose()
Dispose shall notify the browser that the Java implementation is no longer interested in this node instance and it is free to do as required with the node representation. Any further requests to methods of this instance of the node reference shall generate an InvalidNodeException. If two separate instances of the same class represent the same node (as defined by the equals() method returning true) and one has dispose called, this shall not effect the other instance.
B.5.4 Field services
B.5.4.1 Field Representation
vrml.eai.field package
vrml.eai.field.BaseField and subclasses.
The Java implementation of the field services does not directly follow the model outlined in 6.5 Field Services. Instead, it makes heavy use of the Object Oriented nature of Java to provide directly the capabilities suggested by the services specified. All the services are implemented in the classes provided in the vrml.eai.field package.
The following outlines how the Java binding conforms to the requirements of the EAI.
B.5.4.2 getAccessType
6.5.2 getAccessType is not a directly callable method in the Java implementation. The access type is implied by the class that represents the field. For example, calling
EventIn trans = some_transform.getEventIn("set_translation");
will return an EventIn class reference. From this the implication is that the access type of this field is an eventIn.
B.5.4.3 getType
int BaseField.getType()
The getType() method of vrml.eai.field.BaseField returns an identifier of the type of field that the instance of the class represents. The list of legal type identifiers is included as public final variables in the class. The return value of the getType() method shall be one of these values.
The class instance is also used as an alternative type of representation of the node type. There shall be one class for each type of VRML field, one derived from EventIn and one derived from EventOut. The class reference returned from a call to Node.getEventIn() or Node.getEventOut() shall return an instance of one of these classes respectively.
B.5.4.4 getName
The 6.5.3 getName service is not supported by the Java language bindings
B.5.4.5 getValue
The getValue() method of vrml.eai.field.BaseField is supported only on classes derived from eventOut. It is not possible to read values from eventIn as there is no method to support this operation. On fields which are exposedFields, an eventOut derived class will be needed to access the field to read its value.
The getValue() method returns values in a format appropriate to the individual field type. If the method returns an array of values, the array shall be guaranteed to be created on each call. The implementation shall not reuse return value references between calls to the methods. This is to guarantee thread-safe data integrity.
To provide similarity to ISO/IEC 14772-1 B Java platform scripting reference, a get1Value() method is provided for MF fields. This allows access to a single value out of the many values. When an attempt is made to access a value at an index greater than the number of items in that eventOut, a java.lang.ArrayIndexOutOfBoundsException shall be generated. Each time the getValue() method is called, a new instance of the returned array shall be generated.
An alternate form of the getValue()and get1Value() methods shall be available for the MF eventOuts. These forms shall take arrays as parameters that can be used to write values in. See the javadoc outline of each class for proper definitions of what methods are to be provided.
B.5.4.6 setValue
The setValue() method of vrml.eai.field.BaseField is supported only on classes derived from EventIn. It is not possible to write values from eventIn as there is no method to support this operation. On fields which are exposedFields, an EventIn derived class will be needed to write a new value.
To provide similarity with ISO/IEC 14772-1 B Java platform scripting reference, a set1Value() method is provided for MFFields. This allows the ability to change a single value of a field without having to re-create the entire array of values. When an attempt is made to set a value at an index greater than the number of items in that eventIn, a java.lang.ArrayIndexOutOfBoundsException shall be generated. See B.4.6.4 set1Value for other behavioural aspects of this method.
B.5.4.7 Register Field Interest
void EventOut.addVrmlEventListener(VrmlEventListener)
void EventOut.removeVrmlEventListener(VrmlEventListener)
The shall be no capabilities to attach listeners to eventIns. Listening to eventOuts is available. This restriction is implemented as part of the Java API implementation which has separate classes for eventIn and eventOut representation. Where a field is declared to be an exposedField, listeners can only be attached to the eventOut portion.
B.6 Java Class Hierarchy
B.6.1 Establishing Browser Connections
Classes/Interfaces
vrml.eai.Browser
vrml.eai.BrowserFactory
vrml.eai.BrowserFactoryImpl
vrml.eai.VrmlComponent
Exceptions
vrml.eai.NoSuchBrowserException
vrml.eai.NotSupportedException
java.net.UnknownHostException
B.6.2 Browser Services
Classes/Interfaces
vrml.eai.Browser
vrml.eai.Node
vrml.eai.event.BrowserListener
vrml.eai.event.BrowserEvent
Exceptions
vrml.eai.InvalidBrowserException
vrml.eai.InvalidVrmlException
vrml.eai.InvalidNodeException
vrml.eai.InvalidURLException
vrml.eai.URLUnavailableException
vrml.eai.field.InvalidEventInException
vrml.eai.field.InvalidEventOutException
B.6.3 Node Services
Classes/Interfaces
vrml.eai.Node
vrml.eai.field.EventOut
vrml.eai.field.EventIn
Exceptions
vrml.eai.InvalidNodeException
vrml.eai.field.InvalidEventInException
vrml.eai.field.InvalidEventOutException
B.6.4 Field Services
Classes/Interfaces
vrml.eai.field.BaseField
vrml.eai.field.EventIn
vrml.eai.field.EventInMFColor
vrml.eai.field.EventInMFFloat
vrml.eai.field.EventInMFInt32
vrml.eai.field.EventInMFNode
vrml.eai.field.EventInMFRotation
vrml.eai.field.EventInMFString
vrml.eai.field.EventInMFTime
vrml.eai.field.EventInMFVec2f
vrml.eai.field.EventInMFVec3f
vrml.eai.field.EventInSFBool
vrml.eai.field.EventInSFColor
vrml.eai.field.EventInSFFloat
vrml.eai.field.EventInSFImage
vrml.eai.field.EventInSFInt32
vrml.eai.field.EventInSFNode
vrml.eai.field.EventInSFRotation
vrml.eai.field.EventInSFString
vrml.eai.field.EventInSFTime
vrml.eai.field.EventInSFVec2f
vrml.eai.field.EventInSFVec3f
vrml.eai.field.EventOut
vrml.eai.field.EventOutMField
vrml.eai.field.EventOutMFColor
vrml.eai.field.EventOutMFFloat
vrml.eai.field.EventOutMFInt32
vrml.eai.field.EventOutMFNode
vrml.eai.field.EventOutMFRotation
vrml.eai.field.EventOutMFString
vrml.eai.field.EventOutMFTime
vrml.eai.field.EventOutMFVec2f
vrml.eai.field.EventOutMFVec3f
vrml.eai.field.EventOutSFBool
vrml.eai.field.EventOutSFColor
vrml.eai.field.EventOutSFFloat
vrml.eai.field.EventOutSFInt32
vrml.eai.field.EventOutSFNode
vrml.eai.field.EventOutSFRotation
vrml.eai.field.EventOutSFString
vrml.eai.field.EventOutSFTime
vrml.eai.field.EventOutSFVec2f
vrml.eai.field.EventOutSFVec3f
vrml.eai.event.VrmlEvent
vrml.eai.event.VrmlEventListener
Exceptions
vrml.eai.field.InvalidFieldException
vrml.eai.field.InvalidEventInException
vrml.eai.field.InvalidEventOutException
B.6.5 Class Hierarchy/Package Arrangements
Package vrml.eai
+- vrml.eai.Browser
+- vrml.eai.BrowserFactory
+- vrml.eai.Node
+- vrml.eai.BrowserFactoryImpl
+- vrml.eai.VrmlComponent
+- vrml.eai.VrmlException
+- vrml.eai.InvalidBrowserException
+- vrml.eai.InvalidVrmlException
+- vrml.eai.InvalidNodeException
+- vrml.eai.InvalidURLException
+- vrml.eai.NoSuchBrowserException
+- vrml.eai.NotSupportedException
+- vrml.eai.URLUnavailableException
Package vrml.eai.event
+- vrml.eai.event.BrowserListener
+- vrml.eai.event.BrowserEvent
+- vrml.eai.event.VrmlEvent
+- vrml.eai.event.VrmlEventListener
Package vrml.eai.field
+- vrml.eai.field.BaseField
+- vrml.eai.field.EventIn
| +- vrml.eai.field.EventInMFColor
| +- vrml.eai.field.EventInMFFloat
| +- vrml.eai.field.EventInMFInt32
| +- vrml.eai.field.EventInMFNode
| +- vrml.eai.field.EventInMFRotation
| +- vrml.eai.field.EventInMFString
| +- vrml.eai.field.EventInMFTime
| +- vrml.eai.field.EventInMFVec2f
| +- vrml.eai.field.EventInMFVec3f
| +- vrml.eai.field.EventInSFBool
| +- vrml.eai.field.EventInSFColor
| +- vrml.eai.field.EventInSFFloat
| +- vrml.eai.field.EventInSFImage
| +- vrml.eai.field.EventInSFInt32
| +- vrml.eai.field.EventInSFNode
| +- vrml.eai.field.EventInSFRotation
| +- vrml.eai.field.EventInSFString
| +- vrml.eai.field.EventInSFTime
| +- vrml.eai.field.EventInSFVec2f
| +- vrml.eai.field.EventInSFVec3f
+- vrml.eai.field.EventOut
+- vrml.eai.field.EventOutMField
+- vrml.eai.field.EventOutMFColor
+- vrml.eai.field.EventOutMFFloat
+- vrml.eai.field.EventOutMFInt32
+- vrml.eai.field.EventOutMFNode
+- vrml.eai.field.EventOutMFRotation
+- vrml.eai.field.EventOutMFString
+- vrml.eai.field.EventOutMFTime
+- vrml.eai.field.EventOutMFVec2f
+- vrml.eai.field.EventOutMFVec3f
+- vrml.eai.field.EventOutSFBool
+- vrml.eai.field.EventOutSFColor
+- vrml.eai.field.EventOutSFFloat
+- vrml.eai.field.EventOutSFInt32
+- vrml.eai.field.EventOutSFNode
+- vrml.eai.field.EventOutSFRotation
+- vrml.eai.field.EventOutSFString
+- vrml.eai.field.EventOutSFTime
+- vrml.eai.field.EventOutSFVec2f
+- vrml.eai.field.EventOutSFVec3f
+- vrml.eai.VrmlException
+- vrml.eai.field.FieldException
+- vrml.eai.field.InvalidEventInException
+- vrml.eai.field.InvalidEventOutException
B.7 Examples
The following is an example Java EAI script that finds a Material node called BoxMaterial in the scene graph and changes its diffuseColor field to be 0 1 0. This has the effect of changing the box from its original red color to green. To view this example within a web browser, the following HTML segment is used.
<embed src="box.wrl" height="300" width="300">
<applet code="box.class" mayscript height="1" width="1">
</applet>
box.wrl
#VRML V2.0 utf8
Shape {
appearance Appearance {
material DEF BoxMaterial Material {
diffuseColor 1 0 0
}
}
geometry Box { size 2 2 2 }
}
box.java
import java.applet.*;
import vrml.eai.field.*;
import vrml.eai.Node;
import vrml.eai.BrowserFactory;
import vrml.eai.Browser;
public class box extends Applet {
public void init() {
super.init();
}
public void start() {
Browser browser = null;
Node material = null;
EventInSFColor boxcolor = null;
// Get the VRML Browser - try 10 times
for (int count = 0; count < 10; count++) {
browser = BrowserFactory.getBrowser(this);
if (browser != null) break;
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {}
}
// Get the diffuseColor eventIn of the DEF'd material node
try {
material = browser.getNode("BoxMaterial");
boxcolor = (EventInSFColor) material.getEventIn("set_diffuseColor");
} catch (vrml.eai.InvalidNodeException ignored) {}
// Sleep for 1 second
try {
Thread.sleep(1000);
} catch ( InterruptedException ignored ) {}
// Change the material's diffuse color to green (0,1,0)
float[] newcolor = new float[3];
newcolor[0] = 0.0f; newcolor[1] = 1.0f; newcolor[2] = 0.0f;
boxcolor.setValue(newcolor);
}
}
The next example shows how to create new geometry and add this to an existing scene using the EAI. In this case, the VRML file contains a red cuboid and the EAI script creates and overlays a blue sphere. The HTML segment for embedding this example in a web browser is as follows.
Figure B.1 — CreateVrmlFromString example
<embed src="create.wrl" height="300" width="300">
<applet code="create.class" mayscript height="1" width="1">
</applet>
create.wrl
#VRML V2.0 utf8
DEF NewNode Group {}
Shape {
appearance Appearance {
material DEF BoxMaterial Material {
diffuseColor 1 0 0
}
}
geometry Box { size 2 2 1 }
}
create.java
import java.applet.*;
import vrml.eai.field.*;
import vrml.eai.Node;
import vrml.eai.BrowserFactory;
import vrml.eai.Browser;
public class create extends Applet {
public void init() {
super.init();
}
public void start() {
Browser browser = null;
Node rootnode = null;
EventInMFNode children = null;
// Get the VRML Browser - try 10 times
for (int count = 0; count < 10; count++) {
browser = BrowserFactory.getBrowser(this);
if (browser != null) break;
try { Thread.sleep(200); } catch (InterruptedException e) {}
}
// Get the set_children eventIn of the DEF'd Group node
try {
rootnode = browser.getNode("NewNode");
children = (EventInMFNode) rootnode.getEventIn("set_children");
} catch (vrml.eai.InvalidNodeException ignored) {}
// Create a new blue Sphere Shape node
String newvrml =
"#VRML V2.0 utf8\nShape { appearance Appearance { material " +
"Material { diffuseColor 0 0 1 } } geometry Sphere { radius 1 } }";
// Create and add the new node to the scene graph
children.setValue( browser.createVrmlFromString( newvrml ) );
}
}
This example illustrates cycling between different cameras in a scene using the EAI. The VRML file contains a yellow cone with three Viewpoint nodes specified. The EAI script then continually binds each viewpoint in succession with a 1 second delay between each switch. The HTML segment for embedding this example in a web browser is as follows.
<embed src="viewswitch.wrl" height="300" width="300">
<applet code="viewswitch.class" mayscript height="1" width="1">
</applet>
viewswitch.wrl
#VRML V2.0 utf8
DEF View1 Viewpoint {
position 0 -3 6
orientation 1 0 0 0.46
description "Viewpoint 1"
}
DEF View2 Viewpoint {
position 0 7 0
orientation 0 -.707 -.707 3.1416
description "Viewpoint 2"
}
DEF View3 Viewpoint {
position 0 0 10
orientation 0 0 1 0
description "Viewpoint 3"
}
Shape {
appearance Appearance {
material DEF BoxMaterial Material {
diffuseColor 1 1 0
}
}
geometry Cone {}
}
viewswitch.java
import java.applet.*;
import vrml.eai.field.*;
import vrml.eai.Node;
import vrml.eai.BrowserFactory;
import vrml.eai.Browser;
public class viewswitch extends Applet {
public void init() {
super.init();
}
public void start() {
Browser browser = null;
EventInSFBool bind1 = null;
EventInSFBool bind2 = null;
EventInSFBool bind3 = null;
// Get the VRML Browser - try 10 times
for (int count = 0; count < 10; count++) {
browser = BrowserFactory.getBrowser(this);
if (browser != null) break;
try { Thread.sleep(200); } catch (InterruptedException e) {}
}
// Get the set_bind eventIns for the three DEF'd Viewpoint nodes
try {
Node view1 = browser.getNode("View1");
Node view2 = browser.getNode("View2");
Node view3 = browser.getNode("View3");
bind1 = (EventInSFBool) view1.getEventIn("set_bind");
bind2 = (EventInSFBool) view2.getEventIn("set_bind");
bind3 = (EventInSFBool) view3.getEventIn("set_bind");
} catch (vrml.eai.InvalidNodeException ignored) {}
// cycle through each Viewpoint node at 1 sec intervals
while (true) {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
bind1.setValue(true);
try { Thread.sleep(1000); } catch (InterruptedException e) {}
bind2.setValue(true);
try { Thread.sleep(1000); } catch (InterruptedException e) {}
bind3.setValue(true);
}
}
}
This next example shows how to perform scene graph traverals using the EAI. The script will search for all Switch nodes in a scene and set their whichChoice fields to a certain value. Two buttons are created in the applet's canvas to let the user set all Switch nodes to their first or second nodes. For the particular VRML file show here, this causes a switch between a purple cube and a cyan sphere. Note that we use the beginUpdate() and endUpdate() browser methods so that the scene graph is only updated once the traversal process has completed.
<APPLET CODE="switcher.class" HEIGHT="32" WIDTH="400" MAYSCRIPT>
</APPLET>
<EMBED SRC="switcher.wrl" WIDTH="400" HEIGHT="400">
switcher.wrl
#VRML V2.0 utf8
DEF RootNode Group {
children [
NavigationInfo { type [ "EXAMINE", "ANY" ] }
Switch {
whichChoice 0
choice [
Shape { # Switch 1
appearance Appearance { material
Material { diffuseColor 1 0 1 }
}
geometry Box { size 4 4 4 }
}
Shape { # Switch 2
appearance Appearance { material
Material { diffuseColor 0 1 1 }
}
geometry Sphere { radius 2 }
}
]
}
]
}
switcher.java
import java.awt.*;
import java.applet.*;
import vrml.eai.Node;
import vrml.eai.BrowserFactory;
import vrml.eai.Browser;
import vrml.eai.field.*;
public class switcher extends Applet {
Browser browser = null;
String button1 = "Flick Switch 1";
String button2 = "Flick Switch 2";
// create the two applet buttons and get the browser reference
public void start() {
setBackground(Color.white);
add(new Button(button1));
add(new Button(button2));
browser = BrowserFactory.getBrowser(this);
}
// search scene graph for all Switch nodes and update their whichChoice
public void set_switch(int value) {
browser.beginUpdate();
Node root = browser.getNode("RootNode");
set_switch_recur((EventOutMFNode) root.getEventOut("children"), value);
browser.endUpdate();
}
// recursive method to do the scene graph traversal
public void set_switch_recur(EventOutMFNode children, int value) {
if (children == null) return;
Node nodes[] = children.getValue();
int num_nodes = nodes.length;
for (int i = 0; i < num_nodes; ++i) {
String node_type = nodes[i].getType();
if (node_type.compareTo("Switch") == 0) {
// Grab the whichChoice field of the Switch and change it
EventInSFInt32 whichChoice = (EventInSFInt32)
nodes[i].getEventIn("whichChoice");
whichChoice.setValue(value);
} else if (node_type.compareTo("Group") == 0 ||
node_type.compareTo("Transform") == 0 ||
node_type.compareTo("Collision") == 0) {
// recurse into grouping nodes - other grouping nodes possible
set_switch_recur((EventOutMFNode) nodes[i].getEventOut("children"),
value);
}
}
}
// The button event handling routine
public boolean action(Event event, Object what) {
if (event.target instanceof Button && browser != null) {
Button b = (Button) event.target;
if (b.getLabel() == button1) {
set_switch(0);
} else if (b.getLabel() == button2) {
set_switch(1);
}
}
return true;
}
}
This final example shows the creation of widgets in a Java applet that can be used to control items in the scene graph. Here the EAI is used to build a helix model using an Extrusion node and to animate this model. The applet then allows the user to change the number of coils in the helix. The HTML segment for embedding this example in a web browser is as follows.
Figure B.2 — Helix example
<embed src="helix.wrl" border=0 height="200" width="200">
<applet code="helix.class" mayscript height="100" width="200">
</applet>
helix.wrl
#VRML V2.0 utf8
Viewpoint {
position 0 4 5
orientation 1 0 0 -0.5
}
Shape {
appearance Appearance {
material Material {
diffuseColor 0.8 0.8 0.9
shininess 1
}
}
geometry DEF Coil Extrusion {
crossSection []
spine []
creaseAngle 3.14
}
}
helix.java
import java.awt.*;
import java.applet.*;
import vrml.eai.field.*;
import vrml.eai.Node;
import vrml.eai.BrowserFactory;
import vrml.eai.Browser;
public class helix extends Applet implements Runnable {
EventInMFVec3f spine = null;
EventInMFVec2f crossSection = null;
Thread thread = null;
Choice choice;
int spineLimit = 250;
float[][] spineValue = new float[spineLimit+1][3];
int crossSectionLimit = 10;
float[][] crossSectionValue = new float[crossSectionLimit+1][2];
float numCoils = 5f;
// set up the applet controls
public void init() {
super.init();
setBackground(Color.white);
Panel p1 = new Panel();
Label lblNCoils = new Label("Number of Coils");
p1.add(lblNCoils);
choice= new Choice();
choice.addItem("5"); choice.addItem("4"); choice.addItem("3");
choice.addItem("2"); choice.addItem("1");
p1.add(choice);
add(p1);
}
public void start() {
// get the VRML Browser reference
Browser browser = null;
for (int count = 0; count < 10; count++) {
browser = BrowserFactory.getBrowser(this);
if (browser != null) break;
try { Thread.sleep (200); } catch (InterruptedException e) {}
}
if (browser == null) {
throw new Error("Failed to get the browser after 10 tries!");
}
// get the spine and crossSection fields of the Extrusion node
try {
Node coil = browser.getNode("Coil");
spine = (EventInMFVec3f) coil.getEventIn("set_spine");
crossSection = (EventInMFVec2f) coil.getEventIn("set_crossSection");
} catch (vrml.eai.InvalidNodeException ne){
System.out.println("Node Exception Error:" + ne.getMessage());
}
if (thread == null) {
thread = new Thread(this);
thread.start();
} else
thread.resume();
}
public void stop() {
if (thread != null) thread.suspend();
}
public void destroy() {
thread.stop();
thread = null;
}
public void run() {
// calculate and set the crossSection values of the Extrusion node
float thickness = 0.1f;
float diameter = 1.5f;
float two_pi = (float) Math.PI * 2.0f;
for (int j = 0; j <= crossSectionLimit; j++) {
float angle = j * two_pi / crossSectionLimit;
crossSectionValue[j][0] = thickness / 2 * (float) Math.sin(angle);
crossSectionValue[j][1] = thickness / 2 * (float) Math.cos(angle);
}
crossSection.setValue(crossSectionValue);
// oscilate the spring between 0.3 and 1, with 0.05 increments
float inc = 0.05f;
float value = 0.3f;
float springLength = 2f;
while (true) {
value += inc;
//calculate and set the coordinates for the whole spine
for (int i = 0; i <= spineLimit; i++) {
float stepsPerCoil = (float) Math.round(spineLimit / numCoils);
float angle = i * two_pi / stepsPerCoil;
spineValue[i][0] = diameter / 2 * (float) Math.cos(angle);
spineValue[i][1] = springLength / numCoils * value * i / stepsPerCoil;
spineValue[i][2] = diameter / 2 * (float) Math.sin(angle);
}
spine.setValue(spineValue);
// sleep for 0.1 seconds
try { thread.sleep(100); } catch (InterruptedException e) {}
// reverse movement direction
if (value >= 1f && inc == 0.05f)
inc = -0.05f;
else if (value <= 0.3 && inc == -0.05f)
inc = 0.05f;
}
}
// handle input (deprecated Java API)
public boolean handleEvent(Event event) {
if (event.id == Event.ACTION_EVENT && event.target == choice)
changeNumCoils();
return super.handleEvent(event);
}
// changes number of coils in the helix
private void changeNumCoils() {
String number = choice.getSelectedItem();
numCoils = (new Float(number)).floatValue();
}
}