Follow the steps below to create a service component:
Except for a few special requirements described here, you define a service component’s interface and properties in EAServer Manager as you would do for any component. Chapter 4, “Defining Components” describes how to define components in EAServer Manager.
Service components require these EAServer Manager settings in the Component Properties window:
IDL Interface Your service component must implement the CtsServices::GenericService interface. You can define additional methods in one or more additional IDL interfaces if necessary.
Concurrency and Bind Thread Options For best performance, you must enable the Concurrency option on the Instances tab, and disable the Bind Thread option.
Selecting the Concurrency option allows multiple method invocations to occur simultaneously. Concurrent access can decrease client response time. Also, if your component has a run() method that executes indefinitely, you must enable the Concurrency option or no clients will be able to invoke methods. To support concurrency, you must ensure that access to read/write instance variables is synchronized in your component.
Disabling the Bind Thread option allows EAServer to run the component on any available thread. This option is only required by ActiveX components (where it is on implicitly) and by components that use thread-local storage. It should be disabled in any other case.
Sharing Option For simplified implementation, select the Sharing option on the instances tab. This option ensures that only a single instance of your component is created. One instance serves all client requests. With Sharing enabled, the component can store data in class instance variables. If Sharing is disabled, you must coordinate access to shared data among multiple instances of the component (typically, data shared by multiple instances is stored in static class variables, in a database, or in EAServer shared properties).
Transaction Attribute Do not create service components that are transactional. On the Transactions tab, choose Not Supported. If you require EAServer’s transaction semantics, implement a component to perform the transaction-created work and call this component from your service component
Automatic Demarcation/Deactivation If a service component is installed to run in multiple service threads, the component must be stateless.You must enable this option if the multiple instances will run as service components. See “Install the component as an EAServer service” for information on configuring the component so multiple instances run as services.
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 Advanced 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.
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.
Be careful of consuming CPU cycles
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 use a
monitor object and call the Object.wait() method.
In C, C++, ActiveX, or PowerBuilder, EAServer 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.
If coding service components in PowerBuilder, code your component’s run method to call the JagSleep C routine; do not use the PowerBuilder timer event, which may suspend the EAServer process.
Services with a client interface
If your component runs as a service and also provides a client
interface for remote invocations, beware that the run method
may not have executed when the first client request arrives. run is
called on a different thread after start returns;
client invocations may arrive between the return from start and
the invocation of run, and initialization performed
in run may not have completed when the remote
method executes on a different thread. To avoid problems, use one
of these approaches:
Do not code remote methods that rely on initialization performed in the run method. Initialization can be performed in the start method, which is guaranteed to complete before client invocations arrive.
Use a synchronized boolean variable that is set when run has performed necessary initialization, and code remote methods to check this variable and wait for it to be set before executing code that relies on initialization performed in run.
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 ... synchronized(_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 synchronized (_lock) { _lock.notifyAll(); } } }
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 ... } };
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:
In order to run as a service, your service component must be added to the host server’s list of services, as follows:
Installing services
Start EAServer Manager if it is not already running.
Expand the Servers folder.
Expand the icon for the server.
Highlight the Installed Services folder under the server icon, then choose File | Install Services from the menu.
Components that implement the CtsComponents::GenericService interface are listed. Pick the component to install, then click OK.
The service will run the next time you refresh or restart the server.
Configuring a service to run in multiple threads
By default, one thread runs per service. You can specify a larger number of threads as follows:
Display the server properties.
In the list of properties, select “com.sybase.jaguar.server.services”, then click Modify.
The value of this property is the list of services, using the form Package/Component, with entries separated by commas. To specify multiple threads for a service, enter the number of threads in brackets after the component name. For example:
YourPackage/YourService[10]
Click Ok to close the Modify Property window.
Click Ok to close the Server Properties window.
The change takes affect the next time you refresh or restart the server.
The host 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.
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 © 2005. Sybase Inc. All rights reserved. |
![]() |