Creating services

This section describes considerations related to creating custom services.

Basic JRun services: extending ServiceMBean and ServiceAdapter

In the simplest case, creating a service involves the following tasks:

Service naming convention

JMX enforces the following naming convention: your MBean interface name must end in MBean and your concrete class must have exactly the same name without the MBean suffix. For example, a service named MyService would have an MBean interface named MyServiceMBean.java, and the concrete service class would be named MyService.java.

Service composition: extending ServicePartitionMBean and ServicePartition

In some cases, services must contain other services, and those internal services have no real meaning outside the context of their parent. The jrunx.kernel.ServicePartitionMBean interface and jrunx.kernel.ServicePartition class are designed to provide this functionality. These classes extend the ServiceMBean and ServiceAdapter to permit adding new services to the partition's JMX domain rather than the default global JMX domain. The ServicePartition has the following two methods to facilitate this behavior:

The JRun EJB architecture uses this behavior. Each EJB container spawned by the EJBContainerFactory is a ServicePartition. EJB containers contain interceptors that handle functionality such as security, persistence, transactions, and so on. Each of these interceptors is a standard service, because they have no external meaning, they are not bound to the global default JMX domain. Instead, the container (since it extends ServicePartition) adds them to the container's domain.

Creating services using jrun.xml

To define a service in the jrun.xml file, perform the following tasks:

The following example shows an XMLLogEventHandler service that is defined as a service within ThreadedLogEventHandler service in the jrun.xml file:

...
<service class="jrunx.logger.ThreadedLogEventHandler" name="ThreadedLogEventHandler">

  <service class="jrunx.logger.FileLogEventHandler" name="FileLogEventHandler">
    <attribute name="filename">
{jrun.rootdir}/logs/{jrun.server.name}-event.log</attribute>
    <attribute name="rotationSize">200000</attribute>
    <attribute name="rotationFiles">3</attribute>
    <attribute name="heading">
# Created by JRun on {date MM/dd HH:mm:ss}</attribute>
    <attribute name="closeDelay">5000</attribute>
  </service>

  <service class="XMLLogEventHandler" name="XMLLogEventHandler">
    <attribute name="filename">
{jrun.rootdir}/logs/{jrun.server.name}-event.xml
</attribute>
  </service>
</service>
...

Creating services programmatically

The majority of manageable services in a running JRun server are not configured using jrun.xml. Typically, you configure a factory service or deployer service using jrun.xml, and that service creates and deploys numerous other services. You configure the other services using a deployment descriptor (for example, web.xml or ejb-jar.xml), a separate server-defined descriptor (for example, jrun-users.xml or jrun-jms.xml), or through hard coded operations inside another service (for example, the EJB deployer creates an EJBContainerFactory using a secure, final hard coded invocation).

Using the createService method

The simplest way to automatically create a service and register it implicitly with the underlying JMX server is to use the jrunx.kernal.ServiceFactory object's static createService method:

// ServiceFactory takes (1) the MBean server, which is known
// by the variable "this.server" within all extensions of 
// ServiceAdapter, (2) the name of the service, (3) the Class of the 
// service (as a String), and (4) a Properties object containing 
// attribute names and values to be automatically set on the Service.
Properties props = new Properties();
props.put("foo", "foobar");
ServiceFactory.createService(this.server, "service=FooService","jrun.example.FooService", props);

Creating the service manually

Another programmatic method of creating such services is to manually create the service and subsequently register it with the underlying MBean server:

// Create the object
SomeService svc = new SomeService();
// Often the service name is included as the value of 
// the interface's static String OBJECT_NAME.
// Here the OBJECT_NAME is set to "service=FooService"
svc.setName(svc.OBJECT_NAME);
svc.setFoo("foobar");
svc.setWhateverInt(789);
// Register the object using this server's MBean Server
this.server.registerMBean(svc, svc.getName());
// Since you created the service, you must invoke its startup methods
svc.init();
svc.start();

Using the addService method

If the service extends ServicePartition, it can use one of the addService methods:

// executed within a ServicePartition -- this snip is taken 
// from the jrunx.kernel.prototype.PrototPartition example:
ProtoService newservice = new ProtoService();
newservice.setSomething("partition test");
newservice.setName("testPartitionedService");
addService(newservice);
// partitions must invoke the lifecycle methods of their services
newservice.init();
newservice.start();
newservice.setBindToJNDI(true);
newservice.bind();

Custom service example

The following section describes steps and sample code to create a custom service that implements a custom log event handler. For more information on JRun logging, see JRun Administrator's Guide.

To create a customized log event handler, you must perform the following steps:

  1. Code an MBean interface.
  2. Code a log event handler.
  3. Define a service element in the jrun.xml file.

Coding an MBean interface

The MBean interface, which is required as part of the JRun JMX-based architecture, defines methods that correlate to properties in the jrun.xml file. When you specify values for these properties in the jrun.xml file, JRun automatically initializes these values when the server starts. A log event handler MBean interface must extend the LogEventHandlerMBean interface and must also include the following items:

Example

The following code defines an MBean interface for the XML log event handler:

import jrunx.logger.*;
import jrunx.kernel.*;

/**
 * MBean interface for the XML Log Event Handler
 *
 * @author Macromedia, Inc.
 * @date 5December2001
 */
public interface XMLLogEventHandlerMBean
  extends LogEventHandlerMBean {

  /**
   * Sets the name of the file to be used for XML logging
   * @param filename The filename
   */
  public void setFilename(String filename);

  /**
   * Gets the name of the file to be used for XML logging
   * @return The filename
   */
  public String getFilename();
}

Coding a log event handler

A log event handler is a Java class that must include the following items:

JRun calls log event handler methods in the following order:

Example

The following code defines a log event handler that writes log messages in a simple XML-like format:

import java.io.*;
import java.util.*;
import java.text.*;
import jrunx.logger.*;

/**
 * Log events in XML format to a file
 * This extends LogEventHandler, which requires that this
 * class implement the logEvent method.
 * It implements XMLLogEventHandlerMBean, which defines the
 * getFilename and setFilename methods.
 */
public class XMLLogEventHandler extends LogEventHandler
   implements XMLLogEventHandlerMBean {
    protected String filename;
    protected SimpleDateFormat dateFormat = new SimpleDateFormat("MM/HH hh:mm:ss");
    protected String defaultFormat = null;

    // JRun initializes the writer at server startup
    public void init(Properties props) {
        dateFormat = new SimpleDateFormat("MM/HH hh:mm:ss");
    }

   /**
    * Sets the name of the file to be used for XML logging.
    * @param filename The filename
    */
   public void setFilename(String filename) {
        if (filename == null) {
            this.filename = "xml.log";
        }
        else {
         this.filename = filename;
        }
   }

  /**
   * Gets the name of the file to be used for XML logging
   * @return The filename
   */
  public String getFilename() {
     return filename;
  }

    // JRun calls the logEvent method when a log action is requested.
    public synchronized boolean logEvent(LogEvent event) {
        PrintWriter out = null;

        try {
            FileOutputStream fos = new FileOutputStream(filename, true);
            out = new PrintWriter(fos, true);

            // Get the pieces and parts.
            Properties p = event.getVariables(defaultFormat);
            String level = (String)p.get("log.level");
            String msg = (String)p.get("log.message");
            String exception = (String)p.get("log.exception");
            Date date = new Date();

            String formattedDate;
            synchronized(dateFormat) {
                formattedDate = dateFormat.format(date);
            }

            // Crude format.
            out.println("<log>");
             out.println(" <time>" + date + "</time>");
             out.println(" <level>" + level + "</level>");
             out.println(" <message>" + msg + "</message>");
             out.println(" <exception>" + exception + "</exception>");
            out.println("</log>");
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        finally {
            if (out != null) {
                out.close();
            } // end if
        }  // end finally
       return true;
    }  // end logEvent method

    public void flush()
    {
        // No-op
    }
}

Defining a service element

You define the XMLLogEventHandler as a service within ThreadedLogEventHandler service in the jrun.xml file. The service contains a filename attribute, as the following example shows:

...
<service class="jrunx.logger.ThreadedLogEventHandler"
name="ThreadedLogEventHandler">

  <service class="jrunx.logger.FileLogEventHandler" name="FileLogEventHandler">
  <attribute name="filename">{jrun.rootdir}/logs/{jrun.server.name}-event.log
  </attribute>
    <attribute name="rotationSize">200000</attribute>
    <attribute name="rotationFiles">3</attribute>
    <attribute name="heading">
    # Created by JRun on {date MM/dd HH:mm:ss}</attribute>
    <attribute name="closeDelay">5000</attribute>
  </service>

  <service class="XMLLogEventHandler" name="XMLLogEventHandler">
    <attribute name="filename">
    {jrun.rootdir}/logs/{jrun.server.name}-event.xml</attribute>
  </service>
</service>
...

 

Send me an e-mail when comments are added to this page | Comment Report

Current page: http://livedocs.adobe.com/jrun/4/JRun_SDK_Guide/creatingservices3.htm