Platform Service Development Guide

From Agent Factory

Jump to: navigation, search

Contents

Editorial History

??/??/07: Initial Version - Overview of how to write a platform service that is taken directly from an earlier document that outlined the process.

12/06/08: Version 2 - Updated to reflect new PlatformService API that will be released as part of the Agent Factory Run Time Environment Version 1.3.0.

What is a Platform Service?

According to the Foundation for Intelligent Physical Agents (FIPA) standards, the purpose of a platform service is to “provide support services for agents.” That is, a platform service implements some functionality that is needed by one or more agents in order to achieve the tasks that they are assigned.

Typical examples of platform services envisaged by FIPA include Message Transport Services, the Agent Management Service and Directory Facilitator Services. However, the platform services concept can also be applied to other kinds of resource, including shared interfaces to databases, shared file management interfaces, or any other shared system resource.

While this guide aims to provide support for the creation and deployment of platform services, it does not address how an agent can be programmed to bind to and make use of any available platform services. For details of how to program an agent to bind to and use a platform service, please consult the relevant language guides (e.g. the AFAPL Programmers Guide or the ALPHA Programmers Guide).

Platform Services and Agent Factory

Agent Factory (AF) supports the creation of, and access to, platform services through a core component of the AF Agent Platform (AP), known as the Platform Service Manager. Figure 1 below provides a schematic of this agent platform that shows how the Platform Service Manager is responsible for managing the deployment of different platform services, and how it constrains access to those services via a corresponding component of the AP, known as the Security Module.

Figure 1: Schematic of an Agent Factory Agent Platform
Figure 1: Schematic of an Agent Factory Agent Platform


To ensure security of platform services, each agent wishing to use a service, must first bind itself to that service. This binding process is basically a registration process, where the agent declares it intent to use the service. Once bound, the agent has free and un-mediated access to that platform service. Additional benefits gain through the utilization of this binding process include:

  • the ability to allow a platform service to configure itself in order to provide necessary support for the bound agent, and
  • the abiliy to can keep track of which agents are using a given platform service.


Platform Service Lifecycle

As shown in figure 3, a platform service will normally go through 4 key states in its lifecycle:

  • The initialize state is used to initialize and configure the platform service.
  • The start state is used to activate the service, for example, in cases where the service implements a server (e.g. a message transport service), it is at this state that the server is started.
  • The use state is the principal state of a service, and it is in this state the agents may bind to the service, use the service, and unbind from the service.
  • Finally, the stop state is used to deactivate the service, for example, it is during the stop state that a server being used by a message transport service will be shutdown.
Figure 3: The lifecycle of a platform service
Figure 3: The lifecycle of a platform service

Creating a Platform Service

The platform service creation process is responsible for the creation of the platform service and its transition through the first two states in its lifecycle. Figure 4 below uses a UML Sequence Diagram to illustrate the key interactions between the PlatformServiceManager and the PlatformService that is being created.

Figure 4: UML Sequence Diagram depicting the creation of a platform service
Figure 4: UML Sequence Diagram depicting the creation of a platform service

Once the service is started, it enters into the use state. At this point, agents are able to bind to and user the service.

Binding an Agent to a Platform Service

Once a platform service enters the use state, agents are able to bind to it and use it. As described above, binding to a platform service requires that the agent send a binding request to the PlatformServiceManager component. This component first performs a security check to ensure that the agent is allowed to use the service, and then binds the agent to the service. This binding process is illustrated below in figure 5.

Figure 5: UML Sequence Diagram depicting the binding of an agent to a platform service
Figure 5: UML Sequence Diagram depicting the binding of an agent to a platform service

Unbinding an Agent from a Platform Service

To be completed

Destroying a Platform Service

To be completed

Securing Platform Services

In some situations, allowing open access to a platform service can be inappropriate. To deal with this, Agent Factory employs a Security Module component, which maintains a set of policies that defines which agents can access what platform services. Specifically, the Security Module includes a security policy for each platform service. Each security policy defines the global (default) access rights, together with a set of agent specific access rights. Each time an agent attempts to bind to a platform service, the Platform Service Manager requests that the Security Module perform an access check to ensure that the agent is allowed to bind to the specified platform service. A diagrammatical overview of the binding process is presented below in figure 2.

Figure 2: The Platform Service binding process
Figure 2: The Platform Service binding process


The declaration of what services are to be deployed on an agent platform and what security policies are to be used to control access to those services are defined in the Platform Configuration File, details of which are described in the Platform Administrators Guide.

Implementing a Platform Service

In AF, platform services are implemented using Java. Creating a platform service basically involves the implementation of one or more Java classes that extend pre-existing base classes that are provided as part of the core run-time APIs.

The Platform Service API

All platform services must extend the abstract com.agentfactory.platform.service.PlatformService base class. This class implements two core features of a platform service:

  • a unique name, which acts as the service identifier, and
  • a priority, which can be used to specify preference orderings between deployed platform services.

In addition, the PlatformService class also supports the following extension points:

  • an init(...) method that can be used to initialize the platform service;
  • an onBind(...) method that can be used to perform some configuration when an agent is bound to the platform service;
  • an onUnbind(...) method that can be used to add custom code that should be performed when an agent is unbound from the platform service;
  • a onStop() method that should be used to specify any steps that should be performed when the platform service is being terminated; and
  • a onStart() method that should be used to specify the startup steps associated with the service (NOTE: start is performed after init);

Default versions of each of these methods are provided that do nothing; and should be overridden in any concrete platform service.

In addition to the above extension points, the underlying PlatformService class also maintains information about the other agents that are currently bound to the service. To access this information, you can use the getBoundAgents() method, which returns a List of Agent objects.

Example: A Whiteboard Service

To illustrate the concepts associated with the creation and deployment of a platform service, we will implement a simple example service, known as a WhiteBoardService. The basic purpose of this platform service is to provide a shared resource that all agents can use to post information that may be relevant to a shared task. An agent can perform three basic operations: it can put a piece of information onto the whiteboard, it can remove the information that it previously put on to the whiteboard, and get a list of all the information currently on the whiteboard. A constraint on the system is that an agent can only put one piece of information on the whiteboard at a time. Each agent that is bound to the whiteboard can view the information that is added by the other agents.

To implement this platform service, we must first subclass the com.agentfactory.platform.service.PlatformService class, and implement the 5 mandatory platform service methods: init(...), onStart(...), onBind(...), onUnbind(...), and onStop(...) method if necessary. In addition, you must implement a number of service specific methods that realise the functionality required by the service. An outline of the WhiteBoardService class is presented below:

   package whiteboard; 

   import com.agentfactory.platform.service.PlatformServiceDescriptor; 
   import com.agentfactory.platform.service.PlatformServiceManager; 
   import com.agentfactory.platform.service.PlatformService; 
   import java.util.ArrayList; 
   import com.agentfactory.platform.core.Agent;
   
   public class WhiteBoardService extends PlatformService { 
   
       // Mandatory Platform Service Methods
       public void init(PlatformServiceDescriptor descriptor) {} 
    
       public void onStart() {} 
    
       public void onBind(Agent agent) {} 
    
       public void onUnbind(Agent agent) {} 
    
       public void onStop() {} 
    
       // Service Specific Methods
       public synchronized void putInformation(Agent agent, String information) {} 

       public synchronized String removeInformation(Agent agent) { return null; } 
    
       public synchronized List getInformation() { return null; } 
   }

Service Data Members

To implement the WhiteBoardService, we require two data members:

  • Firstly, we need a data structure that can be used to store the information that is placed on the board by the various agents. As each agent can only place one piece of information on the board at a

time, we will use an instance of the java.util.HashMap class. For this service, the key used is the agent’s name, and the value is the information that the agent has put on to the whiteboard.

  • Secondly, we would like to allow users of the service to have the option of a debugging mode. To achieve this, we will assume that the service will take one optional parameter, debug. If the debug parameter is added to the service statement in the Platform Configuration File, then the service will output key debugging information to the console. We will discuss this in more detail later in this chapter, however, for now we need a data member to define whether or not the debugging mode has been activated. This can be done through a boolean data member.

The resulting data members for the WhiteBoardService are:

   private HashMap information; 
   private boolean debug;

Mandatory Platform Service Methods

The init(...) method

This method is called when the service is first created. Its purpose is to perform any initial configuration of the service and to read in any arguments that are specified by the service statement in the Platform Configuration File.

As discussed in the previous section, the WhiteBoardService takes one optional argument, debug, which defines whether or not debugging messages should be displayed to the console.

   public void init(PlatformServiceDescriptor descriptor) { 
       information = new HashMap(); 
       if (descriptor.numberArguments() > 0) { 
           debug = descriptor.getArgument(0).equalsIgnoreCase("debug"); 
       } else { 
           debug = false; 
       } 

       if (debug) System.out.println(“[WhiteBoardService] Debugging Mode Activated.”); 
   }
The onStart() method

This method is called when the service has been successfully created. It is separated from the init(...) method to separate service configuration from service activation. Once the service has been activated, agents are able to bind to the service as appropriate.

In our example, the service does not require any activation steps. However, for debugging purposes (if debugging mode has been activated), we require that the service print a message to the console stating that the service has been started.

   public void onStart() { 
         if (debug) System.out.println(“[WhiteBoardService] Started”); 
   }
The onBind(...) method

This method is called when an agent successfully binds to the service. It should perform any configuration that is necessary.

In the case of our WhiteBoardService, no configuration is necessary. However, for debugging purposes (if debugging mode has been activated), we require that the service display a message on the console stating that an agent has bound itself to the service.

   public void onBind(Agent agent) { 
       if (debug)
           System.out.println(“[WhiteBoardService] “ + agent.getName() + “ has joined the service”);
   }
The unbind(...) method

This method is called when an agent successfully unbinds from a service. The method should remove any references to the agent and undo any relevant configuration.

In the case of the WhiteBoardService, this includes the removal of any messages that the agent has posted to the whiteboard. In addition, for debugging purposes (if debugging mode has been activated), we require that the service display a message on the console stating that an agent has unbound itself from the service.

   public void onUnbind(Agent agent) { 
       information.remove(agent.getName());
       if (debug)
           System.out.println(“[WhiteBoardService] “ + agent.getName() + “ has left the service”); 
   }
The onStop() method

This method is called when the platform service is about to bet terminated. Any steps that are required in order to safely terminate the service should be specified here. For example, this may include closing remote interfaces, database connections, bespoke network connections or any other input-output streams that are being used by the service.

In the case of the WhiteBoardService', no steps are necessary. However, for debugging purposes, (if debugging mode has been activated), we require that the service display a message on the console stating that the service is terminating.

   public void onStop() { 
       if (debug)
           System.out.println(“[WhiteBoardService] Terminating"); 
   }

Service Specific Methods

The putInformation(...) method

This is the first of the service specific methods that are implemented in this example service. This method implements some of the functionality that is required by the service.

Specifically, its purpose is to place some information, provided by the agent, on the whiteboard. The method takes two parameters: the agent that is trying to put the information, and the information that it is trying to put. In our implementation, a message is “put” onto the whiteboard by adding an entry to the information data member. As discussed earlier in this section, the key part of the entry is the agent’s name, and the value part of the entry is the information that the agent wishes to put on the whiteboard.

   public synchronized void putInformation(Agent agent, String info) { 
       information.put(agent.getName(), info);  
       if (debug)
           System.out.print(“[WhiteBoardService] “ + agent.getName() + “ has added: “ + info); 
   } 
    
The removeInformation(...) method

This second method implements more of the functionality provided by the service. Its purpose is to remove the current information, which was previously provided by the agent, from the whiteboard. The method takes one parameter: the agent that is trying to remove the information.

   public synchronized String removeInformation(Agent agent) { 
       if (debug)
           System.out.print(“[WhiteBoardService] Removing Information for “ + agent.getName()); 
       return (String) information.remove(agent.getName());  
   } 
    
The getInformation(...) method

This method is used to generate and return an instance of the java.util.ArrayList class that contains all of the information that is currently on the whiteboard. Ultimately, an agent will use this method to capture the information on the message board, and to use that information to reason about the associated task(s) that it must perform. Consequently, the format in which the information is put into the list is vital.

For the purposes of this service, we choose to use the AFAPL content language format (see the AFAPL Developers Guide for more information about this format). This format is based on the first-order structure, and takes the form of a functor together with a comma-delimited list of arguments that are contained within brackets. Specifically, the functor used is “information” and the arguments are the name of the agent and the information associated with the agent.

   public synchronized List getInformation() { 
       if (debug) System.out.print(“[WhiteBoardService] Getting Information.“); 
       List list = new ArrayList(); 
 
       String key = null;  
       Iterator it = information.keySet().iterator(); 
       while (it.hasNext()) { 
           key = (String) it.next(); 
           list.add(“information(“ + key + “,” + information + “)”); 
       } 
       return list;  
   } 
    

Ultimately, the information returned by this method could be used to generate a set of beliefs outlining what shared information exists and who has shared it.

The Implemented Service

We now put all the bits together, and present the full implementation of our whiteboard service. All that remains now it to construct the agent components that are necessary to use the service and then to implement the agent programs that describe how the service will be used.

   package whiteboard; 

   import com.agentfactory.platform.service.PlatformServiceDescriptor; 
   import com.agentfactory.platform.service.PlatformServiceManager; 
   import com.agentfactory.platform.service.PlatformService; 
   import java.util.HashMap; 
   import java.util.ArrayList; 
   import java.util.Iterator; 
   import com.agentfactory.platform.core.Agent;

   public class WhiteBoardService extends PlatformService { 
    
       private HashMap information; 
       private boolean debug; 

       public void init(PlatformServiceDescriptor descriptor, PlatformServiceManager manager) { 
           information = new HashMap(); 
           if (descriptor.numberArguments() > 0) { 
               debug = descriptor.getArgument(0).equalsIgnoreCase("debug"); 
           } else {
               debug = false; 
           } 
           if (debug) System.out.println(“[WhiteBoardService] Debugging Mode Activated.”); 
       } 
    
       public void onStart() { 
           if (debug) System.out.println(“[WhiteBoardService] Started”); 
       } 
    
       public void onBind(Agent agent) { 
           if (debug)
               System.out.println(“[WhiteBoardService] “ + agent.getName() + “ has joined the service”); 
       } 
    
       public void onUnbind(Agent agent) { 
           information.remove(agent.getName());
           if (debug)
               System.out.println(“[WhiteBoardService] “ + agent.getName() + “ has left the service”); 
       }
   
       public void onStop() { 
           if (debug)
               System.out.println(“[WhiteBoardService] Terminating"); 
       }
 
       public synchronized void putInformation(Agent agent, String info) { 
           information.put(agent.getName(), info);  
           if (debug)
               System.out.print(“[WhiteBoardService] “ + agent.getName() + “ has added: “ + info); 
       } 

       public synchronized String removeInformation(Agent agent) { 
           if (debug)
               System.out.print(“[WhiteBoardService] Removing Information for “ + agent.getName()); 
           return (String) information.remove(agent.getName());  
       } 

       public synchronized List getInformation() { 
           if (debug) System.out.print(“[WhiteBoardService] Getting Information.“); 
           List list = new ArrayList(); 
 
           String key = null;  
           Iterator it = information.keySet().iterator(); 
           while (it.hasNext()) { 
               key = (String) it.next(); 
               list.add(“information(“ + key + “,” + information + “)”); 
           } 
           return list;  
       } 
   }

Compiling the Service from the Command Line

To compile a platform service, you must download the Run-Time Environment (RTE) component of Agent Factory from Sourceforge. Once you have downloaded and installed the RTE (more information on installing AF can be found in the Installation Guides), you can compile the package via the standard Java compiler.

For Linux / Mac:

   javac -cp $AF_HOME/lib/af_rte.jar:. WhiteBoardService.java

For Windows:

   javac -cp %AF_HOME%/lib/af_rte.jar;. WhiteBoardService.java

Once compiled, normal practice for distribution of the service is to package it up into a JAR file that can be deployed either system wide or locally within a project (again, see the Installation Guides for more details on this).

Implementing a Message Transport Service

Message Transport Services are treated as a special class of Platform Service. Specifically, MTS are created by subclassing the com.agentfactory.platform.mts.MessageTransportService abstract base class. This itself extends from the com.agentfactory.platform.service.PlatformService class.

More details on this will follow...

Deploying a Platform Service

To deploy a platform service, you must make a number of changes to the Platform Configuration File (i.e. the .cfg file). Details of the format of this file can be found in the Platform Administrators Guide. In this section, we will describe only those aspects of the PCF that are relevant to a platform service.

For the purposes of this guide, we assume that the compiled platform service is referenced within the class path of the agent platform. If it is not, then we recommend that you create a jar file for your platform service, and that you copy this jar file into the lib folder before you start the agent platform. For more details regarding the file structure employed by Agent Factory, please read the Getting Started Guide.

Configuring the Platform Service

To configure the platform service, you must add a SERVICE statement to the PCF. As is discussed in the Platform Administrators Guide, this statement takes the form:

   SERVICE <service-id> <service-class> [<arg>*]

For our whiteboard service example, let us adopt the identifier: af.eg.wbd. The second parameter of the SERVICE statement is the name of the principle class that implements the service. This is the class that is a subclass of com.agentfactory.platform.service.PlatformService. For our whiteboard service example, the implementing class is: whiteboard.WhiteBoardService.

The final parameter is a set of arguments that are associated with the service. For the whiteboard service, one optional argument is defined. If we wish to run the service in debugging mode, then we must add the debug keyword as an argument. Otherwise, wedo not specify any arguments.

So, to configure the agent platform to include an instance of the whiteboard service that is running in debugging mode, we must should the following SERVICE statement to the PCF:

   SERVICE af.eg.wbd whiteboard.WhiteBoardService debug

Conversely, to configure the agent platform to include an instance of the whiteboard service that is not running in debugging mode, we should add the following SERVICE statement to the PCF:

   SERVICE af.eg.wbd whiteboard.WhiteBoardService

Securing Platform Services

In addition to the SERVICE statement, we must also include a number of SECURITY_POLICY statements to specify what agents should have access to the platform service. As discussed in the Platform Administrators Guide, the SECURITY_POLICY statement takes 3 parameters:

   SECURITY_POLICY <right> <agent-name> <service-id> 

The first parameter specifies what type of right you are defining. For a full list of rights, please consult the Platform Administrators Guide. Here, we will briefly discuss two types of right: the ALLOW right, and the DENY right. The former right can be used to specify agents that are allowed to access the service, while the latter right can be used to specify agents that are not allowed access to the service.

The second parameter of this statement specifies the agent that the right applies to. This may take two types of value: it may take the name of a specific agent, or it may take the “all agents” wildcard, denoted by a “*”. In the former case, the right is taken to apply only to the specified agent, while in the latter case the right is taken to apply to all agents for which a specific policy has not been defined. This general case is known as the global security policy. If no global security policy is defined for a platform service, then the default policy is to DENY access to the platform service.

The final parameter in the SECURITY_POLICY statement identifies the service, identified by the unique service identifier, to which the policy should apply. In the case of the whiteboard service that was discussed earlier in this chapter, the unique service identifier is af.eg.wbd. Consequently, to ALLOW all agents residing of the platform to have access to this service, you should include the following SECURITY_POLICY command in the PCF:

   SECURITY_POLICY ALLOW * af.eg.wbd

If you want to deny a specific agent, say the agent called Rem, access to this service then you should include a statement similar to the following in the PCF:

   SECURITY_POLICY DENY Rem af.eg.wbd

Creating Message Transport Service

TBD