The following is an example SBB that uses an sbbpart written using the generated sbbpart super class for the Ping Pong API.

pingpong api.drawio
Using the Ping Pong API

There are two aspects to this example:

  1. A root SBB that defines an SBB local interface.

  2. An sbb-part that extends the generated sbb-part superclass. The sbb-part will interact with the root SBB via the root SBB local interface.

Tip
Advantages of using the generated sbb-part superclass
  • all required slee annotations are generated by the Rhino REST API Framework

  • the code to access the API provider is generated for you

  • the API event handlers are generated for you

  • simple to extend the generated superclass to implement event handler behaviour

Create an SBB class and SBB local interface

SBB local interface

The sbb-part will interact with the root SBB by invoking methods on its SBB local interface. In this example, the root SBB local interface includes a single operation triggerScenario().

SBB Local interface
public interface TriggerScenario {
    boolean triggerScenario(String api, String scenario);
}
@Library(
    id = @ComponentId(name = "@component.name@",
                    vendor = "@component.vendor@",
                   version = "@component.version@")
)
public interface ExampleRestApiSbbLocal extends TriggerScenario, SbbLocalObject {
}

SBB class

The root SBB implements the business logic of the service. The slee-annotations on the root SBB define the service, root SBB and a dependency on our Ping Pong SBB-Part. In this simple example, the root SBB will write a trace message in response to triggerScenario().

Root SBB
@SleeService( 1
    id = @ComponentId(name = "@component.name@",
                    vendor = "@component.vendor@",
                   version = "@component.version@"),
    rootSbb = @RootSBB(sbb = @ComponentId(name = "example-rest-api-sbb",
                                        vendor = "@component.vendor@",
                                       version = "@component.version@"))
)
@SBB( 2
    vendorExtensionID = "example-rest-api-sbb-id",
    id = @ComponentId(name = "example-rest-api-sbb",
                    vendor = "@component.vendor@",
                   version = "@component.version@"),
    sbbClasses = @SBBClasses(
        localInterface = @SBBLocalInterface(
                interfaceName = "com.exampleco.slee.rest.ExampleRestApiSbbLocal"),
        abstractClass = @SBBAbstractClass(reentrant = true)
    ),
    libraryRefs = {
        @LibraryReference(library = @ComponentId(name = "example-service-sbblocal",
                                               vendor = "@component.vendor@",
                                              version = "@component.version@"))
    }
)
@OcSBB(
    vendorExtensionID = "example-rest-api-sbb-id",
    sbbParts = {
        @SBBPartReference(id = @ComponentId(name = "example-pingpong-api-sbbpart", 3
                                          vendor = "@component.vendor@",
                                          ersion = "@component.version@"))
    },
    sbbClasses = @OcSBBClasses()
)
public abstract class ExampleRestApiSbb implements javax.slee.Sbb, TriggerScenario {
  1. defines the service and identifies the root SBB

  2. the example SBB (the root SBB for the service)

  3. the sbb-part annotation links the root SBB to our Ping Pong sbb-part

Implement the SBB local interface
    @Override
    public boolean triggerScenario(String api, String scenario) {
        tracer.fine("Triggering: api={}, scenario={}", api, scenario);
        return true;
    }

Create an sbb-part

SBB-Part class

The PingpongSbbpart class extends the generated sbb-part superclass (PingpongApiServerSbbpart).

PingpongSbbpart
@LibraryReferences(
  libraryRefs = {
    @LibraryReference(library=@ComponentId(name="example-service-sbblocal",
                                         vendor="@component.vendor@",
                                        version="@component.version@"))
  }
)
public class PingpongSbbpart extends PingpongApiServerSbbpart {

Implement sbb-part constructor

The PingpongSbbpart calls the superclass constructor and creates a Ping API object.

PingpongSbbpart sbb-part constructor
    public PingpongSbbPart(SbbPartContext context) {
        super(context);
        this.pingApi = getApiProvider().getApiClient(
                ApiConfiguration.standardConfiguration()).getPingApi();
    }

Override protected methods from the generated sbb-part superclass

The generated superclass defines protected methods that our sbb-part overrides to implement the service logic of the service.

Override protected methods from PingpongApiServerSbbpart
    protected final void handlePingRequest(PingRequest request,
                                           ActivityContextInterface aci,
                                           EventContext eventContext) throws IOException
    {
        getTracer().finest("Ping! {}", request);
        // defer to the root sbb; call triggerScenario() on its sbb-local interface
        final PingContext context = request.getPingContext();
        final TriggerScenario testsbb = (TriggerScenario) getSbbPartContext().getSbbLocalObject();
        testsbb.triggerScenario(context.getApi(), context.getScenario());
        // send a success response
        RestResponseBuilder response = request.create_200_SuccessResponse("text/plain", "Pong!");
        pingApi.sendResponse(response, aci);
    }

    protected final void rejectPingRequest(PingRequest request, ActivityContextInterface aci) {
        try {
            final RestResponseBuilder errorResponse = request.createDefaultResponse(
                    501,"application/json",
                    new Error().code(501)
                            .message("Failed to process Ping request: " + request.getPingContext()));
            pingApi.sendResponse(errorResponse, aci);
        }
        catch (IOException e) {
            getTracer().finest("Failed to send 501 error response", e);
        }
    }

Implement handlePingRequest by calling triggerScenario() on the sbb-local interface, passing the api and scenario values from the PingReqest.

Understanding the Generated Code in PingpongApiServerSbbpart

The generated sbb-part superclass handles all the necessary wiring code required to access the PingPong REST API.

  • @SBBPart, @RATypeBindings and @SBBPartDeployableUnit slee annotations

  • SBB Part constuctor that does required JNDI lookups for the PingPong REST API provider

  • implements event handlers for each event supported by the PingPong REST API

  • defines protected methods that developers override to implement service logic

PingpongApiServerSbbpart sbb-part annotations
@SBBPart(
    id = @ComponentId(name = "@component.name@",
                    vendor = "@component.vendor@",
                   version = "@component.version@"),
    sbbPartClasses = @SBBPartClasses(
        sbbPartClass = @SBBPartClass(
            className="@sbbpart.class.name@"
        ),
        activityContextInterface = @SBBPartActivityContextInterface(interfaceName = "@sbbpart.class.aci@")
    ),
    libraryRefs = {
        @LibraryReference(library = @ComponentId(name = "@guava-library.name@",
                                               vendor = "@guava-library.vendor@",
                                              version = "@guava-library.version@")),
        @LibraryReference(library =
            @ComponentId(name = "@rest-api-common.LibraryID.rest-api-common.name@",
                       vendor = "@rest-api-common.LibraryID.rest-api-common.vendor@",
                      version = "@rest-api-common.LibraryID.rest-api-common.version@"))
    }
)
@RATypeBindings(
    raTypeBindings = {
        @RATypeBinding(
            raType = @ComponentId(name = "pingpong-api-server",
                                vendor = "ExampleCo",
                               version = "1.0"),
            resourceAdaptorObjectName
                    = PingpongApiServerSbbpart.pingpong_PROVIDER_JNDI_NAME,
            resourceAdaptorEntityLink = "unified-rest-ra",
            activityContextInterfaceFactoryName
                    = PingpongApiServerSbbpart.pingpong_ACI_FACTORY_JNDI_NAME
        )
    }
)
@SBBPartDeployableUnit(
    securityPermissions =
        @SecurityPermissions(securityPermissionSpec = "grant { permission java.security.AllPermission; };")
)
public class PingpongApiServerSbbpart {
PingpongApiServerSbbpart sbb-part constructor
    public static final String pingpong_PROVIDER_JNDI_NAME = "api/pingpong-api-server/provider";
    public static final String pingpong_ACI_FACTORY_JNDI_NAME = "api/pingpong-api-server/acifactory";

    public PingpongApiServerSbbpart(SbbPartContext context) {
        this.sbbPartContext = context;
        this.tracer = (ExtendedTracer) sbbPartContext.getTracer(context.getSbbPart().getName());
        try {
            final Context env = (Context) new InitialContext().lookup("java:comp/env");
            this.apiProvider = (PingpongApiServerProvider)
                    env.lookup(pingpong_PROVIDER_JNDI_NAME);
            this.apiAciFactory = (PingpongApiServerACIFactory)
                    env.lookup(pingpong_ACI_FACTORY_JNDI_NAME);
        }
        catch (NamingException e) {
            throw new RuntimeException("NamingException trying to locate PingpongApiServerProvider", e);
        }
    }
PingpongApiServerSbbpart sbb-part PingRequest event handler
    @EventMethod( 1
        eventType = @ComponentId(name = "com.exampleco.openapi.pingpong.api.PingRequest",
                               vendor = "ExampleCo",
                              version = "1.0"),
        initialEvent = true,
        initialEventSelectVariable = IESVariableType.ActivityContext
    )
    public void onPingRequest(PingRequest request, 2
                              ActivityContextInterface aci,
                              EventContext eventContext)
    {
        // handle PingRequest event
        tracer.finest("Received: {}", request);
        try {
            handlePingRequest(request, aci, eventContext);
        }
        catch(IOException e) {
            tracer.finest("Failed to handle: {}", request, e);
            rejectPingRequest(request, aci);
        }
    }

    protected void handlePingRequest(PingRequest request, 3
                                     ActivityContextInterface aci,
                                     EventContext eventContext) throws IOException
    {
        throw new IOException("handlePingRequest() is not implemented.");
    }

    protected void rejectPingRequest(PingRequest request, ActivityContextInterface aci) { 4
        tracer.info("rejectPingRequest() is not implemented.");
    }
  1. slee-annotation for the PingRequest event handler

  2. implementation of the PingRequest event handler

  3. developer overrides this method to define normal behaviour for handling a PingRequest

  4. developer overides this method to define the behaviour when handling a PingRequest fails.

Previous page Next page