This article discusses Crispy. Crispy goal is to provide a single point of entry for remote invocation for a wide number of transports: eg. RMI, EJB, JAX-RPC or XML-RPC. It works by using properties to configure a service manager, which is then used to invoke the remote API.

Sachin Mahajan, Software Development, IBM

Sachin MahajanSachin Mahajan has 9+ years experience in software development including technical and managerial roles. Currently working in the development team for LotusLive, IBM’s SaaS offering.



07 May 2009

Also available in Chinese Japanese

Introduction

Crispy stands for Communication per Remote Invocation for different kinds of Services via ProxYs. Crispy is a remote invocation framework supporting a range of transport protocols such as RMI, EJB, JAX-RPC, XML-RPC. In simple terms, Crispy is as easy as configuring a Service manager (through a properties file) to call the supported remote API’s.

For starters the code listed below is a sample example for configuring Crispy:

Listing 1. Sample code for configuring Crispy
Properties prop = new Properties();
prop.put(Property.REMOTE_URL_AND_PORT, serviceUrl);
prop.put(Property.EXECUTOR_CLASS, typeOfExecutor);

ServiceManager manager = new ServiceManager(prop);
LibraryService library =  (LibraryService) manager.createService(LibraryService.class);
String author = library.findAuthor(myBook);
String isbn = library.findISBN(myBook);
…

In the above code, we created a properties object and set the remote url and the type of executor. The type of executor can be of JAX RPC, JBoss Remoting, RMI executor, XML RPC, REST or http executor type. After the configuration of properties an instance of the Crispy ServiceManager can be created. Now the remote service object (in this case OrderService) can be created using the ServiceManager (Factory pattern).


Background

Now that we have had a brief look at Crispy, let’s look at a sample of how a plain vanilla version of remoting is done without Crispy.

Listing 2. Web service (JAX-RPC)
public static final String LIBRARY_SERVICE_ENDPOINT = 
"http://myservicehost:9080/axis/services/LibraryService";
Service service = (Service) ServiceFactory.newInstance().createService(null);
Call call = service.createCall();
call.setTargetEndpointAddress("LIBRARY_SERVICE_ENDPOINT ");
call.setOperationName(new QName("findAuthor"));
QName paramXmlType = new QName(String.class.getName());
call.addParameter("arg0", paramXmlType, String.class, ParameterMode.IN);
call.setReturnType(new QName(String.class.getName()));
String result = (String) call.invoke(new String[] {”Alice in Wonderland”});
System.out.println("Author of Alice in Wonderland: " + result);

The “call” object is used to invoke the web service. You can either fill it yourself or through a WSDL document. We set the operation, parameters and return type in the call object and “invoke” the web service to get the required result.

Listing 3. XML-RPC (Apache XML-RPC)
XmlRpcClient client = new XmlRpcClient("http://myservicehost:9090");
Vector param = new Vector();
param.add(”Alice in Wonderland”);
String result = (String)
client.execute("crispysample.LibraryService.findAuthor", param);
System.out.println("Author of Alice in Wonderland: " + result);	
…

XmlRpcClient is the main access point for the XML-RPC client. Using the execute method, request is performed on method “calculateTip” using the parameters passed in as param.


Enter Crispy

The above code show just two way to make remote invocations, viz. through JAX-RPC and XML-RPC. Other ways through which one can make remote calls are RMI, EJB, REST, http etc. With Crispy all the above mentioned remote calls can be unified using a configured ServiceManager. The configuration is done using a Properties object.

Listing 4. JAX-RPC
MiniAxisServer server = new MiniAxisServer();
try {
	server.addService(LibraryService.class.getName(), 
    LibraryServiceImpl.class.getName());
	server.start();	
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, "LIBRARY_SERVICE_ENDPOINT");
properties.put(Property.EXECUTOR_CLASS, JaxRpcExecutor.class.getName());
} catch (Exception e) {
	e.printStackTrace();
}
finally {
	server.stop();
}
…
Listing 5. XML-RPC
MiniXmlRpcServer server = new MiniXmlRpcServer();
try {

server.addService(LibraryService.class.getName(), LibraryServiceImpl.class.getName());
	server.start();
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, " http://myservicehost:9090");
properties.put(Property.EXECUTOR_CLASS, XmlRpcExecutor.class.getName());
} catch (Exception e) {
	e.printStackTrace();
}
finally {
	server.stop();
}
…

Once the ServiceManager is configured, it can be instantiated and remote method invoked as:

Listing 6. ServiceManager Example
ServiceManager manager = new ServiceManager(properties);
Library library =  (LibraryService) manager.createService(LibraryService.class);
System.out.println("Author of Alice in Wonderland: " + result);

From the above code we can see that making remote calls using Crispy is made very easy. The configuration of the Service manager is very convenient; also remote calls are called similar to local calls. In addition the client does not need to know too many details about the remote technology they are calling.


Crispy in action

Crispy internals

The Crispy framework consists of three components the client or service composer, the internal service provider and the external service provider. All three components require the communication library while the server component only needs the service implementation and the client, the service interface.

Figure 1. The Crispy (client server) components (Courtesy: Crispy documentation)
The Crispy (client server) components

Figure 2 below describes the communication between the client and server components. As shown this is a typical client server communication. Memory representation of the data (includes the parameters and the result) is transformed into a format suitable for transmission to the server. This is called marshalling. The reverse of this which happens on the server prior to execution of the method, is called un-marshalling.

Figure 2. Communication between Crispy components (Courtesy: Crispy documentation)
Communication between Crispy components

From the client side the ServiceManager object creates a dynamic or static proxy to communicate with the server and call method in the proxy object. Before marshalling the call to the server an optional call to transform the parameters is invoked. As shown in figure 3, this process is accomplished by using net.sf.crispy.util.Converter.makeSimple. When the server receives the request, un-marshalling is completed and returns the transformed the object using net.sf.crispy.util.Converter.makeComplex.

Figure 3. Object transformations in Crispy (Courtesy: Crispy documentation)
Object transformations in Crispy

As mentioned earlier, this is an optional step which can be invoked if you do not want to implement the java.io.Serializable interface for your transfer objects. As shown in the above figure, complex Java objects are transformed to Java HashTable (java.util.HashTable) objects, where the keys are the attribute names from the Java object and the values are the attribute values. Relationships are mapped using a Java Vector object (java.util.Vector).


Crispy for Synchronous or Asynchronous Execution

For purposes of synchronous and asynchronous execution the framework is mainly for the client to make the corresponding calls. Testing can be done using the MiniServer object (net.sf.crispy.impl.MiniServer) assuming that an equivalent server has already been started. Below is an example of ways to set the nature of execution (either synchronous or asynchronous).

Listing 7. MiniServer object
MiniRmiServer server = new MiniRmiServer();
try {
		server.addService(LibraryServiceImpl.LOOKUP_NAME, 
        LibraryServiceImpl.class.getName());
	server.start();	
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, "rmi://localhost:1098");
prop.put(Property.DYNAMIC_PROXY_CLASS, Property.VALUE_FOR_CGLIB_DYNAMIC_PROXY);
properties.put(Property.EXECUTOR_CLASS, RmiExecutor.class.getName());
//Register the interface implementation mapping
prop.put(LibraryService.class.getName(), LibraryServiceImpl.class.getName());
ServiceManager manager = new ServiceManager(prop);
LibraryService library = manager.createService(LibraryService.class);
System.out.println("Author of Alice in Wonderland: " + 
        library.findAuthor(“Alice in Wonderland”));
} catch (Exception e) {
	e.printStackTrace();
}
finally {
		server.stop();
}
...

In the above example the default execution is synchronous. On the other hand for asynchronous execution the implementation of the AsynchronousCallback object (net.sf.crispy.concurrent.AsynchronousCallback) must be registered by the ServiceManager object. In this example the LibraryService object is created with the registered callback, the method name for asynchronous execution and the maximum size of threads for execution.

Listing 8. LibraryService object
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, "rmi://localhost:1098");
prop.put(Property.DYNAMIC_PROXY_CLASS, Property.VALUE_FOR_CGLIB_DYNAMIC_PROXY);
properties.put(Property.EXECUTOR_CLASS, RmiExecutor.class.getName());
//Register the interface implementation mapping
prop.put(LibraryService.class.getName(), LibraryServiceImpl.class.getName());
AsynchronousCallback callback = new AsynchronousCallbackForTests();
ServiceManager manager = new ServiceManager(prop);
 LibraryService library = manager.createService
(LibraryService.class,callback,new String[]{“findAuthor”},INT_MAX_NO_THREADS);
...

Acknowledgements

A big thank you to Mario Linke, author of the Crispy framework, who spent time from his busy schedule in reviewing and providing expert comments on this article.


Summary

In this article we saw the convenience and ease of Crispy in completing remote calls in addition to the inner workings of Crispy. We also highlighted some details on utilizing Crispy for both Synchronous and Asynchronous execution, in addition to making remote calls through JAX-RPC and XML-RPC. This is the first part of a two part series on Crispy. In the next section we will look at a RESTful application example using Crispy as well as extending Crispy with other frameworks.

Resources

  • Additional information on the Crispy Sourceforge website.
  • With reference to relevance of Crispy in SOA, check out the new to SOA, article as it provides an introduction on SOA and its relevance to IT and business.
  • Useful tips and hints on JAX-RPC.
  • Web services using XML-RPC.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into SOA and web services on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services
ArticleID=389050
ArticleTitle=CRISPY web services: Part 1: A Primer
publish-date=05072009