Chapter 33 Creating Service Components


Creating service components

Follow the steps below to create a service component:

  1. "Define the component interface and properties"
  2. "Implement GenericService interface methods"
  3. "Implement other required methods"
  4. "Install the component as a Jaguar service"

Define the component interface and properties

Except for a few special requirements described here, you define a service component's interface and properties in Jaguar Manager as you would do for any component. Chapter 5, "Defining Components" describes how to define components in Jaguar Manager.

Service component properties

Service components require these Jaguar Manager settings in the Component Properties window:

Required client roles

You can assign the role ServiceControl to service components so that base clients and other components cannot create instances of the component and call the start and stop methods. No users can be added to this role. To assign this role to a component, display the All Properties tab in the Component Properties dialog and modify the com.sybase.jaguar.component.roles property. Add "ServiceControl" to the list of comma-separated role names.

Implement GenericService interface methods

Each service component must implement the CtsServices::GenericService interface. Your component can implement additional interfaces if necessary. This section describes how to implement the CtsServices::GenericService in C++ and Java.

Note   If your service will perform background processing, your implementation must have access to a thread-aware sleep mechanism. In Java, call the java.lang.Thread.sleep() method, or create a synchronized object and call the Object.wait() method. In C or C++, Jaguar provides the JagSleep routine. The run method in your service must call one of these APIs periodically to suspend execution of the current thread. Otherwise, your service will dominate the server's CPU time and prevent other components from executing.

Java example of GenericService methods

The example uses a static Boolean instance variable, _run, to indicate when the service should cease running. There is also a java.lang.Object that is used as a semaphore to allow synchronization among multiple threads. The start() method sets the _run variable to true; start() must also perform any other necessary initialization that are needed by your service, such as opening files, database connections, and so forth. run() executes a while loop as long as the _run variable is true. In each loop iteration, run() performs some of the work that the service is responsible for, such as refreshing a copy of a remote database table, then calls the Object.wait() method to relinquish the CPU. The stop() method sets the _run variable to false and calls the Object.notifyAll() method on the semaphore, causing the run() method to return. Before returning, run() cleans up resources that were allocated in the start() method.

public class MyService
{
public static boolean _run;
public static Object _lock = new Object();

public void start()
{
_run = true;
... perform necessary initializations ...
}

public void run()
{
while (_run)
{
try
{
... do whatever this service does
on each iteration, then go back
to sleep for a while ...
synchronize(_lock)
{
_lock.wait(100000);
}
}
catch (InterruptedException ie)
{
_run = false;
}
}
... perform necessary cleanup and deallocations ...

}

public void stop()
{
_run = false;
// Wake up any instances that are waiting on the mutex
_lock.notifyAll();
}
}

C++ example of GenericService methods

The code fragment below shows how the GenericService methods can be implemented in a C++ component. This example uses a static Boolean instance variable, _stop, to indicate when the service should cease running. The start() method sets the _stop variable to false; start() must also perform any other necessary initialization that are needed by your service, such as opening files, database connections, and so forth. run() executes a while loop as long as the _stop variable is false. In each loop iteration, run() performs some of the work that the service is responsible for, such as refreshing a copy of a remote database table, then calls the JagSleep C routine to relinquish the CPU. The stop() method sets the _stop variable to true. stop() must also clean up any resources that were allocated in the start() method.

#include <jagpublic.c> // For JagSleep API

class MyService
{
private:
static boolean _stop; // Declared static in case multiple
// instances are run.

public:
void start()
{
_stop = false;
... perform necessary initializations ...
}

void stop()
{
_stop = true;
}

void run()
{
while (! _stop)
{
... do whatever this service does
on each iteration ...
JagSleep(1000);
}
... perform necessary cleanup and deallocations ...
}

};

Implement other required methods

Your component may implement additional interfaces besides CtsServices::GenericService. For example, in a component that manages application-specific log files, you need a method that other components can call to write to the application log. Follow the implementation rules for the component model that you are using. See the following chapters for more information:

Install the component as a Jaguar service

In order to run as a service, your service component must be added to the Jaguar server's list of services, as follows:

  1. Start Jaguar Manager if it is not already running.
  2. Display the property sheet for the server where you want to run the service as follows:
    1. Expand the Servers folder.
    2. Select the icon for the server.
    3. Choose File | Server Properties from the menu.
  3. Display the All Properties tab.
  4. In the list of properties, select "com.sybase.jaguar.server.services", then click Modify.
  5. Add the name of your component to the list of services, using the form Package/Component. If multiple services are installed, use a comma to separate names in the list. For example:
    ExistingPackage/ExistingService, YourPackage/YourService

    By default, one thread will run a service. You can specify a larger number of threads in brackets after the component name. For example:
    YourPackage/YourService[10]

  6. Click Ok to close the Modify Property window.
  7. Click Ok to close the Server Properties window.

The service will run the next time you refresh or restart the server.

When multiple threads are requested

The Jaguar server calls the component's run method from the specified number of threads. If the Sharing option is enabled, all threads call run on the same component instance as start was called in. Otherwise, each thread will create a new instance of the component and call run on that instance. Each thread terminates when run returns. This feature is useful when your service component performs a background task that lends itself to parallel processing. For example, if the run implementation extracts work requests from a queue and performs the requested operation, you can configure the server so multiple threads read requests from the queue and process them simultaneously. The component must be coded to ensure that access to the queue is thread-safe, for example, in Java, you might create synchronized methods to queue and dequeue.

The component must be stateless in order to run in multiple threads. Make sure the Automatic Demarcation/Deactivation is option is checked on the Transactions tab in the Component Properties window.

Note   The start method and stop methods are only called on one instance of a service component. If Sharing is not set for the component, start must store any data required by the run method or other methods. For access by multiple instances, data must be stored in static fields or a persistent data store.

 


Copyright © 2000 Sybase, Inc. All rights reserved.