[ Previous] [Next] [Cookbook Index]

The architecture of Sieve: An inner view

An application interacts with Sieve by communicating with the Workbench (class sieve.workbench.Workbench). In Swing terms, the Workbench is a JLayeredPane, a component that is able to contain other components in a certain z order. Being the Workbench a component, it can be inserted in an interface. But it does more than that; the Workbench talks with the collaboration support classes to replicate any event notification received by any of the Workbenchs of the other applications in the current session. There are two type of events of interest to the Workbench: interface events, like mouse movements, and component property changes, like a change in the background color of some component or in the range of values allowed in it.

Component Creation and the Workbench

The Workbench by itself does not contain the components that are shared; instead every component instance is wrapped by a WorkbenchComponent (interface sieve.workbench.WorkbenchComponent), a class that works as an adapter between the Workbench and the bean. This design allow a component writer to ignore how sieve achieves collaboration and at the same time enable the component to be shared.

Wrapping components with subclasses of WorkbenchComponent before being added to the Workbench is a task of what in Sieve’s parlance is called a Tool (interface sieve.workbench.Tool). For every component class that can be inserted in the Workbench, there is a Tool instance that wraps the component with a specific WorkbenchComponent.

How to Sieve knows what kind of Tool to use for a certain component class? Record that association is the task of the Tool Factory (class sieve.workbench.ToolFactory). Tools can be pre-registered in the Tool Factory to work with specific classes by calling ToolFactory.registerTool(Class componentClass, Class toolClass), where the first argument is the component and the second is the tool in charge of that component. If there is no preregistered tool class for a certain component class , then the Tool Factory looks for a class following a name convention: the tool name must be the name of the component with the word Tool appended. For example if the component class is called MyComponent then the tool name must be MyComponentTool.

Once you have the right tool, you can get a WorkbenchComponent instance by calling Tool.getWorkbenchComponent().

In short,

Editing Component Properties

Following the policy of separating visual appearance from behavior, Sieve does not define a method to edit properties, although it provides support for it. The workbench accepts the registration of a WorkbenchComponentEditor by calling

    Workbench.setWorkbenchComponentEditor(WorkbenchComponentEditor editor).

The Workbench will notify this object will be every time a component is selected, by calling

    WorkbenchComponentEditor.setTarget(WorkbenchComponent compo)

In this way a Property editor may query the bean about its properties and present an interface for property edition.

Links

Links (interface sieve.workbench.Link) work as adapters between two instances: a source and a destination. Links are not necessarily listeners; the way a link notifies a destination about an event in the source is implementation-dependent. Note that this communication may be not simple, since both protocols can be different. All link classes must implement the sieve.workbench.Link interface. There is nothing in the link class that forces a determinate link policy; the way a link makes the events of the source available to the destination is application-dependent.

Link Creation

Link creation starts when the Workbench receives a requestLinkStart() request with a Workbench component as argument. This WorkbenchComponent will be the link source. Link creation is started typically by a WorkbenchComponent (although it is not mandatory). The Workbench keeps track of what link is being created (only tracks one link at a time). Any further attempt to select a component in the Workbench will be interpreted by the latter as the designation of a destination component for the active link, calling the setDestComponent() method for the link. After Link.setDestComponent() returns, the link is called to be realized.

But wait, how does anybody know what kind of Link to create when the link is started, if the destination is still unknown?

Good Point. One possible solution is the one implemented in the Sieve inetBench. What is created when the link starts is not the real link, but an instance of LinkProxy. A link proxy acts like a link, but delays the decision of creating a real link until the destination component is known. Since that happens when Link.SetDestComponent is called, the link selection policy (that is, how to decide which link to instantiate) is delayed in LinkProxy up to that point.

Since finding a link can be a time-consuming task, the Link protocol was enhanced in Sieve 2 with the following methods:
public void setDestComponentNotify(WorkbenchComponent c, LinkListener anObject) throws LinkException

setDestComponentNotify() performs like setDestComponent(), but with the following differences:

  • anObject.linkRealized() is called when the link realization has finished, either succesfully or not.
  • SetDestComponentNotify() must be non-blocking. It must return as fast as possible, and any time-consuming operation must be performed as a separate thread.
  • Parameter anObject must implement the LinkListener interface.

The purpose of this method is to allow a message-driven notification when link realization is a time-consuming process, in order to allow non-blocking

public Class getSourceClass()

  • In order to allow pre-registration of links, a link must identify what kind of component it expects as a source.

public Class getDestClass()

  • In order to allow pre-registration of links, a link must identify what kind of component it expects as a destination.

Link Selection Policy

Sieve by itself does not implement a link selection policy; it is up to the object that notifies the Workbench of link creation to choose the proper link class and instantiate it. To help in this task there exists the LinkFactory class (class sieve.workbench.LinkFactory). LinkFactory implements one possible link policy. This policy is as follows:

Links can be pre-registered calling LinkFactory.registerLink(Class linkClass). Pre-registered link are cached and found very quickly.

There are 3 ways in LinkFactory to request a link:

  1. Using getLocalLinkType()
    • This method only search for a compatible link within the pre-registered list of links.

  2. Using getRemoteLinkType()
    • This method ignores pre-registered links, and tries to find and load a class that is a candidate link for the source and destination components. In order to find the class this method assumes a naming convention is followed: all link class names end with the Link word. For example, a link class from component class X to component class Y is assumed to be named XYLink.

  3. Using getLinkType()

All flavor of getLinkType() methods search for links in the same order:

sourceClasses = List of all superclasses and interfaces of the class of source component.
destClasses = List of all superclasses and interfaces of the class of destination component.
N = number of candidate links desired
L = number of candidate links found
for each class src in sourceClasses while N ¹ L
  for each class dest in destClasses while N ¹ L
    check for a Link from src to dest.
    If (link found)
      add it to the list of candidate links
    L = L+1
    end if
  end for
end for

Look & Feel

Sieve does not define a look (appearance) and feel (interaction method). The Workbench delegate mouse events to different objects in different moments to let them implement the proper look and feel for the application.


[ Previous] [Next] [Cookbook Index]