[WARNING: this is a local copy of http://www.vrml.org/WorkingGroups/vrml-eai/ExternalInterface.html. It may be OUTDATED! ]

Proposal for a VRML 2.0 Informative Annex

External Authoring Interface Reference

Chris Marrin
Silicon Graphics, Inc.

November 21, 1997

For communication between a VRML world and an external environment an interface between the two is needed. This interface is call an External Authoring Interface and it defines the set of functionality of the VRML browser that the external environment can access. To understand the relationship between this interface and the rest of the VRML environment please see Anatomy of a VRML Browser.

1 Concepts

1.1 Introduction

1.2 Node access

1.3 The Browser Script Interface

1.4 Sending events

1.5 Reading eventOut values

1.6 Notification of eventOut changes

2 Language Based Interface

2.1 Introduction

2.2 The browser object

2.3 Initialize and shutdown

2.4 Node access

2.5 The Browser Script Interface

2.6 Sending events

2.7 Reading eventOut values

2.8 Notification of eventOut changes

3 Protocol Based Interface

3.1 Introduction

3.2 The browser object

3.3 Initialize and shutdown

3.4 Node access

3.5 The Browser Script Interface

3.6 Sending events

3.7 Reading eventOut values

3.8 Notification of eventOut changes

  A Java Language Support

A.1 Introduction

A.2 The Browser classes

A.3 Initialize and shutdown

A.4 BeginUpdate and endUpdate

A.5 Accessing nodes

A.6 Sending events

A.7 Accessing an eventOut

A.8 The EventOutObserver

A.9 Interface Hierarchy

A.10 Java Interface

A.10.1 Package vrml
A.10.2 Package vrml.field
A.10.3 Package vrml.exception

B Example Programs

1 Concepts

1.1 Introduction

The interface described here is designed to allow an external environment to access nodes in a VRML scene using the existing VRML event model. In this model, an eventOut of a given node can be routed to an evenIn of another node. When the eventOut generates an event, the eventIn is notified and its node processes that event. Additionally, if a script in a Script node has a reference to a given node it can send events directly to any eventIn of that node and it can read the last value sent from any of its eventOuts.

The EAI adapts this interface by giving access to the top-level named nodes in the system to the external environment. The interface then mimics the access of the Script node with a reference to the named node. To facilitate the sending of events to the external environment, a new mechanism is made available. To receive notification when an event is sent to an eventOut, the external environment registers interest in it. This mechanism is similar in concept to the processEvents functionality in the VRML specification, but is effectively different due to the asynchronous nature of the external environment.

This interface can be applied to both language based and protocol based implementations (see 2. Language Based Interface and 3. Protocol Based Interface). The interface in either case is conceptually identical.

Conceptually, the External Authoring Interface allows 4 types of access into the VRML scene:

  1. Accessing the functionality of the Browser Script Interface.
  2. Sending events to eventIns of nodes inside the scene.
  3. Reading the last value sent from eventOuts of nodes inside the scene.
  4. Getting notified when events are sent from eventOuts of nodes inside the scene.

1.2 Node access

Most operations in the EAI begin by obtaining a reference to a node. To reference a node it must be named using the DEF construct. Once a reference is obtained, the eventIns and eventOuts of that node can be accessed. Since an exposedField implicitly contains an eventIn and eventOut, these are accessible as well, using the set_ and _changed modifiers.

1.3 The Browser Script Interface

As in 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.

1.4 Sending events

 Once a node reference is made available to the external environment, an event may be sent to any eventIn of that node. The data sent is specific to the field type of that eventIn and is formatted appropriate to the language or protocol used.

1.5 Reading eventOut values

Any eventOut of a node to which the external environment has a reference can be read. The value read is the last value sent to that eventOut or the default value for that eventOut type if no event has ever been sent. The data read is specific to the field type of that eventOut and is formatted appropriate to the language or protocol used.

1.6 Notification of eventOut changes

The external environment can register to receive notification when a given eventOut changes. The registration request is made to the node containing the eventOut. During the registration process the external environment can supply a token that will be returned along with the data value of the event. This token can be used by the external environment  to uniquely identify this event in cases where events are not implicitly unique. The data supplied during notification is specific to the field type of that eventOut and is formatted appropriate to the language or protocol used. There shall also be a corresponding mechanism to unregister notification of a particular eventOut.

2 Language Based Interface

2.1 Introduction

 Language based implementations use a set of methods or functions to provide the functionality of the EAI to the specific language. An application, written in the language, uses this interface to access and control the VRML scene. The exact style and structure of the interface is language specific but shall follow the conceptual framework provided here.

The concepts of a language based EAI are similar to those of Script Authoring Interface, which provides the interface for languages supported by the VRML Script node. There are two conceptual differences between the two. The first has to do with obtaining a node reference through which eventIns and eventOuts can be accessed. When creating a VRML file a Script node (and therefore the script it contains) can get a node reference with the USE construct (see Instancing). Since the external environment has no implicit access to this mechanism an explicit method is provided to get the reference from its DEF name string.

EventOut notification is also conceptually different since creating a ROUTE is not possible between the VRML scene and the external environment. The application must create a method to be called when the eventOut occurs. This method is registered with an eventOut of a given node. When the eventOut generates an event the registered method is called.

2.2 The browser object

The application communicates with a VRML world by first obtaining a reference to a browser object. This allows the application to uniquely identify a particular VRML scene in environments where multiple scenes are available. This object can be created, in which case the application is responsible for providing all information needed to introduce the object into the environment. the application can also obtain a reference to a browser already in existance in the environment. The details of how a browser reference is obtained is language specific. For object oriented languages a Browser class is referenced or instanced. For other languages a createBrowser( ) or getBrowser( ) method is used.

Because some environments may be inherantly asynchronous, getting a reference to an existing browser instance may block the application until that instance is created.

2.3 Initialize and shutdown

To allow the browser to inform the application when it's scene is loaded and unloaded, initialize( ) and shutdown( ) methods can be created by the application and registered with the browser. The initialize( ) method is called upon completion of loading of the base file. The shutdown( ) method is called when the scene is about to be unloaded. This can occur when the VRML browser object is destroyed, or when the scene is replaced with the replaceScene( ) or loadURL( ) call. In the latter two cases another initialize( ) method is called upon completion of loading of the new scene.

For object oriented languages these are virtual methods which can be added to the Browser class through subclassing or interface implementation. For other languages, these are callback methods, passed as parameters to the createBrowser( ) or getBrowser( ) methods.

2.4 Node Access

Once a reference to a browser is obtained, it can be used to gain access to specific nodes in the VRML world currently contained by the browser. This is done using a getNode( ) method, which is passed the DEF name of the desired node and returns a reference to that node. Only DEF names in the base VRML scene are accessible. Names in Inline files and those created with createVRMLFromString( ) or createVRMLFromURL( ) are not accessible. Since VRML files can have multiple occurances of the same DEF name only the node with the last occurance of a given name is accessible.

When a VRML scene is changed through use of the replaceWorld( ) method, the named nodes of that scene are not available to the application. The only way to access such a world is through the root nodes, which are passed as a parameter to replaceWorld( ). However, when a scene is changed using the loadURL( ) method, the new URL becomes the base scene and therefore the named nodes of that scene are available to the application.

A VRML scene may be in the process of loading when an application attempts to access nodes in it. The requested nodes will not be accessible in this case, and the getNode( ) call will fail. To prevent this, access to the scene should not be attempted until the initialize( ) method is called.

2.5 The Browser Script Interface

All methods in the Browser Script Interface are available to an EAI application. The interface is the same as for Script node scripts. Any node reference obtained with the getNode( ) method can be used in these methods.

2.6 Sending events

Once a node reference is obtained, all its eventIns are accessible using the getEventIn( ) method. This method is passed the name of the eventIn and a reference to that eventIn is returned. This may then be used to send events to it by calling any of various methods related to the eventIn reference. The exact interface of these event sending methods is language specific. An object oriented language shall provide member functions on an EventIn class. Other languages shall provide event sending methods which take the eventIn reference as a parameter.

In order to better control the sending of events to the scene, language-based implementations shall provide a beginUpdate( ) and endUpdate( ) mechanism. If these methods are not invoked, each event sent to the scene shall be processed immediately. All event sending methods called after the first call to beginUpdate( ) shall not have their events sent until after the last call to endUpdate( ). These two calls shall implement proper nesting (i.e., if three calls to beginUpdate( ) are made, three calls to endUpdate( ) must be called before the events are sent).

2.7 Reading eventOut values

Once a node reference is obtained, all its eventOuts may be read by first calling the getEventOut( ) method to obtain a reference to the desired eventOut. This method is passed the name of the eventOut and a reference to that eventOut is returned. This may then be used to read the current value of the eventOut by calling any of various methods related to the eventOut reference. The exact interface of these event reading methods is language specific. An object oriented language shall provide member functions on an EventOut class. Other languages shall provide methods which take the eventOut reference as a parameter.

2.8 Notification of eventOut changes

To receive notification when an eventOut is generated from a named node in the scene, the application must first create a method which will be called when the event is generated. For object oriented languages this shall be a subclass or implementation of the EventOutObserver class or interface, implementing the callback( ) member function. This instance shall then be passed to the advise( ) method of the desired EventOut instance. For other languages this shall be a callback method registered with the desired eventOut. A language specific token is also passed when registering the callback. This token is passed to the callback to uniquely identify this transaction. It allows a single callback to be used for multiple eventOuts. When the eventOut occurs the callback is called with the value of the eventOut, the timestamp the event was generated, and the token.

There shall also be an unadvise( ) method on EventOut to terminate notification for that eventOut. The EventOutObserver is supplied to distinguish which observer is being terminated, in the case where a single eventOut has multiple observers.

3 Protocol Based Interface

 3.1 Introduction

 Protocol based implementations use packets of data sent between the external environment and the VRML scene. The exact format of the packets used is protocol specific, but shall follow the conceptual framework provided here.

Since the Script Authoring Interface does not support the concept of protocol based interfaces, the two are functionally quite different. But conceptually the interaction with the VRML scene is very similar, with two differences. The first has to do with obtaining a node reference through which eventIns and eventOuts can be accessed. When creating a VRML file a Script node (and therefore the script it contains) can get a node reference with the USE construct (see Instancing). Since the external environment has no implicit access to this mechanism the protocol must supply an identifier for the desired node. This identifier is equivalent, but is not necessarily identical, to the DEF name of the node.

EventOut notification is also conceptually different since creating a ROUTE is not possible between the VRML scene and the external environment. The protocol must register interest in an eventOut of a given node. When the eventOut generates an event a packet is sent to the external environment.

3.2 The browser object

The external environment communicates with a VRML world by first obtaining an identifier for a browser object. This allows the external environment to uniquely identify a particular VRML scene in environments where multiple scenes are available. This object can be created, in which case the protocol is responsible for providing all information needed to introduce the object into the environment. the external environment can also obtain an identifier to a browser already in existance. The details of how a browser identifier is obtained is protocol specific.

Because some environments may be inherantly asynchronous, getting an identifier for an existing browser instance may require that an acknowledgement packet be sent in response to an identifier request.

3.3 Initialize and shutdown

To allow the browser to inform the external environment when it's scene is loaded and unloaded, initialize and shutdown packets shall be sent from the browser. The initialize packet is sent upon completion of loading of the base file. The shutdown packet is sent when the scene is about to be unloaded. This can occur when the VRML browser object is destroyed, or when the scene is replaced with the replaceScene or loadURL function.

3.4 Node Access

In order to access nodes in the scene, packets contain a node identifier. This identifier is equivalent, but not identical, to the DEF name of the node. That is to say the only nodes that can be accessed through a node identifier are those nodes in the base scene that have a DEF name. But this identifier need not be a name string. Its definition is protocol and environment specific. Nodes in Inline files are not accessible. Those created with createVRMLFromString or createVRMLFromURL are assigned node identifiers by the VRML scene. These identifiers can then be used to access these nodes in future interactions.

When a VRML scene is changed through use of the replaceWorld function, the named nodes of that scene are not available to the application. The only way to access such a world is through the root node, which is passed as a parameter to replaceWorld. However, when a scene is changed using the loadURL( ) method, the named nodes of that scene are available through the same node identifier system as the original scene.

A VRML scene may be in the process of loading when an external environment attempts to access nodes in it. The requested nodes will not be accessible in this case. To prevent this, access to the scene should not be attempted until the initialize packet is received.

3.5 The Browser Script Interface

All functions in the Browser Script Interface are available to the external environment. The interface is conceptually the same as for Script node scripts. The exact format of the parameters for each function is protocol specific. Any node identifier can be used in these methods.

3.6 Sending events

The eventIns associated with a given node identifier are accessible using an eventIn identifier. This identifier is equivalent, but not necessarily identical, to the name of the eventIn. The definition of this identifier is protocol specific and is used to send events to the eventIn. The exact format of the data sent is protocol specific.

3.7 Reading eventOut values

The eventOuts associated with a given node identifier are accessible using an eventOut identifier. This identifier is equivalent, but not necessarily identical, to the name of the eventOut. The definition of this identifier is protocol specific and is sent to the scene to request that a packet containing the current value of the eventOut be returned. The exact format of the data in the returned packet is protocol specific.

3.8 Notification of eventOut changes

In addition to sending a request that the current value of an eventOut be returned, the external environment can also request that a packet be returned whenever an event is generated from a given eventOut. The same eventOut identifier used, and the request may include a token to be returned with the packet containing the data to uniquely identify this transaction. When the eventOut occurs a packet is sent to the external environment with the value of the eventOut, the timestamp the event was generated, and the token. The format of these elements is protocol specific.

There shall also be a mechanism to terminate this notification.

A Java Language Support

A.1 Introduction

The Java platform is an object-oriented system of user defined and standard classes which allow applications to be built and run on a variety of systems and environments. These applications can be embedded within another environment (such as a HTML browser) or run as standalone components on a variety of computer systems. The EAI operates as a set of classes which extend the Java platform for access to one or more VRML scenes within this environment.

A.2 The Browser classes

A Java application communicates with a VRML world by first obtaining an instance of a Browser or CBrowser class, both of which implement the IBrowser interface. The IBrowser interface is the Java encapsulation of the VRML scene. It contains the entire Browser Script Interface as well as a getNode() method which returns a Node when given a DEF name string. The IBrowser class also contains beginUpdate( ) and endUpdate( ) methods to allow grouping of events to be sent to the scene.

An instance of an existing scene is obtained by instantiating a Browser class. This class is used when the application is embedded in another environment (such as a HTML browser), which has already instantiated one or more VRML scenes. This class may be instantiated in two ways:

    public Browser(Applet pApplet);
    public Browser(Applet pApplet, String frameName, int index);

The Applet class is a standard Java class which is the encapsulation of the application in the environment. The first form associates the first or only VRML scene with the instantiation. The second form is more general and allows a frameName string identifying the container owning the desired VRML scene to be specified. Passing NULL or the empty string selects the first or only container in the environment. Additionally, an index of the VRML scene within the container can be specified. This is used in environments where a given container can own more than one sub-component. If this is not the case, a value of 0 shall be specified.

To create a new instance of a VRML scene, the CBrowser class is used. This class implements the Browser interface and also extends the AWT Component class. Therefore it can have all the capabilities of accessing the scene, plus it can be added to an AWT Container class. When creating an instance of CBrowser, the replaceWorld( ) or loadURL( ) methods of the Browser class are used to add the initial scene.

Both the Browser and CBrowser classes contain  initialize( ) and shutdown( ) methods (see A.3 Initialization and shutdown). The author may extend these classes, providing a new implementation for these methods.

A.3 initialize and shutdown

 Upon instantiation of a browser class, the scene may not yet be loaded. When loading is complete, but before any events are processed or the scene is displayed, the initialize( ) method is called. The author may subclass this method to receive notification that the scene has been loaded and nodes can be accessed using the getNode( ) method. Similarly, when the scene is replaced or unloaded (e.g., when the application has been terminated) the shutdown( ) method is called. Once this method is called, further access to the current scene shall produce undefined results. In the case where one scene is unloaded and another is loaded (e.g., when replaceWorld( ) is called), shutdown( ) is called to signal the unloading of the previous scene, then initialize( ) is called to signal the loading of the new scene.

A.4 beginUpdate and endUpdate

Normally, when events are sent to the VRML scene from the EAI, they are immediately processed and the scene is updated. This leads to excessive updates and poor performance if the author intends for several events to be considered a single unit. The JSAI solves this problem because events sent from individual browser invoked methods are sent simultaneously. Since the EAI has no browser invoked methods, the beginUpdate( ) and endUpdate( ) methods simulate this functionality. Any event sending method called after beginUpdate( ) is not sent immediately. When endUpdate( ) is called, any pending event is sent with the timestamp of the instant endUpdate( ) was invoked. Calls may be nested; if two calls are made to beginUpdate( ), then two calls must be made to endUpdate( ) before the events are sent.

A.5 Accessing Nodes

Once an instance of the browser is obtained, it can be used to gain access to specific nodes in the VRML world currently contained by the browser. This is done using the getNode( ) method of the Browser class, which is passed the DEF name of the desired node and returns a reference to that node. This reference can then be used to access eventIns and eventOuts of that node, or in calls to the Browser Script Interface.

A.6 Sending Events

Once a node reference is obtained, all its eventIns are accessible using the getEventIn( ) method. This method is passed the name of the eventIn and returns a reference to an EventIn instance, if an eventIn with that name is found. ExposedFields can also be accessed, either by giving a string for the exposedField itself (such as "translation") or by giving the name of the corresponding eventIn (such as "set_translation").

Once an instance of the desired EventIn is obtained, an event can be sent to it. But EventIn has no methods for sending events. It must first be cast to the appropriate eventIn subclass, which contains methods for sending events of the given type.

Here is an example of sending an eventIn to a VRML scene containing this node:

    DEF Mover Transform { ... }
Here is the Java code for sending an event to change the translation field (assume browser is the instance of a Browser, ABrowser, or CBrowser class gotten from a previous call):
    Node mover = browser.getNode("Mover");
    EventInSFVec3f translation = 
                (EventInSFVec3f) mover.getEventIn("set_translation");

    float value[3] = new float[3];
    value[0] = 5; value[1] = 0; value[2] = 1;
    translation.setValue(value);
In the above example, the translation value (5, 0, 1) is sent to the translation field of the Transform node.

Events are sent immediately when setValue is called unless the call is preceeded by one or more beginUpdate( ) calls. In that case events are deferred until a corresponding endUpdate( ) is called. These calls nest. If three beginUpdate( ) calls are made, three endUpdate( ) calls must be made before any events after the first beginUpdate( ) call are sent.

A.7 Accessing an eventOut

Once a node reference is obtained, all its eventOuts are accessible using the getEventOut( ) method. This method is passed the name of the eventOut and returns a reference to and EventOut instance, if an eventOut with than name is found. ExposedFields can also be accessed, either by giving a string for the exposedField itself (such as "translation") or by giving the name of the corresponding eventOut (such as "translation_changed").

Once an instance of a desired EventOut is obtained, two operations can be performed. The current value of the eventOut can be retrieved, and a callback can be setup to be invoked whenever the eventOut is generated. EventOut does not have any methods for getting the current value so it must be cast into the appropriate eventOut subclass type, which contains appropriate access methods.

Using the eventIn example above, the current value of the translation field can be read like this:

    float current[] = ((EventOutSFVec3f)
              (mover.getEventOut("translation_changed"))).getValue();
The array current now contains 3 floats with the x, y, and z components of the current translation value.

A.8 The EventOut Observer

To receive notification when an eventOut is generated from the scene, the applet must first subclass the EventOutObserver class, implementing the callback() method. Next the advise() method of EventOut is passed the EventOutObserver. Then whenever an event is generated for that eventOut, the callback() method is executed and is passed the value and timestamp of the event. The advise() method is also passed a user defined object. This value is passed to the callback() method when an event is generated and can be used by the application author to pass user defined data to the callback. It allows a single EventOutObserver subclass to handle events from multiple sources. It is a subclass of the standard java Object class so it can be used to hold any data.

Using the above example again, the applet can get notified when the translation field of the Transform is changed like this:

    public class MyObserver implements EventOutObserver {
        public void callback(EventOut value, 
                             double timeStamp, 
                             Object data)
        {
            // cast value into an EventOutSFVec3f and use it
        }
    }

    ...

    MyObserver observer = new MyObserver;
    mover.getEventOut("translation_changed").advise(observer, null);
When the eventOut from the translation exposedField occurs, observer.callback() is invoked.

The EventOut class also has an unadvise( ) method which is used to terminate notification for that eventOut. The original EventOutObserver instance is supplied to distinguish which observer is being terminated, in the case where a single eventOut has multiple observers.

A.9 Interface Hierarchy

The Java implementation of the External Authoring Interface is specified in three Java packages: vrml.external, vrml.external.field, and vrml.external.exception. All of the members of package vrml.external.exception are classes derived from java.lang.RuntimeException; the rest of the members of the packages are specified as interfaces (with the exception of vrml.external.field.FieldTypes, which merely defines an integer constant for each EventIn/EventOut type). This allows the compiled Java applet to be used with any VRML browser's External Authoring Interface implementation.
vrml.external
  |
  +- vrml.external.IBrowser
  |       +- vrml.external.Browser
  |       +- vrml.external.CBrowser
  |
  +- vrml.external.Node
  +- vrml.external.field
  |       +- vrml.external.field.EventIn
  |       |       +- vrml.external.field.EventInMFColor
  |       |       +- vrml.external.field.EventInMFFloat
  |       |       +- vrml.external.field.EventInMFInt32
  |       |       +- vrml.external.field.EventInMFNode
  |       |       +- vrml.external.field.EventInMFRotation
  |       |       +- vrml.external.field.EventInMFString
  |       |       +- vrml.external.field.EventInMFVec2f
  |       |       +- vrml.external.field.EventInMFVec3f
  |       |       +- vrml.external.field.EventInSFBool
  |       |       +- vrml.external.field.EventInSFColor
  |       |       +- vrml.external.field.EventInSFFloat
  |       |       +- vrml.external.field.EventInSFImage
  |       |       +- vrml.external.field.EventInSFInt32
  |       |       +- vrml.external.field.EventInSFNode
  |       |       +- vrml.external.field.EventInSFRotation
  |       |       +- vrml.external.field.EventInSFString
  |       |       +- vrml.external.field.EventInSFTime
  |       |       +- vrml.external.field.EventInSFVec2f
  |       |       +- vrml.external.field.EventInSFVec3f
  |       |
  |       +- vrml.external.field.EventOut
  |       |       +- vrml.external.field.EventOutMField
  |       |       |       +- vrml.external.field.EventOutMFColor
  |       |       |       +- vrml.external.field.EventOutMFFloat
  |       |       |       +- vrml.external.field.EventOutMFInt32
  |       |       |       +- vrml.external.field.EventOutMFNode
  |       |       |       +- vrml.external.field.EventOutMFRotation
  |       |       |       +- vrml.external.field.EventOutMFString
  |       |       |       +- vrml.external.field.EventOutMFVec2f
  |       |       |       +- vrml.external.field.EventOutMFVec3f
  |       |       |
  |       |       +- vrml.external.field.EventOutSFBool
  |       |       +- vrml.external.field.EventOutSFColor
  |       |       +- vrml.external.field.EventOutSFFloat
  |       |       +- vrml.external.field.EventOutSFImage
  |       |       +- vrml.external.field.EventOutSFInt32
  |       |       +- vrml.external.field.EventOutSFNode
  |       |       +- vrml.external.field.EventOutSFRotation
  |       |       +- vrml.external.field.EventOutSFString
  |       |       +- vrml.external.field.EventOutSFTime
  |       |       +- vrml.external.field.EventOutSFVec2f
  |       |       +- vrml.external.field.EventOutSFVec3f
  |       |
  |       +- vrml.external.field.EventOutObserver
  |       +- vrml.external.field.FieldTypes
  |
  +- vrml.external.exception
          +- vrml.external.exception.InvalidEventInException
          +- vrml.external.exception.InvalidEventOutException
          +- vrml.external.exception.InvalidNodeException
          +- vrml.external.exception.InvalidVrmlException

A.10 Java Interface

Here is a complete list of the .java files making up the interface:

A.10.1 Package vrml.external

IBrowser.java

// Specification of the External Interface for a VRML browser.

public interface IBrowser {
  // Get the "name" and "version" of the VRML browser (browser-specific)
  public String        getName();
  public String        getVersion();

  // Get the current velocity of the bound viewpoint in meters/sec,
  // if available, or 0.0 if not
  public float         getCurrentSpeed();

  // Get the current frame rate of the browser, or 0.0 if not available
  public float         getCurrentFrameRate();

  // Get the URL for the root of the current world, or an empty string
  // if not available
  public String        getWorldURL();

  // Replace the current world with the passed array of nodes
  public void          replaceWorld(Node[] nodes)
       throws IllegalArgumentException;

  // Load the given URL with the passed parameters (as described
  // in the Anchor node)
  public void          loadURL(String[] url, String[] parameter);

  // Set the description of the current world in a browser-specific
  // manner. To clear the description, pass an empty string as argument
  public void          setDescription(String description);

  // Parse STRING into a VRML scene and return the list of root
  // nodes for the resulting scene
  public Node[]        createVrmlFromString(String vrmlSyntax)
       throws InvalidVrmlException;

  // Tells the browser to load a VRML scene from the passed URL or
  // URLs. After the scene is loaded, an event is sent to the MFNode
  // eventIn in node NODE named by the EVENT argument
  public void          createVrmlFromURL(String[] url,
                                         Node node,
                                         String event);

  // Get a DEFed node by name. Nodes given names in the root scene
  // graph must be made available to this method. DEFed nodes in inlines,
  // as well as DEFed nodes returned from createVrmlFromString/URL, may
  // or may not be made available to this method, depending on the
  // browser's implementation
  public Node          getNode(String name)
       throws InvalidNodeException;

  // Add and delete, respectively, a route between the specified eventOut
  // and eventIn of the given nodes
  public void          addRoute(Node fromNode, String fromEventOut,
                                Node toNode, String toEventIn)
       throws IllegalArgumentException;
  public void          deleteRoute(Node fromNode, String fromEventOut,
                                   Node toNode, String toEventIn)
       throws IllegalArgumentException;

  // begin and end an update cycle
  public void          beginUpdate();
  public void          endUpdate();
  // called after the scene is loaded, before the first event is processed
  public void initialize();

  // called just before the scene is unloaded
  public void shutdown();
}

Browser.java

// Specification of the External Interface for a VRML applet browser.

public class Browser implements IBrowser {
  // construct an instance of the Browser class
  // Associates this instance with the first embedded plugin in the current frame.
  public Browser(Applet pApplet);

  // construct an instance of the Browser class
  // If frameName is NULL, current frame is assumed.
  public Browser(Applet pApplet, String frameName, int index);

  // Get the "name" and "version" of the VRML browser (browser-specific)
  public String        getName();
  public String        getVersion();

  // Get the current velocity of the bound viewpoint in meters/sec,
  // if available, or 0.0 if not
  public float         getCurrentSpeed();

  // Get the current frame rate of the browser, or 0.0 if not available
  public float         getCurrentFrameRate();

  // Get the URL for the root of the current world, or an empty string
  // if not available
  public String        getWorldURL();

  // Replace the current world with the passed array of nodes
  public void          replaceWorld(Node[] nodes)
       throws IllegalArgumentException;

  // Load the given URL with the passed parameters (as described
  // in the Anchor node)
  public void          loadURL(String[] url, String[] parameter);

  // Set the description of the current world in a browser-specific
  // manner. To clear the description, pass an empty string as argument
  public void          setDescription(String description);

  // Parse STRING into a VRML scene and return the list of root
  // nodes for the resulting scene
  public Node[]        createVrmlFromString(String vrmlSyntax)
       throws InvalidVrmlException;

  // Tells the browser to load a VRML scene from the passed URL or
  // URLs. After the scene is loaded, an event is sent to the MFNode
  // eventIn in node NODE named by the EVENT argument
  public void          createVrmlFromURL(String[] url,
                                         Node node,
                                         String event);

  // Get a DEFed node by name. Nodes given names in the root scene
  // graph must be made available to this method. DEFed nodes in inlines,
  // as well as DEFed nodes returned from createVrmlFromString/URL, may
  // or may not be made available to this method, depending on the
  // browser's implementation
  public Node          getNode(String name)
       throws InvalidNodeException;

  // Add and delete, respectively, a route between the specified eventOut
  // and eventIn of the given nodes
  public void          addRoute(Node fromNode, String fromEventOut,
                                Node toNode, String toEventIn)
       throws IllegalArgumentException;
  public void          deleteRoute(Node fromNode, String fromEventOut,
                                   Node toNode, String toEventIn)
       throws IllegalArgumentException;

  // begin and end an update cycle
  public void          beginUpdate();
  public void          endUpdate();
  // called after the scene is loaded, before the first event is processed
  public void initialize();

  // called just before the scene is unloaded
  public void shutdown();

  // return an instance of the Browser class
  // This returns the first embedded plugin in the current frame.
  static public Browser getBrowser(Applet pApplet);

  // return an instance of the Browser class
  // If frameName is NULL, current frame is assumed.
  static public Browser getBrowser(Applet pApplet, String frameName, int index);
}

CBrowser.java

// Specification of the External Interface for a VRML browser component.

public class CBrowser implements IBrowser extends Component {
  // Construct an instance
  public CBrowser();

  // Get the "name" and "version" of the VRML browser (browser-specific)
  public String        getName();
  public String        getVersion();

  // Get the current velocity of the bound viewpoint in meters/sec,
  // if available, or 0.0 if not
  public float         getCurrentSpeed();

  // Get the current frame rate of the browser, or 0.0 if not available
  public float         getCurrentFrameRate();

  // Get the URL for the root of the current world, or an empty string
  // if not available
  public String        getWorldURL();

  // Replace the current world with the passed array of nodes
  public void          replaceWorld(Node[] nodes)
       throws IllegalArgumentException;

  // Load the given URL with the passed parameters (as described
  // in the Anchor node)
  public void          loadURL(String[] url, String[] parameter);

  // Set the description of the current world in a browser-specific
  // manner. To clear the description, pass an empty string as argument
  public void          setDescription(String description);

  // Parse STRING into a VRML scene and return the list of root
  // nodes for the resulting scene
  public Node[]        createVrmlFromString(String vrmlSyntax)
       throws InvalidVrmlException;

  // Tells the browser to load a VRML scene from the passed URL or
  // URLs. After the scene is loaded, an event is sent to the MFNode
  // eventIn in node NODE named by the EVENT argument
  public void          createVrmlFromURL(String[] url,
                                         Node node,
                                         String event);

  // Get a DEFed node by name. Nodes given names in the root scene
  // graph must be made available to this method. DEFed nodes in inlines,
  // as well as DEFed nodes returned from createVrmlFromString/URL, may
  // or may not be made available to this method, depending on the
  // browser's implementation
  public Node          getNode(String name)
       throws InvalidNodeException;

  // Add and delete, respectively, a route between the specified eventOut
  // and eventIn of the given nodes
  public void          addRoute(Node fromNode, String fromEventOut,
                                Node toNode, String toEventIn)
       throws IllegalArgumentException;
  public void          deleteRoute(Node fromNode, String fromEventOut,
                                   Node toNode, String toEventIn)
       throws IllegalArgumentException;

  // begin and end an update cycle
  public void          beginUpdate();
  public void          endUpdate();
  // called after the scene is loaded, before the first event is processed
  public void initialize();

  // called just before the scene is unloaded
  public void shutdown();
}

Node.java

// Specification of the Java interface to a VRML node.

package vrml.external;

import vrml.external.field.EventIn;
import vrml.external.field.EventOut;
import vrml.external.exception.InvalidEventInException;
import vrml.external.exception.InvalidEventOutException;

public class Node {
  // Get a string specifying the type of this node. May return the
  // name of a PROTO, or the class name
  public String        getType();

  // Means of getting a handle to an EventIn of this node
  public EventIn       getEventIn(String name)
       throws InvalidEventInException;

  // Means of getting a handle to an EventOut of this node
  public EventOut      getEventOut(String name)
       throws InvalidEventOutException;
}

A.10.2 Package vrml.external.field

EventIn.java

// Specification of the base interface for all eventIn types.

public class EventIn {
  // Get the type of this EventIn (specified in FieldTypes.java)
  public int           getType();
}

EventInMFColor.java

public class EventInMFColor extends EventIn {
  public void          setValue(float[][] value)
       throws IllegalArgumentException;
  public void          set1Value(int index, float[] value)
       throws IllegalArgumentException;
}

EventInMFFloat.java

public class EventInMFFloat extends EventIn {
  public void         setValue(float[] value)
       throws IllegalArgumentException;
  public void         set1Value(int index, float value)
       throws IllegalArgumentException;
}

EventInMFInt32.java

public class EventInMFInt32 extends EventIn {
  public void          setValue(int[] value)
       throws IllegalArgumentException;
  public void          set1Value(int index, int value)
       throws IllegalArgumentException;
}

EventInMFNode.java

public class EventInMFNode extends EventIn {
  public void          setValue(Node[] node)
       throws IllegalArgumentException;
  public void          set1Value(int index, Node node)
       throws IllegalArgumentException;
}

EventInMFRotation.java

public class EventInMFRotation extends EventIn {
  public void          setValue(float[][] value)
       throws IllegalArgumentException;
  public void          set1Value(int index, float[] value)
       throws IllegalArgumentException;
}

EventInMFString.java

public class EventInMFString extends EventIn {
  public void          setValue(String[] value)
       throws IllegalArgumentException;
  public void          set1Value(int index, String value)
       throws IllegalArgumentException;
}

EventInMFVec2f.java

public class EventInMFVec2f extends EventIn {
  public void          setValue(float[][] value)
       throws IllegalArgumentException;
  public void          set1Value(int index, float[] value)
       throws IllegalArgumentException;
}

EventInMFVec3f.java

public class EventInMFVec3f extends EventIn {
  public void          setValue(float[][] value)
       throws IllegalArgumentException;
  public void          set1Value(int index, float[] value)
       throws IllegalArgumentException;
}

EventInSFBool.java

public class EventInSFBool extends EventIn {
  public void          setValue(boolean value); 
}

EventInSFColor.java

public class EventInSFColor extends EventIn {
  public void          setValue(float[] value)
       throws IllegalArgumentException;
}

EventInSFFloat.java

public class EventInSFFloat extends EventIn {
  public void          setValue(float value);
}

EventInSFImage.java

public class EventInSFImage extends EventIn {
  public void          setValue(int width, int height, int numComponents,
                                byte[] pixels)
       throws IllegalArgumentException;
}

EventInSFInt32.java

public class EventInSFInt32 extends EventIn {
  public void          setValue(int value);
}

EventInSFNode.java

public class EventInSFNode extends EventIn {
  public void          setValue(Node value)
       throws IllegalArgumentException;
}

EventInSFRotation.java

public class EventInSFRotation extends EventIn {
  public void          setValue(float[] value)
       throws IllegalArgumentException;
}

EventInSFString.java

public class EventInSFString extends EventIn {
  public void          setValue(String value);
}

EventInSFTime.java

public class EventInSFTime extends EventIn {
  public void          setValue(double value);
}

EventInSFVec2f.java

public class EventInSFVec2f extends EventIn {
  public void          setValue(float[] value)
       throws IllegalArgumentException;
}

EventInSFVec3f.java

public class EventInSFVec3f extends EventIn {
  public void          setValue(float[] value)
       throws IllegalArgumentException;
}

EventOut.java

// Specification of the base interface for all eventOut types.

public class EventOut {
  // Get the type of this EventOut (specified in FieldTypes.java)
  public int           getType();

  // Mechanism for setting up an observer for this field.
  // The EventOutObserver's callback gets called when the
  // EventOut's value changes.
  public void          advise(EventOutObserver f, Object userData);

  // terminate notification on the passed EventOutObserver
  public void          unadvise(EventOutObserver f);
}

EventOutObserver.java

// Interface which all observer classes must implement.

public interface EventOutObserver {
  void callback(EventOut value, double timeStamp, Object userData);
}

EventOutMField.java

public class EventOutMField extends EventOut {
  public int           getSize();
}

EventOutMFColor.java

public class EventOutMFColor extends EventOutMField {
  public float[][]     getValue();
  public float[]       get1Value(int index);
}

EventOutMFFloat.java

public class EventOutMFFloat extends EventOutMField {
  public float[]       getValue();
  public float         get1Value(int index);
}

EventOutMFInt32.java

public class EventOutMFInt32 extends EventOutMField {
  public int[]         getValue();
  public int           get1Value(int index);
}

EventOutMFNode.java

public class EventOutMFNode extends EventOutMField {
  public Node[]        getValue();
  public Node          get1Value(int index);
}

EventOutMFRotation.java

public class EventOutMFRotation extends EventOutMField {
  public float[][]     getValue();
  public float[]       get1Value(int index);
}

EventOutMFString.java

public class EventOutMFString extends EventOutMField {
  public String[]      getValue();
  public String        get1Value(int index);
}

EventOutMFVec2f.java

public class EventOutMFVec2f extends EventOutMField {
  public float[][]     getValue();
  public float[]       get1Value(int index);
}

EventOutMFVec3f.java

public class EventOutMFVec3f extends EventOutMField {
  public float[][]     getValue();
  public float[]       get1Value(int index);
}

EventOutSFBool.java

public class EventOutSFBool extends EventOut {
  public boolean       getValue();
}

EventOutSFColor.java

public class EventOutSFColor extends EventOut {
  public float[]       getValue();
}

EventOutSFFloat.java

public class EventOutSFFloat extends EventOut {
  public float         getValue();
}

EventOutSFImage.java

public class EventOutSFImage extends EventOut {
  public int           getWidth();
  public int           getHeight();
  public int           getNumComponents();
  public byte[]        getPixels();
}

EventOutSFInt32.java

public class EventOutSFInt32 extends EventOut {
  public int           getValue();
}

EventOutSFNode.java

public class EventOutSFNode extends EventOut {
  public Node          getValue();
}

EventOutSFRotation.java

public class EventOutSFRotation extends EventOut {
  public float[]       getValue();
}

EventOutSFString.java

public class EventOutSFString extends EventOut {
  public String        getValue();
}

EventOutSFTime.java

public class EventOutSFTime extends EventOut {
  // Note that this returns a VRML "Time" - the number of seconds since
  // Jan 1, 1970 GMT, rather than a Java time which is a long, the number
  // of milliseconds since Jan 1, 1970 GMT
  public double        getValue();
}

EventOutSFVec2f.java

public class EventOutSFVec2f extends EventOut {
  public float[]       getValue();
}

EventOutSFVec3f.java

public class EventOutSFVec3f extends EventOut {
  public float[]       getValue();
}

FieldTypes.java

// Wrapper class specifying the types of all VRML eventIns/eventOuts.

public final class FieldTypes {
  public final static int UnknownType  = 0;
  public final static int SFBOOL       = 1;
  public final static int SFIMAGE      = 2;
  public final static int SFTIME       = 3;
  public final static int SFCOLOR      = 4;
  public final static int MFCOLOR      = 5;
  public final static int SFFLOAT      = 6;
  public final static int MFFLOAT      = 7;
  public final static int SFINT32      = 8;
  public final static int MFINT32      = 9;
  public final static int SFNODE       = 10;
  public final static int MFNODE       = 11;
  public final static int SFROTATION   = 12;
  public final static int MFROTATION   = 13;
  public final static int SFSTRING     = 14;
  public final static int MFSTRING     = 15;
  public final static int SFVEC2F      = 16;
  public final static int MFVEC2F      = 17;
  public final static int SFVEC3F      = 18;
  public final static int MFVEC3F      = 19;

  // This class should never need to be instantiated
  private FieldTypes() {}
}

A.10.3 Package vrml.external.exception

InvalidEventInException.java

public class InvalidEventInException extends RuntimeException
{
    /**
     * Constructs an InvalidEventInException with no detail message.
     */
    public InvalidEventInException() {
        super();
    }

    /**
     * Constructs an InvalidEventInException with the specified detail message.
     * A detail message is a String that describes this particular exception.
     * @param s the detail message
     */
    public InvalidEventInException(String s) {
        super(s);
    }
}

InvalidEventOutException.java

public class InvalidEventOutException extends RuntimeException
{
    public InvalidEventOutException() {
        super();
    }

    public InvalidEventOutException(String s) {
        super(s);
    }
}

InvalidNodeException.java

public class InvalidNodeException extends RuntimeException
{
    public InvalidNodeException() {
        super();
    }

    public InvalidNodeException(String s) {
        super(s);
    }
}

InvalidVrmlException.java

public class InvalidVrmlException extends RuntimeException
{
    public InvalidVrmlException() {
        super();
    }

    public InvalidVrmlException(String s) {
        super(s);
    }
}

B Example Programs

This section has been remove ONLY from this version at TECFA !!

See http://tecfa.unige.ch/guides/vrml/examples/eai/ instead for a bigger selection of examples.

This proposal and all examples and source code contained herein are hereby placed in the public domain. No rights are claimed or inferred by the author or Silicon Graphics, Inc.

Contact chris@marrin.com with questions or comments.