Developer's guide

1. Adding support for a new data source

BeTelGeuse can be extended to new data sources by programming a parser for one and adding it to the program. Parser classes are called Readers in BeTelGeuse. Different data types produced by the Readers are called parameters (for example, longitude, latitude). All context data communication between different components of BeTelGeuse go through the blackboard. Readers must implement the Customer interface and push new data to the Blackboard.

There are 3 ways of receiving data from a Reader inside BeTelGeuse:

  1. Subscribing to the Reader's data through the blackboard. Customer components can subscribe to data from other Customers using the blackboard. Every time when new data is available from the source, blackboard calls the newData(..) method of the Customer. The data is returned as CustomerData object.

  2. Polling the Reader, using the getParameter method, for a single parameter value. Polling returns only one sample of data from a parameter.

  3. Subscribing directly to the Reader. Subscribing objects need to implement the Observer interface. The subscribing objects' update(..) method is called when the Reader receives new data. The update(..) method has two parameters: a Vector array and the Reader that is updating the subscriber. The Vector array holds the current data from the Reader. First index in the array is a Vector that holds the data corresponding to the first parameter name. Method getParamerNames(..) returns the parameter names in a String array. Parameter names, actual data, parameter types, etc, are expected to be in ta same order in arrays.

    Instead of subscribing directly to a Reader, components should subscribe to the data through the blackboard.

Objects inside Vectors, that are passed in the update(..) and newData(..) methods, can be Strings, Integers, Floats or Doubles. However, only one type is allowed per Vector (or per parameter). Reader's and CustomerData's getParameterTypes() returns an integer array describing what type of an object is used for each parameter. A zero in the parameter type array means that the parameter in question is saved as a String object in the Vector. One correspods to an Integer object, two to a Double and three to a Float object.

Context parsers (Readers) can be divided into 3 types:

  1. Bluetooth parsers. This kind of a parser is automatically created when a Bluetooth sensor is detected that has been mapped to it. See the User Manual for how to map Bluetooth sensor devices to parsers.

  2. Blackboard producers. Other applications running on the client device can provide context data to BeTelGeuse by connecting to the blackboard. When an external component connects to the blackboard, a producer object is created to parse the data.

  3. Other parsers, which need to be manually created.

1.1 Implementing a parser for a Bluetooth sensor

Before creating a new Reader implementation, check if you have to implement the Reader interface directly or if you can extend an abstract Reader. You might only need to extend the ReaderSkeleton class. The Reader interface defines a common class for reading data from sensing devices. It does not restrict the Readers only to Bluetooth devices.

BeTelGeuse creates a Reader by calling empty constructor for it and then initializing it with the initialize method specified in the Reader interface. The interface extends Runnable, so every Reader implementation must have a run() method. BeTelGeuse creates a thread from each Reader object.

Connection to a Bluetooth sensor is provided in the initialize method. It is up to the Reader to open input and output streams to the sensor, close the connection when Reader is closed and call restoreConnection() method if the connection to the sensor is lost. ReaderFactory class offers a method for connection restoration.

Readers should always update an internal counter when they receive new data batch from the sensor. This internal counter can be inquired with getLastDataNumber(). On some Bluetooth implementations, connections can fail without being closed and throwing an exception. Should this happen, getLastDataNumber() method is the only way of determining that the Reader has disconnected from the sensor.

1.2 Implementing a parser for a client device data source

Client device applications can provide context data to BeTelGeuse by connecting to the blackboard. To add support for new client device data source, a new Customer needs to be implemented, that parses the data. This can be done by extending ProducerReaderSkeleton class, that implements both Customer and Reader interfaces. New Customer can also be implemented by extending CustomerSkeleton or directly implementingCustomer. However, this kind of implementation needs to be added dirctly to the blackboard, while a ProducerReaderSkeleton implementation can be easily added to BeTelGeuse (see next section).

1.3 Adding the parser to BeTelGeuse

After a new parser has been implemented, it needs to be added to the hiit.mapper.Properties class. After reserving an identifier number for the new parser, the number needs to be mapped to the full class name of the new parser implementation. This id number is used inside BeTelGeuse to create and manage the parser.

If the new parser is for a Bluetooth device, and you want to be able to map a sensor device to it, add also mapping from a short parser name/description to the id number. This description is used in the BeTelGeuse user interface when mapping a Bluetooth device to a parser. The Properties class also include default values for parsers' stream mode.

If the new parser is a blackboard producer, which should be created when a specific component connects to the blackboard, a mapping should be added in the serverReaderMap Hashtable. The key of the mapping is the component id used by the data source (see the blackboard protocol specification), and the value is the parser's id number.

2. Adding a plugin

It is possible to program plugins and attach them to the GUI. For example the Transmitter, which is used to send data to a server, is a plugin. The plugin's GUI needs to implement the PCPlugin or the MIDPPlugin interface, depending on the BeTelGeuse version (PC and MIDP, respectively). To add a plugin to the program, create it in the initializePlugins() method in the BeTelGeuseMIDP class or TabGUI in the PC version. The plugin should announce its GUI to BeTelGeuse using addPlugin(..) method. This GUI should be of the type Displayable in the MIDP version and of type JPanel in the PC version.

3. Porting BeTelGeuse to a new platform

The core of BeTelGeuse only uses Java features that are compatible with CLDC 1.1 and MIDP 2.0, Java 1.3, and Personal Profile. The GUI, device mapping implementations (Mapper and Recorder), some Readers and plugins are platform dependent and may need to be reimplemented when porting BeTelGeuse to another platform. In addition to Java runtime environment, BeTelGeuse requires a JSR-82 Bluetooth stack to run. Since there are minor differences in JSR-82 Bluetooth stacks, some platform - JSR-82 combinations might require reimplementation of some parts of the core. For example, on HP iPAQ hx4700 PDA with the commercial version of Aventana stack, Bluetooth connection creation works only if Avetana stack's own Connector object is used.