Apache Service Specification

Version 1.0

Abstract: This document specifies the behavior and life cycle of an abstract Java™ service, in relation to its native container. In addition it defines a mechanism for controlling a service, and its interaction with the native OS process in which its existance is confined.

Index

  1. Introduction
  2. Scope of this specification
  3. The Service interface and its life cycle
    1. Instantiation
    2. Initialization
    3. Startup
    4. Stop
    5. Destruction

Introduction

Since 1994, the Java™ programming language evolved and became a valid tool to develop, other than applets and client applications, reliable and performant server applications. The major disadvantage of the Java™ platform is that still today the only portable way to start a Java™ applcation relies on a single point of entry: the public static void main(String[]) method.

Having a single-point of entry is a valid solution for client applications, where interactively a user can command to the application to quit (which can terminate the Virtual Machine process at calling the System.exit(int) method), but in those cases where the application is not interactive (server applications) there is currently no portable way to notify the Virtual Machine of its imminent shutdown.

A server application written in Java might have to perform several tasks before being able to shutdown the Virtual Machine process. For example in the case of a Servlet container, before the VM process is shut down, sessions might need to be serialized to disk, and web applications need to be destroyed.

One common solution to this problem is to create (for example) a ServerSocket and wait for a particular message to be issued. When the message is received, all operations required to shut down the server applications are performed and at the end the System.exit method is called to terminate the Virtual Machine process. This method, however, implies several disadvantages and risks: for example in case of a system-wide shutdown, it might happen that the Virtual Machine process will be shut down directly by the operating system, without notifying the running server application. Or, for example, if an attacker finds out what is the required message to send to the server, and discovers a way to send this message to the running server application, he can easily interrupt the operation of a server, bypassing all the security restrictions implemented in the operating system.

Most multi-user operating systems already have a way in which server applications are started and stopped, under Unix based operating systems non interactive server applications are called daemons and are controlled by the operating system with a set of specified signals. Under Windows such programs are called services and are controlled by appropriate calls to specific functions defined in the application binary, but although the ways of dealing with the problem are different, in both cases the operating system can notify a server application of its imminent shutdown, and the application has the ability to perform certain tasks before its process of execution is destroyed.

Scope of this specification

The scope of this specification is to define an API in line with the current Java™ Platform APIs to support an alternative invocation mechanism which could be used instead of the above mentioned public static void main(String[]) method. This specification cover the behavior and life cycle of what we define as "Java ™ services", or, in other words, non interactive Java™ applications.

This specification does not cover how the container of a Java™ service must be implemented, or how to build a native liaison between the operating system and the Service interface, but defines the relation between the an operating system process and the Service implementation life cycle. It should be trivial for implementors to build a native liaison and container for Java™ services.

This specification, together with the related API documentation, can be used by software deveopers to build portable non interactive applications based on the Java™ platform.

The Service interface and its life cycle

The Service interface (defined as follows) is the main interface representing a Java™ service:

package org.apache.service;

public interface Service
extends Runnable {

    public void init(ServiceContext context)
    throws Exception;

    public void run();

    public void die();

    public void destroy();
}

A service is managed through a well defined life cycle that defines how it is loaded, initialized, started, stopped and destroyed. This life cycle is expressed in the API by the init(...), run(), die() and destroy() methods of the Service interface.

Instantiation

The service container is responsible for instantiating services. Because of this, concrete implementations of the Service interface must always expose a public void constructor, which will be used by the service container to create instances of the class. For example:

package mypackage;

import org.apache.service.*;


public class MyService
implements Service {

    /** This constructor must be here. */
    public MyService() {
        super();
        ...
    }
    ...
}

Once the Virtual Machine process is started in the underlying operating system, and the Virtual Machine itself is created and configured, the service container associated with its native liaison constructs a new instance of the concrete class implementing the Service instance. It is not defined by this specification how the instance is constructed, or how many instances of one or more concrete services implementation can coexist in the same Virtual Machine.

As a side note, in case of multiple services running within the scope of the same virtual machine, developers should not rely on static methods and variables for proper operation, as it is advisable for security reasons to load each different service instance in a separate class loader.

Initialization

After the service instance has been constructed, the container must initialize it before it can be started. Initialization is provided so that a service can read persisten configuration data, access native resources, and perform other one-time activities.

Under certain operating systems (typically Unix based operating systems), and if the native liaison of the container supports and it is configured accordingly, this method might be called with super-user privileges. For example, within the scope of this method, it might be wise to create all required ServerSocket instances (as under several operating systems this requires super-user privileges).

That said, it is very important that within the scope of this method "untrusted" data cannot be processed (for example, starting an acceptor thread on a ServerSocket which receives and processes data from unknown sources), as this would serious security hazards.

The service container must guarantee that the init(...) method is called at least once, and only once on an instance of a service object, and that it will be called before any access to the run(), die() or destroy() methods.

During initialization, the service instance can throw any Exception preventing a the successful completion of the init(...) method. In this case the service instance must not be started, and the destroy() method must not be called before the instance is released by the container to allow garbage collecting.

Startup

As the Service interface extends the Runnable interface, to start the operation of a service, the container calls the run() method within the scope of a Thread. A service is said to be "running" until the thread