[Top] [Prev] [Next] [Bottom]


Developing Channels

A channel is the basic functional unit in IntelliPortal. Channels segment IntelliPortal functionality into discrete components like an investment channel or a statement viewer. Virtually all client application software is comprised of channels. They provide an easy, efficient mechanism for distributing both applications and data to the client workstation. One channel can call another channel and they can work together.

A channel is basically a directory associated with a channel name. This directory is populated with files that perform some function. This can be as simple as a collection of files to be displayed on the screen (e.g. a series of images or HTML pages) or it can be a complete Java application. This section explains how to create and organize these files to create a channel that runs in the IntelliPortal environment. See the Java source code for the Sample Channels on the IntelliPortal CD-ROM for examples of code that you can cut and paste, and for insights into how channels are created.

___________________________________

Topics in this section

Getting Started

There are Java channels and HTML channels. Unless specifically noted, you can assume that the discussion refers to Java channels. Channels can also be visible or invisible. Invisible channels are usually helper, or administrative, channels that are started automatically or by other channels. Visible channels can appear to the user as separate applications or products, or what appears as an individual application might actually consist of several channels bundled together.

To develop a channel, you create the overall structure as described on the following pages. Then configure the channel with the IntelliPortal Server Administrator tool. This mostly involves telling the IntelliPortal server about the channel and identifying its links to any external data sources it might need. When published (using the Publisher tool), the channel files are copied to the transmitter and the channel properties file is created.

When a client subscribes to a channel the content is transmitted and installed. The subscription can be mandatory or discretionary, visible or invisible. Periodically, the channel is updated; new channel files are published to the transmitter, and only those files that have changed are transmitted to the client application. For example, new channel files might be dynamically created based on data received from outside data sources, or might originate with the channel developer.

To develop a simple Java channel
  1. Extend MecaBaseChannel overriding any methods you desire.
  2. Add your own functionality.
  3. Use the services in the IMecaApplicationContext to interact with the client application as desired.
  4. Optionally, publish TunerEvents to make information available to other channels, and subscribe to TunerEvents to receive information from other channels.

Developing Java Channels

Channel development consists of developing, configuring, and publishing (and periodically updating) channels. For the most part, creating a Java channel is much like creating any other type of Java application. What makes it a "channel" is how it recognizes and utilizes its relationship with other IntelliPortal components and other channels. This relationship has two main parts. (1) IMecaApplication is the actual interface that enables a channel to play in the IntelliPortal environment. (2) ITunerEventService is an internal messaging system that lets channels communicate with the client application and with other channels.

IMecaApplicationContext is an interface that gets passed to the channel when it is started by the client application. It makes information about its operating environment available to the channel, including other channels that may be running, and services that are available to the channel.

How a Java Channel Works

IntelliPortal has a client shell that is in charge of starting and stopping channels. For this to work properly, the Java channel needs to be organized in a particular way. In the base directory of each channel is a file called properties.txt which tells the client shell about your channel. In it, you specify the channel's main class using the Publisher tool. The main class contains a start() method, which is what the client shell calls to start the channel. (Channels do not use a main( String args[] ) method.) When a channel starts,

  1. The request to start a channel is received by the client shell which instantiates the channel. (There is only one copy of a channel ever running. Multiple requests to start a running channel will not result in additional instances of the channel being created. If the channel happens to be a visible channel, these requests will result in the channel displaying in the foreground of the client shell.)
  2. The channel receives the IMecaApplicationContext object via a call to its setContext(IMecaApplicationContext) method.
  3. The channel's start() method is called and the channel can begin executing whatever it is you want it to do.
  4. When a request is issued to stop the channel, the client shell calls the channel's stop() method. The channel itself can request that it be stopped by calling context.stop().

You generally begin developing a channel by extending an abstract class called MecaBaseChannel. This class implements the necessary interfaces so that your application will have the functionality described above. The MecaBaseChannel class is provided as a base class and will likely meet the needs of developers building lightweight visible channels. Channels are not required to extend from this base class, rather it is provided as a convenience.

Ways to Create Java Channels

Each channel has a main class that is called using the Publisher tool. There are two basic requirements for this class.

  1. It must be a class that implements IMecaApplication. This lets it play inside the tuner as a IntelliPortal channel.
  2. It may need to be a class that is a TunerEventListener. This lets it listen for and respond to outside events (either within the tuner or in other channels).

MecaBaseChannel fulfills both of these requirements. It is a default base class that implements IMecaApplication. As such, it provides default behavior for the methods in IMecaApplication and is a complete channel in itself that you can modify with your own functionality. Depending on your requirements, you can use MecaBaseChannel in three ways. How you use or don't use this base channel class is determined by your own functional requirements.

Regardless of how you develop your channel, the following discussion should provide a better understanding of the various components and how they interrelate.

You can extend from whatever class you want provided that the main class of the channel implements the IMecaApplication interface. (The main class is identified by the main property in the channel's properties.txt file.)

Java Channel Components

An IntelliPortal Java channel has interrelated components that work together rather than separately. For example, every channel must implement IMecaApplication to act as a channel in the IntelliPortal environment. It must also be registered as a TunerEventListener to be able to communicate with other channels. The following basic components and the fundamental relationships among them are explained on the following pages.

IMecaApplication

IMecaApplication is an interface to the tuner. It is the application interface that allows applications (i.e. channels) to be aware of the context in which they are executing. A channel must implement this interface to run in the IntelliPortal client. There are four methods in IMecaApplication that are described in detail on the following pages.

setContext( IMecaApplicationContext context )

The first method called after the default constructor is always setContext( IMecaApplicationContext ). It is called immediately following the construction of the main class of the channel. IMecaApplicationContext is an interface to the tuner that lets channels access services that are available to the client. To use the services, the IMecaApplicationContext must be accessible to any objects that you create.

If you are implementing IMecaApplication, you should save the reference to IMecaApplicationContext as a data member in your class so that you can use it while your channel is executing. You need to save the reference because this class provides the channel with its only means of communicating with the tuner and its services. MecaBaseChannel does this and saves the reference in a protected variable. It also provides the helper method getContext() that a channel can call to retrieve the application context.

MecaBaseChannel also uses the context to get and save references to two commonly used services: the ILayoutService and ITunerEventService.These services are stored in protected variables as a convenience to developers since these two services are present in every implementation of IntelliPortal and will most likely be used frequently. It is unlikely that you will ever need to override this method.

It is important to note that at this point in the channel's life, it is not known whether or not the channel is going to be running. The tuner may have instantiated the channel because an update is available and the channel has been set up to receive notification (see Using Triggers and History). In this scenario, the channel's constructor would get called, then its setContext method, followed by the delivery of an event indicating that an update is available. Therefore, you should not assume at this point that the channel will get started. With this in mind, it is a good idea to defer the construction of any GUI components (or other components related to the normal running of the channel) to the start() method.

start()

When a channel is being started (or restarted after an update), the start() method is called after the channel is instantiated and the IMecaApplicationContext is set. This is the point at which you can code any unique initialization or startup tasks needed by a channel. MecaBaseChannel provides a "bootstrap" routine that does the following:

  1. Uses the ILayoutService to put the channel into the panel identified by the location property in the channel's properties.txt file.
  2. Loads the trigger list.
  3. Subscribes to three TunerEvents:
  4. Pulls the default CHANNEL_START trigger.

Most likely, you will want to override this method so that you can at least introduce your own functionality. The easiest way to chain your own routines to the default start() functionality is to call super.start()at the beginning of your own implementation, and then insert your own routines. Keep in mind that calling super.start() will add the MecaBaseChannel panel to the tuner using the ILayoutService. Until you call this method or add yourself directly to the tuner using the ILayoutService, your panel will not be parented. Depending on how you want your channel's functionality activated, you might:

stop()

This method is the last method to run before the channel stops and goes away. Override this to kill any threads and dispose of any graphics, windows, or other resources you have opened. The default implementation of MecaBaseChannel unsubscribes the channel from the ITunerEventService, pulls the CHANNEL_STOP trigger, and saves the trigger table if changes have been made. See Using the Trigger Editor to learn more about the CHANNEL_STOP trigger.

handleEvent( Event e )

The handleEvent( Event e ) method is used to handle a number of channel events that are typically used in connection with channel updates. During an update, the channel is passed an event object and you can query this object for a certain type of event.

Use these events (in conjunction with the entries in the properties.txt file) to control channel behavior at various points in the update process. See Updating Channels for more information on how handleEvent( Event e ) is used. Note that a channel may be started to handle an update without its start() method being called. If an update occurs when a channel is not running, the tuner starts the channel by calling handleEvent() and DATA_UPDATE_EVENT.

Channel events are different than TunerEvents. Use handleEvent( Event e ) to process channel events, particularly updates; use tunerMessage( TunerEvent e ) to process TunerEvents.

IMecaApplicationContext

This interface lets channels access services provided by the client application. It encapsulates much standard channel communication and provides additional IntelliPortal-specific methods. It provides access to information about the environment and other channels, and provides access to the client services. It also provides additional IntelliPortal-specific features such as a shared directory across multiple channels. It is the single point of contact among the client, the tuner, and the channel. IMecaApplicationContext has numerous methods, including the following, most of which are self-explanatory.

You always request a service using the method getService(String). The interface com.mecasw.eb.services.IServiceConstants has static string definitions for all available IntelliPortal services. To request a service, use the appropriate string as the argument for the service. See the examples that follow.

Service Constant Interface String
ALERT_SERVICE com.mecasw.eb.services.IAlertService
BUSY_SERVICE com.mecasw.eb.services.IBBusyService
BOOKMARK_SERVICE com.mecasw.eb.services.IBookmmarkService
CHANNEL_SERVICE com.mecasw.eb.services.IChannelSelectorService
DATABASE_SERVICE com.mecasw.eb.services.IDatabaseService
EXTERNAL_BROWSER_SERVICE com.mecasw.eb.servicesIExternalBrowserService
GENERIC_SERVICE com.mecasw.eb.services.IGenericService
HISTORY_SERVICE com.mecasw.eb.services.IHistoryService
KEY_MANAGER_SERVICE com.mecasw.eb.services.IKeyManagerService
LAYOUT_SERVICE com.mecasw.eb.services.ILayoutService
LOG_SERVICE com.mecasw.intf.ILogService
REPORT_SERVICE com.mecasw.eb.services.IReportService
REQUEST_BUFFER_SERVICE com.mecasw.eb.services.IRequestBufferService
TICKER_SERVICE com.mecasw.eb.services.ITickerService
TUNER_EVENT_SERVICE com.mecasw.eb.services.ITunerEventService
USAGE_TRACKING_SERVICE com.mecasw.eb.services.IUsageTrackingService
VERSION_SERVICE com.mecasw.eb.services.IVersionRegistryService

Example 1

import com.mecasw.eb.services.IServiceConstants;
public class Foo extends MecaBaseChannel
{
    private ITunerEventService ts;
    public void start ()
    {
        tx = (ITunerEventService)m_context.getService 
(IServiceConstants.TUNER_EVENT_SERVICE );
    }
}

Example 2

import com.mecasw.eb.services.IServiceConstants;
public class Foo extends MecaBaseChannel implements IServiceConstants
{
    private ITunerEventService ts;
    public void start ()
    {
        tx = (ITunerEventService)m_context.getService (TUNER_EVENT_SERVICE );
    }
}

Client Disk Storage

All IntelliPortal channels (Java and HTML) have access to three directories (Base, Data, and Shared) for disk space on the client workstation. All three directories are available through the IMecaApplicationContext object passed to channels.

Base Directory - Each channel has read access to its Base directory. Data received as part of the channel update process or in response to a client request for data (e.g. stock quotes, statement information, etc.) is stored in the channel's base directory when installed.

Data Directory - Each channel has read/write access to its own Data directory that is defined by the client application. This directory is the same each time the channel is instantiated so you can use it to store data that will be needed across channel launches. This directory is for internal channel use only.

Shared Directory - Each channel also has read/write access to a Shared directory which is used for storing data that is available to all channels. You can get this directory in two ways

TunerEvent Messaging

TunerEvent messaging is also function of IMecaApplicationContext. The TunerEvent messaging architecture lets the client application communicate with channels. The architecture is centered around TunerEvents objects that encapsulate messages and associated data, and the ITunerEventService that receives TunerEvents and routes them to the appropriate objects.

TunerEvent objects have two responsibilities. (1) They publish all event notifications (i.e. TunerEvents) to the ITunerEventService rather than to individual objects. (2) They subscribe with the ITunerEventService to TunerEvents which are of interest to them. With this design, objects can receive only those events they wish to receive and that are relevant to their purpose. Plus, they can receive all such events regardless of where they originate.

For data security, only instances of system classes can be shared between channels. Instances of classes loaded from a channel cannot be shared with other channels.

IntelliPortal has an interface called TunerEventConstants that includes a number of predefined TunerEvent constants that correspond to the most common TunerEvents. Most of these are used by the tuner to tell channels to perform specific actions. They include channel start/stop, channel subscribe/unsubscribe, and navigation requests. Other TunerEvents encapsulate user actions, such as keystrokes and mouse clicks, and status messages from channels.

As an example, consider a history channel which maintains a running list of all of the channels that a user has viewed during a session. IntelliPortal includes a TunerEventConstant called ENTER_BOOKMARKABLE which indicates that the user has visited a specific location within a channel. So, the history channel would register as listener with the ITunerEventService, subscribing to ENTER_BOOKMARKABLE events. Every time the ITunerEventService receives an ENTER_BOOKMARKABLE event, it forwards it to the history channel. You could also further refine the scope of TunerEvents such that you only get notified of events for a specific channel, and only then when the event details match specified criteria (see Creating Custom TunerEvents for details).

Creating and Publishing TunerEvents

You need to perform the following steps to create and publish TunerEvents. If you extend MecaBaseChannel, they are done automatically.

To create TunerEvents
  1. Import the class com.mecasw.eb.system.TunerEvent. This lets you create TunerEvent objects.
  2. Get a reference to the ITunerEventService from your context or use the protected instance available in MecaBaseChannel (assuming you extend that class).
  3. Create and publish the event with a single statement similar to this:

    m_tunerService.publish (new TunerEvent(EVENT_NAME));

    or

    ITunerEventService ts = (ITunerEventService) m_context.getService( TUNER_EVENT_SERVICE );

    ts.publish( new TunerEvent( EVENT_NAME ) );

The TunerEvent class includes many constructors that let you bundle other information with the event in a variety of ways. While the previous example used only the event name, you can include up to four string arguments, plus an additional object of whatever type you wish. It also includes get and set methods that let another object extract the additional data (see the javadoc for specific constructors and methods). The full constructor for a TunerEvent is as follows. See the javadoc on TunerEvents for details).

TunerEvent( String eventName, String eventType, String option1, String option2, 
Object value )

Receiving TunerEvents

It requires two pieces of code to receive TunerEvents. The first is the subscription request; the second is the implementation of the tunerMessage( TunerEvent e ) method that specifies what the channel should do when an event is received. You need to perform the following steps to subscribe to TunerEvents. Again, if you extend MecaBaseChannel, they are done automatically.

To subscribe to TunerEvents
  1. Import the class com.mecasw.eb.system.TunerEvent. This lets you create TunerEvent objects.
  2. Get a reference to the ITunerEventService. See Creating and Publishing TunerEvents above.
  3. Implement the interface TunerEventListener using the single method tunerMessage(e).
  4. Subscribe to the event with a statement similar to this:

    m_tunerService.subscribe( this, new TunerEvent(EVENT_NAME));

    or

    ITunerEventService ts = (ITunerEventService) m_context.getService( TUNER_EVENT_SERVICE );

    ts.subscribe( this, new TunerEvent( EVENT_NAME ) );

Then, as part of the tunerMessage( TunerEvent e ) method, specify what to do when the event EVENT_NAME is received. Typically, this method consists of a number of if:else statements which encompass each of the events your channel subscribes to. See tunerMessage( TunerEvent e ).

Creating Custom TunerEvents

As noted, the TunerEvent class includes constructors that let you bundle other information with the event. You can use these optional parameters to create what are effectively your own custom TunerEvents. You can construct and publish custom TunerEvents as follows.

Example 1

m_tunerService.publish(new TunerEvent(PortfolioManager.EVENTS, 
PortfolioManager.UPDATES, PortfolioManager.VALUE, new Double( 
currentPortfolioValue ));

This TunerEvent might be used to broadcast the current value of the portfolio. The event name (EVENTS) is a constant from the main channel as is the event type (UPDATES) and option (VALUE). The value of the portfolio is represented by a Double since you cannot pass primitive types.

Example 2

m_tunerService.subscribeTunerEvent(this, new 
TunerEvent(PortfolioManager.EVENTS));

This statement subscribes to all the events of the PortfolioManager, regardless of their type or the data they contain.

Example 3

m_tunerService.subscribe(this, new TunerEvent(PortfolioManager.EVENTS, 
PortfolioManager.UPDATES));

This statement subscribes to only those TunerEvents from the PortfolioManager that deal with updates.

Example 4

m_tunerService.subscribe(this, new TunerEvent(PortfolioManager.EVENTS, 
PortfolioManager.UPDATES, PortfolioManager.VALUE));

This statement subscribes to only those events from the PortfolioManager that deal with updates in values. This statement makes use of the event, type, and option1 filters of the TunerEvent. You could further qualify it by adding a second option filter but you cannot filter on the Object field. See the javadoc for a more detailed explanation.

Extending MecaBaseChannel

The MecaBaseChannel base class is a shell channel that provides a complete implementation of an IntelliPortal channel including update processing, and loading and processing triggers. It supports history and bookmarking via triggers, and it locates the appropriate panel that it is designed to play in. You can use the default behavior (as explained on the following pages) of MecaBaseChannel methods, you can override them, or you can create your own. The only thing you need to do is add your own functionality and logic, and override the methods that are not appropriate. The following sections describe some of the likely hookpoints for customizing it.

MecaBaseChannel is a default implementation of IMecaApplicationContext. MecaBaseChannel provides a TunerEventListener and an overridable method. MecaBaseChannel automatically listens for many of the things that you want to create a listener for (or be a listener for). It calls a virtual method that you can override or create your own behavior for. Some of the more significant methods in MecaBaseChannel are explained below. The default behavior of these methods is described on the following pages.

Many of the methods described here refer to triggers and TunerEvents, which are more fully described in TunerEvent Messaging and Using Triggers and History.

tunerMessage( TunerEvent e )

This method makes a channel a TunerEventListener. This is one of the two basic requirements for a channel. (It must also implement IMecaApplication.) It gets called by the ITunerEventService when it has a TunerEvent that your channel has subscribed to, passing to it the subscribed event. Typically this method consists of a series of case:switch or if:else routines.

Each TunerEvent that your channel subscribes to must be handled here. The default implementation handles the TunerEvents subscribed to in the start() method. These are

If you are extending MecaBaseChannel and overriding the tunerMessage method, be sure to call super.tunerMessage( TunerEvent ) since the parent's implementation redirects the events above to the appropriate methods (which you can also override).

announceMe()

This method gets called whenever the channel's display panel is brought to the foreground. For this to occur, the following must happen:

  1. The start() method must subscribe to SHOW_PANEL.
  2. The tunerMessage( TunerEvent e ) method must call announceMe() when a SHOW_PANEL event is received.

The default implementation of MecaBaseChannel does this, but if you override either start() or tunerMessage( TunerEvent e ) it might not, unless you explicitly provide for it. The default implementation of announceMe() simply gets the current channel location and pulls any trigger that might be associated with it.

notifyAvailable( String dir )

This method is called when updated data becomes available and before it is installed on the client machine. Use this method to specify how the data will be installed. The default behavior is to read the properties.txt file and follow the instructions specified with the update.action parameter. The String parameter indicates the topmost subdirectory of the channel that will receive the update. The default implementation of notifyAvailable( String dir ) is to store the details of the update (an IUpdates instance) in a protected variable.

notifyInstall( String dir )

This method is called after updated data is successfully installed. Override if you want to do anything after the data is installed or with the new data (e.g. display it on the screen). The default implementation merely checks to see if there have been any updates to the channel's Trigger directory, and if so updates the TriggerTable.

vetoStop()

When the client application is about to be shut down, a VETOABLE_STOP event is broadcast. If your channel is engaged in an operation that should not be interrupted (e.g. reading information from a database), this event is designed to give the channel an opportunity to veto the shutdown request. This boolean method is provided as a convenience method to handle this event.

To use a VETOABLE_STOP
  1. Subscribe to the VETOABLE_STOP event. The default implementation of start() does this for you.
  2. In tunerMessage( TunerEvent e ), call this method in response to the VETOABLE_STOP. The default implementation does this.
  3. Override vetoStop() to implement your desired processing. Return Boolean.TRUE to veto the stop request, or Boolean.FALSE to submit to it.

Note that in the default MecaBaseChannel implementation, the return value of vetoStop() is actually wrapped in the return object for tunerMessage( TunerEvent e ), as follows:

[tunerMessage( TunerEvent e )]
if (evt.getOption1().equals(VETOABLE_STOP))
{
   Boolean b = vetoStop();
   return(b);
}

The default implementation of vetoStop() does nothing but returns Boolean.FALSE.

MecaBaseChannel Example

The easiest way to create a channel is to extend MecaBaseChannel. The following code shows a "Hello World" example that is a complete and self-contained channel. It has an application context, a layout, and its own functionality (it prints "Hello World"). It is very simply created by extending MecaBaseChannel. By default, this interface satisfies the two basic requirements for a Java-based channel: (1) it implements IMecaApplication and (2) it registers itself as a TunerEventListener. If the default behavior of MecaBaseChannel is adequate, you can extend directly from it and greatly simplify channel development.

import java.awt.*;
import javax.swing.*;
import com.mecasw.eb.channels.MecaBaseChannel;

public class HelloWorldPanel extends MecaBaseChannel
{
    public HelloWorldPanel ()
    {
    }

public void start()
  {  
    super.start();
    System.out.println( "channel started...\n" );
    add (new JTextArea ("Hello, World!"));
    
    return;
  }
}

Not Extending MecaBaseChannel

You can also create your own channel class from scratch without extending MecaBaseChannel. If you do not extend MecaBaseChannel, you still have to implement IMecaApplication and make your class a TunerEventListener (by implementing IMecaApplicationContext and calling the ITunerEventService).

The following code shows a "Hello World" channel that has been created by implementing IMecaApplication (and by default IMecaApplicationContext). It does not extend MecaBaseChannel. See the comments in the listing for more information and examine the following code closely. It shows much of the behavior that is performed by default if you do choose to extend MecaBaseChannel.

import java.awt.*;
import com.sun.java.swing.*;
import com.mecasw.intf.*;
import com.mecasw.eb.intf.*;
import com.mecasw.eb.services.*;

public class HelloWorld implements IMecaApplication
{
    protected IMecaApplicationContext m_context;
    protected JPanel m_parentPanel;

     /**
     * Start the application. This method is called by the
     * tuner to notify that the application is started.
     */
    public void start ()
    {
        ILayoutService lay = null;
        IServiceProvider isp = m_context.getServiceProvider ();

        try
        {
            lay = (ILayoutService)isp.getService ( 
IServiceConstants.LAYOUT_SERVICE );
            m_parentPanel = lay.getNewPanel (m_context.getParameter 
("Location"), m_context.getChannelName ());
            m_parentPanel.setLayout (new BorderLayout ());

            JTextArea t = new JTextArea ("Hello, World!");
            Font f = new Font ("Serif", Font.ITALIC, 32);
            t.setFont (f);
            t.setForeground (Color.blue);

            m_parentPanel.add (t, BorderLayout.CENTER);
            m_parentPanel.setName (m_context.getChannelName ());
            lay.showPanel (m_context.getChannelName ());
        }

        catch (IllegalArgumentException e)
        {
            e.printStackTrace();
        }
        m_parentPanel.validate ();
    }

    /**
     * Stop the applicaton. This method is called by the tuner
     * to notify the application that it will be killed. To stop
     * an application call stop() in the ChannelApplicationContext.
     */
    public void stop ()
    {
        // clean up after the channel here
    }

    /**
     * Handle an event. Events are posted to the application to
     * notify applications of changes in its status.
     */
    public boolean handleEvent (Event evt)
    {
        switch (evt.id)
        {
            case  DATA_AVAILABLE_EVENT:
                System.out.println (" Data Available");
                return true;
            
            case  DATA_UPDATE_EVENT:
                System.out.println (" Requesting Update");
                return false;
                
            case  DATA_INSTALLED_EVENT:
                System.out.println (" Installed!");
                return true;

            case  DATA_NOTIFY_EVENT:
                System.out.println (" Notify INACTIVE."); 
                return true;

            case  DATA_NONE_AVAILABLE_EVENT:
                System.out.println (" No Data Available");
                return true;
        }
    
        return (false);
    }
    
    public void setContext (IMecaApplicationContext context)
    {
        m_context = context;
    }
} 

Updating Channels

(Java and HTML Channels)

Updating a channel simply means that new files are copied to the channel base directory on the client machine. There are three ways to update a channel and they apply to both static and dynamic channels. Also, note that one channel can automatically initiate an update in other channels.

Channel Update Method Description
Automatically (This is the only update method for HTML channels.) Channel updates can be scheduled in the properties.txt file. You can specify separate update frequencies for when the channel is running or is not running. These updates are executed automatically and are transparent to users. You can also turn off automatic updates (see Property Files for more information).
Developer-initiated You can also initiate an update from the developer's side, so that if you create new channel content you can transmit it immediately to all subscribers regardless of the update schedule. (It is installed on clients' machines the next time they connect.)
Channel-initiated A channel can always request an update at any time, by calling the context.update()method. For example, you might set up a channel so that an update request is issued after the user enters some data in a field.

All channels have a data stream associated with them called their profile to which the channel can write. When the tuner sends an update request to the transmitter, it includes the profile stream, giving the channel a mechanism to add data to any update request. When the tuner is about to make an update request, it sends the channel a DATA_UPDATE_EVENT that gives the channel the opportunity to write to the profile stream any data it has been holding. The handleEvent( Event e ) method in MecaBaseChannel processes this event although you can override the default implementation.

Note that you will still receive a DATA_UPDATE_EVENT even if the update request originated within the channel. If you want to write data to the profile, you can either do this when you call context.update(), or after you receive the DATA_UPDATE_EVENT. When the updated files (if any) have been received by the tuner from the transmitter, the tuner notifies the channel that an update has occurred. What happens next is determined by entries in the properties.txt file and by whether or not the channel is running.

Updating Active Channels

The tuner sends a DATA_AVAILABLE_EVENT to the channel when it receives the updated data. This is received by the handleEvent( Event e ) method, which calls the notifyAvailable( String dir ) method. This does the following.

  1. It reads the update.action entry in the properties.txt file.
  2. It takes the following actions based on the update.action value:

After the data is installed, the tuner sends the channel a DATA_INSTALLED_EVENT. This is also processed by handleEvent( Event e ), which calls the channel's notifyInstall( String dir ) method. If the channel update did not return any new data, the tuner sends handleEvent( Event e ) a DATA_NONE_AVAILABLE_EVENT. No action is taken as a result of this event. See Extending MecaBaseChannel for more information about these methods.

Updating Inactive Channels

The tuner reads the install.inactive entry in the properties.txt file and interprets its value as follows:

The DATA_NOTIFY_EVENT is directly handled by the handleEvent( Event e ) method. If this method returns TRUE, the channel's start() method is called; if FALSE, the stop() method is called. The default implementation of handleEvent( Event e ) in MecaBaseChannel returns TRUE for this event. You can override this behavior in your channel class that extends from MecaBaseChannel. For example, you might want to look at the data first, returning TRUE or FALSE depending on what you find.

Dynamic Updating

Many channel applications require the ability to process a request for data that is customized for a specific user or group of users. Such data is supplied as part of the update process. This data can be customized for specific clients in two ways. The end user might prepare a one-time request for specific data, where the customization information originates with input at their machine. Examples would be inputting a series of ticker symbols for news or quotes, or clicking on a button to see current mortgage rates.

Channel content can be static or dynamic. Static content is generic for all clients; they all get the same content delivered by the selected update method. Dynamic content is customized for individual client applications and can be tailored according to usage tracking or profiling.

A data request might also be customized for a specific user or group of users, where the customization information comes from an external source such as a database of customer profiles. Examples of this would be targeted advertising, or news that is only relevant to certain people. Both scenarios require the channel to assemble and transmit dynamic files. Files which are to be transmitted to all subscribers are referred to as static files. Note that an update of dynamic files might also include static files as well. A request for data is processed as follows:

  1. The channel receives the data which specifies a request, e.g. a list of ticker symbols and a description of what type of information is desired. This is generally encapsulated within a CHANNEL_DATA_EVENT that the channel adds to its profile stream.
  2. When the channel is updated, other server routines (MecaPlugin, DataFeed, and IAdapter) read and parse the data in the profile and get the data from the data source.
  3. The data is returned to the channel via dynamically constructed files which are written to the channel's base directory and the channel is notified that updated data is available.
  4. The channel processes the updated data (e.g. displays it on the screen).
To create a dynamic update request
  1. Write the channel code. This includes code for handling the data request from the client application and code for processing the data returned to the client application.
  2. Identify the data sources and formats as part of the channel configuration process.
  3. Write the adapter code that is the interface between the server and the external data source.

Write Channel Code

The data a channel needs might consist of several different types of data. For example, a portfolio channel might be responsible for returning charts, current prices, and other data and news. You would identify these as different groups within the channel, each with a distinct name: "Charts," "News," "Quotes," etc. Group names are formalized with the Server Administrator tool. Then use the methods in the IRequestBufferService to build a properly-formatted byte array that can be added to the profile stream.

To build a formatted byte array
  1. Get a reference to IRequestBufferService. From this you can obtain an actual request buffer.
  2. Then, use the add() method to format the data request. Call the method once for each group for which you are requesting data.

    The add() builds a buffer with the successive chunks of data. The examples here pass three strings (group name, a series of ticker symbols, and the delimiter character that should be used to parse the chunk of data). add() has a number of different implementations than you can use. (See the javadoc for details.)

  3. Once your data request is complete, use the commitBuffer method to add it to the profile stream. Note that in addition to sending strings, you can also send serialized objects to the server.
    IRequestBufferService bs = ctx.getService
    (IServiceConstants.REQUEST_BUFFER_SERVICE)
    IRequestBuffer rb = bs.getBuffer ();
    rb.add("News", "IBM~SUNW~AMZN~MSFT", "~");
    rb.add("Quotes", "IBM~SUNW~AMZN~MSFT", "~");
    rb.add("Charts", "IBM~SUNW~AMZN~MSFT", "~");
    bs.commitBuffer (rb, ctx);
    

When you commit an IRequestBuffer using the commitBuffer() method, the buffer remains in existence and is sent to the server for all updates unless the buffer is explicitly cleared or overwritten with a new call to commitBuffer(). To clear the buffer, call commitBuffer() with null for the IRequestBuffer argument: requestBufferService.commitBuffer(null, context);

Identify Data Sources and Formats

Use the Server Administrator tool to describe the process by which the server will parse the data from the profile log. For each group (e.g. News, Quotes, etc.) that you identified in step one in the previous section, you need to provide the following information in the Server Administrator.

Administrator Field Description
Group Name Must match the argument provided with the addToBuf() method.
Target Name Uniquely identifies the data to get from the data source. For example, this might be a URL template which includes tokens to be replaced by data from the profile stream. Such a URL might look like the following: http://dataservice. stockquote.com/cgi-bin?symbol=~ where "~" is replaced by a ticker symbol.
Filename Specifies the file where the data will be saved when the channel is updated. Again, you can use a token to construct a template such as: ~_QUOTE where "~" is replaced by a ticker symbol. These files are written to the channel's base directory on the client machine. See the Server Administrator Guide for more information on these steps.

You also need to specify the name of an adapter which is the class that will actually get the data from the data source. The server uses the above information to create an object with a properly formatted target and pass it to an instance of the adapter which opens a connection to the data source, manages the connection, and returns the data. If the proper adapter does not already exist on your system, you must write Java code to create it.

Return Data to Client

Once the requested data is received by the server from the data source, the following process occurs.

  1. The channel is notified that updated data is available by a call to its notifyAvailable( String dir ) method. MecaBaseChannel has a default implementation of this method that installs the data or not depending on the value of update.action in properties.txt.
  2. If you have configured the channel so that new data is installed when the channel is updated, it is written to files in the channel base directory. The filenames are constructed as described earlier.
  3. Once the data is installed, the channel's notifyInstall( String dir ) method is called. The notifyInstall( String dir ) method is where you code any post-install processing of the updated data. For example, if the update returned stock prices, you might read the update files and display them on the screen.

Using Triggers and History

(Java and HTML Channels)

Another way to take advantage of TunerEvent messaging and other services in the tuner is by using triggers. Triggers associate actions like the production of TunerEvents with the value of a key field. Triggers are a convenient way to cause changes in other channels based on criteria that can be set in advance. For example, you can create a trigger that automatically starts a particular channel whenever a certain HTML page is displayed. See Using the Trigger Editor for a complete description of how to use this tool.

Triggers produce the same result as publishing and subscribing to TunerEvents or using the services available in the tuner directly. The key advantage of triggers is that the actions associated with the triggers exist outside the channel's codebase and are managed in a separate object called a TriggerTable. The abstraction of the triggers from a channel's codebase enables non-Java channels like HTML channels to interact with the tuner, services, and other channels without having to include custom applets within the HTML content itself.

The Trigger Editor tool provides a GUI front-end to the TriggerTable that can be used to build triggers and keys. Once you have coded a channel with trigger capabilities, you can create and manage links and dependencies between channels without further Java programming. This also allows developers of HTML channels to take advantage of the TunerEvent functionality without coding any additional tags or applets in their channel content.

The trigger mechanism is simply a vehicle for producing TunerEvents or interacting with the services available from the context.

Trigger Architecture

As shown below, the trigger architecture has three levels of component classes, the lowest being TriggerItem.

Trigger Class Description
TriggerItem Performs some action, depending on its type and delegate, when it is pulled. This action typically involves publishing a TunerEvent or using one of the IntelliPortal services.
Trigger Essentially a vector of TriggerItems. When a Trigger is pull()'d, it walks the vector and pull()s all of the TriggerItems. An additional feature uses dependencies such that you can set TriggerItem A to pull() only if TriggerItems B, C, and D pull()'d successfully.
TriggerTable Organizes all of the triggers for a channel into a table. The TriggerTable is the primary interface to triggers for channels.

TriggerItem Class

A TriggerItem is class whose purpose is to perform some type of action when "pulled" by calling its pull() method. The exact nature of this action depends upon the value of the type field and the value of the delegate field. All TriggerItems have the three properties shown in the table.

TriggerItem Property Description
ID A unique identifier for this TriggerItem. Must be unique within a trigger such that no two TriggerItems within a trigger have the same ID. Used to set dependency (see Setting Dependencies below).
Expiration time Either a specific time, or you can use a predefined constant to set the TriggerItem to never expire or to expire immediately when pulled. For more details, see the Expirable interface.
Type Determines what happens when the TriggerItem is pulled. ENTER_BOOKMARKABLE - notifies the service that the IBookmarkable object has entered a bookmarkable state. EXIT_BOOKMARKABLE - notifies the service that the IBookmarkable object has entered a non-bookmarkable state. TUNEREVENT_PRODUCER - capable of producing a TunerEvent. SERVICE_USER - delegate action to IServiceUserObject RUNNABLE - delegate action to Runnable object. HISTORY_ENTRY - delegate action to IHistoryService.

Trigger Class

A trigger is a Vector of TriggerItems accompanied by a key. The Trigger class has its own pull() method which pulls each of its TriggerItems when called. The two most important tasks at the trigger level are setting the trigger's key and setting dependencies among the TriggerItems.

Setting Dependencies

If you don't care about the order in which TriggerItems get pulled within the trigger, skip this paragraph and go to Keys, Tokens, and Cleaning Triggers below.

Use the Trigger Editor to associate a TriggerItem with one or more other TriggerItems in the same trigger such that the TriggerItem will not fire unless the other selected TriggerItems fire successfully. For example, if a Trigger has TriggerItems A, B, C, and D, you could specify that C will not fire unless A fires successfully, and D will not fire unless B and C fire successfully.

For each TriggerItem that depends on another, the Trigger constructs a vector which articulates the dependencies and is stored in a hashtable. You can use the getDepend() method to get the table itself or the dependency vector for any of the TriggerItems. You could also use setDepend() to set dependencies (see the javadoc for specific constructors).

Keys, Tokens, and Cleaning Triggers

Filenames and URLs are frequently used as trigger keys. However, since you can't know the absolute path of the channel's files, IntelliPortal lets you construct trigger keys with three different tokens (BASE, DATA, and SHARED) which correspond to the channel's base, data, and shared directories. For example, you might specify an HTML page as BASE\filename.html. See the javadoc for ITriggerCleaner for the constants you need to use.

IntelliPortal automatically replaces the tokens with the proper directory strings in a process known as cleaning. A TriggerTable automatically cleans its triggers when loaded. The cleaning is performed by an object which implements the ITriggerCleaner interface; such an object is passed to the TriggerTable when it is instantiated. Often, this will be the ITriggerTable's channel. MecaBaseChannel has an inner class that implements the ITriggerCleaner interface, so if your channel extends MecaBaseChannel you are done.

Default Triggers

In order to use the default triggers that are provided with IntelliPortal, you must publish the sample trigger file. If the sample trigger file is published with the channel, it will have default triggers with the following keys: CHANNEL_START, CHANNEL_STOP, and DEFAULT. The first two triggers are automatically pulled when a channel starts and stops. These are provided in the default implementations of start() and stop() in MecaBaseChannel. In the default configuration, the CHANNEL_START trigger fires an ENTER_BOOKMARKABLE event and the CHANNEL_STOP trigger fires a EXIT_BOOKMARKABLE event. You can add to or change this behavior with the Trigger Editor. The DEFAULT trigger is pulled when the TriggerTable is searched for a trigger that is not found (except for CHANNEL_START and CHANNEL_STOP). Use the Trigger Editor to add TriggerItems to this trigger as necessary.

TriggerTable Class

The TriggerTable is basically a hashtable of triggers for a particular channel. The TriggerTable class also includes a number of methods which are used by the channels as the primary interface to trigger functionality. The channel will typically instantiate a TriggerTable and expose one or more services to the TriggerTable as well as passing in one or more references via a IGenericService. MecaBaseChannel exposes the ITunerEventService, IBookmarkService, and IHistoryService by default and also provides references to ITriggerCleaner and IBookmarkable objects via an IGenericService.

How Channels Use Triggers

Although the triggers themselves can be created and modified with the Trigger Editor, you need to have the channel check for the triggers at the appropriate time. With HTML channels, this is easy because the Java class that renders the pages in the IntelliPortal frame automatically checks for triggers each time a new page is displayed; all you need to do is publish the channel normally, and then use the Trigger Editor to create the triggers, keyed to the URLs of the channel's pages. With Java channels, it's slightly more complicated.

To check the TriggerTable (Java channels)
  1. Load the channel's trigger table with the statement loadTriggers(). The default implementation of MecaBaseChannel's start() method does this automatically. MecaBaseChannel checks the data directory first to see if a fully loaded and cleaned TriggerTable exists from a previous session. If none exists, a new table is instantiated and populated with the serialized triggers (if any) found in the channel's base directory. (These directories are explained in Using Triggers and History.) The second part of the load process is for the channel to add whatever services it wants to the TriggerTable's IServiceManager.
  2. Identify the appropriate times to check whether a trigger exists and should be pulled. At those times, supply the TriggerTable with a key value, and if a Trigger in the table has that value it is pulled.

There several ways to accomplish the second step. MecaBaseChannel includes a convenience method called pullTrigger( String ) that you can use for this purpose and that is already used by other MecaBaseChannel methods. In addition to a String which contains the key value, it also accepts a TunerEvent that you can take advantage of if you override the method. Use this method as follows:

try
   {
   pullTrigger(key_value, evt); //evt can be null if desired
   }
catch(TriggerException e)
   {
   [handle exception]
   }

If you choose not to use pullTrigger, you can pull the trigger yourself by getting a reference to the TriggerTable and calling its pull() method: getTriggerTable().pull(key_value);

The TriggerTable also includes the boolean method containsTrigger() which you can use to find out whether a trigger or key exists in the TriggerTable without pulling it. You can call this method passing it either a key value or a trigger itself.

Using Bookmarks

(Java and HTML Channels)

A bookmark is a pointer to a channel in a particular state or condition. Bookmarks let users mark a specific location in a channel that can be revisited later. As a channel developer, you decide which parts of a channel (e.g. which HTML pages) are "bookmarkable." When a bookmark is restored, the tuner starts the channel (or brings it to the front) and uses the bookmark object to restore its previous location (if getBookmark() and restoreBookmark() are implemented appropriately).

Any channel can be bookmarked to its initial state. The bookmark facility is accessed by channels via the com.mecasw.eb.services.IBookmarkService interface. An object that implements the bookmark service interface is instantiated during tuner startup. It is then added to the IServiceProvider for channels to access before any channels are actually started.

The IBookmarkService API lets channels add or remove bookmarks from the bookmark list as well as to set a flag indicating that the channel is bookmarkable. This flag is set by calling the EnterBookmarkable( IBookmarkable ) method on the bookmark service and passing in a reference to the bookmarkable object. When the user hits the bookmark button, the bookmarkable object that was passed in via the enterBookmarkable method is used to construct a bookmark.

When the channel enters a non-bookmarkable area then the channel should call the exitBookmarkable( IBookmarkable ) method in the service, again passing in a bookmarkable object. When the exitBookmarkable method is called and the bookmarkable object is the same as the one passed with the enter method, the bookmark button on the client application is disabled, indicating that the current content is not bookmarkable.

MecaBaseChannel has a generic implementation of the IBookmarkable interface to handle channel bookmarking requirements. The protected inner class Bookmarkable can be extended to provide channel-specific bookmark implementation.

Instantiating IBookmarkService

The tuner instantiates the IBookmarkService class and installs it as an IService into IServiceProvider. The IBookmarkService starts before any channels are running. The BookmarkService class registers itself as a listener for the starting and stopping of the BookmarkChannel. If any calls to the BookmarkService methods are made before the BookmarkChannel starts, these calls are queued. Once the channel starts, any commands in the queue are delivered to the BookmarkChannel in the order in which they were received. This is accomplished through the use of the TunerEventPublisher class. Once the BookmarkChannel is started, all calls to the BookmarkService are delivered to the BookmarkChannel via TunerEvents.

Bookmark Property Description
Key A unique ID that identifies a trigger in the TriggerTable. Can be a filename or URL for an HTML channel.
Type ENTER_BOOKMARKABLE - notifies the service that the IBookmarkable object has entered a bookmarkable state. EXIT_BOOKMARKABLE - notifies the service that the IBookmarkable object has entered a non-bookmarkable state.
Tag String Tag string associated with a bookmark
Category Name Name on Channel Menu.
Value Default name for bookmarked channel.

Using IBookmarkService

Channels that want to use the IBookmarkService to add or remove bookmarks or to report that they have entered or exited a bookmarkable state simply get a reference to the IBookmarkService from the IServiceProvider available from their IMecaApplicationContext.

IBookmarkService bs = (IBookmarkService) context.getService( BOOKMARK_SERVICE );
bs.add( myBookmark );
bs.remove( myBookmark );
bs.enterBookmarkable( myBookmarkable );
bs.exitBookmarkable( myBookmarkable );

Bookmarkable States

Whenever a channel enters a bookmarkable state, it should call the enterBookmarkable method on the IBookmarkService. This tells the BookmarkChannel that the channel has entered a state that can be bookmarked and enables the BookmarkButton. This allows the end user to hit the bookmark button to save the state of the channel in a Bookmark object which is then be added to the BookmarkList. Calling the exitBookmarkable method on the IBookmarkService has the opposite effect: the bookmark button is disabled until it receives an enterBookmarkable call.

The BookmarkChannel saves the IBookmarkable reference that it is passed with the enterBookmarkable and exitBookmarkable methods. When the user clicks on an enabled bookmark button, an ActionEvent is fired which notifies the BookmarkChannel. The BookmarkChannel then uses the IBookmarkable reference it received from a previous enterBookmarkable call to create a Bookmark object and adds it to the BookmarkList. Thus the creation of the Bookmark object is deferred until the user actually clicks on the bookmark button.

Using MecaBaseChannel.Bookmarkable

The recommended base class for channel developers (MecaBaseChannel) contains an inner class which provides a basic implementation of the IBookmarkable interface. This implementation uses the channel's TriggerTable to determine whether or not the channel is bookmarkable. This is accomplished by using the channel's current location (as returned by the String getLocationInChannel() method) as a key into the TriggerTable. If a Trigger exists at the key which contains a TriggerItem of type TriggerItem.ENTER_BOOKMARKABLE, the channel is considered to be in a bookmarkable state.

The use of the inner class provides channel developers with a means to extend the class and override one or more the methods to provide their own implementation. Bowser3 (the default browser for HTML channels) extends the Bookmarkable inner class in MecaBaseChannel to return the current URL for the location in the channel and to restore a Bookmark object using the bookmark's tagString field to load a new URL.

Developing HTML Channels

HTML channels are those whose functionality is limited to displaying HTML pages. HTML channels are similar to a website, except that the entire channel is downloaded and stored as a whole rather than page by page. HTML channels have two main components. One is the HTML pages themselves. The other is a Java channel "wrapper" that renders the HTML pages in the client shell and administers the IMecaApplicationContext and messaging services as described earlier. This Java channel lets you display HTML pages directly in IntelliPortal so that you don't need a separate browser program.

To create HTML-based channels
  1. Develop the HTML content and store it in a base directory on the server from which it will be published.
  2. Use the Publisher to create a channel name and configure the properties.

There are two ways to build HTML channels. You can build a channel for offline viewing, in which case all HTML pages are copied to the client machine. You can also build an online channel that only consists of a pointer to a URL. (In this case, you can skip step one above). When you click on the online channel, the system opens an Internet connection and displays the indexed page.

.

All HTML content must conform to HTML Version 3.2. IntelliPortal supports frames and applets that follow 3.2 conventions (i.e. use <APPLET> instead of <OBJECT>, etc.). IntelliPortal does not support JavaScript, dynamic HTML, ActiveX, or VBScript. (JavaScript availability is planned for the second half of 1999.)

HTML Parameters.txt

In addition to standard properties that all channels have (see Property Files), HTML channels have an additional parameters.txt file in the channel's base directory. This parameters.txt tells the channel where to find the first HTML page. This file is required in addition to the properties.txt file that is required for all channels. It is created by the Publisher when you publish a channel and can be modified with a text editor. The parameters.txt file has the following contents.

loadmode=channel | web
defaultURL=

Keyword Description Publisher Field
loadmode=channel The defaultURL is an HTML page stored locally in the channel's base directory. Index Source
loadmode=web The defaultURL is the qualified URL (the complete path) of the starting HTML page. Index Source
defaultURL= The local filename of the first HTML page that will be loaded when the channel starts, or the URL that contains that page. Index Page

You can also use the parameters.txt file to customize the browser navigation controls for specific HTML channels. You can add statements to parameters.txt that override the default statements in the browser.ini file. The statements you add are the same as those in the browser.ini file; you simply add statements for the controls you want to change. When the channel runs, the browser uses the statements in the parameters.txt file rather than the default statements in the browser.ini file. See the Client Customization Guide for complete details.

Building an Ad Channel

An advertisement channel, as shown in the example, lets you group ads together into an "ad queue" and lets you manage the rotation of the queue. Upon connection, the server supplies the ad queue to the client. The advertisements displayed on the client can be static, or can trigger another channel or jump to a web site if you click on the ad.

On the client side, the ad channel can be assigned to any available (and appropriate) panel in the client layout. The channel fetches and displays the appropriate ad from the queue for a configurable duration. This duration is the amount of time (15 seconds minimum) to display each ad before showing the next ad in the queue. Additional properties determine how channels are mapped to categories of ads.

On the server side of the channel, all ad files (JPEGs, GIFs, or animated GIFs) must reside in one directory. This directory also includes a catalog of the all ads in the directory. For each ad there are one or more categories (set in advance) that are used to construct bookmarks if you click on the ad. Any update connection fetches all the ads that are currently in the server ad directory.

This section explains how to build an ad display channel from scratch. It explains how to set up the required files and how to configure the client and the server. An ad sample channel is included with IntelliPortal. See the AdChannel for details.

All ad files are stored in a directory on the server and the pre-built FileReaderAdapter is used to retrieve and send them to the client at update time. There is no caching of ads on the server; this means that any update connection always gets all the ads that are currently stored on the server. The ad channel can be assigned to any available panel in the client layout. Always test the channel to be sure that it can properly display all images, animated GIFs, etc. An ad channel will not work if the client panel is not large enough to accommodate the images. See Client Layout for more information about panels.

The ad channel must be designated as Autorun when published so that it runs in the designated panel at startup. It should also register as a listener for TunerEvents relating to TO_FRONT and SHOW_PANEL so it knows what channel is currently in front and visible to the user. An ad channel should typically respond to only those channels that are displayed in the main content panel. Similarly, an ad change is triggered whenever a new channel is brought to the front. See the Java code for the AdChannel sample for details on how this is all accomplished.

Use the following basic steps to build and configure an ad channel
  1. Write the ad channel using the FileReaderAdapter. For best results, copy and rename the AdChannel sample channel.
  2. Create the required server files (or modify the files that came with the sample channel). Put these files in a directory on the server along with the ad image files. All these files must be in the same directory without subfolders.
  3. Configure the ad channel and the InvisibleHtml channel properties.
  4. Configure the adapter. Using the Server Administrator, create a datafeed record and a channel record that points to the directory you used in Step 2.
  5. Publish the channel.

Creating Server Files

Assuming you have created an ad channel, the next step is to create the server files. The ad channel requires certain files on the server. Theses include (1) your ad images; (2) a category file; and (3) a criteria file. These later are typically called categoryfile and criteriafile. They are referenced on the client side in the ad channel's properties.txt file. They are comma-delimited ASCII files with no embedded spaces. For best results, modify the pre-built files that are included with the sample channel. These files are located on the installation CD-ROM in the directory misc\channels\SampleChannels\AdChannel. You can modify them with any editor and add them to the appropriate directory on the server. All images (JPEGs, GIFs, animated GIFs, etc.) must be present in the same directory as the category and criteria files.

categoryfile Associates a channel with a category. Only one category is associated with each channel.
criteriafile Associates ads with categories. Multiple categories can be associated with one ad.

When creating these files, keep the following concepts in mind: the category file associates channels with categories; the criteria file associates categories with specific ads. Together, they determine which ads are displayed for a given channel.

categoryfile

This file maps channels to developer-defined categories. Each category is unique and cannot be duplicated. There is only one category per channel which is the ad queue for that channel. When the channel starts, the ads in that category are displayed in the ad channel panel. The file has the following comma-delimited format.

<categoryname>,<channel name>

In the following example, the transactions category is associated with the Register channel.

transactions,RegisterChannel
accounts,AccountListChannel
departments,CategoryListChannel

criteriafile

This file is a catalog that completely describes each ad that is available for display. In addition to name and filename, it has a target URL that is used to construct a bookmark that is invoked when you click on the ad. It also lists the categories in which the ad is included. This file also determines the order in which ads are displayed. The ads are displayed sequentially in the order in which they are listed in the file. It has the following comma-delimited format.

<ad name>,<ad file name>,<target URL>,<category1>,...<category-n>

In the following example, the ad name diamonds displays the animated diamonds.gif image, and links to diamonds.com when clicked. It displays ads in the transactions and general categories.

diamonds,diamonds.gif,http://www.diamonds.com,transactions
medical,medical.gif,http://www.medicalshopper.com,accounts
drugstore,drugstore.gif,http://www.drugstore.com,departments,general
trade,ameritrade.gif,http://www.ameritrade.com,general

Note that there is no general entry in the category file. Ads with the general category are only displayed for channels that do not have an associated category. For example, if you publish a new channel (and do not update the category file) it gets all ads in the criteria file that have the general category. This means that if you set all ads to general and leave the category file empty but still present, all the channels get all the ads.

Configuring Channel Properties

The ad channel and the InvisibleHtml channels must both be configured and published for an ad channel to run properly.

Set Properties for Ad Channel

If you published and are using the AdChannel sample channel, the default properties were published with the channel. You only need to set properties and re-publish if you change these default properties. These properties include the following.

ad.categoryfile Name of the category file residing on server.
ad.criteriafile Name of the criteria file residing on server.
ad.duration How long (minimum 15 seconds) before displaying next ad in queue.
ad.selector Name of a Java class (com.mecasw.channels.addisplay.AdSelector) that implements the AdSelector interface. This class is automatically published with the channel.

To change ad channel properties
  1. Locate the properties.txt file for the ad channel.
  2. Open this file in a text editor and modify the lines shown in bold with values that are appropriate for your site.
    Autorun=True
    Category=Ads
    LOG_LEVEL=255
    Mandatory=True
    Selectable=False
    VisibleName=Ads
    ad.categoryfile=categoryfile
    <