Getting Started With Nemo

You have multiple options how to incorporate Nemo into your project. Here at the Aqualab, we use Maven and Eclipse to maintain and build our Java projects.

In any case, you need a Java runtime environment to run and a Java Development Kit to build applications based on Nemo. You can download the latest Java version from Sun. Nemo and its dependencies are tested with the latest Java 2 Platform Standard Edition 5.0 (JDK 5.0).

Getting Started With Maven

After downloading Maven 2, setup a new maven project using the following pom.xml. Please refer to the documentation of Maven for how to configure a project. If you start with the template below, just replace the fields with your project information.

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>your.group.id</groupId>
        <artifactId>yourprojectid</artifactId>
        <packaging>jar</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>Your Project Name</name>
        <url>http://your.www.com/path/to/project/home/page/</url>
        <inceptionYear>2006</inceptionYear>
        <organization>
                <name>Your Organization</name>
                <url>http://your.www.com</url>
        </organization>
        <licenses>
                <license>
                        <name>The GNU General Public License, Version 2.0</name>
                        <url>/LICENSE.txt</url>
                </license>
        </licenses>
        <developers>
                <developer>
                        <id>userid</id>
                        <name>Your Name</name>
                        <email>Your email address</email>
                        <organization>Your organization</organization>
                </developer>
        </developers>
        <dependencies>
                <dependency>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                        <version>3.8.1</version>
                        <scope>test</scope>
                </dependency>
                <dependency>
                        <groupId>edu.nwu</groupId>
                        <artifactId>heimdall</artifactId>
                        <version>1.0-SNAPSHOT</version>
                        <scope>compile</scope>
                </dependency>
                <dependency>
                        <groupId>edu.nwu</groupId>
                        <artifactId>nucommon</artifactId>
                        <version>1.0-SNAPSHOT</version>
                        <scope>compile</scope>
                </dependency>
                <dependency>
                        <groupId>edu.nwu</groupId>
                        <artifactId>multicast</artifactId>
                        <version>1.0-SNAPSHOT</version>
                        <scope>compile</scope>
                </dependency>
                <dependency>
                        <groupId>edu.nwu</groupId>
                        <artifactId>nemo</artifactId>
                        <version>1.0-SNAPSHOT</version>
                        <scope>compile</scope>
                </dependency>
                <dependency>
                        <groupId>commons-logging</groupId>
                        <artifactId>commons-logging</artifactId>
                        <version>1.0.3</version>
                        <scope>compile</scope>
                </dependency>
        </dependencies>
        <build>
                <resources>
                        <resource>
                                <directory>src/main/resources</directory>
                                <filtering>true</filtering>
                        </resource>
                </resources>
                <plugins>
                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-compiler-plugin</artifactId>
                                <configuration>
                                        <source>1.5</source>
                                        <target>1.5</target>
                                </configuration>
                        </plugin>
                </plugins>
        </build>
</project>

Once you got the pom.xml setup, simple invoke maven from the command line inside the project directory. It will then automatically fetch all the dependencies for your projects.

Using Eclipse

Using a graphical development environment offers a number of advantages. Consequently, maven supports several of them. To generate the project descriptor for Eclipse, simply type:

 mvn eclipse:eclipse

Building Your First Nemo-based Application

We provide an example application with the sources of Nemo which you can locate at:

 edu.nwu.nemo.examples.MulticastAgent

Here, we go over the first step to build a simple multicast application in your own project. A multicast application, in general, consists of at least three different types of agents:

  1. bootstrap agents
  2. subscribers
  3. publishers

    A bootstrap agent is a rendez-vous point for subscribers and publishers. Below is a code snippet that initializes a Nemo bootstrap service on a specified port.

    package edu.nwu.nemo.examples;
    
    ...
    
    public final class MulticastAgent
    {
        /**
         * Sole entry point to class and application.
         * @param args array of string arguments
         */
        public static void main(String[] args)
        {
            try
            {
                SocketAddress[] bootstrap = new SocketAddress[0];
                IPacketSocketFactory socketFactory = ...;
                IReefService service = null;
                IReefConfiguration config = new NemoConfiguration();
    
                switch (args.length)
                {
                    ...
                }
    
                            // initiate the bootstrap service
                service = new NemoBootstrapService();
    
                            // setup the service
                service.setup(socketFactory, TimestampFactory.getInstance(),
                    EpochServiceFactory.getInstance(), config, bootstrap);
    
                ...
            }
        }
    }

    Setting up a multicast agent that can be a subscriber or/and a publisher is no more difficult.

    package edu.nwu.nemo.examples;
    
    ...
    
    public final class MulticastAgent
    {
        /**
         * Sole entry point to class and application.
         * @param args array of string arguments
         */
        public static void main(String[] args)
        {
            try
            {
                SocketAddress[] bootstrap = new SocketAddress[0];
                IPacketSocketFactory socketFactory = ...;
                IReefService service = null;
                IReefConfiguration config = new NemoConfiguration();
    
                switch (args.length)
                {
                    ...
                }
    
                            // initiate the multicast service
                service = new NemoService();
    
                            // setup the service
                service.setup(socketFactory, TimestampFactory.getInstance(),
                    EpochServiceFactory.getInstance(), config, bootstrap);
    
                ...
            }
        }
    }

    In contrast to the bootstrap service, we can attach subscribers to the multicast agent.

    package edu.nwu.nemo.examples;
    
    ...
    
    public final class MulticastAgent
    {
        /**
         * Sole entry point to class and application.
         * @param args array of string arguments
         */
        public static void main(String[] args)
        {
            try
            {
                ...
                
                service = new NemoService();
                service.setup(socketFactory, TimestampFactory.getInstance(),
                    EpochServiceFactory.getInstance(), config, bootstrap);
    
                System.out.println("Subscribing to multicast session");
    
                if (service instanceof IMulticastSubscriber
                    && config instanceof ISubscriberConfiguration)
                {
                    IMulticastSubscriber sub = (IMulticastSubscriber) service;
                    sub.addSubscriber(Identifier.create(SESSION_IDENTIFIER),
                        new MulticastSubscriber("example.subscriber",
                            (ISubscriberConfiguration) config));
                }
                else
                {
                    ...
                }
            }
        }
    }

    Setting up a publisher is not more difficult.

    package edu.nwu.nemo.examples;
    
    ...
    
    public final class MulticastAgent
    {
        /**
         * Sole entry point to class and application.
         * @param args array of string arguments
         */
        public static void main(String[] args)
        {
            try
            {
                ...
                
                service = new NemoService();
                service.setup(socketFactory, TimestampFactory.getInstance(),
                    EpochServiceFactory.getInstance(), config, bootstrap);
    
                System.out.println("Publishing at " + publishRate
                    + " ms intervals");
    
                if (service instanceof IMulticastPublisher)
                {
                    IMulticastPublisher pub = (IMulticastPublisher) service;
                    IMulticastPublisherSession ses = pub.joinSession(Identifier
                            .create(SESSION_IDENTIFIER));
    
                    publisher = new MulticastPublisher(0, ses, publishRate);
    
                    new Thread(publisher).start();
                }
                else
                {
                    ...
                }
            }
        }
    }

    We have by now briefly introduced the concept of bootstrap nodes, multicast agents, subscribers and publishers. Below you find the complete example application that puts together all this functionality.

The Full Source Code

package edu.nwu.nemo.examples;

import edu.nwu.multicast.api.IMulticastPublisher;
import edu.nwu.multicast.api.IMulticastPublisherSession;
import edu.nwu.multicast.api.IMulticastSubscriber;
import edu.nwu.multicast.api.ISubscriberConfiguration;
import edu.nwu.multicast.examples.MulticastPublisher;
import edu.nwu.multicast.examples.MulticastSubscriber;
import edu.nwu.nemo.bll.NemoBootstrapService;
import edu.nwu.nemo.bll.NemoConfiguration;
import edu.nwu.nemo.bll.NemoService;
import edu.nwu.net.api.IPacketSocketFactory;
import edu.nwu.net.wfl.PacketSocket;
import edu.nwu.net.wfl.SharedPacketSocket;
import edu.nwu.reef.api.AgentId;
import edu.nwu.reef.api.IReefConfiguration;
import edu.nwu.reef.api.IReefService;
import edu.nwu.reef.api.Identifier;
import edu.nwu.reef.bll.EpochServiceFactory;
import edu.nwu.util.bll.TimestampFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;

import java.util.logging.Level;

/**
 * An example multicast agent.
 *
 * @author Stefan Birrer
 */
public final class MulticastAgent
{
    /** The logger for this class. */
    private static Log logger = LogFactory.getLog(MulticastAgent.class);

    /** The unique session indentifier. */
    private static final byte[] SESSION_IDENTIFIER = new byte[]
        {
            0, 0, 0, 0, 0, 0, 0, 0
        };

    /**
     * Creates a new instance of multicast agent.
     */
    private MulticastAgent()
    {
        // prevent instantiation
    }

    /**
     * Sole entry point to class and application.
     *
     * @param args array of string arguments
     */
    public static void main(String[] args)
    {
        org.apache.log4j.Logger.getRoot().setLevel(org.apache.log4j.Level.WARN); // comment out for more debug output

        try
        {
            SocketAddress[] bootstrap = new SocketAddress[0];
            int publishRate = -1;
            IPacketSocketFactory socketFactory = null;
            IReefService service = null;
            IReefConfiguration config = new NemoConfiguration();
            MulticastPublisher publisher = null;

            switch (args.length)
            {
            case 3:
                publishRate = Integer.parseInt(args[2]);

            case 2:
                bootstrap = new SocketAddress[]
                    {
                        AgentId.parseAgentId(args[1]).getSocketAddress()
                    };

            case 1:

                int port = Integer.parseInt(args[0]);
                InetSocketAddress addr = null;

                if (port > 0)
                {
                    addr = new InetSocketAddress(InetAddress.getLocalHost(),
                            port);
                }

                socketFactory = new SharedPacketSocket(new PacketSocket(addr));

                break;

            default:
                usage();
                System.exit(-1);
            }

            if (bootstrap.length > 0)
            {
                System.out.println("setup multicast service");
                service = new NemoService();
            }
            else
            {
                System.out.println("setup bootstrap service");
                service = new NemoBootstrapService();
            }

            service.setup(socketFactory, TimestampFactory.getInstance(),
                EpochServiceFactory.getInstance(), config, bootstrap);

            if (publishRate > 0)
            {
                System.out.println("Publishing at " + publishRate
                    + " ms intervals");

                if (service instanceof IMulticastPublisher)
                {
                    IMulticastPublisher pub = (IMulticastPublisher) service;
                    IMulticastPublisherSession ses = pub.joinSession(Identifier
                            .create(SESSION_IDENTIFIER));

                    publisher = new MulticastPublisher(0, ses, publishRate);

                    new Thread(publisher).start();
                }
                else
                {
                    System.err.println("Service must implement "
                        + IMulticastPublisher.class);
                }
            }
            else
            {
                System.out.println("Subscribing to multicast session");

                if (service instanceof IMulticastSubscriber
                    && config instanceof ISubscriberConfiguration)
                {
                    IMulticastSubscriber sub = (IMulticastSubscriber) service;

                    sub.addSubscriber(Identifier.create(SESSION_IDENTIFIER),
                        new MulticastSubscriber("example.subscriber",
                            (ISubscriberConfiguration) config));
                }
                else
                {
                    System.err.println("Service must implement "
                        + IMulticastSubscriber.class
                        + " and configuration must implement "
                        + ISubscriberConfiguration.class);
                }
            }

            // wait for termination
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                        System.in));
            String line = null;

            do
            {
                System.out.print("Type 'quit' to terminate the session\n");
                line = reader.readLine();
            }
            while ((line == null) || !line.equalsIgnoreCase("quit"));

            if (publisher != null)
            {
                publisher.terminate();
            }
        }
        catch (Exception e)
        {
            logger.fatal(e.getMessage(), e);
            System.exit(-1);
        }
    }

    /**
     * Print the usage pattern.
     */
    private static void usage()
    {
        System.out.println(MulticastAgent.class.getName()
            + ": localport {bootstrap:port} {publish-rate}");
    }
}

You will need to start up multiple instances of this multicast agent, each with a different functionality:

  1. You need one bootstrap agent,
  2. one or potentially many subscribers,
  3. and one or a few publishers.

You need to pass the correct classpath with all the dependency in order to start the multicast agents. Following a small bash script to fasciliate this task:

 #!/bin/bash

java \
-mx128m \
-classpath \
nemo-1.0.jar:\
heimdall-1.0.jar:\
jug-1.1.jar:\
commons-logging-1.0.3.jar:\
commons-collections-3.1.jar:\
log4j-1.2.8.jar:\
colt-1.0.3.jar \
edu.nwu.nemo.examples.MulticastAgent $@

Alternatively, you can start the application from within Eclipse.

The bootstrap agent requires only one parameter, a unique local port. A subscriber additionally needs the address of the bootstrap agent. Finally, a publisher requires a third parameter that specifies the packet send interval.