Adaptive Technology Resource Centre, University of Toronto
The previous documents described the minimum requirements for
implementing a plug-in such as drawing up a properties file in the
correct way and implementing a plug-in interface. For configuration
plug-ins, however, the Web-4-All jar also includes a library of code
that encapsulates a variety of common operations. The package
provides a set of utilities that facilitate plug-in
implementation. In addition, the Control Hub provides functions
that retrieve information defined by the plug-in's ".properties" file.
This document describes these supports available to a developer when
implementing a configuration plug-in. The Control Hub's
information retrieval functions are discussed first.
back to top
When the Web-4-All system launches, it locates plug-ins by examining
the "3rd_party" folder, looking for ".properties" files. It is
assumed that each file defines the characteristics of a plug-in.
The Control Hub loads each property file, and stores it according to
both its "appID" and "appType" properties. This enables plug-ins
to access their core and local properties by querying the Control
Hub. The following section, "Properties via the Conrol Hub",
describes the methods of the ControlHub that a plug-in can use to
recover its core properties. The section following that, "Local Properties - class
AbstractSetterLauncher", describes how the plug-in can access its
Each core property is listed below along with a corresponding
Control Hub method. The Control Hub method provides access to the
core property. Note that all properties are read only. Note
also that the first property, appID, is not retrieved from the Control
Hub, but from the
AccLipInfoPackage instance used to
"call" the plug-in.
AccLipInfoPackageand then passed to the plug-in via the
AccLipInfoPackage.getSpecificPrefs()method which returns the
<application>element from the AccLIP. One of the attributes of that element is a
nameattribute, whose value is the appID.
setAppID()method, that takes an
<application>element as input and determines the appID from it. Thus, a plug-in derived from
AccLipInfoPackage.getSpecificPrefs(), passing the returned value to
setAppID()to retrieve the application name from the preferences document, and store it within the plug-in.
public Vector get3rdPartyAppTypes (String inAppID) throws MissingResourceException
public String get3rdPartyPrefsClass (String inAppID) throws MissingResourceException;
public String get3rdPartyConfigClass (String inAppID) throws MissingResourceException;
public String get3rdPartyExecutable (String inAppID) throws MissingResourceException;
public String get3rdPartyIni (String inAppID) throws MissingResourceException;
public String get3rdPartyFullProductName (String inAppID);
As noted earlier, the configuation plug-in API is defined by
That interface has a method
the local properties are understood only by the plug-in, implementors
have complete control over how they define these properties, and how to
use them. Web-4-All does not constrain the implementation of
in any way. However, the class
defines a default way of initializing the plug-in's local properties,
and a default method for acquiring a property.
It works as follows: The Control Hub has a method allowing
plug-ins access to their local properties. This method's
public ResourceBundle get3rdPartyProperties (String inAppID) throws MissingResourceException;
The plug-in provides its appID, and the
Control Hub returns all of the properties for that application
java.util.ResourceBundle. If no such
application exists as defined by the
java.util.MissingResourceException is thrown.
by calling the Control Hub's
then storing that
ResourceBundle locally. If the
plug-in needs to do more than this, then a sub-class can override this
behaviour by first using it as is, and then adding the required extra functionality.
AbstractSetterLauncher also provides a utility method
for acquiring a given local property. A plug-in derived from
can use this to acquire a known local property. The method's
protected String getLocalProperty (String inPropName) throws MissingResourceException;
By passing the name of the property, its value is
returned, if any such property exists. If not, then a
is thrown. Note that
initLocalProps() method to have been called prior
to using the
getLocalProperty() method; that is, the
properties must have been stored internally before they are queried.
In order to distinguish between technology settings as the technology itself uses them, and
the corresponding preferences in the AccLIP, they are described in two
ways in this document. The terms "preference" and "preference
value" refer to the preference in the AccLIP document. The terms
"parameter" and "setting" refer to the way a third party technology
represents that preference. Both preferences and parameters have
two aspects: a name and a value. For example, suppose the AccLIP
has an alternative pointing device preference whose name
is "doubleClickSpeed" and whose value is "0.4".
That preference maps to the Kensington Trackball parameter named
"DBL_CLICK_SPEED" and to the value "416".
In summary, "preference" refers to some content within the AccLIP,
"parameter" or "setting" to a third-party technology setting, "name" to
the name of a preference or parameter, and "value" to its value.
What does a configuration plug-in do? Most of the work
involves translating the preferences as defined in the AccLIP schema to
a form that a specific technology can use. The complexity of the
translation ranges from simple and straightforward to complicated and
involved. An example of the simple case is where the AccLIP
encodes volume as a floating point value in the range [0.0, 1.0].
A given technology might represent volume as a signed single byte
integer in the range [-127, 128]. The translation from the AccLIP
to the technology's setting is a simple linear relationship. At
the other extreme, speech pitch is represented as a relative value,
again in the range [0.0, 1.0], in the AccLIP. To represent a
relatively low pitch, say 0.2, a speech synthesizer might be configured
to use an adult male voice. Similarly, a high-pitched voice is
achieved by using a woman's or perhaps a child's voice.
AbstractSetterLauncher has a mechanism for performing
arbitrarily complex translation via a mapping lookup table. That
is, a plug-in derived from
install any number of "value maps", a "value map chooser", and a "name
A value map is a lookup table that defines a relationship
between the AccLIP preference value and technology's setting.
Using the voice pitch example from the previous paragraph, the plug-in
could use a "voice pitch value map" that maps floating point pitch
values to various synthesizer voices.
The value map chooser is another lookup table that, given
an technology parameter name, chooses the appropriate value map.
This is most useful when the plug-in employs a number of different
value maps for each distinct preference. In this case, the lookup
is performed based on the technology parameter name: Again, using
the voice pitch example, the plug-in sees that there is a "pitch"
preference in the AccLIP. It passes the corresponding parameter
AbstractSetterLauncher's value map chooser, which
looks up the correct value map (here, the pitch map), and then
determines the parameter value from the map and the AccLIP value.
This results in the correct parameter value.
Finally, there is a third type of map that associates AccLIP
preference names with technology parameter names. This map is
termed a name map.
If you wish to use
AbstractSetterLauncher's value map
machinery, there are some restrictions. With respect to the value
maps and value map chooser, a plug-in can define them in any way it sees
fit, however, they must be derived from
The name map, however, must be a
or be derived from that class.
SettingsBundle is a
with one extra feature. It has a technology-type characteristic,
and a method to query it for that type (
The AccLIP schema defines the type returned.
Recall that a technology can satisfy more than one type, e.g., it
can be both a screen reader and a screen enhancer. Since a
technology might by multi-type, its configuration plug-in would need to
SettingsBundle instances for each
type. This is consistent with the information passed to the
plug-in in the form of a list of
instances. Each of these is defined in terms of a technology type
as well. There should be a one-to-one correspondence between the
technology types, and the
SettingsBundle object contains a lookup table whose
keys are AccLIP preferences names. The value associated with each
key is an instance of a
ParameterState object is an object that maintains an
association between a parameter name, whether that parameter has been
"written", whether it is required that it be written, and its default
value. For the moment, consider only the parameter name: the
performs the function of mapping the AccLIP preference name to a
specific technology's parameter name. That parameter name is then
used in conjunction with the value map chooser to locate the
appropriate value map.
In a nutshell, here is how a plug-in uses
value map system. First, create a
each of the technology's settings, that maps an AccLIP preference value
to a technology's parameter value. Each constitutes a value
Second, create another
ResourceBundle whose keys are
the technology parameter names. Each name maps to one of the value maps
created in step one. This is the value map chooser.
Third, create a
SettingsBundle whose keys are the names
of AccLIP preferences, and whose values are
objects that each contains a parameter name. These parameter names
are inputs to the value map chooser created at step two. Create
SettingsBundle for each type of technology that
the plug-in handles. An algorithm for mapping from an AccLIP
preference to a technology setting is as follows:
SettingsBundleto retrieve a
ParameterState, and, from it, the corresponding parameter name.
With the proper initialization,
performs steps one through five "for free". The initialization is
accomplished via the methods:
protected void init();and
protected void setUpParameters (SettingsBundle inParams, ResourceBundle inValueMapChooser);
The former is abstract, and must be
implemented in the derived class. It is advised that, at least,
the derived class call the
setUpParameters() method from
init() method. The first argument is an array of
objects, where each member of the array is distinct in terms of a type
of technology. The second argument is the value map chooser, i.e.
the lookup table that maps parameter names to value maps.
The sequence outlined above is accomplished by a number of
methods. Steps two and three are handled by the
methods. Steps four and five by the
method. Steps two through five are effectively accomplished by
by essentially calling
in succession. All of these methods are are fully documented in
the plug-in API documentation.
Value maps are useful for complex relationships between AccLIP
preference values and an application's parameter values.
Frequently, there is a simpler mathematical equation that will transform
an preference value to the correct parameter setting.
provides one of these; specifically, a method that performs a linear
transform. Its signature is:
public float linearCalcTechVal (String inAccLipVal, float inSlope, float inIntercept);
caller passes in the AccLIP value (x),
a slope (m), and intercept (b). The method returns the value (y) transformed according to the
linear equation y = mx + b.
Once the translation is complete, the technology's setting must be
realized. In our experience, there are two ways to accomplish
this. First, some technologies take their settings from an
initialization file; for example, on Windows, a file with the extension
".ini". This is a text file consisting of parameter names and
values. When the technology starts up, it configures itself
according to the contents of this ".ini" file.
Secondly, some technologies use "registry" values as their parameter
settings. In that case, it is useful to translate the AccLIP
preferences into an array of in-memory parameter values, which are then
transferred to the appropriate place in the registry.
AbstractSetterLauncher provides methods for both writing
to an initialization file, and installing settings into a
registry. The former is accomplished via the
methods, and the
writeSetting() methods. The latter
by the methods
If your plug-in requires an initialization file, use one of the
methods to create the initialization file. The difference in the methods
is that they provide different ways of defining the path to the
intialization file. In one case, the path is relative to the
directory from which Web-4-All was launched. In a second case, it
is relative the the Web-4-All's plug-in folder. Finally, a full
path to the file can be specified. In all cases,
and records the file, and returns it as a
writeSetting() methods use this
to output the parameter name and its value. These ".ini" related
methods are are fully documented in the plug-in API documentation.
An alternative technique to writing parameters to a file is one that uses an in-memory
argument array, and is based on the idea that a command line utility
will be used to transfer the settings to something similar to a
registry. The command line arguments are represented as a
array. The array can either be created by using
or passed in if
setArgsArray() is used.
Note: The use of a command line utility to write settings to a
"registry" was employed to avoid specifically committing to the Windows registry. The
AbstractSetterLauncher class could have
been implemented such that it transferred relevant parameter settings
directly to the registry, but that would not have been platform
neutral. By deferring the writing of the "registry" to a command
line utility, the transfer utility can move the settings to wherever it is
It is assumed that the argument array is positional, e.g., that the
third argument represents, say, the volume setting. As such, there
must also exist a technique that, based on the parameter, places the
setting in the correct position of the array. Plug-ins that
use the argument array feature of
must also provide an index map via the
method. The argument index map is a
whose keys are parameter names, and whose value is the index in the
argument array for that parameter. The place to initialize the
arguments index map is in the plug-in's implementation of
addArgToArray() is called, it will use the parameter
name and argument index map to place the parameter value in the proper
position of the argument array.
When all preferences have been processed, the completed argument
array can be retrieved via the
At that point, it is up to the plug-in to do what is necessary with the
argument list. That is,
not define any method to transfer the settings to the "registry"; it
only provides a means to collect the settings. Like the
initialization file writing methods, these argument array methods are
fully described in the plug-in API documentation.
Finally, the reader might wonder why
has a set of methods both for writing settings to an initialization
file, and another set for creating an positional parameter list.
Why not factor this functionality out between two implementations of
SetterLauncher? The answer is that some
plug-ins require both techniques for "writing" settings. That is,
some plug-ins will write certain settings to an initialization file, and
other settings to a registry. Placing the writing utilities all
in a single class allows a derived class to write exclusively to an
initialization file, or exclusively to a registry, or to both.
doSettings() is one method that
does not implement. However,
does implement a number of other methods out of which an implementation
doSettings() can be built.
doSettings() amounts to examining the AccLIP preferences passed to it, translating them, and writing the
translations. The AccLIP contains a set of generic preferences,
and, potentially, a set of technology-specific preferences.
defines two loop methods, one for handling the generic settings, and
another for the specific settings.
The signature of the generic loop method is:
protected void loopThruGenerics (String inTechType, Element inGenericContainer);
Note that the first argument defines the type of technology (e.g.,
onscreen keyboard). For each generic preference in the
does the following:
Note the emphasis on "Write" in step four. At this
loopThruGenerics() dispatches to the method
which is another abstract method of
Its signature is:
protected void doWriteSetting (String inParameter, String inValue);
inParameter is a
parameter name, and
inValue is its value.
can be implemented by calling one of the
methods described above, or the
addArgToArray() method, or
both as required. This is why
abstract -- how a specific plug-in actually outputs the setting cannot
be known by
AbstractSetterLauncher. It is up to the
implementor of the plug-in to determine how the setting is "written";
and, they can make use of the two utility methods that "write" the
The corresponding loop for specific settings,
is identical in control flow to
It is defined as a separate method, however, since it is likely that an
implementation of a plug-in will want to keep
as is, while completely replacing the technique for handling specific
does not define the
doLaunch() method of
SetterLauncher. However, there are associated methods that
sub-classes should use to track the result of a
It is assumed that plug-ins will make use of the
object and its
exec() method to actually launch the third
Runtime.exec() returns an object of
defines the utilities
setProcess() and a
order to make it easy for a sub-class to keep track of that
if required. In addition to tracking the
launched, they are useful for the
AbstractSetterLauncher does provide a basic
implementation of the
kill() method. This amounts to
shutting down the
Process created by
This simple shutdown of the process is not suffiicent in most
cases. Sub-classes should override
kill() to first
reset the third party technology to some default state before killing
the process. As such, an override of
kill() should be
written to first reset the technology's configuration, and then call
kill() to actually shut it down.
This document has described various utility methods of the Control
Hub and the
AbstractSetterLauncher class that are useful
for implementing a configuration plug-in. It described how to
retrieve global properties of the plug-in from the Control Hub, and how
to use the basic implementation in
to acquire its local properites. It also described utilities that
provides for, namely:
Copyright © 2003-2006 Adaptive Technology Resource Centre,
University of Toronto.
All rights reserved.
Last modified: Mar 28, 2006. Joseph Scheuhammer.