french english

RSS 1.0 
 
 Login 
 Password 
 Sign in 
 
05-01-09 / 03:52 : CP2JavaWS : Cappuccino/Java services bridge (cjed)
CP2JavaWS is a bridge between Cappuccino rich desktop applications and Java services deployed on a web server. It consists of a proxy (client side) and a servlet (server side), and manages parameters namespace, encoding, ordering and JSONP (cross-domain) if needed.
An early beta version can be found at the project's sourceforge page (includes working examples). This framework is provided under the GNU LGPL license (a copy is included, as copyrights in source files).

Usage
On the client-side :
var endPoint = [CP2JavaWSEndPoint createForURL:@"http://localhost:8080/CP2JavaWSServletTest/CP2JavaWSEndpoint1"];
var remoteService = [endPoint proxyForJavaServiceInterface:@"com.cp2javaws.demo.services.IDemoService1" delegate:self sameDomain:false];
//[remoteService addMappingForObjJClass:@"CPMyObject" andJavaClass:@"com.company.MyObject"];
[remoteService method1:@"arg1StringValue" andWithArg2:2 andWithArg3:new Date() delegateRespHandler:@selector(manageServiceMethod1Response:) delegateFailHandler:@selector(manageServiceMethod1Fail:)];

On the server-side :
Just subclass the provided CP2JavaWSJSONServlet servlet and implement the (abstract) method protected Object getService(Class serviceInterface).

Limitations
- support for custom objects is limited in this first (early) release : deserialization and serialization of complex objets works on the server side (JSON value from request parameters and JSON value returned by the servlet), but it isn't fully fonctionnal on the client side (also due to the reason below).
-as Cappuccino Foundation classes and runtime do not yet implement the full Objective-C refection APIs (methodSignatureForSelector isn't implemented and Method-->method_types isn't used), there isn't any mean to check for arguments passed through the proxy during remote service method invocation. In GWT such checking is made against a delcared Java interface for the remote serivce. Once required APIs are available in Cappuccino, we we will be able to check for arguments (count and type) against an Objective-J interface (protocol) delcared for the remote service (will correspond to the remote service Java interface).
- as the service method's signatures aren't available, number arguments (always of class CPNumber and javascript type 'number') can't be accurately recognized : we can't determine from what init method CPNumber instances have been created for example (and afer all there is the problem of arguments passed as primitive values ), so only a provided interface/protocol will help. For now we just check if the number value is an int or a float (and we can't rely on the passed value length - could be higher than the expected type max value). We assume integers as to be java.lang.Integer on the server side (ok because use 4 bytes), and floats as to be java.lang.Double (8 bytes, ok for most high numbers and high precision).
- support for cross-domain (JSONP) is included but still needs some check as jsonData is returned as an untyped javascript object (ok with CPURLConnection, returns a string).

Why using JSON / namespace consideration / CP2JavaWS comparison with GWT / Spring 3 REST servlet
JSON is intended to be used as a simple serialization format for REST exchanges, so it doesn't manage namespace problematics. We can read a useful article about its limitations and read a thread that explores possible extensions for JSON to be namespace aware :
http://blogs.sun.com/bblfish/entry/the_limitations_of_json
http://groups.google.com/group/json-schema/browse_thread/thread/dd1a8c9e55035c67

A more robust solution would have been to use a format such as XStream one, but it would have required an Objective-J implementation of that framework. Like Ojbective-C, Objective-J still provides its own object serialiazation format through coders (objects data are available as CPData). However on the other side (Java server) an implementation would have also been required, and the CP classes definition would be required (for custom complex classes, in order to access to their coder definition), either at runtime or in the generation tool alla GWT if using one. GWT produces javascript serializers for Java objects definitions (their serialization informations) and doesn't rely on an existing coder/decoder format on the client side, so additional information isn't required.

GWT doesn't face this problem as the client code (generated into javascript) is written in Java, so the generation tool can use the same serialization Java APIs (furthermore each service parameter object is defined only once. With CP2JavaWS it has to be defined both in Java and in Objective-J). However the powerful (and fully tested since NeXT era) AppKit/FoundationKit frameworks and Interface Builder available in Cappuccino overcome that little overhead.
Moreover Cappuccino allows mixing Objective-J code and javascript code (in a completely transparent manner, as Objective-C with C/C++ code), what is interesting considering the Objective-J code is compiled (by a JIT pre interpreter) into javascript at runtime.
GWT uses a generation step to allow client-side javascript<-->JSON serializers/deserializers generation, as they have to be static (are javascript code). Objective-J runtime dynamic feature doesn't require any manual generation step, as the end javascript is produced at execution time. The CPJSObjectCreateJSON and CPJSObjectCreateWithJSON methods could even eventually be used from/to Objective-J objects variables as they are finally (after the pre-interpreter work at runtime) converted into javascript.

CP2JavaWS only uses JSON for complex service arguments objects and service return (for both simple and complex result objects). For the former the java type is appended to the request parameter name, not the value (so JSON string value - for complex arguments - is a standard one. Simple argument values are passed as is - not in JSON).
In the service response, as there is no other place to provide the result object type, the class name is prepended to the JSON string (before the starting "{")), so it isn't regular JSON. To have a consistent decoding on the client-side (being able to use the same CPJSObjectCreateWithJSON for simple and complex result object - we then extract recursively each JSObject field and set in as an attribute for the newly created CP class), simple result objects are also encoded into JSON : that string however only contains one property, whose name is fixed ("result").

The Spring project also plans to provide such of REST bridge servlet for Spring 3 version, and the namespace problematics are widely discussed. We can find an example of JSON to Spring beans request parameters mapping servlet here : http://weblogs.java.net/blog/rexyoung/archive/2008/11/how_to_bind_fro.html.

Why not a Java to Objective-J generation tool for Cappuccino, like with GWT ?
I thought about such GWT like Java to Objective-J generation tool when I wrote notes/ideas about CP2JavaWS bridge late December (only for the remote service bridge, the GUI would have still been defined with CP classes and InterfaceBuilder, not in Swing). However I rejected that idea because it is sort of simplification/cheat : on one hand it allows far more easier development of the solution, it can lead to more optimized code (faster because of static code produced, no dynamic feature), it allows writing code in Java (and business objects used as services's parameters and return are declared only one time). But on the other hand it breaks the development cycle and isn't elegant.
After all, what would we say if object-relationnal mapping frameworks required to use a tool to generate some DAO from the mapping files ? Instead they use reflection APIs to dynamically generate objects from mapping description files. I know some implementations (based on the JDO specification) are based on a bytecode enhancement step (to compare with GWT generation step), that allows datastore type abstraction (database, but also filesystem, CICS, etc.) and better performance. But the result is that most people stayed with standard reflection based solutions (notably Hibernate, a defacto standard - not even based initially on any specification...)
Google had no other way to make GWT work than to use a generation step, because their end client code is pure javascript (so no way to implement such remote service proxy). Thanks to Cappuccino Objective-C runtime (converts Objective-J code into javascript at runtime using a JIT pre-interpreter), the proxy could be implemented without requiring a generation step.
The dynamic approach for Cappuccino to remote services seems better for me.
Comments
A new version - 0.2-beta - is available :

- remote services methods calls using JSONP (sameDomain setted to false) now work properly (the data passed to the javascript callback function is a javascript object contrary to sameDomain XMLHTTPRequest.response-text, as for cross-domain the application/ javascript content-type is managed by the browser - execution occurs inside a <script type="javascript" src="..."> element). The CP2JavaWSJSONDecoder decodes the javascript object return into the expected Objective-J class.

- the java remote service result can now be a collection, either a List (converted into a CPArray) or a Map (converted into a CPDictionnary). Collection cannot be used as services methods's arguments however for now (rare case hopefully).

- Custom Java (and CP equivalent on the client-side) classes can also be used as remote services methods's results, or as calls's arguments. However their attributes must be simple for now : string, integer, double. Date type isn't managed for now as it is considered as a "object" javascript type, and the CP2JavaWSJSONDecoder iterates through javascript objects keys -(we lacks ivar.type for now, undefined). In the next version the namespace will be added for each attribute in the returned JSON string, and we will iterate from the class definition ivars instead of javascript keys (the provided namespace for each JSON string node will circumvent the lack of ivar.type).

- services results of collections type can also use custom objects as their elements class, besides simple types. All elements are supposed to be of the same class.

- collections used for services results must be at the root level for now. For example a List (or Map) of Strings objects (or custom class) is allowed, but if using a custom class as the result, it cannot contains a collection as an attribute (you will have to use an additional call to another service to retrieve that nested collection).

- added examples are included for new use cases in the provided client- side demo AppController and service-side demo service implementation.

- next 0.3 version will allow full objects graphs to be passed as methods arguments and/or return, without any limitation on their type and depth (it will also allow nested collections).
(submitted at 01-12-09, 01:48 by cjed)
An alpha version of CP2JavaWS 0.3 is available here.It uses Objective-J categories to encode/decode full objects graphs (any depth, with nested collections - CPArray/List and CPDictionary/Map, and with heterogeneous collection elements) to/from JSON, allowing customization and cleaner code. The server-side manages decoding of the JSON parameters (full object's graphs support, also including nested collections and heterogeneous collection elements).
Encoding of the return (result) graph isn't completed however (has to be modified to add the objjClass).
Now the client sends/receives objjClass information in JSON strings, so it is independant from server language, and we can plan other implementations (PHP, etc.)
The final 0.3 version is due in a few days.
(submitted at 01-26-09, 02:51 by cjed)
Write a comment 
  
    
  image de securisation du formulaire


  
      (will be added after validation)