Request Trial

The java client

A guide to use the java client


» Next - More about the JavaScript and other clients

How to work with the client

The java client works similar to an MVC framework controller structure. The difference is, that the routing and message security handling is done by another authority.


The Controller

The controller has a lot of options to control how actions are handled and called. The following sample shows some of those possibilities:

//@UriNamespace(namespace = "com.connectanum") the dot is added anyway
//@UriNamespace(namespace = "com.connectanum",forceTailingDot=false) no dot is added
@UriNamespace(namespace = "com.connectanum.")
public static class ProcedureProvider extends AbstractMessageEventListenerProvider implements IAbstractMessageEventListenerProvider {

Remote procedures

After the client has successfully authenticated to the router, all remote procedures are registered automatically. This code shows who to tell the client which controller to register:

IClientChallenger[] challengers = {new SimpleClientCraChallenger()};
int nThreads = 10;

DefaultMessageEventHandler handler = new DefaultMessageEventHandler(challengers,nThreads);
// This is where the controller is registered
messageEventHandler.registerMessageEventListeners(MyController.class);

During the registration process the client gathers all actions and their lambdas. This way no slow class reflection work is done when the action is called.

The controller has a lot of options to control how actions are handled and called. The following sample shows some of those possibilities:

//@UriNamespace(namespace = "com.connectanum") the dot is added anyway
//@UriNamespace(namespace = "com.connectanum",forceTailingDot=false) no dot is added
@UriNamespace(namespace = "com.connectanum.")
public static class ProcedureProvider extends AbstractMessageEventListenerProvider implements IAbstractMessageEventListenerProvider {

    /**
     * is parsed to the uri: com.connectanum.this.is.a.snake.case
     * uriPattern: UriPattern.SNAKE_CASE,UriPattern.CAMEL_CASE or UriPattern.PLAIN + uri='my.uri.something'
     * pattern: Register.Options.MATCH_PREFIX, Register.Options.MATCH_WILDCARD or ""
     * invocationPolicy: They are needed to tell the router how to load balance
     *     Register.Options.INVOCATION_POLICY_FIRST
     *     Register.Options.INVOCATION_POLICY_LAST
     *     Register.Options.INVOCATION_POLICY_RANDOM
     *     Register.Options.INVOCATION_POLICY_ROUND_ROBIN
     *     Register.Options.INVOCATION_POLICY_SINGLE
     * anonymousExceptions: A boolean value to tell the client if exceptions are passed anonymous or not
     * discloseCaller: A remote method caller is allowed to be anonymous or not
     *
     * It is important to know that generic IInvocationDeferred can tell the client to parse result arguments in custom beans
     * To do so replace the generic Invocation with a custom Invocation class
     */
    @ProcedureInvocationHandler(uriPattern = UriPattern.SNAKE_CASE,invocationPolicy = Register.Options.INVOCATION_POLICY_RANDOM)
    public IInvocationDeferred<Invocation /*or MyCustomInvocation*/> this_is_a_snake_case(){
        return  (invocation, session) -> {
            ...
            /** do something **/
            ...
            return new Result();
        };
    }

    /**
     * If some custom operation is needed before the actual call
     */
    @Before // or @After or @Before(uri = {"com.connectanum.something.1","com.connectanum.something.2"})
    public IInvocationAspect someBeforeCallingAllInvocation (){
        return (invocation, session) -> ... /** do something **/ ...;
    }

}

The result object is very generic and can use a lot of formats to pass data back to the router.

@ProcedureInvocationHandler
public IInvocationDeferred someMethod(){
    return (invocation, session) -> {
        return new Result();
        // Regular results
        return new Result();
        return new Result("[1]");
        return new Result("{\"Some\":\"Map\"}");
        return new Result("SomeBinary".getBytes());
        return new Result("Some transparent string payload");
        return new Result(new List<Object>());
        return new Result(new HashMap<String,Object>());
        return new Result(new List<Object>(),new HashMap<String,Object>());
        return new Result(true);
        // Progressive Results
        return new Result("[1]",true);
        return new Result("{\"Some\":\"Map\"}",true);
        return new Result("SomeBinary".getBytes(),true);
        return new Result("Some transparent string payload",true);
        return new Result(new List<Object>(),true);
        return new Result(new HashMap<String,Object>(),true);
        return new Result(new List<Object>(),new HashMap<String,Object>(),true);
        // Error Results
        return new Result(new Exception("Some Error"));
        return new Result(new Exception("Some Error"),"[1]");
        return new Result(new Exception("Some Error"),"{\"Some\":\"Map\"}");
        return new Result(new Exception("Some Error"),"SomeBinary".getBytes());
        return new Result(new Exception("Some Error"),"Some transparent string payload");
        return new Result(new Exception("Some Error"),new List<Object>());
        return new Result(new Exception("Some Error"),new HashMap<String,Object>());
        return new Result(new Exception("Some Error"),new List<Object>(),new HashMap<String,Object>());
    };
}

Publish / Subscribe

Events are registered just like remote procedures. The difference is, that events have a void return value. The following code shows a simple example that should demonstrate the use.

//@UriNamespace(namespace = "com.connectanum") the dot is added anyway
//@UriNamespace(namespace = "com.connectanum",forceTailingDot=false) no dot is added
@UriNamespace(namespace = "com.connectanum.")
public static class ProcedureProvider extends AbstractMessageEventListenerProvider implements IAbstractMessageEventListenerProvider {

    /**
    * is parsed to the uri: com.connectanum.this.is.a.snake.case
    * uriPattern: UriPattern.SNAKE_CASE,UriPattern.CAMEL_CASE or UriPattern.PLAIN + uri='my.uri.something'
    * pattern: Register.Options.MATCH_PREFIX, Register.Options.MATCH_WILDCARD or ""
    *
    * It is important to know that generic IEventListener can tell the client to parse result arguments in custom beans
    * To do so replace the generic Event with a custom Event class
    */
    @PublishEventHandler(uriPattern = UriPattern.SNAKE_CASE /*, pattern = Register.Options.MATCH_PREFIX*/)
    public IEventListener<Event /*or MyCustomIEventListener*/> this_is_a_snake_case(){
        return  (event, session) -> {
            ...
            /** do something **/
            ...
        };
    }

    /**
    * If some custom operation is needed before or after the actual event
    */
    @Before // or @After or @Before(uri = {"com.connectanum.something.1","com.connectanum.something.2"})
    public IEventAspect someBeforeCallingAllEvents (){
        return (invocation, session) -> ... /** do something **/...;
    }

}

Client usage

The RPC and Event endpoints can be passed to the client like as a list of classes. Those classes will be parsed at creation time to increase performance at runtime.

Class[] providers = new Class[] {
    MyProvider1.class,
    MyProvider2.class
};

Client.getBuilderInstance()
    .setHost(Router.Builder.DEFAULT_TCP_HOST)
    .setPort(Router.Builder.DEFAULT_TCP_PORT)
    .setMessageEventListenerProviders(providers)
    .setCredentials("authId","secret","some.realm.de")
    .setReconnectTime(-1L) // is not going to reconnnect
    .createAndRun().addListener(future -> {
        if(future.isSuccess()){
            Client client = (Client) future.get();
        }
    });

Where to use Get started The router The java client JavaScript and other clients