History | Log In     View a printable version of the current page.  
Issue Details (XML)

Key: BLZ-246
Type: Feature Request Feature Request
Status: Under Investigation Under Investigation
Priority: B B
Assignee: Mete Atamel
Reporter: Rémi Flament
Votes: 7
Watchers: 5
Operations

If you were logged in you would be able to see more operations.
BlazeDS

Transparent services invokation with java dynamic proxies

Created: 09/26/08 12:28 PM   Updated: 05/12/09 06:21 PM
Component/s: Java AMF Client
Security Level: Public (All JIRA Users )

File Attachments: 1. Java Source File AMFClientFactory.java (2 kb)
2. Java Source File AMFClientProxy.java (2 kb)
3. Java Source File AMFClientProxy.java (2 kb)



 Description  « Hide
Here are two simple classes to invoke existing services in a transparent manner thanks to java dynamic proxies.

This way you can call your services exactly the same way that if you were not using amf serialization (i.e same classloaders). It is the same thing that apache cxf simple frontend (http://cwiki.apache.org/CXF20DOC/simple-frontend.html) , but for Amf !

Here is a simple example of usage :

AMFClientFactory factory = new AMFClientFactory();
factory.setServiceName("contractService");
factory.setServiceClass(ContractService.class);
factory.setUrl("http://localhost:8081/xxxxx/messagebroker/amf");
ContractService service = (ContractService) factory.create();

 List<Contract> contracts = service.findContractType();


If you use spring, the first part can be done by using a spring factory bean. It also supports basic authentication.

It opens a new connection on each method invokation, but it can easily be changed if it is not the best way to do it...

 All   Comments      Sort Order:
Rémi Flament - [09/26/08 01:16 PM - edited ]
Here is a example of spring usage :

Spring configuration for AMF remote invokation :

<bean id="contractServiceFactory" class="AMFClientFactory">
<property name="serviceClass" value="xxxxx.xxxx.contract.api.ContractService" />
<property name="url" value="http://localhost:8081/xxxxx/messagebroker/amf" />
<property name="username" value="admin" />
<property name="password" value="admin" />
<property name="serviceName" value="contractService" />
</bean>

<bean id="contractService" class="xxxxx.xxxx.contract.api.ContractService" factory-bean="contractServiceFactory" factory-method="create"/>

Spring configuration local invokation :

        <bean id="contractService" class="xxxxx.xxxx.contract.impl.ContractServiceImpl" />

Java code :

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-client.xml");

        ContractService service = (ContractService) context.getBean("contractService");

        List<Contract> contracts = service.findContractType();


As you can see, the java code doesn't change at all when you switch from local invokation to amf remote invokation.

Rémi Flament - [10/02/08 03:14 AM ]
Here is a fix for BLZ-248 : it checks the return type expected by the developper and it transforms the return double in an int if needed.

Sebastien Guimont - [02/15/09 03:11 PM ]
When I try to code, I got a ClassCast exception related to object array as result of amfconnection.call that was other than Object[].

here's the correction I made in the AMFClientProxy.java file

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

AMFConnection connection = new AMFConnection();

if (username != null) {
String userpasswd = username + ":" + password;
String encoding = new String(new Base64().encode(userpasswd.getBytes()));
connection.addHttpRequestHeader("Authorization", "Basic " + encoding);
}

connection.connect(url);

Object[] params = args;
if (null == params) {
params = new Object[0];
}

Object callResult = connection.call(serviceName + "." + method.getName(), params);

connection.close();

                          // Creates a new array with the valid type from the call result
if (method.getReturnType().isArray()) {
Object[] arrayOfValidType = (Object[]) Array.newInstance(method.getReturnType().getComponentType(), ((Object[]) callResult).length);
System.arraycopy(callResult, 0, arrayOfValidType, 0, ((Object[]) callResult).length);
callResult = arrayOfValidType;
}

return callResult;
}

MS - [02/20/09 05:24 AM ]
This is very helpful - thanks!

jvroom - [02/24/09 03:18 PM ]
Mete can you take a look at this approach? Is it something that can be layered on top of our existing product or do we need to make product changes to enable this use case?