Wiki

Clone wiki

ieeg / DevPlatform

Introduction

Initially IEEG targeted time series data, but today we envision it as an extensible platform more like Eclipse. This document sketches how to extend the platform.

This is broken down as follows.

Details

IEEG Platform Architecture

The IEEG platform is primarily based on a model/view/presenter architecture, where components communicate with one another via events on an event bus, and communicate with the server via asynchronous remote procedure calls (a response handler is called once the RPC returns its result).

The server-side of IEEG is multithreaded and runs as a servlet. Memory allocation should be kept relatively small (and certainly bounded) to prevent crashes due to multiple concurrent requests. The client-side is typically written in Java but is translated to JavaScript via GWT. Note that JavaScript is single-threaded, so you should not do computation in long-running loops -- instead break your task into smaller components and trigger events to cause the next stage to invoke.

A rough map of the code is given in ViewerStructure. In general, the main aspects are as follows. The main client-side code is in: * WebConsole: the GWT EntryPoint * Login: constructs the base objects on login * ClientFactory: the main access point for most of the data access objects

Client-to-server code is in the following interfaces: * ClientFactory.getPortal() / EEGDisplay: the main point of access for portal login, registration, snapshot add/remove, etc. * ClientFactory.getAsync() / ServerAccess: a caching point of entry to the SnapshotServices. * ClientFactory.getSearch() / SearchServices: snapshot search capabilities.

Server code starts in the following classes: * EEGServiceImpl: server-side functions for the main portal * SnapshotServiceImpl: server-side functions for snapshot access / manipulation * SearchServiceImpl: server-side functions for search

A separate server for the UploadPipeline is designed to be called on data upload. This is entirely separate from the main portal.

Extensibility

The portal is designed to be a "container" over a set of Web plugins and modules. There are three main areas of extension:

  • (Server-side): processing of uploads (includes filtering, transcoding, and more). See UploadPipeline.
  • (Server-side): filtering of time series data during data-fetch. See below.
  • (Client+server-side): new kinds of metadata, e.g., used in returning and browsing search results. See below and ExtensibleMetadata.
  • (Client+server-side): new kinds of permissions, e.g., for plugins. See below and ExtensiblePermissions.
  • (Client-side): new plugins in the main panel. See below.

Server-side extensibility makes use of a .properties file to register new class names, and employs Java's Reflections API and a series of interfaces to register new classes with the server. All extensible modules must have unique names represented by strings.

Client- and client-server-side extensibility must deal with the limitations of GWT, namely that Java Reflections are not available on the client-side. Hence on the client side, we must actually modify source code (largely to Factories) in order to add new plugin classes.

Metadata development

The metadata hierarchy is described in more detail in ExtensibleMetadata. Briefly: * GeneralMetadata -- core class for metadata, with basic interface including getId(), getLabel() * SerializableMetadata -- can be serialized to a GWT client. Must be @GwtCompatible(serializable=true). * PresentableMetadata -- implements some additional key methods for further detail (like getPermissions, getOwner, getCategory) but also a MetadataPresenter. The MetadataPresenter is used to render an image and a set of columns in the tree viewer and beyond.

BASIC_CATEGORIES specifies the core metadata categories using an enumerated type. Each enumerated value is by default turned into a string. One can actually introduce further categories as strings.

Permissions development

If you are adding special permissions with a new kind of data or metadata, you may want to refer to ExtensiblePermissions.

Filter development

Filters are server-side only, meaning that our implementation can fully leverage Reflections. Thus developing a new filter implementation requires only a few subtasks:

  • Subclass edu.upenn.cis.eeg.filters.TimeSeriesFilter and implement an empty constructor, the init() and apply() methods, the getFilterType() method with a unique name, and the create() method.
  • Add your class to the comma-separated list of values of filters in filters.properties.
  • The result will be that this class gets registered both with TimeSeriesFilterFactory and with SignalProcessingFactory.

Immediately upon registration with the factories, the client will allow the user to select your filter.

Plugin panel development

Developing a plugin panel for the IEEG portal is fairly straightforward. Create a new model class to represent the programmatic state corresponding to your new plugin.

See edu.upenn.cis.db.mefview.client.plugins.sample for a template. In more detail:

  • Create a new view class, subclassed from AstroTab, using GWT controls to visualize the key aspects of the model. The view should:
    • Implement the presenter.Display interface mentioned below.
    • Have a property called NAME with a unique string name describing the view. This same name should be returned by the getType() method.
    • Have an empty constructor that simply registers the object with PanelFactory.register() under the NAME property.
    • Implement the method called create, which constructs a new object and returns it.
  • Create a new presenter class, extending BasicPresenter, that controls how the model (and any incoming events from the rest of the portal) are visualized in the view. This class should:

    • Have an interface called Display (subclassing BasicPresenter.Display) with the various methods of the view that are to be called by the presenter.
    • Implement getDisplay() to return the specialised Display.
    • Have a string property NAME, matching the view's NAME.
    • Have a string-set property TYPES, containing string names from BuiltinDataTypes
  • Implement a default constructor and a parameterized constructor, which call super()'s constructor with the client factory (null if unavailable); the NAME; the TYPES.

  • Have an static constructor which calls PresenterFactory.register() to register the object under the NAME property.
  • Implement the AstroPanel method getIcon() to return an ImageResource representing the icon for your panel (or null for no icon).
  • Implement the AstroPanel method getTitle() to return a title string to be used in the panel tab, as well as the context menu and the toolbar.
  • Implement the method bind() to associate an instance of the viewer with the presenter. Typically binding will register event listeners and so on.
  • It's expected that your presenter will also instantiate the model for your plugin.

For now, registration is not fully automatic due to limitations in GWT (there is no reflections interface). Hence you will need to modify the PluginRegistry class (registerPanels) to call new myclass() where myclass is your view for PanelFactory, and your presenter for PresenterFactory. This will force the classes to register themselves with the PanelFactory. (Java does not call static constructors until a class is explicitly touched by the ClassLoader.)

Making the panel activate via the toolbar

Next you should associate the panel/presenter with DynamicToolbar action, such that it is triggerable in the MetadataBrowser. To do this, create an IPluginAction that contains an execute method triggering creation of your particular presenter/panel. (You will also need to define a create() method along the lines of the above.)

Next you can use add an entry to PluginRegistry.bindActionsToDataTypes() that calls the ActionMapper to associate the action with a particular metadata type.

Finally, you can register handlers for the top-line buttons (SEARCH, SHARE, SAVE, HELP) and the menu bar by calling !clientFactory.getHeaderBar().addLocalEntry() or !clientFactory.getHeaderBar().addLocalMenuOptions().

Interacting with the rest of the IEEG portal platform

The ClientFactory/ClientFactoryImpl is the overall application controller. It lets you interact with the rest of the platform. * To interact with other panels, or to initiate most behaviors, you should call clientFactory.fireEvent() to trigger an event (usually a request or a notification). You can call addHandler to be notified about an event firing. (Please make sure you unregisterHandler(this) unbind().) * To trigger a new panel, or to switch to a panel, fire the event OpenDisplayPanelEvent. One of the parameters is the panel type -- this is the value of {MyDesiredPanel}.NAME. * To interact asynchronously with the server, you can get !EEGService via the clientFactory.getPortal() method. * To get user information, you can call clientFactory.getUserInfo(). * To get detailed info about the portal setup, you can call clientFactory.getServerConfiguration(). * To find a snapshot you can call clientFactory.getSearch().getSnapshotsFor(). * To look up the metadata (SearchResult) associated with a snapshot ID, you can call clientFactory.getSnapshot().getSearchResultForSnapshot().

To add new capabilities, you may want to extend EEGService (client-side stub) and its corresponding EEGServiceImpl (server-side implementation). If you use the GWT Eclipse plugin, these two should be kept in sync as you change the interfaces. Note that if the capability you are adding is likely to be of use in several aspects of the platform, you should use events to trigger the request and to notify about the response. This allows such updates to be globally shared.

Updated