wiki:MiddleWareConnection

Version 17 (modified by welberge, 7 years ago) (diff)

--

Hooking up AsapRealizer to your own middleware framework

Communication to and from AsapRealizer is set up using the RealizerPort interface, a lightweight Java interface through which  BML and  BML feedback is communicated as Java Strings.

Example: creating RSB adapters

In this example I will show how to connect AsapRealizer to a Behavior Planner using messages over the  Robotic Service Bus. To this end, two rsb adapters will be created. The RsbToBMLRealizerAdapter translates Rsb BML messages into BML commands for the BMLRealizerPort and submits feedback from the BMLRealizerPort over rsb. The BMLRealizerToRsbAdapter acts as an RealizerPort. It passes BML commands to the rsb and translates BML feedback from rsb into feedback for listeners registered to it.

Defining the rsb scopes

Rsb messages travel through channels called 'scopes'. For our purposes we define two scopes, one for BML and one for BML feedback:

/**
 * Constants for rsb scopes
 * @author Herwin
 */
public final class RsbAdapterConstants
{
    public static final String BML_SCOPE = "/bml/bml";
    public static final String BML_FEEDBACK_SCOPE = "/bml/bmlfeedback";
    private RsbAdapterConstants(){}
}

RsbToBMLRealizerAdapter

The RsbToBMLRealizerAdapter must transfer BML messages it receives through the BML scope to the connected RealizerPort. This is done using an event handler in an rsb listener. The RsbToBMLRealizerAdapter must submit all feedback messages from the RealizerPort over the Rsb BML_FEEDBACK_SCOPE. This is achieved by connecting the RsbToBMLRealizerAdapter as a feedbacklistener to the RealizerPort and using an rsb informer to send out feedback whenever a feedback callback occurs.

See also  http://docs.cor-lab.de/rsb-manual/0.7/html/examples-basic.html for rsb's information sending/receiving basics.

package asap.rsbadapters;

import lombok.extern.slf4j.Slf4j;
import rsb.AbstractEventHandler;
import rsb.Event;
import rsb.Factory;
import rsb.Informer;
import rsb.InitializeException;
import rsb.Listener;
import rsb.RSBException;
import asap.bml.bridge.RealizerPort;
import asap.bml.feedback.BMLFeedbackListener;

/**
 * Submits rsb BML messages to a RealizerPort; submits RealizerPort feedbacks to the rsb. 
 * Assumes that the connected realizerport is threadsafe (or at least that its performBML function is).
 * @author Herwin
 */
@Slf4j
public class RsbToBMLRealizerAdapter implements BMLFeedbackListener
{
    private final RealizerPort realizerPort;
    private final Informer<String> informer;
    private final Listener listener;
    
    public RsbToBMLRealizerAdapter(RealizerPort port)
    {
        realizerPort = port;
        realizerPort.addListeners(this);
        Factory factory = Factory.getInstance();

        // setup feedback sender
        informer = factory.createInformer(RsbAdapterConstants.BML_FEEDBACK_SCOPE);        

        // setup BML receiver
        listener = factory.createListener(RsbAdapterConstants.BML_SCOPE);
        listener.addHandler(new AbstractEventHandler()
        {
            @Override
            public void handleEvent(Event event)
            {
                realizerPort.performBML(event.getData().toString());
            }
        }, true);
        
        try
        {
            listener.activate();
            informer.activate();
        }
        catch (InitializeException e)
        {
            throw new RuntimeException(e);
        }
    }

    /**
     * Submit feedback over rsb
     */
    @Override
    public void feedback(String feedback)
    {
        try
        {
            informer.send(feedback);
        }
        catch (RSBException e)
        {
            log.warn("Could not submit feedback over RSB.", e);
        }
    }

    public void close()
    {
        informer.deactivate();
        listener.deactivate();
    }
}

BMLRealizerToRsbAdapter

The BMLRealizerToRsbAdapter acts as a RealizerPort. It submits BML messages through the rsb BML scope, using an rsb informer. It receives feedback from the rsb BML_FEEDBACK scope, using an eventhandler of a rsb listener. This feedback is submitted to all registered BMLFeedbackListeners.

package asap.rsbadapters;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.google.common.collect.ImmutableList;

import lombok.extern.slf4j.Slf4j;
import rsb.AbstractEventHandler;
import rsb.Event;
import rsb.Factory;
import rsb.Informer;
import rsb.InitializeException;
import rsb.Listener;
import rsb.RSBException;
import asap.bml.bridge.RealizerPort;
import asap.bml.feedback.BMLFeedbackListener;

/**
 * Submits BML through rsb messages; submits received feedback (from rsb) to registered listeners.
 * @author Herwin
 */
@Slf4j
public class BMLRealizerToRsbAdapter implements RealizerPort
{
    private final Informer<String> informer;
    private final Listener listener;
    private List<BMLFeedbackListener> feedbackListeners = Collections.synchronizedList(new ArrayList<BMLFeedbackListener>());
    
    public BMLRealizerToRsbAdapter()
    {
        Factory factory = Factory.getInstance();

        // setup bml sender
        informer = factory.createInformer(RsbAdapterConstants.BML_SCOPE);  
        
        // setup feedback receiver
        listener = factory.createListener(RsbAdapterConstants.BML_FEEDBACK_SCOPE);
        listener.addHandler(new AbstractEventHandler()
        {
            @Override
            public void handleEvent(Event event)
            {
                synchronized(feedbackListeners)
                {
                    for(BMLFeedbackListener fbl:feedbackListeners)
                    {
                        fbl.feedback(event.getData().toString());
                    }
                }
            }
        }, true);
        
        try
        {
            listener.activate();
            informer.activate();
        }
        catch (InitializeException e)
        {
            throw new RuntimeException(e);
        }
    }
    
    @Override
    public void addListeners(BMLFeedbackListener... listeners)
    {
        feedbackListeners.addAll(ImmutableList.copyOf(listeners));        
    }

    @Override
    public void removeAllListeners()
    {
        feedbackListeners.clear();
    }

    @Override
    public void performBML(String bmlString)
    {
        try
        {
            informer.send(bmlString);
        }
        catch (RSBException e)
        {
            log.warn("Cannot send BML ",e);
        }        
    }
    
    public void close()
    {
        listener.deactivate();
        informer.deactivate();
    }
}

Testing the created adapters

A simple way to test the adapters is by mocking up a Realizer (through a RealizerPort) and a Behavior planner (through a BMLFeedbackListener). The realizer is then connected to the RsbToBMLRealizerAdapter; the feedbacklistener to the BMLRealizerToRsbAdapter. A BML message sent from the BMLRealizerToRsbAdapter should arrive at the mocked up realizer. A feedback message sent from the RsbToBMLRealizerAdapter should arrive at the behavior planner:

package asap.rsbadapters;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import org.junit.After;
import org.junit.Test;

import asap.bml.bridge.RealizerPort;
import asap.bml.feedback.BMLFeedbackListener;

/**
 * Integration tests for the BMLToIpaaca and IpaacaToBML adapters.
 * Requires a running spread daemon.
 * @author Herwin
 */
public class AsaptersIntegrationTest
{
    private RealizerPort mockRealizerPort = mock(RealizerPort.class);
    private BMLFeedbackListener mockFeedbackListener = mock(BMLFeedbackListener.class);
    private BMLRealizerToRsbAdapter bmlToRsb = new BMLRealizerToRsbAdapter();
    private RsbToBMLRealizerAdapter rsbToBML = new RsbToBMLRealizerAdapter(mockRealizerPort);
    
    @After
    public void tearDown()
    {
        bmlToRsb.close();
        rsbToBML.close();
    }
    
    @Test
    public void testPerformBML() throws InterruptedException
    {
        bmlToRsb.performBML("bmltest");
        Thread.sleep(500);
        verify(mockRealizerPort).performBML("bmltest");
    }
    
    @Test
    public void testFeedback() throws InterruptedException
    {
        bmlToRsb.addListeners(mockFeedbackListener);
        rsbToBML.feedback("bmlfeedback");
        Thread.sleep(500);
        verify(mockFeedbackListener).feedback("bmlfeedback");
    }
}

Attachments