If you need special type conversion support (like Joda time to regular AS3 Date), you may use a custom converter and reference it in your granite-config.xml like that:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE granite-config PUBLIC "-//Granite Data Services//DTD granite-config internal//EN" "http://www.graniteds.org/public/dtd/1.0.0/granite-config.dtd"> <granite-config> <converter type="path.to.MyCustomConverter"/> </granite-config>
Your custom converter must implement the org.granite.messaging.amf.io.util.Converter interface (it could of course extend the org.granite.messaging.amf.io.util.DefaultConverter class) and 3 methods:
public Object convertForSerialization(Object value); public Object convertForDeserialization(Object value, Type targetType); public ServiceInvocationContext findServiceMethod( Map<String, Object> headers, Destination destination, Object service, String methodName, Object[] params) throws NoSuchMethodException;
See Javadoc comments in org.granite.messaging.amf.io.util.Converter and default implementation for further details.
See also the Gas3 java2as3class option here in order to extend code generation for your custom types.
If you need special service exception handling (either to add extra informations or to mask implementation details), you may configure a custom ServiceExceptionHandler in services-config.xml:
<?xml version="1.0" encoding="UTF-8"?> <services-config> ... <factories> <factory id="..." class="..."> <properties> <service-exception-handler> path.to.my.CustomServiceExceptionHandler </service-exception-handler> ... </properties> </factory> </factories> ... </services-config>
Your custom service exception handler must implement the org.granite.messaging.service.ServiceExceptionHandler interface (it could of course extend the org.granite.messaging.service.DefaultServiceExceptionHandler class) and 2 methods:
public ServiceException handleNoSuchMethodException( Message request, Destination destination, Object invokee, String method, Object[] args, NoSuchMethodException e ); public ServiceException handleInvocationException( ServiceInvocationContext context, Throwable t );
The first method is called whenever the service invoker cannot find any suitable method with the supplied name and arguments.
The second one is called whenever the method invocation throws an exception. Note that java.lang.reflect.InvocationTargetException are unwrapped (getTargetException) before handleInvocationException is called.
In both cases, the returned ServiceException will be trown (and serialized in a Flex ErrorMessage) instead of the raw NoSuchMethodException e or Throwable t one.
A problem with the default AMF3 serialization is to get the true class name of an object in special cases. For example, a simple myObject.getClass().getName() with a proxied entity bean would return "org.hibernate.proxy.HibernateProxy" instead of the underlying entity bean class name. In order to get through this kind of problem, you must configure a class getter.
For example, here is the full configuration used in graniteds-ejb3-1.0.0.zip:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE granite-config PUBLIC "-//Granite Data Services//DTD granite-config internal//EN" "http://www.graniteds.org/public/dtd/1.0.0/granite-config.dtd"> <granite-config> <classgetter type="org.granite.hibernate.HibernateClassGetter"/> <externalizers> <externalizer type="org.granite.hibernate.HibernateExternalizer"> <include instanceof="test.granite.ejb3.entity.AbstractEntity"/> </externalizer> </externalizers> </granite-config>
The org.granite.hibernate.HibernateClassGetter class is used in order to retreive the correct entity class name from a proxy. You may write and plug your own class getter in a similar way.
When a Java object is not Externalizable nor externalized by a GDS externalizer, it is serialized by the mean of the org.granite.messaging.amf.io.util.DefaultJavaClassDescriptor. This class controls which fields must be serialized and how to retrieve values from those fields.
In similar situations, but at deserialization time, the org.granite.messaging.amf.io.util.DefaultActionScriptClassDescriptor class controls how the corresponding Java object is instanciated and how values are set in this new instance.
You may write and plug your own Java or ActionScript3 descriptors, for example:
public class MyJavaClassDescriptor extends org.granite.messaging.amf.io.util.JavaClassDescriptor { public MyJavaClassDescriptor(Class type) { super(type); } @Override protected List<Property> introspectProperties() { // put your custom code here... } }
public class MyAS3ClassDescriptor extends org.granite.messaging.amf.io.util.ActionScriptClassDescriptor { public MyAS3ClassDescriptor(String type, byte encoding) { super(type, encoding); } @Override public void defineProperty(String name) { // put your custom code here... } @Override public Object newJavaInstance() { // put your custom code here... } }
Then, you should put this kind of declaration in your granite-config.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE granite-config PUBLIC "-//Granite Data Services//DTD granite-config internal//EN" "http://www.graniteds.org/public/dtd/1.0.0/granite-config.dtd"> <granite-config> <descriptors> <descriptor type="path.to.MyClass" java="path.to.MyJavaClassDescriptor" as3="path.to.MyAS3ClassDescriptor" /> <descriptor instanceof="path.to.MyBaseClass" java="path.to.MyJavaClassDescriptor" as3="path.to.MyAS3ClassDescriptor" /> <!-- other descriptor configuration... --> </descriptors> </granite-config>
You must use only one of type or instanceof attributes (ie: should my descriptor(s) be used for all path.to.MyClass objects or for all instances of path.to.MyBaseClass); you may use one of (or both) java or as3 attributes.
You may plug your own AMF3 serializer/deserializer.
A custom AMF3 serializer must implement java.io.ObjectOutput and have a special constructor signature:
public class MyAMF3Serializer implements java.io.ObjectOutput { public MyAMF3Serializer(java.io.OutputStream out) { // ... } // ObjectOutput implemention... }
Then, you must register this serializer in granite-config.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE granite-config PUBLIC "-//Granite Data Services//DTD granite-config internal//EN" "http://www.graniteds.org/public/dtd/1.0.0/granite-config.dtd"> <granite-config> <amf3serializer type="path.to.MyAMF3Serializer"/> </granite-config>
A custom AMF3 deserializer must implement java.io.ObjectInput and have a special constructor signature:
public class MyAMF3Deserializer implements java.io.ObjectInput { public MyAMF3Deserializer(java.io.InputStream in) { // ... } // ObjectInput implemention... }
Then, you must register this deserializer in granite-config.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE granite-config PUBLIC "-//Granite Data Services//DTD granite-config internal//EN" "http://www.graniteds.org/public/dtd/1.0.0/granite-config.dtd"> <granite-config> <amf3deserializer type="path.to.MyAMF3Deserializer"/> </granite-config>
You may of course extend org.granite.messaging.amf.io.AMF3Serializer or org.granite.messaging.amf.io.AMF3Deserializer to override only some parts of the default AMF3 (de)serialization process (all methods in thoses classes are public or protected).
If you need to listen to each service invocation method call, you may plugin a org.granite.messaging.service.ServiceInvocationListener implementation like this:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE granite-config PUBLIC "-//Granite Data Services//DTD granite-config internal//EN" "http://www.graniteds.org/public/dtd/1.0.0/granite-config.dtd"> <granite-config> <invocationlistener type="path.to.MyServiceInvocationListener"/> </granite-config>
Your class must implement the org.granite.messaging.service.ServiceInvocationListener interface and 3 methods:
public Object[] beforeMethodSearch(Object invokee, String methodName, Object[] args); public void beforeInvocation(ServiceInvocationContext context); public Object afterInvocation(ServiceInvocationContext context, Object result);
| Be very carefull with those listeners: you may broke the invocation process if you don't return proper args (beforeMethodSearch), if you modify the ServiceInvocationContext (beforeInvocation) or if you return a different object than the service method call result (afterInvocation)! |
|
Browse Space |
Explore Confluence |
Your Account |
Add Content |
|
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.6.0 Build:#913 Sep 27, 2007) |
|
|
|