Package edu.berkeley.guir.ptk

Overview
How to initialize a Peripheral Display
How to write a Peripheral Display
More Code Examples of Peripheral Displays

See:
          Description

Class Summary
DisplayInfo Includes application-specific information on how to display an event.
Event Contains the data that an input source sends to applications and the metadata identifying this data.
EventPriorityQueue Utility class that queues Event objects within the PTK architecture.
Events Convenience class for a collection of Event objects.
PeripheralDisplay Represents a peripheral display application.
PTK Provides error and debug message printing functionality.
PTKStaticVariables Used by the PTK to provide support for non-distributed applications.
 

Package edu.berkeley.guir.ptk Description

Overview
How to initialize a Peripheral Display
How to write a Peripheral Display
More Code Examples of Peripheral Displays


Overview

There are four components to a peripheral display: Input, Abstractor, Notification Setter, and Output. The "Peripheral Display" or "application" is the part that ties all of these components together. The main parent class for a Peripheral Display is PeripheralDisplay.

A peripheral display can include multiple of any of the four components. Often, a peripheral display consists of multiple Outputs that display information from one or more Inputs each. Most often, an Output will display information from a single Input. In some cases, an Output will display information aggregated from multiple Inputs. Both of these cases are supported by the PTK.

A peripheral display can be either remotely distributed (i.e., the Input is running on a different machine than the Outputs) or non-distributed (i.e., all components of the peripheral display are running on the same machine). This is major distinction between displays and causes a few differences in the way you write and run your peripheral display (see How to write a Peripheral Display, below).

The most important method you will use in PeripheralDisplay is makeConnection. This method takes any permutation of InputSource (singular only, for non-distributed applications) / MetadataItems (for distributed), Outputs, Abstractors, and/or NotificationSetters. This method handles several things behind the scenes:

  1. Adds the metadata of the InputSource to the other components passed in (this ensures that these components will not abstract/set notification/display events from other InputSources -- unless you pass multiple InputSource objects into makeConnection, in which case metadata from each will be added to the components).
  2. In non-distributed applications only (those that instantiate their own InputSource object(s), as described below), it starts both the PTKServer and the InputSource running. The PTK Server handles routing of events from Inputs to PeriphalDisplays and other services.
  3. Sets up the PTK architecture to route events properly through the components.
  4. Subscribes the Outputs to the InputSource via the PTK Server, using the Input's metadata.
There is a special case when you wish to make a connection between multiple Inputs and other components (i.e., all the events created by multiple Inputs go to each of the components). For this case, you pass an array of InputSource objects (for non-distributed applications) or an array of Metadataobjects (for distributed applications) to a makeConnection method. This case is conceptually different from a regular makeConnection because makes a connection between all the Inputs and each individual component (Abstractor, Notification Setter, Output). This means these components will receive events from each of the inputs, so they need to be designed to handle this.

Although makeConnection will add an Input's metadata to an Output (or other component), sometimes an Input will create events of several different types that you wish to route to different Outputs. In this case, an Input will include in its public metadata only those metadata items that are universal to all subscribers. Then when it creates an Event, it will add additional metadata items to the Event to identify it. Each subscribing Output (or other component) should manually add another metadata item that further identifies which Event it can display. This is done when the Output is initialized in PeripheralDisplay.initialize() or in the Output's constructor.

Included with the PTK are several example peripheral display applications (below are listed all the non-distributed versions of the applications; distributed versions are also available by the same name, minus the "Non"):

How to initialize a Peripheral Display

1. Instantiating a Peripheral Display
This example shows the instantiation of a non-distributed peripheral display (AudioOrbAppNon) in a main method. Notice that an application ID is passed into the constructor: this is to identify the application to the PTK Server, which runs in both distributed and non-distributed applications to providing event routing services.


   public static final String MY_ID = "AudioOrbApp";
   public static void main() {
        AudioOrbAppNon pd = new AudioOrbAppNon(MY_ID);		
   }
Here is an example of instantiating a distributed peripheral display (AudioOrbApp) in a main method. Notice that in addition to the ID, you also pass the IP address of the machine and port number where the AudioOrbApp is running.

Also note the line setting the debug printing (beginning with "debug"). This sets the debug printing to maximal verbosity. There are three levels of debug printing verbosity: NO_DEBUG, MIN_DEBUG, MED_DEBUG, and MAX_DEBUG. Currently debug statements are printed with System.out.println by you can override this method in ptk.PTK.


   public static final String MY_ID = "AudioOrbApp";
   public static void main() {
        AudioOrbApp pd = new AudioOrbApp(MY_ID, AudioConstants.APP_IP, MY_PORT);
        debug = pd.getMAX();			
   }
   

How to write a Peripheral Display

1. To write an Input, you must first create a class that "extends PeripheralDisplay".

2. Second, you must implement the buildUI method. This method is used to initialize user interface objects, such as JPanels or hardware. In some peripheral displays this method will not be needed, so you can leave the method body empty. buildUI is called by the PeripheralDisplay constructor.

3. Third, you must implement the initialize method. This method is called by the PeripheralDisplay constructor right after buildUI returns. initialize is where all of the peripheral display components are initialized (Inputs, Outputs, Abstractors, Notification Setters), and connections are made between the components (by calling a PeripheralDisplay.makeConnection or PeripheralDisplay.makeAggregateConnection method).

The content of the initialize method will be slightly different depending on whether or not the application is distributed. First, is an example of an initialize method for a non-distributed application (AudioOrbAppNon).

   public void initialize() {
      AudioInput audio_in = new AudioInput();  // Input
      AudioOrbOutput orb_out = new AudioOrbOutput();  // Output
      // Notification
      DataRange changeblind = new DataRange(0, .100);
      DataRange makeaware = new DataRange(.101, .400);
      DataRange interrupt = new DataRange(.401, .999);
      ThresholdNotificationSetter thresh = new ThresholdNotificationSetter(
           InputConstants.VOLUME, null, changeblind, makeaware, interrupt, null);

      makeConnection(audio_in, orb_out, thresh); // connects the Input, Output, and Notification Setters
   }
In this example, the AudioInput and AudioOrbOutput are instantiated. Then the ThresholdNotificationSetter is instantiated to set notification level to change blind when the VOLUME input is low, to make aware when the VOLUME is mid-range, and to interrupt when the VOLUME is high. Finally, makeConnection is called to connect the three, causing events from audio_in to be sent through thresh on their way to orb_out. makeConnection also causes audio_in to start running.

Next is an example of an initialize method for a distributed application (AudioOrbApp).

   public void initialize() {
      MetadataItem md_in = new MetadataItem(PTKConstants.EVENT_TYPE_ID, AudioConstants.AUDIO);  // Input
      AudioOrbOutput orb_out = new AudioOrbOutput();  // Output
      // Notification
      DataRange changeblind = new DataRange(0, .100);
      DataRange makeaware = new DataRange(.101, .400);
      DataRange interrupt = new DataRange(.401, .999);
      ThresholdNotificationSetter thresh = new ThresholdNotificationSetter(InputConstants.VOLUME, null, changeblind, makeaware, interrupt, null);

      makeConnection(md_in, orb_out, thresh); // connection the Input, Output, and Notification Setters
   }
The only difference is that you do not instantiate an InputSource. It is assumed that the AudioInput is running on some remote machine. To access it, you create a MetadataItem(s) that is included in the metadata the AudioInput creates, and then you call makeConnection with the MetadataItem(s). This does not start the AudioInput running (since it is running elsewhere), but it connects the ThresholdNotificationSetter and AudioOrbOutput to the AudioInput via the PTK Server. (Note: you specify an IP address and port for an InputSource by passing it into the InputSource constructor. The InputSource registers itself with the PTK Server, which also stores the IP address and port.)

More Code Examples of Peripheral Displays

See the package comments for abstraction, input, output, and notification for many more examples of writing peripheral display code. Each of these package comments includes a "how to" on customizing components that covers many useful ways to make the PTK work for your application.