Skip to content

Instantly share code, notes, and snippets.

@ssardina
Last active June 24, 2021 12:55
Show Gist options
  • Save ssardina/ba59838bd6f2c2a64896e79533f35054 to your computer and use it in GitHub Desktop.
Save ssardina/ba59838bd6f2c2a64896e79533f35054 to your computer and use it in GitHub Desktop.

SARL FAQ and Issues

This is a collection of questions/issues that arose from my teaching of Agent Oriented Programming, where I have assessments in SARL and SWI-Prolog, all packaged with Apache Maven.

If you think a question is worth putting it here, please let me know, I am happy to add it! THANKS!

SARL documentation includes three FAQs that you may want to check first:

NOTE: Many of the answers here are almost verbatim explanations from SARL developer Stéphane Galland to my email enquires :-)

Finally, there is also the official SARL Google Discussion Forum at:

https://groups.google.com/g/sarl

Remember to follow good online forum etiquette when posting there

Table of Contents

Syntax

SARL is similar to Java but has different syntax in many places, how come?

Because it uses and builds on XTEND framework.

To check particular SARL syntax and slight differences with Java, please check Section 5.1 in the documentation.

Note directly from SARL developer (Sept 2018): SARL extends a part of Xtend dialect in order to have benefits of several background features, such as the validation tests for type inheritance. Since Xtend and SARL uses Xbase, a large part of the syntax is the same, especially within the blocks of code. (The rest of the syntax is defined in parallel. SARL was inspired by languages such as Scala, Python and Ruby. Several bugs or incoherence of Xtend are fixed in SARL.

There is still a bit of an issue inside the Xbase library; check this sarl/sarl#852 (comment)

I have created an issue regarding null == value: Issue #854. According to the associated discussion within the Xbase group #300, the error message will be updated to push the developers to use ===.

What does ^ mean?

^ is the SARL convention for escaping reserved keywords like agent and skill. So, if you want to use skill as a variable name you have to say ^skill.

What do this and it mean?

Check the answer here.

So, this is like in Java, the current object; whereas it is the object in the lambda expression.

Casting in SARL

Instead of Java casting (X) Y, SARL uses the format X as Y. For example:

this.chargingStations.put(facility.name, facility as ChargingStationData)

See Cast and Type Conversions in SARL documentation.

Active Annotations & Local extension methods

Inspired by other modern programming languages, SARL comes with many "short-hands" to make the life of programmers easier and the code cleaner.

One of them is Active Annotations which allows, among other things, the easy definition of "getters" and "setters". For example, by writing:

@Accessors var name : String

SARL will automatically generate the methods getName() and setName(name: String).

In turn, extension methods allow you to add new methods to existing types without modifying them.

So, we can write occurrence.getEntityState to denote getEntityState(occurrence) (as if the class of occurrence had been extended with the getEntityState method).

HOW-TO

Emit an event in a "compact" way

Instead of:

emit(new E_EntitySensed(last_step, entityName, percepts))

one can write:

emit(new E_EntitySensed => [it.last_step = last_step, entity = entityName, perceptData = percepts])

See how we use it.last_step to refer to the property in the event. The compiler searches for a variable of name v following the steps:

  1. if a local variable named v is accessible, it is used;
  2. if an attribute for it, i.e. it.v, it is used;
  3. if an attribute for this, i.e. this.v, it is used;
  4. if a variable v is statically imported, it is used.

Emit an event with a scope

This will emit the event to agents with addresses a1 and a2 only. The it refers to the receiver agent.

emit(new MyEvent) [ it == a1 || it == a2 ]

The above emit uses scopes with Lambda expressions and implicit variables.

Consdier for following line in the English Auction Tutorial:

emit(new Bid(newPrice)) [ it.ID == defaultContext.ID]

The objective of this line is that only the Auctioneer agent sees the bid. This is how.

The above event is emitted with a scope defined, that is, restricting the agents who will see the event. More concretely, it emits the event Bid with the receiver agent (denoted by it)'s id (denoted by it.ID) equal to the ID of the default context of the Bidder agent emitting the event (that is, defaultContext.ID).

In this particular example, because the Bidder agent emitting the event is in fact a Holon agent inside the Auctioneer agent's inner context, then the default context of the Bidder is indeed the inner context of the Auctioneer. In turn, the ID of an inner context is always the same as the ID of the corresponding agent.

All in all, defaultContext.ID is the ID of the default context of the Bidder, which is the ID of the inner context of the Auctioneer, which is the ID of the Auctioneer agent. And the event is only seen by the Auctioneer as desired. :-)

How to spawn an agent and keep its UUID identification?

Before 0.11.0 there was a spawning mechanism that will return the UUID of the agent created. From 0.11.0, one has to create a UUID and then spawn the agent with that id:

import io.sarl.core.DefaultContextInteractions

//val agent_UUID2 = UUID::randomUUID;  // more "SARLish" way
val agent_UUID = UUID.randomUUID();
spawnInContextWithID(TestAgt_Slave, agent_UUID, defaultContext, 200)

<here you can refer to agent_UUID>

How can I know when an agent has been created fully after being spawn?

An event AgentSpawned will be emitted when an agent has been created and can be handled, say by a coordinator, to know the agent is now alive! Fo example:

on AgentSpawned {
    info("Agent {0} of type {1} has been created successfully and is now alive!",
        occurrence.agentIdentifiers, occurrence.agentType)
}

Can I make SARL wait in the execution on some thread?

Yes, use something like TimeUnit.SECONDS.sleep(5)

Emitting events and spawning agents in "on Intialize" behaviors: be careful!

Check here

More details on how events and spawning are processed by the SARL execution engine

When the event e is received by an agent the following algorithm is applied:

if "on Initialize" is currently running then
    add e to a buffer of events.
else if "on Destroy" is currently running then
    ignore the event.
else
    fire(e)
fi

The function fire(e) retrieves all the "on E" and runs them in parallel, and there is a synchronization point after the running of all the "on E" if E is Initialize or Destroy (for forcing synchronous execution of "on Initialize" and "on Destroy"). At the end of the "on Initialize" (after synchronization point), all the buffered events are fired.

Observe that if the event is fired from within the "on Initialize", the same algorithm is applied whatever the receiving agent.

Regarding spawn(), the function runs in two parts:

  1. First, the spawn agent is created. This part is run in the same thread as the caller of spawn, so the spawn call blocks.
  2. Once the spawn agent has been created, the initialization process runs within a separated thread from the spawner agent. So, the call spawn() is now not locked anymore. Then, the created thread runs all the initialization process, including the synchronous execution of "on Initialize". Consequently, the "on Initialize" of the spawn agent will not block the spawn caller.

Maven Usage/Support

First, you should read the Maven Plugin for the SARL Compiler.

Useful Maven commands

  • mvn compile (use default pom.xml) or mvn compile -f <pom file> to compile the application. Compiled classes will be placed in target/classes
  • mvn clean compile for a clean compile from scratch.
  • mvn jar:jar to produce the compile output into the JAR
  • mvn source:jar to generate the JAR with the sources (if configured in POM)
  • mvn javadoc:jar to generate the Javadoc under target/apidoc and into a JAR file (if configured in POM)
  • mvn package to generate all the configured JAR packages in target/.
  • mvn install will install the generated modules in the user ~/.m2/.

If your project has dependencies then you may want the sources of such dependencies to be able to see the source code (e.g., when developing in ECLIPSE).

  • mvn dependency:sources: to download sources of ALL dependencies (for example to be able to navigate to the source code when developing in ECLIPSE)
  • mvn dependency:sources -Dartifact=groupId:artifactId:version:packaging to get the sources of a particular artifact.
    • For example: mvn dependency:sources -Dartifact=org.bitbucket.ssardina-research:sarl-agtcity-intf:-SNAPSHOT:jar
  • mvn dependency:get -Dartifact=groupId:artifactId:version:packaging:classifier to get any artifact.
    • For example: mvn dependency:get -Dartifact=org.bitbucket.ssardina-research:sarl-agtcity-intf:-SNAPSHOT:jar:<javadoc|sources|...>

This puts the given artifact into your local Maven repository, i.e. usually $HOME/.m2/repository.

Dependencies via JitPack service

JitPack provides a service to get dependencies directly from Git repository services, like Github and Bitbucket. For example, your SARL application may use a core SARL skill interface that is provided in some Bitbucket service.

Include the JitPack under repositories* section be able to connect to bitbucket system:

<repositories>
...
	<!-- JitPack used for remote installation of dependencies from Github -->
	<repository>
		<id>jitpack.io</id>
		<name>JitPack Repository</name>
		<url>https://jitpack.io</url>
	</repository>
...
</repositories>

Copy JAR dependencies in a special directory

For this solution, we shall use the maven-dependency-plugin by instructing it to package all JAR dependencies into a /dependency-jars/ special directory as follows:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
      <execution>
        <id>copy-dependencies</id>
        <phase>package</phase>
        <goals>
          <goal>copy-dependencies</goal>
        </goals>
        <configuration>
          <outputDirectory>
            ${project.build.directory}/dependency-jars/
          </outputDirectory>
        </configuration>
      </execution>
    </executions>
</plugin>      

We should then tell to add the classpath of your project to the manifest and use the special directory we just specified where all JAR dependencies will be copied:

   <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.4</version>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>BootTestAgt</mainClass>
              <classpathPrefix>dependency-jars/</classpathPrefix>
            </manifest>
          </archive>
        </configuration>
      </plugin>

More information about how to specified classpaths here.

Produce JAVADOC for the application

To be able to execute mvn javadoc:jar use the maven-javadoc-plugin plugin within the build section of the POM:

                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-javadoc-plugin</artifactId>
                         <executions>
                           <execution>
                                 <id>attach-javadocs</id>
                                 <goals>
                                   <goal>jar</goal>
                                 </goals>
                           </execution>
                         </executions>
                        </plugin>

Produce JAR files with all sources

If you want your JAR files to include both Java and SARL sources add this to the build section of the POM:

<build>
          <resources>
               <resource>
                    <directory>src/main/sarl</directory>
                    <filtering>false</filtering>
                </resource>
                <resource>
                    <directory>src/main/java</directory>
                    <filtering>false</filtering>
                </resource>
          </resources>
...
<\build>

To be able to produce a JAR file with just the sources (via mvn src:jar) use the maven-source-plugin plugin within the build section of the POM:

       <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-source-plugin</artifactId>
              <executions>
                    <execution>
                          <id>attach-sources</id>
                           <goals>
                               <goal>jar</goal>
                           </goals>
                    </execution>
              </executions>
       </plugin>

Define a booting class

We can tell Maven to use a specific main class when running mvn java:exec via the exec-maven-plugin plugin.

The standard way to start a SARL application is to use io.janusproject.Boot as the main class which wil boot a given SARL agent. We can define then such class as the exec class as follows in pom.xml:

<!--  Class to execute via maven exec:java 
	https://www.mojohaus.org/exec-maven-plugin/ -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
        <addClasspath>true</addClasspath>
        <mainClass>io.janusproject.Boot</mainClass>
</configuration>
</plugin>

However, if we use a specialized booting class (e.g., BootMAS.sarl) as explained above we can instead use:

<!--  Class to execute via maven exec:java 
	https://www.mojohaus.org/exec-maven-plugin/ -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
        <addClasspath>true</addClasspath>
        <!-- THIS WOULD BE THE DEFAULT CLASS TO BOOT
            <mainClass>io.janusproject.Boot</mainClass>
         -->
        <mainClass>BootMAS</mainClass>
</configuration>
</plugin>

Now, when issuing mvn exec:java class BootMAS will be started. See above an example of such class that will ask the user what agent to boot-up.

How do I install a JAR dependency manually?

Suppose your application need version 1.2.0.7.2 of artifact sarl-agtcity-mw from group id org.bitbucket.ssardina-research, but for some reason it cannot be gathered automatically from the cloud. Suppose you can get a hold of that dependency and obtain file sarl-agtcity-mw.jar. How do you install it in the repo? Here it is:

mvn install:install-file -Dfile=sarl-agtcity-mw.jar -DgroupId=org.bitbucket.ssardina-research \
	-DartifactId=sarl-agtcity-mw -Dversion=1.2.0.7.2 -Dpackaging=jar

How do I tell maven to work offline (not check anything on the internet)?

Use the -o option for offline mode (e.g., mvn -o clean package): https://www.packtpub.com/mapt/book/application_development/9781785286124/8/ch08lvl1sec81/working-in-offline-mode

Note you will still need to build the system online at least one, so that your system has the chance to get all the dependencies and store them under ~/.m2/

Why maven is not downloading the sources of dependencies?

ECLPSE IDE seems to download all sources by default. To get the sources via CLI: mvn dependency:sources

To state the POM to get all sources (and javadocs) of dependencies, check this post

Maven can throw lots of warnings and xml messages, how do I filter them?

To remove the WARNING mesages:

mvn exec:java | grep -v -e WARNING 
mvn clean package | grep -v -e WARNING

To also remove all the print out of xml messages (e.g., the ones thrown by the Massim EIS for the Agents in City game):

mvn exec:java | grep -v -e \<.*> -e WARNING -e '^ sent' -e '^ received'

How can I pass arguments to Maven? For example, variable java.library.path?

You can use the MAVEN_OPTS environmnt variable that will apply to all calls to Maven. For example:

export MAVEN_OPTS=-Djava.library.path=/usr/local/swipl-git/lib/swipl/lib/x86_64-linux/

How to configure testing disabled by default?

We use the Maven Surefire Plugin with skipping by default:

 <properties>
    <skipTests>true</skipTests>
  </properties>

<!-- JUNIT testing framework -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <!--<scope>test</scope>-->
</dependency>

<build>
    <testSourceDirectory>src/java/org/jpl7/test</testSourceDirectory>
    ...
    <plugin>
        <!-- Unit test execution -->
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.12.4</version>
        <configuration>
            <!-- Check this: https://maven.apache.org/surefire/maven-surefire-plugin/examples/skipping-tests.html -->
            <skipTests>${skipTests}</skipTests>
        </configuration>
   </plugin>
    ....
</build>

Then, we can enable the tests via mvn surefire:test -DskipTests=false

ECLIPSE IDE

Things to check before you start

  • Make sure the JRE for the project is 1.8, not below.

What plugins are useful?

Some plugins you may find useful:

  • Prolog Development Tool. For Prolog development, though it may be best to use VSCODE. May not be compatible with the latest IDEs.
  • Markdown text editor. There are other similar options in ECLIPSE Marketplace.
  • EasyShell: allows to open a shell window or file manager from the popup menu in the navigation tree or editor view.

No SRE defined for the IDE

The ECLIPSE IDE for SARL 0.11.0 does not pickup the Janus SRE when using Java 11:

no SRE

This is fixed in SARL 0.12.0 but can be resolved by using Java 8 to launch the SARL ECLIPSE IDE. To do so, add the -vm option to eclipse.ini as follows:

-startup
plugins/org.eclipse.equinox.launcher_1.5.700.v20200207-2156.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.1200.v20200508-1552
-vm
/usr/lib/jvm/java-8-openjdk-amd64/bin
-vmargs
-Xms256m
-Xmx1g

Also make sure to set the Java JRE in ECLIPSE to OpenJDK 8.

See issue #1057.

Incorrect reporting of undefined entities in ECLIPSE

The IDE may incorrectly report errors of undefined entities (e.g., properties or methods). These are reported in the code, but not in the "Problem" section. The system compiles well. For example:

incorrect undefined error

One way to solve this is to close and re-open the file giving the mistaken error.

This is a "strange behaviors" due to the Xtext framework on which the SARL compiler is based and it happens when SARL is upgraded.

When upgrading, the following is recommended:

  • fix the SARL versions in the POM file in order to have the exact same versions as in the SARL IDE;
  • do a full Maven compilation (on command-line if possible);
  • if the errors are still present, remove the project form ECLIPSE (without removing the code files), delete by hand the ECLIPSE project files (.project, .classpath, .settings), and import back the project into the Eclipse IDE, as a "SARL Maven project".

Check full explanation in issue #1056.

Error: Project build error: Unresolveable build extension: or Failed to collect dependencies

Somehow Maven is failing to grab the dependencies. Assuming there is network connection to the Internet, update the Maven local repo by doing right click on the project, then select Maven, then Update Project and make sure to select Click Force Update of Snapshots.

Troubleshooting

I get "no compiler is provided" error, why?

Make sure you:

  1. Have JDK installed in your system (the Java development framework that comes with the compiler javac), not just the Java runtime environment JRE.
  2. Your PATH environemnt variable points to the directory where java and javac of the JDK where installed.
  3. Your JAVA_HOME points to the directory where the JDK was installed. Alternative, you will need to specify it in your pom.xm; see here .

List of compile and run-time errors

Here is the list of SARL compiler errors

Here is a list of Janus run-time errors

Discouraged use of the feature occurrence. You should not use the feature occurrence

A discussion on this can be found in the forum here

Basically, the SARL compiler is informing that it was not able to infer that the variable event specified in variable occurrence was a read-only structure. It is intended that an event is read-only because the same event an be handled by different on behavior rules and one would like all behaviors to receive the same event structure/data regardless of the order in which they are executed.

Check errors 28a/b/c

The field X should be synchronized for avoiding value inconsistency due to parallel execution

SARL may produce highly concurrent executions, as all the on behaviors that apply for an event are meant to be executed in parallel.

Consider this code:

on toto {
    do smthg with t // code A
}
on tata {
    do smthg with t // code B
}

If both events toto and tota are emited, code fragments A and B may run together and hence have write access to data t.

SARL will give this warning, calling the user to add explicit synchronization. This can be done in a few ways:

SARL language provides the synchronized keyword:

val lock_t : ReentrantLock = new ReentrantLock();
// val lock_t : Object = new Object()


on toto {
    synchronized (lock_t) {
        do smthg with t // code A
    }
}
on tata {
    synchronized (lock_t) {
        do smthg with t // code B
    }
}   

Even more powerful, synchronized can be used on data directly:

on toto {
    synchronized (lock_t) {
        do smthg with synchronized(t) { t } // code A
    }
}
on tata {
    synchronized (lock_t) {
        do smthg with synchronized(t) { t } // code B
    }
}   

Note: SARL compiler tries to be smart and find out whether there is an issue with certain data. For inmutable data, like Strings, SARL should not give warnings, as two threads can never modify the same object. See this issue.

I cannot pass data to the Initialize of a Behavior, occurrence.parameters is always empty!

Not anymore an issue from 0.9, has been resolved in this issue.

For versions 0.8.6 or less:

From SARL developer in this post:

Currently, there is no way to set the occurrence.parameters values with the current API.

The Initialize event is fired by the registerBehavior function. As you could see, this function does not provide a mean for passing initialization parameters. I think the ability to set the Initialize parameters when registering the behaviors is a missed feature from the SARL API.

You could use the following work around:

behavior MyBehavior {

   var initParam : Object[]

   new (owner : Agent, initParam : Object*) {
	  super(owner)
	  this.initParam = initParam
   }

   on Initialize {
	  // Do something with this.initParam
   }

}

agent MyAgent {

   uses Behaviors

   on Initialize {
	  var beh = new MyBehavior(this, "p1")
	  beh.registerBehavior
   }
}

Note that because registration happens after the creation of the behavior module, the initParam will be available at time of Initialize execution.

Cannot access agent owner of a skill in Initialize behavior, why?

Summary in this thread

The owner of the skill is set when the skill is attached to the agent. It means that the owner cannot be known within the constructor of the skill. The function install is invoked just after the skill is installed into the agent. So:

new {
   super()
   assert this.owner === null
}

def install {
	assert this.owner !== null
}

Importantly, the initialization (via Initialize event) is not at creation time (constructor) but when the entity is attached to the agent.

Within SARL developers' perspective, constructor statements should be redefined only if you want to set the value of a field that is final (val keyword), because it is mandatory regarding the semantic of the val keyword. Consequently, the best practice is that all initializations should be within the on Initialize. They should avoid constructor definition.

So, the "clean" way to access the agent owner is in the install method:

skill SWIJPL_KB_Prolog implements KB_Prolog {
	var module_name : String

		 def install {
		   module_name = this.owner.ID.toString
		 }
... 
}

SARL is giving lots of WARNINGS at compile time, how can I avoid them?

Check here

A list of what can be @SupressWarnings can be found here

One can suppress ALL warnings using @SuppressWarnings("all")

Remove warnings when running the SARL application

Run like this:

$ mvn exec:java | grep -v -e WARNING

SARL & SWI-PROLOG via JPL Connectivity

General information

When using SWI Prolog from Java I recommend checking:

Making JPL work under Mac OS

Please refer to this entry in the JPL documentation. (Note: that is from 2018; it may be fixed in newer versions)

What does +, -, ? mean in predicate specifications?

Check here

Seems SARL application cannot find JPL!

There could be many reasons and it may depend on the OS you are using. You need to have SWI-Prolog, JPL package, and the right environment variables set-up.

Check this question

What environment variables I should care about?

Basically you need to let the system know which SWI Prolog is installed and you want to use.

Linux

If you are using a Linux distribution install, you would do something like this:

export SWI_HOME_DIR=/usr/lib/swi-prolog/
export LD_LIBRARY_PATH=$SWI_HOME_DIR/lib/x86_64-linux/:$SWI_HOME_DIR/lib/amd64/:$LD_LIBRARY_PATH
export LD_PRELOAD=libswipl.so:$LD_PRELOAD   # only if necessary and your app complains

The reason why we have two library paths is that lib/amd64/ is used for SWI 7.6.4, whereas lib/x86_64-linux/ is used in 8.x.x versions.

If, instead, you compiled the SWI from git sources and installed at /usr/local/swipl-git, you would do something like this:

export SWI_HOME_DIR=/usr/local/swipl-git/lib/swipl/
export LD_LIBRARY_PATH=$SWI_HOME_DIR/lib/x86_64-linux/:$SWI_HOME_DIR/lib/amd64/:$LD_LIBRARY_PATH
export LD_PRELOAD=libswipl.so:$LD_PRELOAD   # only if necessary and your app complains

Windows

  • A system variable SWI_HOME_DIR points to the root of SWI install.
  • System variable Path should include %SWI_HOME_DIR%\bin and %SWI_HOME_DIR%\lib\jpl.jar.

My Java/SARL application cannot cannot find JPL!

There could be many reasons and it may depend on the OS you are using.

First of all, make sure you have SWI-Prolog installed, either:

  • Stable version 7.6.4 as per standard Linux repository or executable install from SWI page.
  • Compiled 8.1.x+ version from swipl-devel repo.
    • Note current (Feb 2019) stable 8.0.x version has a problem with libswipl.so which makes JPL crash.

Second, make sure you also have the JPL package installed in the system. This is an additional SWI module, it is not part of the core.

  • In Windows, it is easy as you can click to install JPL Java<-->SWI interface at installation time.
    • You should see jpl.dll file in %SWI_HOME_DIR%/bin and jpl.jar in %SWI_HOME_DIR%/lib.
  • In Linux, you need to make sure libjpl.so and jpl.jar are somewhere! If you cannot find it, then you may need to install JPL.
    • In Ubuntu, it is provided with package swi-prolog-java.
    • In ARCH, you can generate it and install it using AUR package builder and swi-prolog-git package. Running the default PKG build file is enough to get JPL installed.
    • In MAC, we don't know how to make it work, as there is a glitch in one of the packages built for Mac... :-( [if you make it work, please let me know!]

Finally, make sure your system is aware of both SWI and JPL by setting the appropiate env variables; see previous above.

If you are using SARL, you may also refer to the instructions of the SARL Prolog Capacity

Why do I need to set LD_PRELOAD=libswipl.so?

To understand the environment library LD_PRELOAD check this post and this one about library preloading. Also, check this and this posts.

Changes SRE 2.x to SRE 3.x

SARL version 0.11.0 had a major change: it now uses Janus SRE 3 (the run-time environment for SARL). The new Janus is written in SARL itself rather than Java.

Here we list some of the changes you may encounter when migrating previous SAR systems (0.10.x and before).

Booting agents from Java

In the old SRE 2.x, one would start an agent from Java by directly using the Boot class in Janus:

import io.janusproject.Boot

...
Boot.startJanus(typeof(DummyMultiCarController))

In order to avoid any problems due to changes into the Janus implementation, in SRE 3.x it is preferable to use the SRE utility class as follows:

import io.sarl.bootstrap.SRE


var sre = SRE::bootstrap
sre.startAgent(typeof(DummyMultiCarController))

For more info refer to:

While explicitly not recommended, one could still use the "old-way" by using Janus directly via its Boot class (see Section 3 here:

import io.sarl.sre.boot.Boot;
Boot.createMainObject.startAgent(typeof(DummyMultiCarController))`

What happened with Boot.offline and Boot.verboseLevel?

Regarding Boot.offline, this parameter is not any more needed in the kernel of Janus v3. Indeed, the Janus v3 kernel is now based on a new plugin architecture (based on the Bootique API).

With this plugin API, we could write a core software (the kernel) with a minimum set of features and that could be extended with plugins by only adding these plugins on the classpath of the application.

In the context of Janus, the network features were moed into a plugin. One could easily add the network feature by adding the corresponding plugin ja file in the classpath (equivalent to the old Boot.offline = false) or remove it from the classpath (equivalent to Boot.offline = true), or even add another networking plugin that is based on another technology (e.g. MQTT, etc.).

So, Boot.offline function is not any more into the Janus kernel (i.e. the Boot class) but into the configuration of the networking plugin. This plugin is under validation and is planned to be back in SARL 0.12.x.

Regarding Boot.verboseLevel, the SRE utility class provides such a setting. Note that it must be called before any launch of agent since the configuration level of Janus is set at start up. For example:

class BootMAS {
	// Code adapted from example how to boot from name string: 	http://tinyurl.com/ycolmey5
	def static main(args : String[]) : void {
		var sre = SRE::bootstrap
		sre.verboseLevel = 7
//		bootstrap.setVerboseLevel(7)

....

See SARL doc coverage on this too.

Spawn agents and get their UUID

In SRE 2.x, we could spawn an agent and get their assigned UUID code via the spawn method in io.sarl.core.DefaultContextInteractions (here the 200 is a parameter passed to the agent Initialize behavior rule):

val agent_UUID = spawn(TestAgt_Slave, 200)

This method has been deprecated and all spawning methods are provided by the LifeCycle capacity/skill.

To spawn an agent and grab its UUID code, we first generate one and then spawn it with it:

uses DefaultContextInteractions
uses Lifecyle

val agent_UUID = UUID.randomUUID();
spawnInContextWithID(TestAgt_Slave, getDefaultContext, 200)

or more compactly:

uses DefaultContextInteractions
uses Lifecyle

var agent_UUID = UUID::randomUUID
typeof(TestAgt_Slave).spawnInContextWithID(agent_UUID, defaultContext)

The getDefaultContext will provide the default context of the agent.

SRE missing in ECLIPSE IDE

This may arise in 0.11.0 when using Java 11, but it was fixed in the upcoming 0.12.0 (as per Feb 2021).

The work-around for now is to run SARL ECLIPSE IDE using Java 8 by updating eclipse.ini and also change the JRE used in ECLIPSE to Java 8.

Check issue #1057 for details.

Application not booting via Java

The cause of the problem may be the new way in which create the JAR file with all dependencies: several service definitions of SARL/Janus services may not be correctly included into the "with-full-dependencies" jar file.

Check issue 1061

Links and Pointers

General Infrastructure Software

Some Interesting Projects using SARL

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment