Snippets

Sebastian Sardina FAQ for using SARL + SWI/JPL Prolog + Maven

You are viewing an old version of this snippet. View the current version.
Revised by Sebastian Sardina db22027

FAQ for using SARL + SWI Prolog (with JPL) + Maven

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!


ECLIPSE

We use ECLIPSE to develop SARL applications.

How do I make ECLIPSE know about environment variables (e.g., SARL_VERSION)?

I can imagine there are other ways, but the way I made it work is by starting ECLIPSE from CLI with the variable exported already:

$ export SARL_ECLIPSE=0.7.2
$ ./eclipse-sarl

If you find another way that ECLIPSE can gather the environment variables (without re-defining them one by one), let me know!

What plugins are useful to develop on SARL in ECLIPSE?

On the SARL ECLIPSE distribution I install:

IntelliJ

We use IntelliJ to develop pure Java applications.

When I run an application I get erro saying no jpl in java.library.path?

IntelliJ cannot find the native library as it does not have LD_LIBRARY_PATH set correctly. See next question.

How do I tell IntelliJ about environment variables (like LD_LIBRARY_PATH)?

You set environment variables (if not set already system-wide) for each run/debug configuration.

Since it is painful to do it manually for each, one should first modify the Templates in "Run/Debug Configuration" to include the environment variables needed, for example LD_PRELOAD, SWI_HOME_DIR, and LD_LIBRARY_PATH.

See this post

For example, modify the JUnit template by just enter this string in "Environment variables":

   LD_LIBRARY_PATH=/usr/local/swipl-git/lib/swipl/lib/x86_64-linux/;SWI_HOME_DIR=/usr/local/swipl-git/lib/swipl/;LD_PRELOAD=libswipl.so

Then, create a new Run from the template, and it will already inherit the environment variables.


SWI-PROLOG and Java-SWI JPL Connectivity

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

What environment variables I should care about (in Linux)?

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.


MAVEN

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

The version of the maven-compiler-plugin should not be higher than 3.6.2 because the newer versions are using Java 1.9. And, it may cause problems during the compilation process.

In reality, the maven-compiler-plugin is not mandatory at all in the POM because Maven is supposed to download one when needed for compilation. If you encounter strange error related to the use of an Java 9 class from the Google library, then you have to specify the maven-compiler-plugin in order to avoid it:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.2</version>
            <configuration>
                <source>${compiler.level}</source>
                <target>${compiler.level}</target>
                <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
        </plugin>

How to assemble my whole SARL application in a JAR file?

You can use maven-assembly-plugin build pluin:

    <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>BootMAS</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>

            <!--  EXECUTIONS -->
            <executions>
                <!--  Assemble an application bundle or distribution from an assembly descriptor.  -->
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Note that with version 3.1.0 this may take quite longer to compile, as all dependencies are packaged into a single, often large, JAR file.

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 .

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


SARL

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

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

Because it uses and builts on XTEND framework.

Seems my 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

Can we document SARL code for JAVADOC?

Presumably yes:

http://www.sarl.io/docs/official/faq/SyntaxFAQ.html#1-11-can-we-document-sarl-code-for-javadoc

Additionnally, in later version, a sarldoc command-line tool for helping will be provided.

In 0.8.6 I was not successful. Check this post: https://groups.google.com/forum/#!topic/sarl/E_mhpFWyBFo

How do I control the log-level of the Logging built-in capacity?

See here.

How can we 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)
}

Equality and identity comparison (==, ===, !=, !==) in SARL and checking for null: same as Java ?

Check here

I believe the mapping is like this because:

  • In Xtend the equals operators (==, !=) are bound to Object.equals.
  • Java’s identity equals semantic is mapped to the tripple-equals operators === and !== in Xtend.

Check xtend doc here for more details and SARL doc here.

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 incoherencies of Xtend are fixed in SARL.

There is still a bit of an issue inside the Xbase library; check this https://github.com/sarl/sarl/issues/852#issuecomment-420842088

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 ===.

How to return two values? Pairs in SARL

Check here

I cannot pass data to the Initialize of a Behaivor, 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](https://groups.google.com/forum/#!topic/sarl/E0TuX-V123U):

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

I cannot define a static field in an agent tye declaration (agent, skill, behavior), why?

Check here

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 spawnning 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.

Strange error in CLI when using occurence on left hand side of assignments

From 0.9.0, there is an error if the SARL compiler has detected an assignment to a field of occurrence. Passing a field of occurrence to a function becomes a warning (See FAQ 0.9).

For older versions:

http://www.sarl.io/docs/official/faq/SyntaxFAQ.html#1-10-why-is-an-error-or-a-warning-put-on-the-occurrence-keyword

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.