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 using the NetLogo Extension API.
The NetLogo Extension API Specification contains further details.
To use an extension in a model, add the extensions keyword at the beginning of the Procedures tab, before declaring any breeds or variables.
After extensions comes a list of extension names in square brackets. For example:
extensions [sound speech]
Using extensions tells NetLogo to find and open the specified extension and makes the custom commands and reporters found in the extension available to the current model. You can use these commands and reporters just as if they were built-in NetLogo primitives.
NetLogo will look for extensions in several places:
extensions
folder in the same location as the
NetLogo application.
Each NetLogo extension consists of a folder with the same name as the extension, entirely in lower case. This folder must contain a JAR file with the same name as the folder. For example the sound extension is stored in a folder called sound with a file inside called sound.jar. For more information about the contents of an extension's folder, please see the section of this manual on Writing Extensions.
To install a NetLogo extension for use by any model, put the
extension's folder in the extensions
directory in
the NetLogo directory. Or, you can just keep the extension's
folder in the same folder as the model that uses it.
Some extensions depend on additional files. These files will be in the extension's folder along with the JAR file. The folder may also contain other files such as documentation and example models.
Models saved as applets (using "Save as Applet" on NetLogo's File menu) can make use of extensions. The extension must be placed in the same directory holding the model file. However, applets still cannot use extensions that require additional external jars. (We plan on fixing this in a later release.)
We assume you have experience programming in Java.
A NetLogo extension consists of a folder with the following contents: Required:
To build your extension, you must include NetLogo.jar in your class path.
Several sample extensions with full Java source code are included with NetLogo. Some others are available for download here.
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 0 through n - 1. (Of
course, you could easily do this just in NetLogo; it's only an
example.)
Since an extension is a folder with several items, we first need to
create our folder. In this example, it is called
example
. We will be doing all of our work in that
folder. We will also want to create a src
sub-folder to
hold our Java code, and a classes
sub-folder for the
compiled classes.
The primitives are implemented as one or more Java classes. The .java
files for these classes should be put in the src
sub-folder.
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, which extend org.nlogo.api.Primitive. In most cases, you can extend the abstract class org.nlogo.api.DefaultReporter or org.nlogo.api.DefaultCommand.
DefaultReporter requires that we implement:
Object report (Argument args[], Context context) throws ExtensionException;
Since our reporter takes an argument, we also implement:
Syntax getSyntax();
Here's the implementation of our reporter, in a file called
src/IntegerList.java
:
import org.nlogo.api.*; public class IntegerList extends DefaultReporter { // take one number as input, report a list public Syntax getSyntax() { return Syntax.reporterSyntax( new int[] {Syntax.TYPE_NUMBER}, Syntax.TYPE_LIST ); } public Object report(Argument args[], Context context) throws ExtensionException { // create a NetLogo list for the result LogoList list = new LogoList(); int n ; // use typesafe helper method from // org.nlogo.api.Argument to access argument try { n = args[0].getIntValue(); } catch( LogoException e ) { throw new ExtensionException( e.getMessage() ) ; } if (n < 0) { // signals a NetLogo runtime error to the modeler throw new ExtensionException ("input must be positive"); } // populate the list // note that we use Double objects; NetLogo numbers // are always doubles for (int i = 0; i < n; i++) { list.add(new Double(i)); } return list; } }
Notice:
A Command is just like a Reporter, except that reporters implement Object report(...) while commands implement void perform(...).
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, extend 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,
src/SampleExtension.java
:
import org.nlogo.api.*; public class SampleExtension 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.
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
:
Manifest-Version: 1.0 Extension-Name: example Class-Manager: SampleExtension NetLogo-Extension-API-Version: 4.0
The NetLogo-Extension-API-Version line should match the actual version of NetLogo Extension API you are using.
Make sure even the last line ends with a newline character.
To create an extension's JAR file, first compile your classes as usual, either from the command line or using an IDE.
Important: You must add NetLogo.jar (from the NetLogo distribution) to your classpath when compiling.
Here's an example of how compiling your extension might look from the command line:
$ mkdir -p classes # create the classes subfolder if it does not exist $ javac -classpath NetLogo.jar -d classes src/IntegerList.java src/SampleExtension.java
You will need to change the classpath argument to point to the
NetLogo.jar file from your NetLogo installation. This command line
will compile the .java and put the .class files in the
classes
subfolder.
Then create a JAR containing the resulting class files and the manifest. For example:
$ jar cvfm example.jar manifest.txt -C classes .
For information about manifest files, JAR files and Java tools, see java.sun.com.
To use our example extension, put the example
folder in
the NetLogo extensions folder, or in the same directory as the model
that will use the extension. At the top of the Procedures tab write:
extensions [example]
Now you can use example:first-n-integers just like it was a built-in NetLogo reporter. For example, select the Interface tab and type in the Command Center:
observer> show example:first-n-integers 5 observer: [0 1 2 3 4]
Your class manager is instantiated at the time a model using the extension is loaded.
Command and reporter objects are instantiated whenever NetLogo code is compiled that uses your commands and reporters.
Don't forget to include NetLogo.jar in your class path when compiling. This is the most common mistake made by new extension authors. (If the compiler can't find NetLogo.jar, you'll get error messages about classes in the org.nlogo.api package not being found.)
There are special NetLogo primitives to help you as you develop and debug your extension. These are considered experimental and may be changed at a later date. (That's why they have underscores in their name.)
print __dump-extensions
prints information about
loaded extensions
print __dump-extension-prims
prints information about
loaded extension primitives
__reload-extensions
forces NetLogo to reload all
extensions the next time you compile your model. Without this
command, changes in your extension JAR will not take effect until
you open a model or restart NetLogo.
If your extension depends on code stored in a separate JAR, copy the extra JARs into the extension's directory. Whenever an extension is imported, NetLogo makes all the JARs in its folder available to the extension.
If you plan to distribute your extension to other NetLogo users, make sure to provide installation instructions.
NetLogo works with Java versions 1.4.1 and later. If you want your extension to be usable by all NetLogo users, your extension should support Java 1.4.1.
The easiest way is to accomplish this is do all your development with the 1.4.1 JDK.
It's also possible to develop for Java 1.4 using the Java 1.5 or 1.6 compiler, but you need to do two things:
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 not yet complete. The API doesn't include everything you might expect to be present. 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.