Skip to content

fritzprix/yarmi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

89 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

yarmi is yet anotehr RMI based on JSON. it's simple yet powerful when developing server & client based distributed application within a network of small scale

Codacy Badge

Features

  1. Support large blob as method parameter or response

yarmi supports blob exchange between client and server by default with BlobSession which exposes familiar read / write APIs

  1. Provide service discovery out-of-the-box

yarmi contains simple service discovery feature and also support another type of service discovery (e.g. DNS-SD) as module

  1. Support various transport

yarmi also provides abstraction over transport layer so it can over any kinds of transport like tcp / ip or bluetooth rfcomm.

  1. Zero-cost migration to (from) RESTful application

Provides conceptual similarity to popular RESTful application framework (like service / controller mapping). and that means not only the migration from / to RESTful implementation is easy but also implementing proxy for any RESTful service in heterogeneous network scenario (like typical IoT application) is also well supported

How-To

Using Maven

  1. Add Maven Repository
<repositories>
    <repository>
        <id>yarmi-core</id>
        <name>yarmi</name>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <url>https://raw.githubusercontent.com/fritzprix/yarmi/releases</url>
    </repository>
</repositories>
  1. Add dependency
<dependencies>
        <dependency>
            <groupId>com.doodream</groupId>
            <artifactId>yarmi-core</artifactId>
            <version>0.0.2</version>
        </dependency>
</dependencies>

Build Service (Server)

  1. Declare controller stub in a very similar way doing with Spring REST Controller
public interface UserIDPController {

    @Get("/{id}")
    Response<User> getUser(@Path(name = "id") Long userId);

    @Get("/list")
    Response<User> getUsers();

    @Post("/new")
    Response<User> createUser(@Body(name = "user") User user);
    
    @Post("/new/thumbnail")
    Response<Long> postThumbnail(@Body(name = "th_nail") BlobSession blob, Long userId);

} 
  1. Implement Controller Stub
public class UserIDControllerImpl implements UserIDPController {

    private HashMap<Long, User> userTable = new HashMap<>();

    @Override
    public Response<User> getUser(Long userId) {
        User user = userTable.get(userId);
        if(user == null) {
            return null;
        }
        return Response.success(user, User.class);
    }

    @Override
    public Response<User> getUsers() {
        return null;
    }

    @Override
    public Response<User> createUser(User user) {
        int id = user.hashCode();
        userTable.put((long) id, user);
        user.id = (long) id;
        return Response.success(user, User.class);
    }
    
    @Override
    public Response<Long> postThumbnail(BlobSession blob, Long userId) {
        // example save blob as file
        byte[] rb = new byte[1024];
        int rsz;
        try {
            Session session = blob.open();
            FileOutputStream fos = new FileOutputStream("thumbnail_" + userId);
            while((rsz = session.read(rb,0, rb.length)) > 0) {
                fos.write(rb, 0, rsz);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            fos.close();
        }
        return Response.success(userId);    
    }
}  
  1. Declare your service with route configuration
@Service(name = "test-service",
        params = {"6644"})
public class TestService {

    @Controller(path = "/user", version = 1, module = UserIDControllerImpl.class)
    UserIDPController userIDPService;
}
  1. Start service & advertise it
public static class SimpleServer {
    
    public static void main (String[] args) {
        RMIService service = RMIService.create(TestService.class, new SimpleServiceAdvertiser());
        service.listen(true);
        // listen will block, you can change the blocking behaviour with the argument
    }
}

Build Client

  1. Discover service & create client
public static class SimpleClient {
    
    public static void main (String[] args) {
            // build target service information
            
            SimpleServiceDiscovery discovery = new SimpleServiceDiscovery();
            discovery.startDiscovery(TestService.class, new ServiceDiscoveryListener() {
                @Override
                public void onDiscovered(RMIServiceProxy proxy)  {
                    discoveredService.add(proxy);
                }
    
                @Override
                public void onDiscoveryStarted() { 
                    discoveredService = new LinkedList<>();
                }
    
                @Override
                public void onDiscoveryFinished() {
                    // pick RMIServiceProxy and create client
                    if(discoveredService == null) {
                        return;
                    }
                    if(discoveredService.size() > 0) {
                        RMIServiceProxy serviceProxy = discoveredService.get(0);
                        if(!serviceProxy.provide(UserIDPController.class)) {
                            // check given controller is provided from the service
                            return;
                        }
                        try {
                                UserIDPController userCtr = RMIClient.create(serviceProxy, TestService.class, UserIDPController.class);
                                // will be create client-side proxy 
                                // and use it just like simple method call
                                
                                User user = new User();
                                user.setName("David");
        
                                Response<User> response = userCtr.createUser(user);
                                assert response.isSuccessful();
                                user = response.getBody();
                                
                                response = userCtr.getUser(user.getId());
                                assert response.isSuccessful();
                                response.getBody();
                                
                                // example : upload file as thumbnail images
                                FileInputStream fis = new FileInputStream("./thumbnail.jpg");
                                byte[] buffer = new byte[2048];
                                BlobSession session = new BlobSession(ses -> {
                                    int rsz;
                                    try {
                                        while((rsz = fis.read(buffer)) > 0) {
                                            ses.write(buffer, rsz);
                                        }
                                        ses.close();
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                });
                                Response<Long> thumbResponse = controller.postThumbnail(session, 1L);
                                assert thumbResponse.isSuccessful();
                                
                            } catch (IllegalAccessException | InstantiationException | IOException e) {
                                e.printStackTrace();
                            }    
                        }
                        
                    }
            });
            
    }
}

License

Apache License, Version 2.0