Extensions Guide

NetLogo 2.0.1 User Manual   

NetLogo allows users to write new commands and reporters in Java and use them in their models. This section of the User Manual introduces this facility.

The first part discusses how to use an extension in your model once you have written one, or once someone has given you one.

The second part is intended for Java programmers interested in writing their own extensions.

Caution! The extensions facility is new in NetLogo 2.0.1 and is still in an early stage of development. Therefore it is considered "experimental". It is likely to continue to change and grow. If you write an extension now, it may need changes in order to continue to work in future NetLogo versions.

The NetLogo API Specification contains further details.

Using Extensions

An extension (which includes one or more custom commands and reporters) is stored in a "JAR" file (short for "Java Archive"). For a model to use an extension, it must declare what JARs it uses and where the JARs are stored.

For this purpose, the NetLogo language includes a keyword, __extensions, which may appear only at the beginning of the Procedures tab, before declaring any breeds or variables.

The keyword begins with two underscores to indicate that it is experimental. In a future NetLogo version, it may have a different name and syntax.

__extensions takes one input, a list of strings. Each string contains a pathname to a JAR file. For example:

__extensions [ "sound.jar" ]

In this example, no directory name is given, only a pathname, so NetLogo will look for the JAR in the same directory that holds the model. You may also use pathnames relative to that directory, or absolute pathnames:

__extensions [ "lib/sound.jar" ]           ;; relative path
__extensions [ "../../jars/sound.jar" ]    ;; relative path
__extensions [ "c:\\myfiles\\sound.jar" ]  ;; absolute Windows path
__extensions [ "/Users/me/sound.jar" ]     ;; absolute Mac/Unix path

You may also use an extension which is stored on an Internet server instead of your local computer. Just use the URL where you have stored the JAR. For example:

__extensions [ "http://yourdomain.net/jars/sound.jar" ]

Using __extensions tells NetLogo to find and open the specified extension and makes the custom commands and reporters found in the JAR available to the current model. You can use these commands and reporters just as if they were built-in NetLogo primitives.

To use more than one extension, list each pathname seperately. For example,

__extensions [ "../sound.jar" "lib/speech.jar" ]

Third party JARs

Some extensions depend on code stored in a separate JAR. (Many Java libraries are distributed as JAR files).

If your model uses an extension that requires extra JARs in addition to the extension itself, copy the extra JARs into the "extensions" folder of your NetLogo installation. (If the folder doesn't exist, create it.) Whenever an extension is imported, NetLogo will make all the JARs in this folder available to the extension.

Extension authors are responsible for providing third-party JARs and for documenting the installation requirements for the NetLogo user.

Applets

Models saved as applets (using "Save as Applet" on NetLogo's File menu) cannot make use of extensions. (We plan to fix this in a future release.)

Writing Extensions

Let's write an extension that provides a single reporter called first-n-integers.

first-n-integers will take a single numeric input n and report a list of the integers 1 through n. (Of course, you could easily do this just in NetLogo; it's only an example.) We'll assume you have experience programming in Java.

Writing Primitives

A command performs an action; a reporter reports a value. To create a new command or reporter, create a class that implements the interface org.nlogo.api.Command or org.nlogo.api.Reporter.

The Reporter interface requires that we implement the following methods:

Reporter newInstance (String name);
Object report (Argument args[], Context context)
  throws ExtensionException;

Reporter extends org.nlogo.api.Primitive, which specifies these additional methods:

String getAgentClassString();
Syntax getSyntax();

Here's the implementation of our reporter, in a file called IntegerList.java:

import org.nlogo.agent.LogoList;
import org.nlogo.api.Argument;
import org.nlogo.api.Context;
import org.nlogo.api.ExtensionException;
import org.nlogo.api.Reporter;
import org.nlogo.api.Syntax;

public class IntegerList implements Reporter
{
    public Reporter newInstance(String name) {
        return new IntegerList();
    }
    public String getAgentClassString() {
        return "OTP";
    }
    public Syntax getSyntax() {
        return Syntax.reporterSyntax
          (new int[] {Syntax.TYPE_NUMBER},
           Syntax.TYPE_LIST);
    }
    public Object report(Argument args[], Context context)
        throws ExtensionException
    {
        LogoList list = new LogoList();
        int n = args[0].getIntegerValue();
        if (n < 0) {
            throw new ExtensionException
              ("input must be positive");
        }
        for (int i = 1; i <= n; i++) {
            list.add(new Integer(i));
        }
        return list;
    }
}

Some things to notice:

A Command is just like a Reporter, except that reporters implement Object report(...) while commands implement void perform(...).

Writing a ClassManager

Each extension must include, in addition to any number of command and reporter classes, a class that implements the interface org.nlogo.api.ClassManager. The ClassManager tells NetLogo which primitives are part of this extension. In simple cases, use the abstract class org.nlogo.api.DefaultClassManager, which provides empty implementations of the methods from ClassManager that you aren't likely to need.

Here's the class manager for our example extension, ExampleManager.java:

import org.nlogo.api.DefaultClassManager;
import org.nlogo.api.PrimitiveManager;

public class ExampleManager extends DefaultClassManager {
    public void load(PrimitiveManager primitiveManager) {
        primitiveManager.addPrimitive
          ("first-n-integers", new IntegerList());
    }
}

addPrimitive() tells NetLogo that our reporter exists and what its name is.

Writing a Manifest

The extension must also include a manifest. The manifest is a text file which tells NetLogo the name of the extension and the location of the ClassManager.

The manifest must contain three tags:

Here's a manifest for our example extension, manifest.txt:
Extension-Name: example
Class-Manager: ExampleManager
NetLogo-Version: 2.0.1

Creating a NetLogo Extension JAR

To create an extension JAR, first compile your classes as usual. Make sure NetLogo.jar (from the NetLogo distribution) is in your classpath. For example:

$ javac -classpath NetLogo.jar IntegerList.java ExampleManager.java
Then create a JAR containing the resulting class files and the manifest. For example:
$ jar cvfm example.jar manifest.txt IntegerList.class ExampleManager.class

For information about manifest files, JAR files and Java tools, please see java.sun.com.

Using your extension

To use our example extension write, at the top of the Procedures tab:

__extensions [ "example.jar" ]  ;; assumes JAR, model in same directory
Now you can use first-n-integers just like it was a built-in NetLogo reporter. For example, select the Interface tab and type in the Command Center:
O> show first-n-integers 5
observer: [1 2 3 4 5]

Extension development hints

There are special NetLogo primitives to help you as you develop and debug your extension. Like the extensions facility itself, these are considered experimental and will be changed at a later date. (That's why they have underscores in their name.)

Conclusion

Don't forget to consult the NetLogo API Specification for full details on these classes, interfaces, and methods.

Note that there is no way for the modeler to get a list of commands and reporters provided by an extension, so it's important that you provide adequate documentation.

The extensions facility is considered experimental. This initial API doesn't include everything you might expect. Some facilities exist but are not yet documented. If you don't see a capability you want, please let us know. Do not hesitate to contact us at feedback@ccl.northwestern.edu with questions, as we may be able to find a workaround or provide additional guidance where our documentation is thin.

Hearing from users of this API will also allow us to appropriately focus our efforts for future releases. We are committed to making NetLogo flexible and extensible, and we very much welcome your feedback.