This library provides a lightweight alternative to RMI (Remote Method Invocation) or [Spring HTTP Invoker] (http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/remoting/httpinvoker/package-summary.html), using HTTP(S) protocol for communication between the client and server side.
- Java-to-Java remote method invocation is done using HTTP(S) protocol
- working with remote objects on the client side differs only in instantiation
process (
new
keyword VSCarmineManager#getRemote()
) - very simple implementation of the server side (e.g. Java EE Servlet)
- exceptions thrown by the remote method implementation are transparently rethrown on the client side
- no dependencies on external libraries - just one small JAR file
- Java SE 6+ compatible
Carmine has been designed for as much simple Java-to-Java remote method invocation as possible, not only for the ease of usage (invocation of remote method is exactly the same as local one, except the object instantiation), but also for the ease of implementing the server side, responsible for method implementation invocation.
The only two things the developer has to do to make things work are:
- Implement the
CarmineInvoker#getImplementation()
method, which takes interface name and returns the actual implementation for it. - Connect the
CarmineInvoker
instance to the input/output stream to handle client requests and responses (e.g.HttpServletRequest#getInputStream()
andHttpServletResponse#getOutputStream()
when using Java EE Servlet).
Note that similar code can be found in the Main class, placed in the carmine-demo-client demo project.
URL remoteServerURL = null;
try {
remoteServerURL = new URL("http://localhost:8080/carmine-demo-server/CarmineServlet");
} catch (MalformedURLException ex) {
// handle the exception
}
CarmineManager cm = new CarmineManager(remoteServerURL);
/*
* RemoteTest.class is the interface class. The real implementation
* of this interface is on the server and all the methods are called
* remotely.
*/
RemoteTest remoteTest = cm.getRemote(RemoteTest.class);
// this is the remotely called method, taking String as an argument
String greetings = remoteTest.getGreetings("Arthur");
// prints 'Greetings from the remote server, Arthur' to console
System.out.println(greetings);
Note that this is the code snippet from the CarmineServlet Java EE Servlet, which can be found in the carmine-demo-server demo project.
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// create the instance of the carmine remote invoker
CarmineInvoker invoker = new CarmineInvoker() {
@Override
@SuppressWarnings("unchecked")
public Object getImplementation(
String interfaceName,
Map<String, Object> properties) throws Exception {
/*
* Represents very simple implementation of this method, trying
* to instantiate an implementation class for the passed
* interface name using the interface name + "Impl" postfix.
*
* Example:
* com.norcane.carmine.demo.RemoteTest
* -> com.norcane.carmine.demo.RemoteTestImpl
*
* In real-world scenario, some security checks should be
* performed before returning the instance back (e.g. whether
* the connected local side is allowed to access this class, or
* implement some kind of authorization using properties map).
*/
String className = interfaceName + "Impl";
Class theClass = Class.forName(className);
return theClass.newInstance();
}
};
invoker.processRequest(request.getInputStream(), response.getOutputStream());
}
Sometimes some additional data are required to be shared between the client
and server side within the Carmine connection (e.g. credentials, security
token, etc). To allow this, Carmine offers mechanism of
connection properties, represented by the Map<String, Object>
object. Any property set either on client or server side will be available to
both of them, during every remote method invocation, until the property is
removed from the map or connection is closed.
To access properties from the client side, simply use CarmineManager
instance:
CarmineManager cm = new CarmineManager(remoteServerUrl);
cm.addProperty("foo", "bar"); // to add property
cm.removeProperty("foo") // to remove property
Map<String, Object> properties = cm.getProperties(); // readonly map of properties
To access the properties on the server side, simply use the parameter passed to
the CarmineInvoker#getImplementation()
method.
- to avoid possible serialization problems, the same major version of JVM should be used on both server and client side (Java SE 6 or newer)
- all objects returned as the result of remote method invocation must be serializable
- all exception objects thrown during remote method invocation must be serializable (allows to transparently rethrow the exception on the client)
- all connection properties values must be serializable