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
- 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
- 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
- Support various transport
yarmi also provides abstraction over transport layer so it can over any kinds of transport like tcp / ip or bluetooth rfcomm.
- 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
- 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>
- Add dependency
<dependencies>
<dependency>
<groupId>com.doodream</groupId>
<artifactId>yarmi-core</artifactId>
<version>0.0.2</version>
</dependency>
</dependencies>
- 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);
}
- 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);
}
}
- 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;
}
- 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
}
}
- 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();
}
}
}
});
}
}
Apache License, Version 2.0