Skip to content

KleinerHacker/jremote

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

82 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JRemote

Remote API and IMPL for Java based on REST with multi client support, push support and more. For documentation see JRemote Documentation or Wiki

Overview

This API provides a client and a server implementation to communicate between clients and server asynchronious. The client gets one or more control services to control the server behavior or functions. Additional a client contains one or more remote models (here the received pushed data are stored) and one or more optional remote observers (contains all listener for model change activities). For event handling there are one or more Remote Event Receivers (contains all event listener for event calls). The server gets one or more push or event services to call all clients are connected.

Internal a client is registered in server (via a registration service) and check its own connection via a keep alive service so if the client is disconnected from server it try reconnect automatically. So if you open the client he waits automatically for service.

Quick Start

This example shows a hello world code. For more information see wiki pages.

@RemotePushModel
public interface HelloPushModel {
    String PROP_GREETING_COUNT = "greeting-count";

    @PushModelProperty(PROP_GREETING_COUNT)
    int getGreetingCount();
}

Now we define a Remote Model where the data from server push is stored into. We store the count of greetings of the server here.

@RemotePushObserver
public interface HelloPushObserver {
    @PushObserverListener(property = HelloPushModel.PROP_GREETING_COUNT, modelClass = HelloPushModel.class)
    void addGreetingCountListener(PushChangedListener l);

    @PushObserverListener(property = HelloPushModel.PROP_GREETING_COUNT, modelClass = HelloPushModel.class)
    void removeGreetingCountListener(PushChangedListener l);
}

Now we define a Remote Observer to listen that the server send a greeting counter update to us. The detection for add or remove listener runs automatically via prefix add or remove. The annotation need the reference to the Remote Model and the property to listen, here HelloModel and greeting.

@RemotePushService
public interface HelloPushService extends Remote {
    @Push(property = HelloPushModel.PROP_GREETING_COUNT, modelClass = HelloPushModel.class)
    void pushGreetingCount(int count) throws RemoteException;
}

This interface is used for the server to push greetings to the connected clients. The greeting is pushed into the client remote model with name HelloModel into property with name greeting.

@RemoteEventReceiver
public interface HelloEventReceiver {
    String EVENT_GREETING = "greeting";

    @EventReceiverListener(EVENT_GREETING)
    void addGreetingListener(EventReceivedListener<String> l);

    @EventReceiverListener(EVENT_GREETING)
    void removeGreetingListener(EventReceivedListener<String> l);
}

We define an EventReceiver to listen on greeting events from server. In client code we want to print out greetings from the event service below.

@RemoteEventService
public interface HelloEventService extends Remote {
    @Event(event = HelloEventReceiver.EVENT_GREETING, eventClass = HelloEventReceiver.class)
    void onGreeting(String greeting) throws RemoteException;
}

This defines the used event service with a method to send greetings to all clients.

public final class GreetingManager {
    private static final AtomicInteger COUNTER = new AtomicInteger(0);

    public static int addGreeting() {
        return COUNTER.incrementAndGet();
    }

    public static int getGreetings() {
        return COUNTER.get();
    }

    private GreetingManager() {
    }
}

To count greetings on server side we need a manager class they allow to access COUNTER from all classes.

public class HelloPushModelData implements HelloPushModel {
    @Override
    public int getGreetingCount() {
        return GreetingManager.getGreetings();
    }
}

Here we define which data are set if a client is registered on server. The server send this client initial all current data and initialize the client Remote Model. In this case we store the count of greetings in the manager (see above) and return it if a new client is connected. This is optional.

@RemoteControlService
public interface HelloControlService extends Remote {
    @Control
    void sayHello(String name) throws RemoteException;
}

This is the control interface to control the service. We want to instruct the server to say Hello with a specified name.

public class HelloControlServiceImpl implements HelloControlService {
    private final Supplier<HelloEventService> eventService;
    private final Supplier<HelloPushService> pushService;

    public HelloControlServiceImpl(Supplier<HelloEventService> eventService, Supplier<HelloPushService> pushService) {
        this.eventService = eventService;
        this.pushService = pushService;
    }

    @Override
    public void sayHello(String name) throws RemoteException {
        final int value = GreetingManager.addGreeting();

        pushService.get().pushGreetingCount(value);
        eventService.get().onGreeting("Hello, " + name);
    }
}

At the end we need an implementation for the control service to push the greeting counter and throws the greetings as event to all clients. In this case we need suppliers cause the proxy is not created if this implementation class is initialized. See below.

public class ServerRunner {
  private static final AtomicReference<RemoteServer> REMOTE_SERVER = new AtomicReference<>();

  public static void main(String[] args) {
    final ServerConfiguration serverConfiguration = ServerFluentConfiguration.create()
                .setHost("localhost")
                .setPort(19999);
    //With default values, optional
    final ExtensionConfiguration extensionConfiguration = ExtensionConfigurationBuilder.create()
                .withNetworkProtocol(RmiProtocol.class)
                .withUpdatePolicy(DefaultUpdatePolicy.class)
                .build();
  
    System.out.println("Startup service...");
    REMOTE_SERVER.set(RemoteServerBuilder.create(serverConfiguration, extensionConfiguration)
            .withRemoteControlService(new HelloControlServiceImpl(
                    () -> REMOTE_SERVER.get().getBroadcast().getEventClient(HelloEventService.class),
                    () -> REMOTE_SERVER.get().getBroadcast().getPushClient(HelloPushService.class)
            ))
            .withRemotePushClient(HelloPushService.class)
            .withRemoteEventClient(HelloEventService.class)
            .withPushModelData(HelloPushModelData.class)
            .build()
    );
    REMOTE_SERVER.get().open();
    
    // Stay open until enter a key
    System.console().readLine();
    
    REMOTE_SERVER.get().close();
  }
}

In this snipped we create the remote server via a builder, put in all interfaces we need on server side (HelloPushService / HelloEventService as client, HelloControlServiceImpl as concrete implementation (no proxy), HelloPushModelData for initialize Remote Model of a new connected client) and open it. After all we wait until user press enter and we close the service.

public class ClientRunner {
  private static final AtomicReference<RemoteClient> REMOTE_CLIENT = new AtomicReference<>();
  private static final String[] NAMES = new String[] {
            "Justin", "Jenny", "Nico", "Alexa", "Caroline"
  };

  public static void main(String[] args) throws Exception {
    System.out.println("Startup client...");
    REMOTE_CLIENT.set(RemoteClientBuilder.create(clientConfiguration, extensionConfiguration)
            .withRemotePushModel(HelloPushModel.class)
            .withRemotePushObserver(HelloPushObserver.class)
            .withRemotePushService(HelloPushService.class)
            .withRemoteEventReceiver(HelloEventReceiver.class)
            .withRemoteEventService(HelloEventService.class)
            .withRemoteControlClient(HelloControlService.class)
            .build()
    );
    REMOTE_CLIENT.get().open();
    
    final HelloPushModel pushModel = REMOTE_CLIENT.get().getData().getRemotePushModel(HelloPushModel.class);
    final HelloPushObserver pushObserver = REMOTE_CLIENT.get().getData().getRemotePushObserver(HelloPushObserver.class);
    final HelloEventReceiver eventReceiver = REMOTE_CLIENT.get().getData().getRemoteEventReceiver(HelloEventReceiver.class);
    final HelloControlService controlClient = REMOTE_CLIENT.get().getControl().getControlClient(HelloControlService.class);
    
    pushObserver.addGreetingCountListener(() -> System.out.println("New count of greetings: " + pushModel.getGreetingCount()));
    eventReceiver.addGreetingListener(greeting -> System.out.println("Receive greetings: " + greeting));
    
    for (final String name : NAMES) {
        System.out.println("Send 'Say Hello' for " + name);
        controlClient.sayHello(name);

        Thread.sleep(1000);
    }
    
    // Stay open until enter a key
    System.console().readLine();
    
    REMOTE_CLIENT.get().close();
  }
}

This is the client implementation. We use a builder, too, and register all needed client side interfaces. Than we get the proxies to add observer / event listener and control the server. After the user press enter the client is closed.

In default JRemote use RMI.

Thats all.

About

Remote API and IMPL for Java based on REST with multi client support, push support and more

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages