Xj3D Networking Component |
Intro
VRML, as file format and runtime system is very heavily dependent on networking
interaction. Anything but the most trivial file will reference at least one
external file, in the form of a texture, script, externproto or inline. In
order to support the more advanced extensions to VRML, such as the
Universal Media Library,
we need to support URNs as well as the more common URLs. These are not supported
in the core JDK toolkits, so this component provides all of the low-level
interfaces for dealing with fetching and processing content at the lowest level.
Background
From the start of the VRML 2.0 process, there was a concerted push by various
members to make sure the specification supported URNs in addition to the
traditional URLs. URNs allow the application to nominate content to use without
needing to know the location. This then allows the browser to locate the nearest
resource, either from disk, cache or somewhere on a network without the end
user ever needing to deal with missing files.
Motivation
The stock JDK APIs provide a facility for fetching content from URLs but not
from URNs. That meant in developing this capability for VRML, we would need to
include our own code and library. Because we may need to do this in many
different places within the scene graph, the networking aspects can be separated
out to a standalone component. In addtion, as there were already publically
available libraries to do most of the grunt work, the contents of this compenent
are designed to extend the existing library with VRML/X3D specific requirements
rather than writing our own from scratch.
Structural Overview
Because this component is designed to extend the standard interfaces provided
by a third-party library, there is not really that much architecture to the
design. It is just a series of disparate classes that extend a collection of
interfaces. These classes are described in Figure 1.
Figure 1: UML description of the static structure of classes in the
network component.
|
When describing the process of going from a URN/URL to the form that we use
internally it is easiest to think of it in terms of a pipeline with a number of
stages. Some of these stages are taken care of by the underlying library, and
other stages we can modify or supplement with our own code. A rough description
of the stages would be:
- Check the string for correctness/resolve relative references
- Decide whether to resolve as URN or URL
- Resolve a URN into a specific location or ordered set of locations
- Determine protocol used to contact server
- Locate appropriate protocol handler
- Open connection and receive header/meta data
- Locate appropriate processor for the content of the stream
- Process content of stream
In all of these steps, we really only need to override three - 3, 5 and 7. In
providing appropriate extensions at these steps, it means we can modify or
provide other capabilities providing in the following steps.
Code Layout
As you can see in Figure 1, there are three separate packages within the component,
where the component is represented in the real code by org.web3d.net
package. Within the component, the separate packages represent the functionality
at the various stages of processing a request to load a file.
URN resolution services
The first stage we get involved in the process is working within the URN
resolution mechanism. If the URN starts with the Namespace ID of
web3d, that's our cue to take control of the resolution and
attempt to find the listed resource.
The current (non-spec-compliant) form of a web3d URN is
urn:web3d:group:path
Our class tries to provide a generic handler for all of the web3d
namespace. Because everything follows the same format, if we know the group and
a path to root directory of the local installation of that functionality and/or
remote locations, it is simple to process each request. To facilitate this, our
class has a method registerPrefixLocation() for registering the
group and the root path to find them. Once set, if any URN that matches the
group keyword is asked to be resolved, we assemble the appropriate string
representing the full location (IAW the relevant RFCs and request types) and
return the values to the caller. If we don't know how to handle it, null is
returned, as per spec.
Protocol Handling
Once it has been decided where to fetch a file from, the next step that we get
involved with is the how. For most protocols like HTTP and files, we leave
that to the underlying system. However, we do have one custom protocol type
that we must handle so that we can be spec-compliant: Provision of inline
ECMAScript code in the URL field of a script with the protocol name
javascript. The implementation of the protocol handler takes the
full "URL" string of the the inline javascript, strips the leading
javascript: keyword and returns the rest of the string as a stream
to the caller.
Content handling
At the end of the chain is the content handlers. These process the raw bytes
from the stream independent of protocol used to fetch them. For our
implementation we provide an instance of the factory that can then produce
our custom content handlers as desired. From the public viewpoint, the actual
content types handled are invisible. Our basic types are the VRML content
itself (ie we're processing an inline)
Extending the Code
Adding new protocol types
Adding new URN namespaces
Adding a new file type
References