Chapter 16. Using Predefined Capabilities

Jadex uses capabilities for the modularization of agents (see Chapter 5, Capabilities), whereby capabilities contain ready to use functionalities. The Jadex distribution contains several ready-to-use predefined capabilities for different purposes. Besides the basic management capabilties for using the AMS (agent management system, see Section 16.1, “The Agent Management System (AMS) Capability”) and the DF (directory facilitator, see Section 16.2, “The Directory Facilitator (DF) Capability”) also a Protocols capability (Section 16.3, “The Interaction Protocols Capability ”) is available for the efficient usage of some predefined FIPA interaction protocols. The interface of a capability mainly consists of a set of exported goals which is similar to an object-oriented method-based interface description. This chapter aims at depicting their usage by offering the application programmer an overview and explanation of their functionalities and additionally a selection of short code snippets that can directly be used in your applications.

The test capability for writing agent-based unit test is explained in the “Jadex Tool Guide”, which also illustrates the usage of the corresponding Test Center user interface.

16.1. The Agent Management System (AMS) Capability

The Agent Management System (AMS) capability provides goals, that allow the application programmer to use functionalties of the local or some remote AMS. Basically the AMS is responsible for managing the agent lifecycle and for interacting with the platform. Concretely this means the AMS capability can be used for

16.1.1. Creating an Agent

The goal “ams_create_agent” creates a new agent via the AMS on the platform.

This goal has the following parameters:

Table 16.1. Parameters for ams_create_agent

NameTypeDescription
ams * AgentIdentifier The AMS agent identifier (only needed for remote requests).
arguments * Map The arguments as name-value pairs for the new agent. Depending on the platform, Java objects (for Jadex Standalone or local JADE requests) or string expressions (for remote JADE requests) have to be supplied for the argument values.
configuration * String The initial agent configuration to use.
name * String The name of the instance to create. If no name is specified, a name will be generated automatically.
type String The type (e.g. XML file name) of the agent you want to create.
start Boolean True, when the agent shoudl be directly started after creation (default). Note that some platforms will not support decoupling of agent creation and starting (e.g. for remote requests in JADE).
agentidentifier [out] AgentIdentifier Output parameter containing the agent identifier of the created agent.

*: optional parameter

To use the “ams_create_agent”-goal, you must first of all include the AMS-capability in your ADF (if not yet done in order to use other goals of the AMS-capability) and set a reference to the goal as described in Figure 16.1, “ Including the AMS capability and the ams_create_agent-goal ”. The name of the goal reference can be arbitrarily chosen, but it will be assumed here for convenience that the same as the original name will be used.

...
<capabilities>
    <capability name="amscap" file="jadex.planlib.AMS" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="ams_create_agent">
        <concrete ref="amscap.ams_create_agent" />
    </achievegoalref>
    ...
</goals>
...

Figure 16.1.  Including the AMS capability and the ams_create_agent-goal

Now you can use this goal to create an agent in your plan:

public void body() {
    ...
    IGoal ca = createGoal("ams_create_agent");
    ca.getParameter("type").setValue("mypackage.MyAgent");
    dispatchSubgoalAndWait(ca);
    AgentIdentifier createdagent = (AgentIdentifier)
        ca.getParameter("agentidentifier").getValue();
    ...
}

Figure 16.2. Creating an agent on a local platform

In listing Figure 16.2, “Creating an agent on a local platform” - in order to create an agent - you instantiate a new goal using the createGoal()-method with the paramter “ams_create_agent”. Then you set its parameters to the desired values, dispatch the subgoal and wait. After the goal has succeeded, you can fetch the AgentIdentifier of the created agent by calling the getValue()-method on the parameter “agentidentifier”.

The same goal is used for remote creation of an agent:

public void body() {
    AgentIdentifier ams = new AgentIdentifier("ams@remoteplatform",
        new String[]{"nio-mtp://134.100.11.232:5678"});
    IGoal ca = createGoal("ams_create_agent");
    ca.getParameter("type").setValue("mypackage.MyAgent");
    ca.getParameter("ams").setValue(ams);
    dispatchSubgoalAndWait(ca);
    AgentIdentifier createdagent = (AgentIdentifier)
        ca.getParameter("agentidentifier").getValue();
   ...
}

Figure 16.3. Creating an agent on a remote platform

In the listing Figure 16.3, “Creating an agent on a remote platform” you can see how to create an agent on a remote platform using its remote AMS. In order to do so, it's of course crucial that you know at least one address of the remote AMS. Moreover, the corresponding transport must be available on the local platform. The transport used by the other platform can be recognized by the prefix of the address (ending with the ://). In this case the prefix is nio-mtp://, which represents the transport jadex.adapter.standalone.transport.niotcpmtp.NIOTCPTransport.

If you know the address of the remote AMS and you're sure that the local platform supports its transport, you must instantiate an AgentIdentifier and set its name and address to that of the AMS that shall create a new agent.

Thereafter you can instantiate a new goal using the createGoal()-method with the paramter “ams_create_agent”. Then you set its parameters to the desired values, dispatch the subgoal and wait. After the goal has succeeded, you can fetch the AgentIdentifier of the created agent by calling the getValue()-method on the parameter “agentidentifier”.

16.1.2. Starting an Agent

The AMS offers the goal “ams_start_agent” to give the application programmer the possibility to start agents, both on the local or a remote platform. This goal is useful if the creation and starting of agents should be decoupled, meaning that you want first to create an agent and start it afterwards.

The goal has the following parameters:

Table 16.2. Parameters for ams_start_agent

NameTypeDescription
agentidentifier AgentIdentifier The identifier of the agent that should be started.
ams * AgentIdentifier The AMS agent identifier (only needed for remote requests).

*: optional parameter

To use the “ams_start_agent”-goal, you must first of all include the AMS-capability in your ADF (if not yet done in order to use other goals of the AMS-capability) and set a reference to the goal as described in Figure 16.4, “ Including the AMS capability and the ams_start_agent-goal ”.

...
<capabilities>
    <capability name="amscap" file="jadex.planlib.AMS" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="ams_start_agent">
        <concrete ref="amscap.ams_start_agent" />
    </achievegoalref>
    ...
</goals>
...

Figure 16.4.  Including the AMS capability and the ams_start_agent-goal

Thus you can start an agent in your plan:

public void body() {
    // Fetching the agent identifier after creating
    AgentIdentifier createdagent = (AgentIdentifier)
         ca.getParameter("agentidentifier").getValue();

    IGoal sa = createGoal("ams_start_agent");
    // sa.getParameter("ams").setValue(ams);  // Set ams in case of remote platform
    sa.getParameter("agentidentifier").setValue(createdagent);
    dispatchSubgoalAndWait(sa);
    ...
}

Figure 16.5. Starting an agent on a local/remote platform

In listing Figure 16.5, “Starting an agent on a local/remote platform” - in order to start an agent - you instantiate a new goal using the createGoal()-method with the paramter “ams_start_agent”. Then you set its agentidentifier-parameter to the desired value, dispatch the subgoal and wait for success. If you want to start the agent on a remote platform the only difference is that you need to supply the agent identifier of the remote AMS.

16.1.3. Destroying an Agent

The AMS offers the goal “ams_destroy_agent” to give the application programmer the possibility to destroy agents, both on a local as well as on remote platforms.

The goal has the following parameters:

Table 16.3. Parameters for ams_destroy_agent

NameTypeDescription
agentidentifier AgentIdentifier The identifier of the agent that should be destroyed.
ams * AgentIdentifier The AMS agent identifier (only needed for remote requests).

*: optional parameter

To use the “ams_destroy_agent”-goal, you must first of all include the AMS-capability in your ADF (if not yet done in order to use other goals of the AMS-capability) and set a reference to the goal as described in Figure 16.6, “ Including the AMS capability and the ams_destroy_agent-goal ”.

...
<capabilities>
    <capability name="amscap" file="jadex.planlib.AMS" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="ams_destroy_agent">
        <concrete ref="amscap.ams_destroy_agent" />
    </achievegoalref>
    ...
</goals>
...

Figure 16.6.  Including the AMS capability and the ams_destroy_agent-goal

Thus you can destroy an agent in your plan:

public void body() {
    IGoal da = createGoal("ams_destroy_agent");
    da.getParameter("agentidentifier").setValue(createdagent);
    // da.getParameter("ams").setValue(ams);  // Set ams in case of remote platform
    dispatchSubgoalAndWait(da);
    ...
}

Figure 16.7. Destroying an agent on a local/remote platform

In listing Figure 16.7, “Destroying an agent on a local/remote platform” - in order to destroy an agent - you instantiate a new goal using the createGoal()-method with the paramter “ams_destroy_agent”. Then you set its agentidentifier-parameter to the desired value, dispatch the subgoal and wait for success. The same goal is used to destroy a remote agent. In this case you only have to additionally supply the remote AMS agent identifier.

16.1.4. Suspending an Agent

The AMS offers the goals “ams_suspend_agent” and “ams_resume_agent” in order to suspend the execution of an agent and later resume. When an agent gets suspended the platform will not process any actions of this agent. Nevertheless, the agent is able to receive messages from other agents and will process them when its execution is resumed.

The “ams_suspend_agent”-goal has the following input parameters:

Table 16.4. Parameters for ams_destroy_agent

NameTypeDescription
agentidentifier AgentIdentifier The identifier of the agent that should be suspended.
ams * AgentIdentifier The AMS agent identifier (only needed for remote requests).
agentdescription [out] AMSAgentDescription This output parameter contains the possibly changed AMSAgentDescription of the suspended agent.

*: optional parameter

To use the “ams_suspend_agent”-goal, you must first of all include the AMS-capability in your ADF (if not yet done in order to use other goals of the AMS-capability) and set a reference to the goal as described in Figure 16.8, “ Including the AMS capability and the ams_suspend_agent-goal ”.

...
<capabilities>
    <capability name="amscap" file="jadex.planlib.AMS" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="ams_suspend_agent">
        <concrete ref="amscap.ams_suspend_agent" />
    </achievegoalref>
    ...
</goals>
...

Figure 16.8.  Including the AMS capability and the ams_suspend_agent-goal

Thus you can suspend an agent in your plan:

public void body() {
    AgentIdentifier agent;  // The agent to suspend
    ...
    IGoal sa = createGoal("ams_suspend_agent");
    sa.getParameter("agentidentifier").setValue(agent);
    // sa.getParameter("ams").setValue(ams);  // Set ams in case of remote platform
    dispatchSubgoalAndWait(sa);
    ...
}

Figure 16.9. Suspending an agent on a local/remote platform

In listing Figure 16.9, “Suspending an agent on a local/remote platform” - in order to suspend an agent - you instantiate a new goal using the createGoal()-method with the paramter “ams_suspend_agent”. Then you set its agentidentifier-parameter to the desired value, dispatch the subgoal and wait for success. As result the goal returns a possibly modified AMS agent description of the suspended agent. The same goal is used to suspend a remote agent. In this case you only have to additionally supply the remote AMS agent identifier.

16.1.5. Resuming an Agent

If you want to resume a suspended agent you can use the goal “ams_resume_agent”. It offers the following input parameters:

Table 16.5. Parameters for ams_resume_agent

NameTypeDescription
agentidentifier AgentIdentifier The identifier of the agent that you want to resume its execution.
ams * AgentIdentifier The AMS agent identifier (only needed for remote requests).
agentdescription [out] AMSAgentDescription The output parameter of this goal contains the possibly changed AMSAgentDescription.

*: optional parameter

To use the “ams_resume_agent”-goal, you must first of all include the AMS-capability in your ADF (if not yet done in order to use other goals of the AMS-capability) and set a reference to the goal as described in Figure 16.10, “ Including the AMS capability and the ams_resume_agent-goal ”.

...
<capabilities>
    <capability name="amscap" file="jadex.planlib.AMS" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="ams_resume_agent">
        <concrete ref="amscap.ams_resume_agent" />
    </achievegoalref>
    ...
</goals>
...

Figure 16.10.  Including the AMS capability and the ams_resume_agent-goal

Thus you can resume an agent in your plan:

public void body() {
    AgentIdentifier agent;  // The agent to resume
    ...
    IGoal ra = createGoal("ams_resume_agent");
    ra.getParameter("agentidentifier").setValue(agent);
    // ra.getParameter("ams").setValue(ams);  // Set ams in case of remote platform
    dispatchSubgoalAndWait(ra);
    ...
}

Figure 16.11. Resuming an agent on a local/remote platform

In listing Figure 16.11, “Resuming an agent on a local/remote platform” - in order to resume an agent - you instantiate a new goal using the createGoal()-method with the paramter “ams_resume_agent”. Then you set its agentidentifier-parameter to the desired value, dispatch the subgoal and wait for success. As result the goal returns a possibly modified AMS agent description of the resumed agent. The same goal is used to resume a remote agent. In this case you only have to additionally supply the remote AMS agent identifier.

16.1.6. Searching for Agents

The goal "ams_search_agents" allows you to search for agents, both on the local platform and on remote platforms, thereby determining if the agent is available at all and learning about its state (e.g. active or suspended).

The goal has the following parameters:

Table 16.6. Parameters for ams_search_agents

NameTypeDescription
ams * AgentIdentifier The AMS agent identifier (only needed for remote requests).
constraints * SearchConstraints Representation of a set of constraints to limit the search process. See FIPA Agent Management Specification.
description AMSAgentDescription The AMSAgentDescription of the agent that you search for.
result [set][out] AMSAgentDescription This output parameter set contains the agent descriptions that have been found.

*: optional parameter

To use the “ams_search_agents”-goal, you must first of all include the AMS-capability in your ADF (if not yet done in order to use other goals of the AMS-capability) and set a reference to the goal as described in Figure 16.12, “ Including the AMS capability and the ams_search_agents-goal ”.

...
<capabilities>
    <capability name="amscap" file="jadex.planlib.AMS" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="ams_search_agents">
        <concrete ref="amscap.ams_search_agents" />
    </achievegoalref>
    ...
</goals>
...

Figure 16.12.  Including the AMS capability and the ams_search_agents-goal

To search for agents in your plan use the goal in the following manner:

public void body() {
    AMSAgentDescription desc = new AMSAgentDescription(new AgentIdentifier("a1", true));
    IGoal search	= createGoal("ams_search_agents");
    search.getParameter("description").setValue(desc);
    // search.getParameter("ams").setValue(ams);  // Set ams in case of remote platform
    dispatchSubgoalAndWait(search);
    AMSAgentDescription[] result = (AMSAgentDescription[])
    search.getParameterSet("result").getValues();
    ...
}
				

Figure 16.13. Searching an agent on a local/remote platform

In listing Figure 16.13, “Searching an agent on a local/remote platform” - in order to search for an agent - you instantiate a new goal using the createGoal()-method with the paramter “ams_search_agents”. The search is constrained by an AMS agent description that need to be provided. You could e.g. create an AMSAgentDescription with a new AgentIdentifier and the boolean true for a local agent as parameter, that is defined only by its name. Then you set its description-parameter to that just created AMSAgentDescription, dispatch the subgoal and wait for success. Supplying an empty agent description with agent identifier of null allows to perform an unconstrained search, i.e. returning all agents on the platform. In case of a remote request you have to set the agent identifier of the remote AMS well.

16.1.7. Shutting Down a Platform

The goal “ams_shutdown_platform” shuts down the platform on which a given AMS is running.

This goal has the following parameters:

Table 16.7. Parameters for ams_shutdown_platform

NameTypeDescription
ams * AgentIdentifier The AMS agent identifier (only needed for remote requests).

*: optional parameter

To use the “ams_shutdown_platform”-goal, you must first of all include the AMS-capability in your ADF (if not yet done in order to use other goals of the AMS-capability) and set a reference to the goal as described in Figure 16.14, “ Including the AMS capability and the ams_shutdown_platform-goal ”.

...
<capabilities>
    <capability name="amscap" file="jadex.planlib.AMS" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="ams_shutdown_platform">
        <concrete ref="amscap.ams_shutdown_platform" />
    </achievegoalref>
    ...
</goals>
...

Figure 16.14.  Including the AMS capability and the ams_shutdown_platform-goal

public void body() {
    IGoal sd = createGoal("ams_shutdown_platform");
    // sd.getParameter("ams").setValue(ams);  // Set ams in case of remote platform
    dispatchSubgoal(sd);
}

Figure 16.15. Shutting down a local/remote platform

In order to shutdown the local platform you instantiate a new goal using the createGoal()-method with the paramter “ams_shutdown_platform” and then dispatch the goal (see listing Figure 16.15, “Shutting down a local/remote platform”). If you want to shutdown a remote platform you have additionally to set the value of the ams parameter to the agent identifier of the remote platform AMS.

16.2. The Directory Facilitator (DF) Capability

The directory facilitator allows the agents to register their services and search for the services offered by other agents. In order to avoid that there are registered services in the DF, that are no longer available, e.g. because the agent offering the service has been destroyed without deregistering its services, Jadex can use “lease times”, that is, the agent's service is only kept registered for that lease time and has to be refreshed by the agent before the lease time expires.

So if you're working with lease times, you have two possibilities of registering an agent. Either you register the agent's service only for the lease time by using the achieve-goal “df_register” with the option to manually refresh the registration with a “df_modify” achieve-goal, or you use the maintain-goal “df_keep_registered” that refreshes the registration automatically.

Depending on the kind of registration you chose, you can deregister an agent, either by using the “df_deregister”-goal as counterpart of “df_register” or you must first call the method drop() on the instance of the maintain-goal “df_keep_registered” and afterwards use a “df_deregister”-goal or keep the (now outdated registration) until the lease time expires.

The DF works with service descriptions. They are specified in the FIPA Agent Management Specification. Generally the agent services are described in form of DF service descriptions which belong to a DF agent description that additionally might contain information about the agent itself.

Concretely this means the DF capability can be used for

16.2.1. Registering an Agent Description

For the registration of an agent description at a DF the “df_register”-goal can be used. This goal is immediately finished after the registration has been performed (or failed). When using “lease times” you can register a service temporarily by using the “df_register”- goal (see Section 16.2, “The Directory Facilitator (DF) Capability”). When not using “lease times” you can use this goal to register the service permanently.

The goal has the following parameters:

Table 16.8. Parameters for df_register

NameTypeDescription
description AgentDescription The agent description containing an arbitrary number of service descriptions to beregistered.
df * AgentIdentifier The DF at which the service shall be registered. Can be used for remote registration.
leasetime * Long The duration of the registration in ms. When a permanent registration is desired, the lease time can be ommitted.
result [out] AgentDescription This output parameter contains the AgentDescription hat has been registered.

*: optional parameter

To use the “df_register”-goal, you must first of all include the DF-capability in your ADF (if not yet done in order to use other goals of the DF-capability) and set a reference to the goal as described in Figure 16.16, “ Including the DF capability and the df_register-goal ”.

...
<capabilities>
    <capability name="dfcap" file="jadex.planlib.DF" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="df_register">
        <concrete ref="dfcap.df_register"/>
    </achievegoalref>
    ...
</goals>
...

Figure 16.16.  Including the DF capability and the df_register-goal

To register an agent with the above mentioned goal proceed in the following way:

public void body() {
    // Create an agent description with service descriptions
    
    ServiceDescription service1 = new ServiceDescription(
        "service_1", "type of service_1", "owner of service_1");

    // Define some characteristics of the services
    String[] languages = new String[]{"language_1", "language_2"};
    String[] ontologies = new String[]{"ontology_1", "ontology_2"};
    String[] protocols = new String[]{"protocol_1", "protocol_2"};

    Property[] properties = new Property[]{
        new Property("property_1", "value_1"),
        new Property("property_2", "value_2")};

    ServiceDescription service2 = SFipa.createServiceDescription(
        "service_2", "type of service_2", "owner of service_2",
        languages, ontologies, protocols, properties);
	
    ServiceDescription[] services = new ServiceDescription[]{service1, service2};

    AgentDescription desc = SFipa.createAgentDescription(null, services, null, null, null);

    IGoal register = createGoal("df_register");
    register.getParameter("description").setValue(desc);
    
    // For a remote DF
    // AgentIdentifier df = ...
    // register.getParameter("df").setValue(df);

    dispatchSubgoalAndWait(register);
    ...
}

Figure 16.17.  Registering an agent description with the df_register goal at a DF

To register a service, you first have to create service descriptions.

When creating a new service description you can define the service name, the service type, the ownership of the service, an array of the languages understood by the service, an array of the ontologies known by the service, an array of the protocols used by the service and last any additional service properties in an array of jadex.adapter.fipa.Property. The property is used to specify parameter/value-pairs and the specification can be found at FIPA Agent Management Specification

After having defined the service descriptions it is necessary to add those to an agent description for the agent.

For the registration a “df_register” goal needs to be created and dispatched. It is necessary to set the parameter "description" to the agent description that should be registered. If you want to register the services to a DF on a remote platform, you also have to set the parameter “df” to the agent identifier of the remote DF.

Finally, you can dispatch the goal and the service should be registered if the goal is successful.

As long as the agent's services are registered at the DF, the only way to add or remove a part of the services is to use the “df_modify”-method (see Section 16.2.3, “Modifying a registration”. Other attempts of registration by the yet registered agent will fail unless you deregister the agent before.

Instead of instantiating the goals in a plan, you can also use an initial goal in your ADF:

...
<configurations>
    <configuration name="default">
        ...
        <goals>
            <initialgoal ref="df_register">
                <parameter ref="description">
                    <value>
                        SFipa.createAgentDescription(null, 
                        SFipa.createServiceDescription("offered_service",
                        "my_agent", "me"))
                    </value>
                </parameter>
                <parameter ref="leasetime">
                    <value>100000</value>
                </parameter>
            </initialgoal>				
        </goals>
        ...
    </configuration>
</configurations>
...

Figure 16.18.  Registering an agent description with an initial goal

16.2.2. Keeping an agent description registered

In contrast to a “df_register”-goal a “df_keep_registered”-goal can be used when one wants to ensure that an agent description remains available at the DF as long as the goal is present in the agent. As it is a maintain goal it will persist unless it will be dropped intentionally. The goal tries to register the contained agent description at the DF an renews its registration whenever it threatens to expire. This means you can using you can register an agent description permanently even with “lease times” by using the “df_keep_registered”-goal (see Section 16.2, “The Directory Facilitator (DF) Capability”).

The goal has the following parameters:

Table 16.9. Parameters for df_keep_registered

NameTypeDescription
description AgentDescription The AgentDescription to be registered.
df * AgentIdentifier The (remote) DF at which the service shall be registered.
leasetime * Long The duration of the registration in ms.
buffertime Long This parameter specifies when to refresh a registration with lease time again, e.g. a buffertime of 5000 ms means that 5 seconds before the lease time will expire the new registration process restarts. This shall guarantee that the agenent won't be deregistered before it is newly registered. The default is 3000 ms.
result [out] AgentDescription This output parameter contains the AgentDescription that has been registered at the DF.

*: optional parameter

Please note that the buffertime is per default set to 3000 ms, so any lease time must be greater than 3000 ms if you don't change the buffertime.

To use the “df_keep_registered”-goal, you must first of all include the DF-capability in your ADF (if not yet done in order to use other goals of the DF-capability) and set a reference to the goal as described in Figure 16.19, “ Including the DF capability and the df_keep_registered-goal ”.

...
<capabilities>
    <capability name="dfcap" file="jadex.planlib.DF" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="df_keep_registered">
        <concrete ref="dfcap.df_keep_registered"/>
    </achievegoalref>
    ...
</goals>
...

Figure 16.19.  Including the DF capability and the df_keep_registered-goal

Now you can register an agent:

public void body() {
    AgentDescription desc = ...

    // Alternative for setting the lease time as goal-parameter
    //desc.setLeaseTime(new Date(System.currentTimeMillis() + 20000));

    IGoal keep = createGoal("df_keep_registered");
    keep.getParameter("description").setValue(desc);
    keep.getParameter("leasetime").setValue(new Long(20000));
    // For a remote DF
    // AgentIdentifier df = ...
    // keep.getParameter("df").setValue(df);
    dispatchSubgoalAndWait(df_keep_registered, 2000);
    AgentDescription resdesc = ((AgentDescription)df_keep_registered
        .getParameter("result").getValue());
    ServiceDescription[] descriptions = resdesc.getServices();
    ...
}

Figure 16.20.  Registering an agent description with the df_keep_registered goal at a DF

In order to keep an agent description registered, you have to create the goal using the createGoal()-method and then set its parameters to the agent description that you want to register and the lease time to the preferred value. If you want to use a remote DF you have additionally to specify its agent identifier in the corresponding parameter. Thereafter, you dispatch the goal and wait for until it is registered and the wait returns. Now the agent description will be registered as long as the agent is alive and the goal is not dropped. The current agent description that was registered can be fetched using the result parameter as shown in the code snippet above.

When dispatching the “keep registered” goal as a subgoal, it will only be adopted as long the corresponding plan is running. If you want the agent to maintain its registration even after the plan has finished, you should dispatch the goal as a top-level goal. Instead of disptaching the top-level goal from a plan, you can also use an initial goal in your ADF:

...
<configurations>
    <configuration name="default">
        ...
        <goals>
            <initialgoal ref="df_keep_registered">
                <parameter ref="description">
                    <value>
                        SFipa.createAgentDescription(null, 
                        SFipa.createServiceDescription("offered_service",
                        "my_agent", "me"))
                    </value>
                </parameter>
                <parameter ref="leasetime">
                    <value>120000</value>
                </parameter>
            </initialgoal>				
        </goals>
        ...
    </configuration>
</configurations>
...

Figure 16.21.  Registering services as initial goal

16.2.3. Modifying a registration

In order to change an agent description that is already registered at the DF the “df_modify”-goal can be used, e.g. if you want to register more services or - in case of temporary registration - you want to increase the lease time.

The goal has the following parameters:

Table 16.10. Parameters for df_modify

NameTypeDescription
description AgentDescription The changed agent description.
df * AgentIdentifier The DF at which the service is registered.
leasetime * Long The duration of the registration in ms.
result [out] AgentDescription This output parameter contains the current agent description that is registered at the DF.

*: optional parameter

To use the “df_modify”-goal, you have to include the DF-capability in your ADF (if not yet done in order to use other goals of the DF-capability) and set a reference to the goal as described in Figure 16.22, “ Including the DF capability and the df_modify-goal ”.

...
<capabilities>
    <capability name="dfcap" file="jadex.planlib.DF" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="df_modify">
        <concrete ref="dfcap.df_modify"/>
    </achievegoalref>
    ...
</goals>
...

Figure 16.22.  Including the DF capability and the df_modify-goal

To modify a registration use the df_modify-goal that way:

public void body() {
    AgentDescription desc = ...
    IGoal modify = createGoal("df_modify");
    modify.getParameter("description").setValue(desc);
    // Set the leasetime up to one day
    modify.getParameter("leasetime").setValue(new Long(86400000));
    // For a remote DF
    // AgentIdentifier df = ...
    // modify.getParameter("df").setValue(df);
    dispatchSubgoalAndWait(modify);			
    AgentDescription resdesc = ((AgentDescription) 
        modify.getParameter("result").getValue());
    ...
}

Figure 16.23. Modifying a DF-registration

The modification of an already registered agent description requires that a “df_modify”-goal is created and its description parameter is set to the modified agent description. If the lease time should be refreshed you can set the lease duration in the leasetime parameter. If you want to use a remote DF you have to specify its agent identifier in the corresponding parameter.

Using the “result”-parameter, you can get the agent description with the services that have been registered and the current absolute lease time.

16.2.4. Deregistration of services

How you deregister services depends on the way that registered them. If you used the “df_register”-goal to register the services, you can use its pendant “df_deregister”. Whereas if you used the “df_keep_registered”-goal, you must first invoke the drop()-method on that goal (see Section 16.2.4, “Deregistration of services”) and can then deregister the agent description by using the “df_deregister” goal.

The goal “df_deregister” has the following parameters:

Table 16.11. Parameters for df_deregister

NameTypeDescription
description * AgentDescription The AgentDescription to be removed from the DF.
df * AgentIdentifier The DF at which the service to remove is registered.

*: optional parameter

To use the “df_deregister”-goal, you must first of all include the DF-capability in your ADF (if not yet done in order to use other goals of the DF-capability) and set a reference to the goal as described in Figure 16.24, “ Including the DF capability and the df_deregister-goal ”.

...
<capabilities>
    <capability name="dfcap" file="jadex.planlib.DF" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="df_deregister">
        <concrete ref="dfcap.df_deregister"/>
    </achievegoalref>
    ...
</goals>
...

Figure 16.24.  Including the DF capability and the df_deregister-goal

public void body() {
    IGoal deregister = createGoal("df_deregister");
    //AgentDescription desc = ...
    //deregister.getParameter("description").setValue(descript);

    dispatchSubgoalAndWait(deregister);
    ...
}

Figure 16.25. Deregistering a DF-registration

If you want to deregister the agents own agent description the goal just needs to be created and can directly be dispatched. In case of a deregistration of an agent description of another agent it is necessary to set the optional “description”-parameter of the goal to the agent description of that agent. This agent description should at least contain the agent identifier of the agent to deregister. If you only want to remove some of the registered services, you need to use the “df_modify”-goal.

As mentioned above, if you used the “df_keep_registered”-goal, you first have to get rid of that goal by invoking the method drop() on it (see Figure 16.26, “Dropping the df_keep_registered-goal”). Otherwise it will register the agent again.

public void body() {
    IGoal keep = createGoal("df_keep_registered);
    ...
    dispatchSubgoal(keep);
    ...
    keep.drop();
    ...
}

Figure 16.26. Dropping the df_keep_registered-goal

16.2.5. Searching for agents and services

The “df_search”-goal offers the possibility to search for agents and services registered at a DF.

It has the following parameters:

Table 16.12. Parameters of the df_search-goal

NameTypeDescription
constraints * SearchConstraints Representation of a set of constraints to limit the searching. See FIPA Agent Management Specification.
description AgentDescription The AgentDescription that shall be searched for.
df * AgentIdentifier The DF that shall be searched. Necessary for remote search requests.
result [set][out] AgentDescription This output parameter set contains all the agent descriptions that have been found.

*: optional parameter

To use the “df_search”-goal, you have to include the DF-capability in your ADF (if not yet done in order to use other goals of the DF-capability) and set a reference to the goal as described in Figure 16.27, “ Including the DF capability and the df_search-goal ”.

...
<capabilities>
    <capability name="dfcap" file="jadex.planlib.DF" />
    ...
</capabilities>
...
<goals>
    <achievegoalref name="df_search">
        <concrete ref="dfcap.df_search"/>
    </achievegoalref>
    ...
</goals>
...

Figure 16.27.  Including the DF capability and the df_search-goal

public void body() {
    // Search for a service with given type.
    IGoal df_search = createGoal("df_search");
    AgentDescription desc = new AgentDescription();
    desc.addService(new ServiceDescription(null, "type of service_1", null))
    df_search.getParameter("description").setValue(desc);
    // For a remote DF
    // AgentIdentifier df = ...
    // modify.getParameter("df").setValue(df);
    dispatchSubgoalAndWait(df_search);
    AgentDescription[] result = (AgentDescription[])df_search
        .getParameterSet("result").getValues();
    if(result.length != 0) {
        AgentIdentifier[] serviceproviders = new AgentIdentifier[result.length];
        for(int i = 0; i < result.length; i++)
            serviceproviders[i] = result[i].getName();
    }		
    ...
}

Figure 16.28. Searching at a DF

In order to search for agents, you first have to create the “df_search”-goal, then you have to create the agent description you search for and set the goal's parameter to it. Optionally you can set some search constraints on the goal that can be used to limit the number of search results (per default this number is not limited). Thereafter you can dispatch the goal and wait. When the goal returns you can fetch the results by invoking getParameterSet("result").getValues() on the goal and cast it to an array of agent descriptions. If you are interested in the agent identifiers of the service providers you can retrieve them via calling getName() on an agent description.

16.3. The Interaction Protocols Capability

Interaction protocols are predefined patterns of allowed message sequences that are designed for different interaction purposes. As certain kinds of interaction objectives are useful in different kinds of application domains FIPA has standardized several domain-independent protocols. Jadex offers built-in support for most of these FIPA protocols and hence facilitates the task of building standardized interactions.

The FIPA specifications define interaction protocols by using AUML sequence diagrams [Bauer et al. 2001]. These sequence diagrams specify the roles of the participating agents, their cardinality and the allowed message occurrences. The specifications do not consider how these protocols should be systematically related to necessary domain activities. Therefore, the protocol- domain interactions have been analyzed and led to the extended specification of goal-oriented interaction protocols. These protocol descriptions devide each role into two distinct parts: the domain and the protocol layer. Together both layers encapsulate the whole functionality of a role. This separation has the objective to make explicit the interaction point between both. The interaction points are defined by the start and the end of the activity (denoted by arrows in the AUML diagrams) and also by the goal signature which shows the purpose of the activity. In addition, the goal signatures contain detailed information about the in- and out-parameters that are used to parametrize the invocations.

The protocols capability offers implementations of the following FIPA interaction protocol specifications:

The protocols capability contains the functionality of the initiator as well as the participant sides of the interactions. To use the functionality of the protocols capability it is necessary to include it within the capability section of the ADF. Generally, if the agent should be enabled to initiate protocols it is also required to reference the corresponding initiator goal types, e.g. for the request protocol the rp_initiate goal type. Within plans a protocol can be started by creating a goal instance of a initiator goal type, setting the needed parameter value and dispatching it. After the protocol has ended the results can be directly read out of the out-parameters of the goal.

On the other hand the participant side of the protocols capability depends not only referencing necessary receiver goals but also on belief settings. Per default the participant role of the capability is turned off meaning that no messages will be handled by it. If you want to use it for handling protocols it is necessary to determine as exactly as possible which kinds of initiator messages should be accepted. For that purpose for each of the supported protocols a filter belief has been defined, e.g. the belief rp_filter is used to determine which request messages should trigger the capability. If the initial fact is set to IFilter.ALWAYS all request messages will be delegated to the capability. Normally, it is advisable to further constrain the kinds of messages that should be routed into the capability by using a custom filter expression.

In the following the meaning and usage of the different protocols will be described in more detail.

16.3.1. FIPA Request Interaction Protocol (RP)

The Request Interaction Protocol (SC00026H) manages the interaction consisting of one initiator and one participant agent. The initiator wants the participant to perform some action.

The Request Protocol

Figure 16.29.  The Request Protocol

The protocol consists of a initiator and a participant side (cf. Figure 16.29, “ The Request Protocol ”). The initiator asks the participant to perform an action by sending a request message. When the participant receives this message it accepts or refuses to perform the action and dependent on that decision it either sends an optional agree message or a refuse message. If it has agreed, the participant subsequently performs the action and when it has finished, the participant sends a failure or an inform message. The inform message may be just a notification that the task was done or contain a result of the task execution.

In Jadex, the Protocols capability offers four corresponding goals. One for the initiator and three for the participant side. Namely “rp_initiate”, “rp_receiver_interaction”, “rp_decide_request” and “rp_execute_request”.

16.3.1.1. Initiator Side

From the view of the initiator side the protocol can be executed completely with dispatching the “rp_initiate”-goal and waiting for its completion.

It has the following parameters:

Table 16.13. Parameters for rp_initiate

NameTypeDescription
action Object The action to be performed by the requested agent.
receiver AgentIdentifier The receiver of the request.
language * String The language to be used in the interaction (for the marshalling of the action and result objects).
ontology * String The ontology to be used in the interaction (for the marshalling of the action and result objects).
timeout * Long The timeout for the request.
interaction_state [out] InteractionState An object allowing to inspect the interaction state after protocol execution.
result [out] Object The result of the protocol execution (if sent in the inform message).

*: optional parameter

In the code snippets below it is shown what needs to be done for starting a request protocol. First, the capability and the rp_initiate goal need to be included as depicted in Figure 16.30, “Inclusion of the rp_initiate goal”. From within a plan the protocol can be started by creating a corresponsing goal instance, setting its parameters to the desired values and dispatching it (cf. Figure 16.31, “Using the rp_initiate goal”). When the goal has finished the results of the protocol execution can be fetched.

...
<capabilities>
    <capability name="procap" file="jadex.planlib.Protocols"/>
    ...
</capabilities>
...
<goals>
    ...
    <achievegoalref name="rp_initiate">
        <concrete ref="procap.rp_initiate"/>
    </achievegoalref>
</goals>
...				

Figure 16.30. Inclusion of the rp_initiate goal

public void body() {
    AgentIdentifier rec = ...
    Object action = ...
    IGoal request = createGoal("rp_initiate");
    request.getParameter("action").setValue(action);
    request.getParameter("receiver").setValue(rec);
    dispatchSubgoalAndWait(request);	
    Object res = request.getParameter("result").getValue();
    ...
}				

Figure 16.31. Using the rp_initiate goal

16.3.1.2. Participant Side

On the participant side a request protocol can be triggered when the rp_filter belief value allows this (per default it is turned off). When a request message arrives that passes the rp_filter a new “rp_receiver_interaction” goal is created. This goal is present during the whole lifetime of the interaction and will contain the results and interaction state of the conversation. If the participant side wants to be informed about the outcome of its conversations it can do so by waiting for the completion of this goal (using the goalfinished trigger type). For the implementation of the requesters domain functionality two goals can be used. If the conversation is handled by the capability it will request domain activities by dispatching subgoals which should be handled by custom user plans.

The “rp_decide_request” goal is used by the capability to decide if the request should be accepted and the optional agree message should be sent. This goal is optional, which means that it needs not to be handled by the user. Per default the request is accepted and no agree message is sent. To accept and send the agree message the goal has be to handled and the accept return value should be set to true. If set to false a refuse message is sent and the interaction is immediately terminated.

Table 16.14. Parameters for rp_decide_request

NameTypeDescription
initiator AgentIdentifier The initiator of the protocol.
action Object The action to be performed by the requested agent.
accept [out] Boolean True, if the request should be accepted and the optional agree message should be sent.

The “rp_execute_request” goal is used by the capability to request the action being executed by the domain layer. The handling of this goal is mandatory for a successful protocol execution. If the domain plan for handling this goal has executed the requested action without problems it can write back to results of this execution to the result parameter of the goal. If the action execution fails this should be indicated by letting the plan fail (by raising an exception).

Table 16.15. Parameters for rp_execute_request

NameTypeDescription
initiator AgentIdentifier The initiator of the protocol.
action Object The action to be performed by the requested agent.
result [out] * Object The result of the action execution.

In the following code cutouts it is shown what needs to be done for handling a request protocol as receiver. First, the capability and the participant goals need to be included as indicated in Figure 16.32, “Inclusion of the participant goals and beliefs”. In the example also the optional rp_decide_request goal is used. It is shown that the agent in the example wants to handle all request messages via its protocol capability, because the rp_filter is set to IFilter.ALWAYS. In addition three plans have been declared, one for each of the protocol goals. The optional rp_finished_plan is used to detect whenever a request interaction has ended. The corresponding plan body can evaluate the results and may perform action in response to them.

...
<capabilities>
    ...
    <capability name="procap" file="jadex.planlib.Protocols"/>
</capabilities>

<beliefs>
    ...
    <beliefref name="rp_filter" class="IFilter">
        <concrete ref="procap.rp_filter"/>
    </beliefref>
</beliefs>

<goals>
    ...
    <performgoalref name="rp_receiver_interaction">
        <concrete ref="procap.rp_receiver_interaction"/>
    </performgoalref>
    <achievegoalref name="rp_decide_request">
        <concrete ref="procap.rp_decide_request"/>
    </achievegoalref>
    <achievegoalref name="rp_execute_request">
        <concrete ref="procap.rp_execute_request"/>
    </achievegoalref>
</goals>

<plans>
    ...
    <plan name="rp_decide_request_plan">
        <parameter name="action" class="Object">
            <goalmapping ref="rp_decide_request.action"/>
        </parameter>
        <parameter name="accept" class="Boolean" direction="out">
            <goalmapping ref="rp_decide_request.accept"/>
        </parameter>
        <body>new MyDecideRequestPlan()</body>
        <trigger><goal ref="rp_decide_request"/></trigger>
    </plan>

    <plan name="rp_execute_request_plan">
        <parameter name="action" class="Object">
            <goalmapping ref="rp_execute_request.action"/>
        </parameter>
        <parameter name="result" class="Object" direction="out" optional="true">
            <goalmapping ref="rp_execute_request.result"/>
        </parameter>
        <body>new MyExecuteActionPlan()</body>
        <trigger><goal ref="rp_execute_request"/></trigger>
    </plan>

    <plan name="rp_finished_plan">
        <parameter name="interaction_state" class="InteractionState">
            <value>(InteractionState)((IRGoalEvent)$event).getGoal()
                .getParameter("interaction_state").getValue()</value>
        </parameter>
        <parameter name="result" class="Object">
            <value>((IRGoalEvent)$event).getGoal()
                .getParameter("result").getValue()</value>
        </parameter>
        <body>new MyResultPlan()</body>
        <trigger>
            <goalfinished ref="rp_receiver_interaction"/>
        </trigger>
    </plan>
</plans>
...
<configurations>
    <configuration name="default">
        <beliefs>
            <initialbelief ref="rp_filter">
                <fact>IFilter.ALWAYS</fact>
            </initialbelief>
            ...
        </beliefs>
        ...
    </configuration>
</configurations>
...				

Figure 16.32. Inclusion of the participant goals and beliefs

In Figure 16.33, “ Plan body of the MyDecideRequestPlan ” the schematic content of the MyDecideRequestPlan body is depicted. The result of the acceptance test is stored in the accept parameter. Similarly, in Figure 16.34, “ Plan body of the MyExecuteRequestPlan ” an outline of the MyExecuteActionPlan is given. It reads out the action description, performs some operation for executing this action and then writes back the result to the result parameter.

public void body()
{
    Object action = getParameter("action").getValue();
    boolean accept = ... // Determine acceptance
    getParameter("accept").setValue(new Boolean(accept));
}				

Figure 16.33.  Plan body of the MyDecideRequestPlan

public void body() {
    Object action = getParameter("action").getValue();
    // Perform the action
    result = ...
    // Store the result
    getParameter("result").setValue(result);
}				

Figure 16.34.  Plan body of the MyExecuteRequestPlan

16.3.2. FIPA Contract Net Interaction Protocol (CNP)

The Contract Net Protocol (SC00029H) is used for negotiations between one initiator and an arbitrary number of participant agents. Its purpose is to delegate a task to other agents and let them execute the tasks on the initiator agent's behalf.

The Contract Net Protocol

Figure 16.35.  The Contract Net Protocol

There is an initiator and a participant side of the protocol. The initiator sends a call for proposal to an arbitrary number of participant agents. Then it waits for proposals of the participants until a given deadline has passed. Up to this deadline the participants can either send a propose message or a refuse message. When the deadline has passed, the initiator decides about all of the received proposals and either sends reject- or accept-proposal messages to the participants. The elected participants now have the commitment to perform the task. Thereafter they send send an inform message with the result (if any), or if the execution has failed, they send a failure message.

In Jadex, there are five corresponding goals, called “cnp_initiate”, “cnp_evaluate_proposals”, “cnp_receiver_interaction”, “cnp_make_proposal” and “cnp_execute_task”. The first two implement the initiator side, the other ones belong to the participant side.

16.3.2.1. Initiator Side

From the view of the initiator side the protocol can be started via dispatching the “cnp_initiate”-goal. During execution of the goal the protocol engine will automatically dispatch a “cnp_evaluate_proposals”-goal. This goal should be handled to decide wich proposals should be accepted.

The cnp_initiate-goal has the following parameters:

Table 16.16. Parameters for cnp_initiate

NameTypeDescription
cfp Object The call for proposals. Will be sent to all participants.
cfp_info * Object Some local information about the cfp. Will not be sent to the participants but is available as input in other initiator goals.
ontology * String The ontology to be used in the interaction (e.g. for the marshalling of the cfp and proposal objects).
language * String The language to be used in the interaction (e.g. for the marshalling of the cfp and proposal objects).
timeout * Long The timeout for the call for proposal.
executeall * Boolean Set to true, when all acceptable proposals should be executed. Defaults to false, such that only one successful proposal is accepted per default.
interaction_state [out] InteractionState An object allowing to inspect the interaction state after protocol execution.
receivers [set] AgentIdentifier The receivers of the call for proposal.
result [set][out] Object The results of the task executions.
history [set][out] NegotiationRecord The negotiation history.

*: optional parameter

The second important goal on initiator side is the "cnp_evaluate_proposals" goal. Its in- and out-parameters are described below.

Table 16.17. Parameters for cnp_evaluate_proposals

NameTypeDescription
cfp Object The original call for proposals as initially sent to participants.
cfp_info [inout] * Object Local information about the cfp if set in the initiate goal.
proposals [set] ParticipantProposal The proposals received from the participants.
history [set] * NegotiationRecord Details about the negotiation.
acceptables [set][out] ParticipantProposal The acceptable proposals that should be selected.

*: optional parameter

In the code that follows it is depicted what needs to be done for executing a contract-net negotiation. First, the capability, the cnp_initiate and the cnp_evaluate_proposals goals need to be included as shown in Figure 16.36, “ Including the protocols capability and the goals for the contract-net protocol ”. In a plan the cnp_initiate goal needs to be created and its mandatory parameters should be set to the desired values. After dispatching the goal (cf. Figure 16.37, “Using the cnp_initiate goal”) one can wait for its completion and read out the results of the protocol execution. During the execution the engine will raise a cnp_evaluate_proposals goal which should be handled by a custom plan.

...
<imports>
    ...
    <import>jadex.planlib.*</import>
</imports>

<capabilities>
    ...
    <capability name="procap" file="jadex.planlib.Protocols"/>
</capabilities>
...
<goals>
    ...
    <achievegoalref name="cnp_initiate">
        <concrete ref="procap.cnp_initiate"/>
    </achievegoalref>
    <querygoalref name="cnp_evaluate_proposals">
        <concrete ref="procap.cnp_evaluate_proposals"/>
    </querygoalref>	
    ...
</goals>
<plans>
    ...
    <plan name="evaluator_plan">
        <parameter name="cfp" class="Object">
            <goalmapping ref="cnp_evaluate_proposals.cfp"/>
        </parameter>
        <parameter name="cfp_info" class="Object" direction="inout" optional="true">
            <goalmapping ref="cnp_evaluate_proposals.cfp_info"/>
        </parameter>
        <parameterset name="proposals" class="ParticipantProposal">
            <goalmapping ref="cnp_evaluate_proposals.proposals"/>
        </parameterset>
        <parameterset name="history" class="NegotiationRecord" optional="true">
            <goalmapping ref="cnp_evaluate_proposals.history"/>
        </parameterset>
        <parameterset name="acceptables" class="ParticipantProposal" direction="out">
            <goalmapping ref="cnp_evaluate_proposals.acceptables"/>
        </parameterset>
        <body>new MyEvaluatorPlan()</body>
        <trigger>
            <goal ref="cnp_evaluate_proposals"/>
        </trigger>
    </plan>
</plans>
...				

Figure 16.36.  Including the protocols capability and the goals for the contract-net protocol

public void body() {
    AgentIdentifier[] recs = ...
    Object cfp = ...
    IGoal cnpini = createGoal("cnp_initiate");
    cnpini.getParameterSet("receivers").addValues(recs);
    cnpini.getParameter("cfp").setValue(cfp);
    dispatchSubgoalAndWait(cnpini);
    Object res = request.getParameterSet("result").getValues();
    ...
}				

Figure 16.37. Using the cnp_initiate goal

Not shown here is the content of the custom evaluator plan body which has the purpose to weight the proposals and choose those which should be performed. This can either be one or many and the acceptable proposals (if any) should be stored in the out-parameterset result. Depending on the value of the "executeall" parameter, the initiator will either sequentially accept the accpetable proposals in turn, until the first participant reports the given task being executed (i.e. answers with an inform message) and reject the remaining proposals ("executeall=false") or the initiator will accept all acceptable proposals in parallel rejecting only inacceptable proposals, thereby collecting potentially many results at once ("executeall=true"). The results of the execution are available in the "result" parameter set of the "cnp_initiate" goal. Additional information can be found in the negotiation history (parameter set "history"), which contains one NegotiationRecord object for the negotiation phase containg all proposals and their evaluations and another one for the execution phase containing the executed proposals and the received results from the participant.

16.3.2.2. Participant Side

On the participant side a cnp protocol is triggered when the cnp_filter belief value allows this (per default it is turned off). When a cfp message arrives that passes the cnp_filter a new “cnp_receiver_interaction” goal is created. This goal is present during the whole lifetime of the interaction and will contain the results and interaction state of the conversation. If the participant side wants to be informed about the outcome of its conversations it can do so by waiting for the completion of this goal (using the goalfinished trigger type). For the implementation of the participant domain functionality two goals need to be supported. If the conversation is handled by the capability it will automatically request domain activities by dispatching subgoals which should be handled by custom user plans.

The “cnp_make_proposal” goal is used by the capability to indicate that a proposal for a cfp should be generated. The custom user plan that handles this goal finds all necessary information about the cfp in the parameters of the goal. On the basis of this knowledge it can decide to participate in the contract-net negotiation by creating a proposal and storing it into the proposal out-parameter.

The “cnp_make_proposal”-goal has the following parameters:

Table 16.18. Parameters for cnp_make_proposal

NameTypeDescription
cfp Object The call-for-propsal that can be handled.
initiator AgentIdentifier The agent identifier of the protocol initiator.
proposal [out] Object The proposal for the cfp that will be sent back to the initiator.
proposal_info [out] * Object Some optional local data for the proposal. It will be available in the cnp_execute_task goal.

*: optional parameter

If a proposal has been made and the initiator selects the participant as one of the winners a "cnp_execute_task" goal will be raised. A custom user plan should be provided that handles the goal, executes the task and reports back the results of the processing.

The “cnp_execute_task”-goal has the following parameters:

Table 16.19. Parameters for cnp_execute_task

NameTypeDescription
proposal Object The proposal that was sent to the initiator and has won.
proposal_info * Object The local proposal data that was generated by the cnp_make_proposal goal
initiator Object The initiator of the cfp.
result [out] * Object Information about the task execution.

*: optional parameter

In the following code snippets it is shown what needs to be done for handling a contract-net protocol as receiver. First, the capability and the cnp_make_proposal, cnp_execute_task goals need to be included as indicated in Figure 16.38, “Inclusion of the participant goals and beliefs”. It is shown that the agent in the example wants to handle all cfp messages via its protocol capability, because the cnp_filter is set to IFilter.ALWAYS. In addition two plans have been declared, one for each of the protocol goals.

...
<capabilities>
    <capability name="procap" file="jadex.planlib.Protocols"/>
    ...
</capabilities>

<beliefs>
    <beliefref name="cnp_filter" class="IFilter">
        <concrete ref="procap.cnp_filter"/>
    </beliefref>
    ...
</beliefs>

<goals>
    <querygoalref name="cnp_make_proposal">
        <concrete ref="procap.cnp_make_proposal"/>
    </querygoalref>
    <achievegoalref name="cnp_execute_task">
        <concrete ref="procap.cnp_execute_task"/>
    </achievegoalref>
    ...
</goals>

<plans>
    <plan name="cnp_make_proposal_plan">
        <parameter name="cfp" class="Object">
            <goalmapping ref="cnp_make_proposal.cfp"/>
        </parameter>
        <parameter name="initiator" class="AgentIdentifier">
            <goalmapping ref="cnp_make_proposal.initiator"/>
        </parameter>
        <parameter name="proposal" class="Object" direction="out">
            <goalmapping ref="cnp_make_proposal.proposal"/>
        </parameter>
        <parameter name="proposal_info" class="Object" direction="out" optional ="true">
            <goalmapping ref="cnp_make_proposal.proposal_info"/>
        </parameter>
        <body>new MyMakeProposalPlan()</body>
        <trigger>
            <goal ref="cnp_make_proposal"/>
        </trigger>
    </plan>

    <plan name="cnp_execute_task_plan">
        <parameter name="proposal" class="Object">
            <goalmapping ref="cnp_execute_task.proposal"/>
        </parameter>
        <parameter name="proposal_info" class="Object" optional="true">
            <goalmapping ref="cnp_execute_task.proposal_info"/>
        </parameter>
        <parameter name="initiator" class="AgentIdentifier">
            <goalmapping ref="cnp_execute_task.initiator"/>
        </parameter>
        <parameter name="result" class="Object" direction="out" optional="true">
            <goalmapping ref="cnp_execute_task.result"/>
        </parameter>
        <body>new MyExecuteTaskPlan()</body>
        <trigger>
            <goal ref="cnp_execute_task"></goal>
        </trigger>
    </plan>
    ...
</plans>
...
<configurations>
    <configuration name="default">
        <beliefs>
            <initialbelief ref="cnp_filter">
                <fact>IFilter.ALWAYS</fact>
            </initialbelief>
            ...
        </beliefs>
        ...
    </configuration>
</configurations>
...				

Figure 16.38. Inclusion of the participant goals and beliefs

Besides the inclusion of the relevant goals and beliefs the main task of the agent programmer consists in developing the two custom domain plans. Here in the example code they are named MyMakeProposalPlan and the MyExecuteTaskPlan. As the basic responsibilities of the two plans consists in performing domain tasks and writing back the results to the goals no further code snippets will be given here.

16.3.2.3. Simplified Protocol Usage

In many cases, the decisions an agent has to make during the execution of a protocol are quite simple and do not necessarily have to be defined in terms of goals and plans. Therefore, the protocols capability offers some simple Java interfaces that can be implemented to describe these decisions instead of having to define plans. For the contract-net usually a plan has to be defined, to evaluate the received proposals and to decide about acceptable proposals. Alternatively, the jadex.planlib.IProposalEvaluator interface can be used for this purpose. An object implementing this interface can be passed in the "cfp_info" parameter of the "cnp_initiate" goal and will then automatically be used by a default plan in the protocols capability to handle the "evaluate_proposals" goal.

The IProposalEvaluator interface requires the evaluateProposals() method to be implemented, which features in essence the same parameters as the "evaluate_proposals" goal. To simplify the usage of the contract-net protocol even more, a default implementation is available (jadex.planlib.ProposalEvaluator), which handles some very common cases. The default implementation allows to determine acceptable proposals by comparing proposals or evaluations to a limit value, given in the constructor. Moreover, the evaluation process is implemented in three methods, which can be separately overwritten if needed, while reusing functionality of the other methods.

  • The proposals are evaluated by calling the the evaluateProposal() method for each of the proposals. The evaluation result is written back into the proposal. The default implementation just checks, if the proposal object itself is suitable as an evaluation (i.e. if it is java.lang.Comparable).
  • For each of the proposals, the acceptability is determined. By default, if a limit value is given, the proposal evaluations are compared to the limit value.
  • Finally, the acceptable proposals are ordered by preference. As a default, the proposals are compared to each other and sorted according to a given ordering.

The usage of the default implementation is illustrated in Figure 16.39, “Simplified usage of the cnp_initiate goal”, in which a newly instantiated ProposalInitiator is used as cfp_info, to automatically accept all proposals greater or equal to 5.

public void body() {
    AgentIdentifier[] recs = ...
    Object cfp = ...
    IProposalEvaluator cfp_info = new ProposalEvaluator(new Integer(5), false);
    IGoal cnpini = createGoal("cnp_initiate");
    cnpini.getParameterSet("receivers").addValues(recs);
    cnpini.getParameter("cfp").setValue(cfp);
    cnpini.getParameter("cfp_info").setValue(cfp_info);
    dispatchSubgoalAndWait(cnpini);
    Object res = request.getParameterSet("result").getValues();
    ...
}				

Figure 16.39. Simplified usage of the cnp_initiate goal

16.3.3. FIPA Iterated Contract Net Protocol (ICNP)

The Iterated Contract Net Protocol (SC00030H) is used for negotiations between one initiator and an arbitrary number of participant agents. Its purpose is to delegate a task to other agents and let them execute the tasks on the initiator agent's behalf. The only difference to the normal contract net protocol described in the last section is that more than one negotiation round may be performed.

The Iterated Contract Net Protocol

Figure 16.40. The Iterated Contract Net Protocol

There is an initiator and a participant side of the protocol. The initiator sends a call for proposal to an arbitrary number of participant agents. Then it waits for proposals of the participants until a given deadline has passed. Up to this deadline the participants can either send a propose message or a refuse message. When the deadline has passed, the initiator decides about all of the received proposals and evaluates if some proposals are acceptable (like in the non-iterated contract-net discussed in the last section). In a second step, the initiator decides, if another negotiation round should be initiated with a possibly refined cfp. New negotiation rounds can be performed with the same or any subset of the original participants. If a subset is chosen the excluded participants will be rejected immediately. When the initiator decides to accept some proposals (i.e. performing no further negotiation round), the winning participants have the commitment to perform the task. Thereafter they send send an inform message with a result (if any), or if the execution has failed, they send a failure message.

In Jadex, there are six corresponding goals, called “icnp_initiate”, “icnp_evaluate_proposals”, “icnp_nextround_info”, “icnp_receiver_interaction”, “icnp_make_proposal” and “icnp_execute_task”. The first three implement the initiator side, the other ones belong to the participant side. The goals are very similar to the non-iterated version of the contract net protocol. The only new goal is the query “icnp_nextround_info” goal, which decides if another negotiation round is necessary and which settings should apply to the next round (if any). As the other goals are identical to their original non-iterated counterparts here only the “icnp_nextround_info” will be explained in detail. For details about the other goals please refer to the explanations from the last section.

16.3.3.1. Initiator Side

From the view of the initiator side the protocol can be started via dispatching the "icnp_initiate" goal. During execution of the goal the protocol engine will automatically dispatch a "icnp_evaluate_proposals" goal. This goal should be handled to decide wich proposals are acceptable. After the evaluation has taken place the engine raises a "icnp_nextound_info" goal which has the purpose to decide if another negotiation round should be performed and if yes, which settings should be used, concerning e.g. the participants, the possibly refined cfp and additional only locally availabe cfp data.

The "icnp_nextound_info" goal has the following parameters:

Table 16.20. Parameters for icnp_nextround_info

NameTypeDescription
cfp [inout] Object The original call for proposals as initially sent to participants. Can be refined for the next round.
cfp_info [inout] * Object Local information about the cfp if set in the "icnp_initiate" or "icnp_evaluate_proposals" goal. Can be refined for the next round.
participants [set][inout] AgentIdentifier The participants of the negotiation. Can be refined for the next round.
proposals [set] ParticipantProposal The proposals received from the participants including the evaluation value possibly created while handling the "icnp_evaluate_proposals" goal.
history [set] NegotiationRecord Contains details about all the negotiation rounds that have been performed so far.
iterate [out] Boolean Flag indicating the decision to iterate (set to true or false to end goal).

*: optional parameter

In the code that follows it is depicted what needs to be done for executing an iterated contract-net negotiation. First, the capability, the "icnp_initiate" goal, the "icnp_evaluate_proposals" goal and the "icnp_nextround_info" goal need to be included as shown in Figure 16.41, “ Including the protocols capability and the goals for the iterated contract-net protocol ”. In a plan the "icnp_initiate" goal needs to be created and its mandatory parameters should be set to the desired values. After dispatching the goal (cf. Figure 16.42, “Using the icnp_initiate goal”) one can wait for its completion and read out the results of the protocol execution. During the execution the engine will raise one "icnp_evaluate_proposals" goal in every negotiation round when the collected proposals need to be evaluated. Additionally an "icnp_nextround_info" goal is created in every round to decide if another round is necessary.

...
<imports>
    ...
    <import>jadex.planlib.*</import>
</imports>

<capabilities>
    ...
    <capability name="procap" file="jadex.planlib.Protocols"/>
</capabilities>
...
<goals>
    ...
    <achievegoalref name="icnp_initiate">
        <concrete ref="procap.icnp_initiate"/>
    </achievegoalref>
    <querygoalref name="icnp_evaluate_proposals">
        <concrete ref="procap.icnp_evaluate_proposals"/>
    </querygoalref>	
    <querygoalref name="icnp_nextround_info">
        <concrete ref="procap.icnp_nextround_info"/>
    </querygoalref>
</goals>
<plans>
    ...
    <plan name="evaluator_plan">
        <parameter name="cfp" class="Object">
            <goalmapping ref="icnp_evaluate_proposals.cfp"/>
        </parameter>
        <parameter name="cfp_info" class="Object" direction="inout" optional="true">
            <goalmapping ref="icnp_evaluate_proposals.cfp_info"/>
        </parameter>
        <parameterset name="proposals" class="ParticipantProposal">
            <goalmapping ref="icnp_evaluate_proposals.proposals"/>
        </parameterset>
        <parameterset name="history" class="NegotiationRecord" optional="true">
            <goalmapping ref="icnp_evaluate_proposals.history"/>
        </parameterset>
        <parameterset name="acceptables" class="ParticipantProposal" direction="out">
            <goalmapping ref="icnp_evaluate_proposals.acceptables"/>
        </parameterset>
        <body>new MyEvaluatorPlan()</body>
        <trigger>
            <goal ref="icnp_evaluate_proposals"/>
        </trigger>
    </plan>
	
    <plan name="icnp_nextround_plan">
        <parameter name="cfp" class="Object" direction="inout">
            <goalmapping ref="icnp_nextround_info.cfp"/>
        </parameter>
        <parameter name="cfp_info" class="Object" direction="inout" optional="true">
            <goalmapping ref="icnp_nextround_info.cfp_info"/>
        </parameter>
        <parameter name="iterate" class="Boolean" direction="out">
            <goalmapping ref="icnp_nextround_info.iterate"/>
        </parameter>
        <parameterset name="participants" class="AgentIdentifier" direction="inout">
            <goalmapping ref="icnp_nextround_info.participants"/>
        </parameterset>
        <parameterset name="proposals" class="ParticipantProposal">
            <goalmapping ref="icnp_nextround_info.proposals"/>
        </parameterset>
        <parameterset name="history" class="NegotiationRecord" optional="true">
            <goalmapping ref="icnp_nextround_info.history"/>
        </parameterset>
        <body>new MyNextroundPlan()</body>
        <trigger>
            <goal ref="icnp_nextround_info"/>
        </trigger>
    </plan>
</plans>
...				

Figure 16.41.  Including the protocols capability and the goals for the iterated contract-net protocol

public void body() {
    AgentIdentifier[] recs = ...
    Object cfp = ...
    IGoal icnpini = createGoal("icnp_initiate");
    icnpini.getParameterSet("receivers").addValues(recs);
    icnpini.getParameter("cfp").setValue(cfp);
    dispatchSubgoalAndWait(icnpini);
    Object res = request.getParameterSet("result").getValues();
    ...
}				

Figure 16.42. Using the icnp_initiate goal

Not shown here is the content of the custom evaluator plan body for the "icnp_evaluate_proposals" plan, which has the purpose to rate the proposals. It may identify one or many acceptable proposals (if any) which should be stored in the out-parameterset acceptables. This information can also be helpful for deciding which agent should participate in the next negotiation round. The information is available in the "icnp_decide_iteration" goal, which decides if another negotiation round should be performed (out-parameter "iterate") and which settings to use (inout-parameters "cfp", "cfp_info", "participants").

As already described for the non-iterated contract-net, the execution of acceptable proposals can be influenced by the value of the "executeall" parameter. When set to false (default) the initiator will either sequentially accept the accpetable proposals in turn, until the first participant answers with an inform message and reject the remaining proposals. When set to true, initiator will accept all acceptable proposals in parallel rejecting only inacceptable proposals, thereby collecting potentially many results at once.

16.3.3.2. Participant Side

On the participant side an iterated contract-net protocol is triggered when the icnp_filter belief value allows this (per default it is turned off). When a cfp message arrives that passes the icnp_filter a new “icnp_receiver_interaction” goal is created. This goal is present during the whole lifetime of the interaction and will contain the results and interaction state of the conversation. If the participant side wants to be informed about the outcome of its conversations it can do so by waiting for the completion of this goal (using the goalfinished trigger type). For the implementation of the participant domain functionality two goals need to be supported. If the conversation is handled by the capability it will automatically request domain activities by dispatching subgoals which should be handled by custom user plans.

The "icnp_make_proposal" goal is used by the capability to indicate that a proposal for a cfp should be generated. The custom user plan that handles this goal finds all necessary information about the cfp in the parameters of the goal. On the basis of this knowledge it can decide to participate in the contract-net negotiation by creating a proposal and storing it into the proposal out-parameter. As the iterated version of the contract-net protocol can consist of an arbirary number of negotiation rounds the protocol engine will raise one "icnp_make_proposal" goal in each round.

If the initiator finally selects the participant as one of the winners a "icnp_execute_task" goal will be raised. A custom user plan should be provided that handles the goal, executes the task and reports back the results of the processing.

16.3.3.3. Simplified Protocol Usage

To simplify the usage of protocols for cases, where no complex plans are needed, the protocols capability offers some simple Java interfaces that can be implemented to describe the required decisions instead of having to define plans. The iterated contract-net usually requires one plan for evaluating proposals and another plan for preparing the settings for the next negotiation round. Alternatively to an evaluate proposals plan, the IProposalEvaluator interface can be used as already described for the non-iterated contract-net protocol in Section 16.3.2.3, “Simplified Protocol Usage”. For determing settings of a further negotiation round the interface IQueryNextroundInfo comes into play for the iterated contract-net. As described before, an object implementing one of this interfaces can be passed in the "cfp_info" parameter of the "cnp_initiate" goal and will then automatically be used by a default plan in the protocols capability to handle the "evaluate_proposals" or the "nextround_info" goal. If you want to supply implementations of both interfaces, you can use the wrapper class ICNPHandler designed specifically for this purpose.

The IQueryNextroundInfo interface requires the queryNextroundInfo() method to be implemented, which resembles the signature of the "nextround_info" goal. As the "nextround_info" goal contains several inout parameters, which can not be mapped directly to method paramters, a helper class NextroundInfo is used to hold the current cfp, cfp_info and participants and allows these settings to be changed for the next round. The queryNextroundInfo() should return true, when another negotiation round is required. Currently, no default implementation for the IQueryNextroundInfo interface is available, so you have to implement the required method yourself. The usage of both interfaces is illustrated in Figure 16.43, “Simplified usage of the icnp_initiate goal”, in which a newly instantiated ICNPHandler is used as cfp_info containing an IProposalEvaluator and an IQueryNextroundInfo object. The proposal evaluator will automatically accept all proposals greater or equal to 5 and the IQueryNextroundInfo, implemented as anonymous inner class, leads to three negotiation rounds being performed.

public void body() {
    AgentIdentifier[] recs = ...
    Object cfp = ...
    IProposalEvaluator pe = new ProposalEvaluator(new Integer(5), false);
    IQueryNextroundInfo qnri = new IQueryNextroundInfo() {
        public boolean queryNextroundInfo(NextroundInfo info, 
            NegotiationRecord[] history, ParticipantProposal[] proposals) {
            return history.length < 3;
        }
    };
    Object cfp_info = new ICNPHandler(pe, qnri);
    IGoal icnpini = createGoal("icnp_initiate");
    icnpini.getParameterSet("receivers").addValues(recs);
    icnpini.getParameter("cfp").setValue(cfp);
    icnpini.getParameter("cfp_info").setValue(cfp_info);
    dispatchSubgoalAndWait(icnpini);
    Object res = request.getParameterSet("result").getValues();
    ...
}				

Figure 16.43. Simplified usage of the icnp_initiate goal

16.3.4. FIPA English Auction Interaction Protocol (EA)

The FIPA English Auction Interaction Protocol (XC00031F) describes an auction with steadily increased offers. The auction consists of an auctioneer and a set of bidders. The auctioneer chooses a start offer below the supposed market value. Round-by-round the offer is increased by the auctioneer as long as at least one bidder accepts the proposal. When no bidder is willing to accept the current offer of the auctioneer the auction has finished and the winner is the agent that has accepted the last offer. As the auctioneer starts the auction below the true market value it has the choice to not sell the good when the offered proposal is below his secret limit value.

The English Auction Protocol

Figure 16.44. The English Auction Protocol

Technically the auction is specified as follows:

The auctioneer starts the auction by sending an “inform-start-of-auction”-message that contains information such as the topic, start time etc. about the planned auction. When the start time of auction has been reached the auctioneer sends a call for proposal (CFP) to all bidders and waits. The bidders can react in three different ways. Firstly, a bidder can send a “not-understood”-message in order to signalize that it is not able to understand or not interested in the CFP. The auctioneer will subsequently exclude this bidder from the auction. Secondy, the bidder can decide to make an offer by sending a propose message. Thirdly, e.g., when the CFP exceeds the price the bidder is currently willing or allowed to pay, it may decide not to answer. In this case, the bidder will stay in the auction and may decide to bid again in a later negotiation round. Of course, the bidder, who won the last round, will usually not bid in the current round. The auctioneer waits for bids until the timeout of a negotiation round. If there is more than one proposal message, only the first one is accepted.[2] (Even if they arrive at the same time, they will technically not be processed concurrently. This is similar to a real English auction, because if two bidders raise their hands at the same time it is also nondeterministic which one of the bidders is selected, as it depends on who is first noticed by the auctioneer.) So the first proposal is answered with an “accept_proposal”-message, any other proposal with a “reject_proposal”-message. The auction lasts as long as at least one bidder answers the current cfp. When in one round no bidder is willing to accept the current cfp, the auction ends. Finally, the auctioneer will send a “inform”-message to all participants.

There are six predefined goals in this capability that offer the possibility to implement an English auction without much coding effort. These goals are “ea_initiate”, “ea_decide_iteration”, “ea_decide_acceptance” “ea_receiver_interaction”, “ea_decide_participation” and “ea_make_proposal”. The first three goals belong to the initiator side while the others are used on receiver side.

16.3.4.1. Initiator Side

From the perspective of the initiator the protocol can be started via dispatching the “ea_initiate”-goal. The protocol engine will raise a “ea_decide_iteration”-goal for every further negotiation round. This goal gives the inititor the chance to decide if a next negotiation round should be performed (e.g. if there are time constraints) and what offer should be made to the participants.

The da_initiate goal needs to be provided with information about the auction (auction_description), the initial call-for-proposal (cfp) and the receivers that shall participate in the negotiation (receivers). Optionally, some local cfp data (cfp_info) as well as a language and ontology for marshalling can also be specified. As result the goal contains the global interaction state (iteraction_state) and the domain output (result).

The ea_initiate goal parameters are further explained in the following table:

Table 16.21. Parameters for ea_initiate

NameTypeDescription
auction_description AuctionDescription A detailed description about the auction.
cfp Object The initial offer of the initiator.
cfp_info * Object Optional locally available further cfp details.
limit * Comparable The secret limit offer of the auctioneer. When specified the protocol engine will test if the last offer is greater or equal than the limit. If this is not the case the good will not be sold to any bidder. When no limit is specified a ea_decide_acceptance goal will be raised and can be used to decide upon acceptance of the final offer.
ontology * String The ontology for marshalling.
language * String The language for marshalling.
receivers [set] AgentIdentifier The agent identifiers of the participants to which the auction will be advertised.
interaction_state [out] InteractionState The interaction state after protocol execution.
result [out] * Object The result of the protocol execution.

*: optional parameter

The ea_decide_iteration goal is used to determine if the next round should be performed and which offer should be used in that round. For that purpose it provides the history of all made CFPs (history) and the only locally available additional cfp information (cfp_info). If a new round shall be performed the new CFP should be written to the cfp out-parameter.

The ea_decide_iteration parameters are further explained in the following table:

Table 16.22. Parameters for ea_decide_iteration

NameTypeDescription
cfp [out] Object The cfp for the next round.
cfp_info [inout] * Object Optional locally available further cfp details. Changes of the cfp_info can be stored in the parameter again.
history [set] Object The negotiation history. Contains all cfps made so far.

*: optional parameter

The ea_decide_acceptance goal comes into play when the auction has ended and the auctioneer needs to decide if he, e.g., wants to sell the good for the reached price. There are two alternative ways how one can influence this decision. Firstly, the limit offer can be set directly in the ea_initiate goal. If this is too inflexible and the limit may vary over time it should be left open in the ea_initiate goal. Secondly, it can be determined by the automatically raised ea_decide_acceptance goal. When the goal is not handled by a custom plan and a winner exists it will be accepted. Otherwise the custom plan can decide upon acceptance.

The ea_decide_acceptance parameters are further explained in the following table:

Table 16.23. Parameters for ea_decide_acceptance

NameTypeDescription
auction_description AuctionDescription The detailed auction description.
cfp Object The current cfp.
cfp_info * Object Optional locally available further cfp details.
winner AgentIdentifier The auction winner.
accept [out] Boolean True, if the current offer should be accepted.
history [set] Object The negotiation history. Contains all cfps made so far.

*: optional parameter

In the code below it is described what needs to be done for executing an English auction. First, the capability, the ea_initiate, the ea_decide_iteration (and optionally the ea_decide_acceptance) goals need to be included as shown in Figure 16.45, “ Including the protocols capability and the goals for the English auction protocol ”. In a plan the ea_initiate goal needs to be created and its mandatory parameters should be set to the desired values. After dispatching the goal (cf. Figure 16.46, “Using the ea_initiate goal”) one can wait for its completion and read out the results of the protocol execution. During the execution the engine will raise a ea_decide_iteration goal in every negotiation round which should be handled by a custom user plan. At the end of the auction a ea_decide_acceptance goal is raised when no limit was specified in the ea_initiate goal.

...
<capabilities>
    <capability name="procap" file="jadex.planlib.Protocols"/>
    ...
</capabilities>
...
<goals>
    ...
    <achievegoalref name="ea_initiate">
        <concrete ref="procap.ea_initiate"/>
    </achievegoalref>
    <querygoalref name="ea_decide_iteration">
        <concrete ref="procap.ea_decide_iteration"/>
    </querygoalref>	
    <querygoalref name="ea_decide_acceptance">
        <concrete ref="procap.ea_decide_iteration"/>
    </querygoalref>	
    ...
</goals>
<plans>
    <plan name="decide_iteration_plan">
        <parameter name="cfp" class="Object" direction="out">
            <goalmapping ref="ea_decide_iteration.cfp"/>
        </parameter>
        <parameter name="cfp_info" class="Object" direction="inout" optional="true">
            <goalmapping ref="ea_decide_iteration.cfp_info"/>
        </parameter>
        <parameterset name="history" class="Object">
            <goalmapping ref="ea_decide_iteration.history"/>
        </parameterset>
        <body>new MyDecideIterationPlan()</body>
        <trigger>
            <goal ref="ea_decide_iteration"/>
        </trigger>
    </plan>
    
    <plan name="decide_acceptance_plan">
        <parameter name="auction_description" class="Object">
            <goalmapping ref="ea_decide_acceptance.auction_description"/>
        </parameter>
        <parameter name="cfp" class="Object">
            <goalmapping ref="ea_decide_acceptance.cfp"/>
        </parameter>
        <parameter name="cfp_info" class="Object" optional="true">
            <goalmapping ref="ea_decide_acceptance.cfp_info"/>
        </parameter>
        <parameter name="winner" class="AgentIdentifier">
            <goalmapping ref="ea_decide_acceptance.winner"/>
        </parameter>
        <parameter name="accept" class="Boolean" direction="out">
            <goalmapping ref="ea_decide_acceptance.accept"/>
        </parameter>
        <parameterset name="history" class="Object">
            <goalmapping ref="ea_decide_acceptance.history"/>
        </parameterset>
        <body>new MyDecideAcceptancePlan()</body>
        <trigger>
            <goal ref="ea_decide_acceptance"/>
        </trigger>
    </plan>
    ...
</plans>
...				

Figure 16.45.  Including the protocols capability and the goals for the English auction protocol

public void body() {
    AgentIdentifier[] recs = ...
    Object cfp = ...
    long starttime = ...
    long roundtimeout = ...
    IGoal eaini = createGoal("ea_initiate");
    eaini.getParameterSet("receivers").addValues(recs);
    eaini.getParameter("cfp").setValue(cfp);
    eaini.getParameter("auction_description").setValue(new AuctionDescription(
        starttime, roundtimeout, "Test auction 1"));
    // Comparable limit = ...
    // eaini.getParameter("limit").setValue(limit);
    dispatchSubgoalAndWait(eaini);
    Object res = request.getParameter("result").getValues();
    ...
}				

Figure 16.46. Using the ea_initiate goal

Not shown here is the content of the custom decide iteration plan body which has the purpose to generate a new cfp if the next auction round should be performed A convenient way to do this consists in using an automatic offer generator following the interface of jadex.planlib.IOfferGenerator. Currently there are two implementation of this interface that allow automatic price generation. For linear price intervals you can use the LinearPriceCalculator and for exponential intervals the ExponentialPriceCalculator. In addition the custom plan body of the decide acceptance is not further illustrated. It only has to check if the offer should be accepted and write back the boolean value to the corresponding out-parameter (accept). Alternatively, the outcommented lines can be used if a fixed limit is admissable.

16.3.4.2. Participant Side

On the participant side an English auction protocol is triggered when the ea_filter belief value allows this (per default it is turned off). When a inform start-auction message arrives that passes the ea_filter a new “ea_receiver_interaction” goal is created. This goal is present during the whole lifetime of the interaction and will contain the results and interaction state of the conversation. If the participant side wants to be informed about the outcome of its conversations it can do so by waiting for the completion of this goal (using the goalfinished trigger type). For the implementation of the participant domain functionality two goals need to be supported. If the conversation is handled by the capability it will automatically request domain activities by dispatching subgoals which should be handled by custom user plans.

The “ea_decide_participation” goal is raised when an inform start-auction message has been received. It is used to determine if the participant wants to participate at the auction. If no plan is provided for handling the goal this is regarded as acceptance and the agent will participate at the auction.

Table 16.24. Parameters for ea_decide_participation

NameTypeDescription
initiator AgentIdentifier The agent identifier of the initiator.
auction_description AuctionDescription A detailed description about the auction.
auction_info [out] * Object Optional details about the auction that are only available locally.
participate [out] * Boolean True if the agent wants to participate.

*: optional parameter

If the agent has decided to particpate and the auction has started it will be requested to react on call-for-proposals of the initiator. For this purpose a “ea_make_proposal” goal will be raised in every negotiation round. A custom user plan should be provided that handles the goal by evaluating the cfp and deciding about its acceptance. Additionally, the agent can also decide to leave the auction in every round via the goal if circumstances have changed.

Table 16.25. Parameters for ea_make_proposal

NameTypeDescription
cfp Object The call-for-proposal represents the current offer of the auctioneer.
auction_description AuctionDescription A detailed description about the auction.
auction_info [inout] * Object Optional details about the auction that are only available locally.
history [set] * Object The history of earlier CFPs.
accept [out] * Boolean True if the agent wants to accept the current cfp.
leave [out] * Boolean True if the agent wants to leave the auction.

*: optional parameter

To use these goals, you must first of all include the Protocols capability in your ADF (if not yet done in order to use other goals of the Protocols capability) and set a reference to the goals as described in Figure 16.47, “ Including the Protocols capability and the participant goals for the English auction ”.

...
<capabilities>
    <capability name="procap" file="jadex.planlib.Protocols"/>
    ...
</capabilities>

<beliefs>
    <beliefref name="ea_filter" class="IFilter">
        <concrete ref="procap.ea_filter"/>
    </beliefref>
    ...
</beliefs>

<goals>
    <performgoalref name="ea_receiver_interaction">
        <concrete ref="procap.ea_receiver_interaction"/>
    </performgoalref>
    <achievegoalref name="ea_decide_participation">
        <concrete ref="procap.ea_decide_participation" />
    </achievegoalref>
    <querygoalref name="ea_make_proposal">
        <concrete ref="procap.ea_make_proposal" />
    </querygoalref>
    ...
</goals>

<plans>
    <plan name="decide_participation_plan">
        <parameter name="initiator" class="AgentIdentifier">
            <goalmapping ref="ea_decide_participation.initiator" />
        </parameter>
        <parameter name="participate" class="Boolean" direction="out" optional="true">
            <goalmapping ref="ea_decide_participation.participate" />
        </parameter>
        <parameter name="auction_description" class="AuctionDescription">
            <goalmapping ref="ea_decide_participation.auction_description" />
        </parameter>
        <parameter name="auction_info" class="Object" direction="out" optional="true">
            <goalmapping ref="ea_decide_participation.auction_info" />
        </parameter>
        <body>new MyDecideParticipationPlan()</body>
        <trigger>
            <goal ref="ea_decide_participation"></goal>
        </trigger>
    </plan>
    
    <plan name="make_proposal_plan">
        <parameter name="accept" class="Boolean" direction="out" optional="true">
            <goalmapping ref="ea_make_proposal.accept" />
        </parameter>
        <parameter name="leave" class="Boolean" direction="out" optional="true">
            <goalmapping ref="ea_make_proposal.leave" /> 
        </parameter>
        <parameter name="cfp" class="Object">
            <goalmapping ref="ea_make_proposal.cfp" />
        </parameter>
        <parameter name="auction_description" class="AuctionDescription">
            <goalmapping ref="ea_make_proposal.auction_description" />
        </parameter>
        <parameter name="auction_info" class="Object" direction="inout" optional="true">
            <goalmapping ref="ea_make_proposal.auction_info" />
        </parameter>
        <parameterset name="history" class="Comparable" optional="true">
            <goalmapping ref="ea_make_proposal.history" />
        </parameterset>
        <body>new MyMakeProposalPlan()</body>
        <trigger>
            <goal ref="ea_make_proposal"/>
        </trigger>
    </plan>
</plans>
...
<configurations>
    <configuration name="default">
        <beliefs>
            <initialbelief ref="ea_filter">
                <fact>IFilter.ALWAYS</fact>
            </initialbelief>
            ...
        </beliefs>
        ...
    </configuration>
</configurations>
...				

Figure 16.47.  Including the Protocols capability and the participant goals for the English auction

Besides the inclusion of the relevant goals and beliefs the main task of the agent programmer consists in developing the custom domain plan(s). Here in the example code they are named MyDecideParticipationPlan and MyMakeProposalPlan. As the basic responsibilities of the two plans consists in performing domain tasks and writing back the results to the goals no further code cutouts are shown here.

16.3.5. FIPA Dutch Auction Interaction Protocol (DA)

The FIPA Dutch Auction Interaction Protocol (XC00032F) describes an auction with steadily decreased offers. The auction consists of an auctioneer and a set of bidders. The auctioneer chooses a start offer much higher than the supposed market value. Round-by-round the offer is decreased by the auctioneer until there is a proposal from a bidder that accepts the offer. In this case the auction has finished successfully. Otherwise the auctioneer can stop the auction if his limit offer has been reached and further bids may not be acceptable for him.

The Dutch Auction Protocol

Figure 16.48. The Dutch Auction Protocol

Technically the auction is specified as follows:

The auctioneer starts the auction by sending an “inform-start-of-auction”-message that contains information such as the topic, start time etc. about the planned auction. When the start time of auction has been reached the auctioneer sends a call for proposal (CFP) to all bidders and waits. The bidders can react in three different ways. Firstly, a bidder can send a “not-understood”-message in order to signalize that it is not able to understand the CFP. The auctioneer will subsequently exclude this bidder from the auction. Secondly, a bidder considers the CFP as inacceptable. In this case it will do nothing and wait for the next negotiation round in which a new CFP will be available. Thirdly, a bidder can send a proposal, i.e. it can accept the offer contained in the CFP from the auctioneer. If there is more than one proposal, only the first one is accepted.[3] (Even if they arrive at the same time, they will technically not be processed concurrently. This is similar to a real Dutch auction, because if two bidders raise their hands at the same time it is also nondeterministic which one of the bidders is selected, as it depends on who is first noticed by the auctioneer.) So the first proposal is answered with an “accept_proposal”-message, any other proposal with a “reject_proposal”-message. At the end of the auction the auctioneer will send a “inform”-message to all participants.

There are five predefined goals in this capability that offer the possibility to implement a Dutch auction with only few lines of code. These goals are “da_initiate”, “da_decide_iteration”, “da_receiver_interaction”, “da_decide_participation” and “da_make_proposal”. The first two goals belong to the initiator side while the others are used on receiver side.

16.3.5.1. Initiator Side

From the perspective of the initiator the protocol can be started via dispatching the “da_initiate”-goal. If the auctioneered good is not bought immediately, the protocol engine will raise a “da_decide_iteration”-goal for every further negotiation round. This goal gives the inititor the chance to decide if a next negotiation round should be performed and what offer should be made to the participants.

The da_initiate goal needs to be provided with information about the auction (auction_description), the initial call-for-proposal (cfp) and the receivers that shall participate in the negotiation (receivers). Optionally, some local cfp data (cfp_info) as well as a language and ontology for marshalling can also be specified. As result the goal contains the global interaction state (interaction_state) and the domain output (result).

The da_initiate goal parameters are further explained in the following table:

Table 16.26. Parameters for da_initiate

NameTypeDescription
auction_description AuctionDescription A detailed description about the auction.
cfp Object The initial offer of the initiator.
cfp_info * Object Optional locally available further cfp details.
ontology * String The ontology for marshalling.
language * String The language for marshalling.
receivers [set] AgentIdentifier The agent identifiers of the participants to which the auction will be advertised.
interaction_state [out] InteractionState The interaction state after protocol execution.
result [out] * Object The result of the protocol execution.

*: optional parameter

The da_decide_iteration is used to determine if the next round should be performed and which offer should be used in that round. For that purpose it provides the history of all made CFPs (history) and the only locally available additional cfp information (cfp_info). If a new round shall be performed the new CFP should be written to the cfp out-parameter.

The da_decide_iteration parameters are further explained in the following table:

Table 16.27. Parameters for da_decide_iteration

NameTypeDescription
cfp [out] Object The cfp for the next round.
cfp_info [inout] * Object Optional locally available further cfp details. Changes of the cfp_info can be stored in the parameter again.
history [set] Object The negotiation history. Contains all cfps made so far.

*: optional parameter

In the code below it is described what needs to be done for executing a Dutch auction. First, the capability, the da_initiate and the da_decide_iteration goals need to be included as shown in Figure 16.49, “ Including the protocols capability and the goals for the Dutch auction protocol ”. In a plan the da_initiate goal needs to be created and its mandatory parameters should be set to the desired values. After dispatching the goal (cf. Figure 16.50, “Using the da_initiate goal”) one can wait for its completion and read out the results of the protocol execution. During the execution the engine will raise a da_decide_iteration goal in every negotiation round which should be handled by a custom user plan.

...
<capabilities>
    <capability name="procap" file="jadex.planlib.Protocols"/>
    ...
</capabilities>
...
<goals>
    ...
    <achievegoalref name="da_initiate">
        <concrete ref="procap.da_initiate"/>
    </achievegoalref>
    <querygoalref name="da_decide_iteration">
        <concrete ref="procap.da_decide_iteration"/>
    </querygoalref>	
    ...
</goals>
<plans>
    <plan name="decide_iteration_plan">
        <parameter name="cfp" class="Object" direction="out">
            <goalmapping ref="da_decide_iteration.cfp"/>
        </parameter>
        <parameter name="cfp_info" class="Object" direction="inout" optional="true">
            <goalmapping ref="da_decide_iteration.cfp_info"/>
        </parameter>
        <parameterset name="history" class="Object">
            <goalmapping ref="da_decide_iteration.history"/>
        </parameterset>
        <body>new MyDecideIterationPlan()</body>
        <trigger>
            <goal ref="da_decide_iteration"/>
        </trigger>
    </plan>
</plans>
...				

Figure 16.49.  Including the protocols capability and the goals for the Dutch auction protocol

public void body() {
    AgentIdentifier[] recs = ...
    Object cfp = ...
    IGoal daini = createGoal("da_initiate");
    daini.getParameterSet("receivers").addValues(recs);
    daini.getParameter("cfp").setValue(cfp);
    daini.getParameter("auction_description").setValue(new AuctionDescription(
        System.currentTimeMillis()+1000, roundtimeout, "Test auction 1"));
    dispatchSubgoalAndWait(daini);
    Object res = request.getParameter("result").getValues();
    ...
}				

Figure 16.50. Using the da_initiate goal

Not shown here is the content of the custom decide iteration plan body which has the purpose to generate a new cfp if the next auction round should be performed A convenient way to do this consists in using an automatic offer generator following the interface of jadex.planlib.IOfferGenerator. Currently there are two implementation of this interface that allow automatic price generation. For linear price intervals you can use the LinearPriceCalculator and for exponential intervals the ExponentialPriceCalculator.

16.3.5.2. Participant Side

On the participant side a Dutch auction protocol is triggered when the da_filter belief value allows this (per default it is turned off). When a inform start-auction message arrives that passes the da_filter a new “da_receiver_interaction” goal is created. This goal is present during the whole lifetime of the interaction and will contain the results and interaction state of the conversation. If the participant side wants to be informed about the outcome of its conversations it can do so by waiting for the completion of this goal (using the goalfinished trigger type). For the implementation of the participant domain functionality two goals need to be supported. If the conversation is handled by the capability it will automatically request domain activities by dispatching subgoals which should be handled by custom user plans.

The “da_decide_participation”-goal is raised when an inform start-auction message has been received. It is used to determine if the participant wants to participate at the auction. If no plan is provided for handling the goal this is valued as acceptance and the agent will participate at the auction.

Table 16.28. Parameters for da_decide_participation

NameTypeDescription
initiator AgentIdentifier The agent identifier of the initiator.
auction_description AuctionDescription A detailed description about the auction.
auction_info [out] * Object Optional details about the auction that are only available locally.
participate [out] * Boolean True if the agent wants to participate.

*: optional parameter

If the agent has decided to particpate and the auction has started it will be requested to react on call-for-proposals of the initiator. For this purpose a “da_make_proposal” goal will be raised in every negotiation round. A custom user plan should be provided that handles the goal by evaluating the cfp and deciding about its acceptance. Additionally, the agent can also decide to leave the auction in every round via the goal if circumstances have changed.

Table 16.29. Parameters for da_make_proposal

NameTypeDescription
cfp Object The call-for-proposal represnts the current offer of the auctioneer.
auction_description AuctionDescription A detailed description about the auction.
auction_info [inout] * Object Optional details about the auction that are only available locally.
history [set] * Object The history of earlier CFPs.
accept [out] * Boolean True if the agent wants to accept the current cfp.
leave [out] * Boolean True if the agent wants to leave the auction.

*: optional parameter

To use these goals, you must first of all include the Protocols capability in your ADF (if not yet done in order to use other goals of the Protocols capability) and set a reference to the goals as described in Figure 16.51, “ Including the Protocols capability and the participant goals for the Dutch auction ”.

...
<capabilities>
    <capability name="procap" file="jadex.planlib.Protocols"/>
    ...
</capabilities>

<beliefs>
    <beliefref name="da_filter" class="IFilter">
        <concrete ref="procap.da_filter"/>
    </beliefref>
    ...
</beliefs>

<goals>
    <performgoalref name="da_receiver_interaction">
        <concrete ref="procap.da_receiver_interaction"/>
    </performgoalref>
    <achievegoalref name="da_decide_participation">
        <concrete ref="procap.da_decide_participation" />
    </achievegoalref>
    <querygoalref name="da_make_proposal">
        <concrete ref="procap.da_make_proposal" />
    </querygoalref>
    ...
</goals>

<plans>
    <plan name="decide_participation_plan">
        <parameter name="participate" class="Boolean" direction="out" optional="true">
            <goalmapping ref="da_decide_participation.participate" />
        </parameter>
        <parameter name="auction_description" class="AuctionDescription">
            <goalmapping ref="da_decide_participation.auction_description" />
        </parameter>
        <parameter name="auction_info" class="Object" direction="out" optional="true">
            <goalmapping ref="da_decide_participation.auction_info" />
        </parameter>
        <body>new MyDecideParticipationPlan()</body>
        <trigger>
            <goal ref="da_decide_participation"></goal>
        </trigger>
    </plan>
    
    <plan name="make_proposal_plan">
        <parameter name="accept" class="Boolean" direction="out" optional="true">
            <goalmapping ref="da_make_proposal.accept" />
        </parameter>
        <parameter name="leave" class="Boolean" direction="out" optional="true">
            <goalmapping ref="da_make_proposal.leave" /> 
        </parameter>
        <parameter name="cfp" class="Object">
            <goalmapping ref="da_make_proposal.cfp" />
        </parameter>
        <parameter name="auction_description" class="AuctionDescription">
            <goalmapping ref="da_make_proposal.auction_description" />
        </parameter>
        <parameter name="auction_info" class="Object" direction="inout" optional="true">
            <goalmapping ref="da_make_proposal.auction_info" />
        </parameter>
        <parameterset name="history" class="Comparable" optional="true">
            <goalmapping ref="da_make_proposal.history" />
        </parameterset>
        <body>new MyMakeProposalPlan()</body>
        <trigger>
            <goal ref="da_make_proposal"/>
        </trigger>
    </plan>
</plans>
...
<configurations>
    <configuration name="default">
        <beliefs>
            <initialbelief ref="da_filter">
                <fact>IFilter.ALWAYS</fact>
            </initialbelief>
            ...
        </beliefs>
        ...
    </configuration>
</configurations>
...				

Figure 16.51.  Including the Protocols capability and the participant goals for the Dutch auction

Besides the inclusion of the relevant goals and beliefs the main task of the agent programmer consists in developing the custom domain plan(s). Here in the example code they are named MyDecideParticipationPlan and MyMakeProposalPlan. As the basic responsibilities of the two plans consists in performing domain tasks and writing back the results to the goals no further code cutouts are shown here.

16.3.6. Abnormal Termination of Protocols

As described in the specification of the FIPA protocols such as FIPA Request and FIPA Contract Net, at any point in time, one side of an ongoing interaction, i.e. the initiator or one of the participants, may decide to leave the interaction. When the initiator decides to leave the interation this will lead to the whole interaction to stop, while when a participant leaves, the initiator will usually continue to interact with the other participants. To indicate that it wishes to leave an interaction, a participant may send a not-understood message, while an initiator can decide to stop the whole protocol by sending a cancel message to all participants.

In the Protocols capability, all interactions are represented by an interaction goal. Therefore, when an agent whishes to leave an interaction it can naturally do so by dropping the corresponding goal. Generic mechanisms available in all implemented protocols will take care of the necessary coordination between initiator and participant(s). These mechanism are described in more detail in the following sections Section 16.3.6.1, “Leaving an Interaction (Participant Side)” and Section 16.3.6.2, “FIPA Cancel Meta Protocol (CM)”.

16.3.6.1. Leaving an Interaction (Participant Side)

The Participant Termination Subprotocol

Figure 16.52. The Participant Termination Subprotocol

The process of leaving an interaction is depicted in Figure 16.52, “The Participant Termination Subprotocol”. At any time after the interaction has started, the domain layer of the participant may decide to drop the interaction goal (e.g. a "cnp_receiver_interation" goal). The protocol will be aborted at the participant side and as an indication, a not-understood message is sent to the initiator, which will exclude the participant from the rest of the interaction. The participant domain layer can check the state after the abortion of the interaction, by waiting for the goalfinished event of the "<protocol>_receiver_interaction" (e.g. rp_receiver_interaction) goal and inspecting the "interaction_state" parameter.

16.3.6.2. FIPA Cancel Meta Protocol (CM)

The FIPA Cancel Meta Protocol

Figure 16.53. The FIPA Cancel Meta Protocol

In Figure 16.53, “The FIPA Cancel Meta Protocol” it is shown, how a protocol can be cancelled from the initiator side. At any time after the interaction has started, the domain layer of the initiator may decide to drop the interaction goal (e.g. a "cnp_initiate" goal). The protocol will be aborted at the initiator side and a cancel message is sent to all participants. According to the FIPA Cancel Meta Protocol, which is specified as part of several other FIPA protocol specifications[4], the participant has two choices. It may either answer with an inform message thereby indicating that it has no problem with the cancellation of the protocol. Otherwise, it might send a failure message containing some description of its objections (e.g. if the participant already performed some costly task it may demand a reimbursement). This decision is delegated to the participant domain layer in form of the query "cm_approve_cancel" goal. It contains the following input and output parameters:

Table 16.30. Parameters for cm_approve_cancel

NameTypeDescription
conversation-id String The id of the interaction to be cancelled. Can e.g. be used to find the corresponding goal in the goal base.
protocol String The name of the cancelled protocol (e.g. "fipa-request").
initiator AgentIdentifier The agent identifier of the initiator of the interaction.
result [out] Boolean Should be set to true if the interaction can be safely cancelled, and to false if there are some problems related to cancelling the interaction.
failure_reason [out] * Object An object describing the participants objections to the cancellation of the protocol.

*: optional parameter

The "conversation-id", "protocol", and "initiator" parameters are used to identify the interaction to be cancelled. The boolean "result" parameter is used to store the decision and another parameter is available for the optional "failure_reason". A default plan exists in the protocols capability that will automatically acknowledge all "cm_approve_cancel" goals. Therefore custom plans for this goal are only necessary, when in some cases a failure message should be sent. Regardless of the goal result, the interaction will be terminated at the participant side, when the "cm_approve_cancel" goal returns. The handling of possibly required compensations is out of the scope of the cancel meta protocol and would have to be performed in a separate interaction between participant and initiatior.

The decision and potentially also the failure reason are communicated back to the sender, after the interaction has been terminated at the participant side. After all participants have answered to the cancel message or after the timout has passed, the protocol also ends at the initiator side. The participant and the initiator domain layer can check the state after the abortion of the interaction, by waiting for the goalfinished event of the "<protocol>_receiver_interaction" goal resp. the "<protocol>_initiate" goal and inspecting the "interaction_state" parameter, which will also contain references to the supplied failure reasons of the participants (if any). This information should be useful to initiate compensation actions, if necessary.



[2] The implementation of the protocol currently only supports a single winner per auction. In future releases, support for multiple winners might be added, e.g., supporting several items of a good to be auctioneered at once.

[3] The implementation of the protocol currently only supports a single winner per auction. In future releases, support for multiple winners might be added, e.g., supporting several items of a good to be auctioneered at once.