This tutorial explains how to develop a simple, but fully working scenario in 15 minutes with the most recent version of the AgentSpeak(L++) source code.
Note: This tutorial aims at developers of multi-agent systems (MAS) and requires some basic understanding in programming.
The basic knowledge about agents and their execution mechanism from the knowledgebase
git
via your favourite package manager should be sufficient.brew install git
.This tutorial gives you a very short introduction to LightJason’s AgentSpeak(L++) structure. Our source code documentation can help you in developing your own MAS project according to your individual requirements.
This tutorial is structured as follows: First you will create your own MAS project based on the template created by the Maven tool. Then you will add the LightJason/AgentSpeak(L++), hosted on maven central as a dependency to your own MAS project.
Note: If you prefer a more bleeding-edge version of AgentSpeak(L++), see → How to Build AgentSpeak from Source.
All further configuration of xml
files and programming will then take place in your own project’s directory.
For the following sections we assume that you are working inside the directory Developer/
. If you want to use another directory, replace Developer
accordingly.
Create an empty Maven project (see Maven in 5 minutes tutorial) inside the Developer
directory:
cd Developer
mvn archetype:generate -DgroupId=myagentproject -DartifactId=myagentapp -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Maven will then create a project template, resulting in the following directory structure:
├── Developer/
│ └── myagentapp/ <-- created by Maven
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── myagentproject/
│ │ └── App.java
│ └── test/
│ └── java/
│ └── myagentproject/
│ └── AppTest.java
Developer/myagentapp/
is the directory in which your own MAS projects resides.
Take a note of the current values of groupId
, artifactId
and version
of the AgentSpeak version provided by maven central:
<dependency>
<groupId>org.lightjason</groupId>
<artifactId>agentspeak</artifactId>
<version>0.0.1</version>
</dependency>
Inside Developer/myagentapp/
open the pom.xml
with your preferred (programming) editor, navigate to the <dependencies>
section and add the complete excerpt above or below the already present <dependency>
entries (for example, you will also find an entry for JUnit within this section).
For LightJason/AgentSpeak to run, it is crucial to enforce Java 1.9 support in your project. Add the following entry before the <dependencies>
section:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.9</maven.compiler.source>
<maven.compiler.target>${maven.compiler.source}</maven.compiler.target>
</properties>
Put the following code inside the <project>
section, e.g. after </dependencies>
. This sets the current Maven components e.g. documentation build, packaging with Maven Shade Plugin which creates an executable JAR when you build your project with mvn package
. The commented-out section defines the LightJason styleguide checking for the project
<build>
<!-- make "package" the default goal to run "mvn package" every time -->
<defaultGoal>package versions:display-dependency-updates versions:display-plugin-updates versions:display-property-updates</defaultGoal>
<!-- using build plugins -->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.6</version>
<configuration>
<tempWebappDirectory>${basedir}/target/site</tempWebappDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- enable compiler warnings -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
<failOnWarning>true</failOnWarning>
</configuration>
</plugin>
<!-- let "mvn clean" clean up additional files -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<filesets>
<fileset>
<directory>.</directory>
<includes>
<include>dependency-reduced-pom.xml</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
<!-- create an executable jar file -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>myagentproject.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<!-- enforce java and maven version -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M1</version>
<executions>
<execution>
<id>defaults</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>[3.1,)</version>
</requireMavenVersion>
<requireJavaVersion>
<version>[${maven.compiler.source},)</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<!-- checkstyle is performed during the compile phase
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.17</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>[7.8.2,)</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>checkstyle</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<configLocation>src/checkstyle/style.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
</plugin>
-->
</plugins>
</build>
Test-build your project by running mvn package
inside Developer/myagentapp/
, i.e. where your pom.xml
is located:
cd Developer/myagentapp/
mvn package
It should print BUILD SUCCESS
.
The resulting, runnable JAR is located at Developer/myagentapp/target/myagentapp-1.0-SNAPSHOT.jar
.
Import your Maven project into your preferred IDE.
Note: The file names and paths provided in the following sections are relative to your project folder. For example src/main/java/myagentproject/MyAgent.java
refers to the file MyAgent.java
located at Developer/myagentapp/src/main/java/myagentproject/
.
Each agent you use must be inherited from our base class IAgent interface, but we recommend our IBaseAgent with a complete execution mechanism. Please note that you need to pass your agent class as a generic parameter to the definition of a LightJason agent class. A necessary property is the serialVersionUID
which is defined by the Java Serializable interface - this allows to serialise the agent e.g. to transfer the agent over the network
Create an agent class MyAgent.java
in src/main/java/myagentproject/
as follows:
package myagentproject;
import org.lightjason.agentspeak.agent.IBaseAgent;
import org.lightjason.agentspeak.configuration.IAgentConfiguration;
import javax.annotation.Nonnull;
final class MyAgent extends IBaseAgent<MyAgent>
{
private static final long serialVersionUID = -2111543876806742109L;
MyAgent( @Nonnull final IAgentConfiguration<MyAgent> p_configuration )
{
super( p_configuration );
}
}
Next create your own agent generator (agent factory). This component is based on the UML factory pattern. Within the factory the agent script (ASL) is parsed once and you can generate a lot of agents with a single factory. We support a general implementation of the factory the IBaseAgentGenerator.
Create an agent generator class MyAgentGenerator.java
in src/main/java/myagentproject/
as follows:
package myagentproject;
import org.lightjason.agentspeak.common.CCommon;
import org.lightjason.agentspeak.generator.IBaseAgentGenerator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.InputStream;
import java.util.stream.Collectors;
final class MyAgentGenerator extends IBaseAgentGenerator<MyAgent>
{
MyAgentGenerator( @Nonnull final InputStream p_stream ) throws Exception
{
super(
p_stream,
CCommon.actionsFromPackage().collect( Collectors.toSet() )
);
}
@Nullable
@Override
public final MyAgent generatesingle( @Nullable final Object... p_data )
{
return new MyAgent( m_configuration );
}
}
In this section you will write your own runtime1 within the main
method of the App
class.
The runtime is responsible for running the agents in each cycle.
We are using Java streams to execute the agent, but you can use also a thread-pool, because all agents implement the Callable interface (the Future object is the agent in the state $cycle + 1$)
package myagentproject;
import java.io.FileInputStream;
import java.util.Collections;
import java.util.Set;
import java.util.logging.LogManager;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
final class App
{
static
{
LogManager.getLogManager().reset();
}
private App()
{
}
public static void main( final String[] p_args )
{
if ( p_args.length < 2 )
throw new RuntimeException( "arguments are not set: ASL script, number of agents" );
final Set<MyAgent> l_agents;
try
(
final FileInputStream l_stream = new FileInputStream( p_args[0] );
)
{
l_agents = Collections.unmodifiableSet(
new MyAgentGenerator( l_stream )
.generatemultiple( Integer.parseInt( p_args[1] ) )
.collect( Collectors.toSet() )
);
}
catch ( final Exception l_exception )
{
l_exception.printStackTrace();
return;
}
IntStream
.range(
0,
p_args.length < 3
? Integer.MAX_VALUE
: Integer.parseInt( p_args[2] )
)
.forEach( j -> l_agents.parallelStream()
.forEach( i ->
{
try
{
i.call();
}
catch ( final Exception l_exception )
{
l_exception.printStackTrace();
throw new RuntimeException();
}
} ) );
}
}
Create a simple Hello World agent for testing purposes.
Add a file agent.asl
in the top-level directory of your project with the following content:
!main.
+!main <-
generic/print("Hello World!");
!mynextgoal
.
+!mynextgoal <-
generic/print("Hello World! (again)");
!mynextgoal
.
The agent starts in cycle $0$ with the initial goal !main
. As the plan main
matches, it gets executed, i.e. it prints “Hello World” and adds mynextgoal
to be triggered in the next cycle.
In cycle $1$ and following cycles $1+n$ the agent will execute the plan mynextgoal
, printing Hello World! (again)
with the current cycle number and adding the trigger for the same plan for the following cycle.
Run Maven within your project directory to build the program:
mvn package
Run the program to create 500 agents based on the agent.asl
and the agents will run 1000 cycles:
java -jar target/myagentapp-1.0-SNAPSHOT.jar agent.asl 500 1000
Observe the CPU load and time with the print actions (code above) and without (code below):
!main.
+!main <-
!mynextgoal
.
+!mynextgoal <-
!mynextgoal
.
i.e. run
java -jar target/myagentapp-1.0-SNAPSHOT.jar agent.asl 500 1000
and compare it with
java -jar target/myagentapp-1.0-SNAPSHOT.jar agent_noprint.asl 500 1000
With an i7-3770 4C/8T CPU (“benchmarked” with the Linux/Unix tool time
) this yields
time java -jar target/myagentapp-1.0-SNAPSHOT.jar agent.asl 500 1000
...
62.57s user 6.33s system 438% cpu 15.727 total
vs.
time java -jar target/myagentapp-1.0-SNAPSHOT.jar agent_noprint.asl 500 1000
...
44.06s user 1.47s system 595% cpu 7.638 total
It is noteworthy that
If you struggled at some point or wish to obtain our exemplary solution with code documentation of this tutorial, you can download the archive containing the source code and an executable jar file: