Wednesday, September 26, 2007

Coping with Flex Asynchronous Remote Calls - Part II

In my previous post about using modal dialogs to give the illusion of synchronous remote calls in flex to the user, I showed one way of coping with flex remote calls being asynchronous.

Another way is to fully accept the asynchronism of the remote calls, and start designing your application using callbacks instead.

Imagine the situation, where some code on the client needs to make this (seemingly simple) call:

var result : String = remoteService.doServerSideCalculations(42);

Where remoteService.doServerSideCalculations() is a call to a remote web service. Looks like a no-brainer when coming from the Java world. It is just a method call with a return value. Well, no. Because the remote call is asynchronous, you will not get the return value of the call into result.

The next thing you try when you do not know actionscript3, is to look for some call in the flex api or actionscript3 language to issue a wait, yield or sleep. This could make it possible to let the client wait for the request to return, and then continue operation from there on. But there exist no such calls or functionality!

What to do then?

Design with Callbacks
What you need to do is start designing with callback methods. What I have done is to wrap the remote service in a proxy class, which takes care of calling the remote service and waiting for results. In the event of remote methods which return a value, the proxy will issue a callback to the caller on the proxy, giving the return value of the remote call as a parameter value.

In the above example, I would create a proxy class in as3 like this:

package com.blogspot.techpolesen {
import mx.rpc.soap.WebService;
import mx.rpc.events.ResultEvent;

public class RemoteService {
private var remoteService : WebService = new WebService();

function RemoteService() : void {
remoteService = new WebService();
remoteService.wsdl = "/services/RemoteService?wsdl";
remoteService.loadWSDL();
}

public function doServerSideCalculation(input : int, callback : Function) : void {
// the listener on the result event will call the callback with the return value
var listener : Function = function(event : ResultEvent) : void {
remoteService.removeEventListener(ResultEvent.RESULT, listener);
callback(remoteService.doServerSideCalculation.lastResult);
};

remoteService.addEventListener(ResultEvent.RESULT, listener);

// do the actual call
remoteService.doServerSideCalculation(input);
}
}
}

Here, the RemoteService as3 class wraps the call to the doServerSideCalculation(int) method in an as3 method, which takes a second argument, the callback function. What the as3 implementation does is to add an event listener, that waits for the ResultEvent. When this event occurs, the return value is ready, and the callback can be made, giving the return value back to the caller of the proxy.

Here is an example on how the above proxy class can be used in the application:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import com.blogspot.techpolesen.RemoteService;

private var remoteServiceProxy : RemoteService = new RemoteService();

private function callIt() : void {
lbl.text = "Calling...";
remoteServiceProxy.doServerSideCalculation(42, function(result : int) : void {
lbl.text = "Result: " + result;
});
}
]]>
</mx:Script>

<mx:Button label="Do remote call using callback" click="callIt()"/>
<mx:Label id="lbl"/>
</mx:Application>

And here is a bit of explanation:
  • When the button is clicked, the callIt() method is called
  • The callIt() method invokes doServerSideCalculation on the client-side as3 proxy for the remote service
  • The key is in the parameters to that method. The first parameter is easy, 42, which is simply the parameter to the actual remote call.
  • But the second parameter, callback, is of Function type. It takes a reference to a method. This method is the callback, that will be called when the remote call returns.
  • In the implementation of doServerSideCalculation, an event listener is added on the result event. This listener will be called by flex, when the remote call returns. The listener in turn grabs the return value from the method, and executes a call on the callback method, passing the remote call return value as parameter.
What happens when you click the button, is that callIt calls the doServerSideCalculation, method giving it a callback method. You can view this method as the left-side of the result = doServerSideCalculation(input) call. It simply assigns the result to a label.

You could also combine the above with a modal dialog or a modal dialogs with some progress indication. You would then open the modal dialog in doServerSideCalculation.

Downloading the source
I have zipped up the sources for you. It can be downloaded from here. Ready to be build with maven.

This is a multi-module maven build. There are two directories:
  • client : Contains the flex source and a pom to build it
  • server : Contains the web service and a pom to build it
The war artifact output from the server module have in it the flash output from the client module and a index.html which loads it.

To start the server after a build, you simply jump into the server directory and do a "mvn jetty:run-exploded".

Other Small Flex Tutorials
This was lesson 8 in my series of posts on what I learn about developing filthy rich flash apps using flex2. If you want to read more, the previous lessons can be found here:

Monday, September 17, 2007

Coping with Flex Asynchronous Remote Calls - Part I

This post is showing you, how to easily use a modal dialog popup with a ProgressBar, when calling a Web Service in Flex. This can help make the impression to the user, that the call is synchronous.

UPDATE: This is Part I in a multipart post. You can view part II here, about using callbacks to cope with the asynchronous calls.

Previously, i blogged about how to call a web service from flex code. In that post, I showed the basics of calling web services from actionscript code, but I only briefly mentioned, that remote calls are asynchronous in flex. Actually, the asynchronity of remote calls has a major impact, on how you design the client.

In this post, I show one way to cope with the asynchronity.

When a remote call is issued, and the result of the call is to be known on the client, before it can let the user continue, we need to "wait" for the operation to finish. This can be done by opening a modal dialog. In this example, the modal dialog also contains an indication of progress, showing the user, that some operation is running.

Here is the code for the client:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="loadWebService()">
<mx:Script>
<![CDATA[
import mx.rpc.soap.WebService;
import mx.rpc.events.ResultEvent;
import mx.managers.PopUpManager;

private var longRunningService : WebService = new WebService();

private function loadWebService() : void {
longRunningService = new WebService();
longRunningService.wsdl = "/services/LongRunningService?wsdl";
longRunningService.loadWSDL();
}

private function callWebService() : void {
var popup : ShowProgress = ShowProgress(PopUpManager.createPopUp(this, ShowProgress, true));
PopUpManager.centerPopUp(popup);
longRunningService.addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void {
PopUpManager.removePopUp(popup);
});
longRunningService.slowOperation();
}
]]>
</mx:Script>

<mx:Button label="Call a long running remote method" click="callWebService()"/>
</mx:Application>

In the above code, loadWebService() is called at application creation time. It loads and parses the wsdl and adds web service operations to the longRunningService variable.

When the button is clicked, it calls callWebService() which:
  1. Creates a popup window from the ShowProgress type (my progress dialog), marking it modal. After this line of code, the modal popup is showing, and no user input can be made.
  2. It then adds an event listener for the ResultEvent.EVENT event, which is dispatched when the web service call completes. This handler will remove the popup when called.
  3. The web service call is made.
And here is the code for the ShowProgress.mxml dialog:

<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" title="Talking to server" creationComplete="init()">
<mx:Script>
<![CDATA[
private function init() : void {
progress.setProgress(1, 0); // to start progress indicator when indeterminate
}
]]>
</mx:Script>
<mx:ProgressBar id="progress" mode="manual" indeterminate="true"/>
</mx:TitleWindow>

It contains only a ProgressBar component, which is set into manual mode and set to be indeterminate. In manual mode, we must use setProgress to update progress. When being indeterminate, it does not show progress against an absolute stop value, but simply indicates "some" progress. In the init() method, I call setProgress(1, 0), which starts the indeterminate progress indicator.

It is important to note here, that the call is not actually synchronous now, just because of the modal dialog. It only appears to be, by the user. The application will continue, after the call to the web service.

Downloading the source
I have zipped up the sources for you. It can be downloaded from here. Ready to be build with maven.

This is a multi-module maven build. There are two directories:
  • client : Contains the flex source and a pom to build it
  • server : Contains the web service and a pom to build it
The war artifact output from the server module have in it the flash output from the client module and a index.html which loads it.

To start the server after a build, you simply jump into the server directory and do a "mvn jetty:run-exploded".

Other Small Flex Tutorials
This was lesson 7 in my series of posts on what I learn about developing filthy rich flash apps using flex2. If you want to read more, the previous lessons can be found here:

Monday, September 10, 2007

A Database Design that JPA Cannot Map

The other day, I had to JPA map a part of a database, that was built over a period of about 3-4 years using EJB 2.x CMP technology. This particular part of the database contains huge amounts of CLOB data, which also needs to be searchable on some of the data in the CLOBs. The CLOB data could be taken offline after some period of time. All of this had led to the following physical database design:

Table: REPORT
id : INTEGER
image_tablename : VARCHAR
search_attribute_1 : INTEGER
search_attribute_2 : VARCHAR

Table: IMAGE1
report_id : INTEGER
data : CLOB

So, we have a parent table REPORT, in which we have important data, extracted from the data CLOB into searchable columns on each row. Each row also contains a column image_tablename, that names which table, the data CLOB can be found in.

This design enables us to take complete image tables of CLOBs offline, without even moving rows around, having to be concerned about oracle watermarking issues, etc. But, having REPORT pinpoint the table where the data CLOB is, also makes it impossible to map with JPA. The @Entity annotation requires the table name to be set at mapping time.

Luckily, we could simply do a couple of native queries. One for locating the tablename on a report_id and one for getting the CLOB data from that table.

Start using String.format and its cousins

Please, by all means, start using String.format and the format methods of PrintWriter and PrintStream instead of string concatenation or keeping with the old hated MessageFormat class. String.format is so much cleaner. Of course, this is only if you are so lucky to be on Java5 or later. If you're not, you have my sympathy.

Here is an example. This horrible code:

System.out.println("This dude '" + personName + "' is " + years + " old");

Becomes this, cleaner code:

System.out.format("This dude '%s' is %d old", personName, years);

Well, this is a simple example. But I am sure you get the point. And the format of the format strings are largely strftime compliant, but look here in the apidocs for java.util.Formatter, for the exact docs on what it supports.

So, what is so damned nice about it? Well, for once, it makes it easier to read the code and easier to see if the strings we are putting together, are correct. But it also uses some things in the JDK, which makes it nice to work with:

It uses varargs, in that all but the first parameter are a variable list of arguments to the format string. A good IDE (IDEA springs to mind) can warn you if the list of arguments matches in number, and if the type of the arguments match the given format string.

You can use static import on the format method. If you are calling String.format more than once in the same class, you should do this, instead:

import static java.lang.String.format;
format("This dude '%s' is %d old", personName, years);
format("This dude '%s' is %d old", personName, years);
...

Friday, September 07, 2007

Could not find destination factory for transport http://schemas.xmlsoap.org/soap/http

A little tip, if you use CXF as a client to some web service, and am getting this exception:

org.apache.cxf.interceptor.Fault: Could not find destination factory for transport http://schemas.xmlsoap.org/soap/http
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:85)
at org.apache.cxf.jaxws.JAXWSMethodInvoker.invoke(JAXWSMethodInvoker.java:82)
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:56)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:56)
at org.apache.cxf.workqueue.SynchronousExecutor.execute(SynchronousExecutor.java:37)
Caused by: java.lang.RuntimeException: Could not find destination factory for transport http://schemas.xmlsoap.org/soap/http
at org.apache.cxf.binding.soap.SoapTransportFactory.getConduit(SoapTransportFactory.java:148)
at org.apache.cxf.endpoint.AbstractConduitSelector.getSelectedConduit(AbstractConduitSelector.java:73)
at org.apache.cxf.endpoint.UpfrontConduitSelector.selectConduit(UpfrontConduitSelector.java:71)
at org.apache.cxf.endpoint.ClientImpl.getConduit(ClientImpl.java:417)
Then you are not alone, as I did too. Here is what I did to solve it: CXF uses spring xml for its configuration, so inside your spring config, do this:

<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml"/>

And you will need the cxf-rt-transports-http-jetty jarfile in classpath.

Wednesday, September 05, 2007

Intergalactic Gotos and the WrappingWronglyCheckedExceptionException Proposal

There is debate about if checked exceptions have their right or not. I think they might have, but more often than not, we use exceptions like intergalactic gotos instead. Many exceptions in the Java APIs that are checked, should have been unchecked in my opinion. The other day, I wrote this code:

String s = ....
return s.getBytes("UTF-8");

And the compiler told me, that getBytes(String) throws the checked exception UnsupportedEncodingException, which I am then forced to catch. So, I end up with:

try {
String s = ....
return s.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
// what the f*** to do with that?
}

The JRE documentation of the java.lang package documents, that UTF-8 is one of the encodings, that all implementations are required to support. So, if I use this method correctly according to its api, and only ask for encodings required to be supported, then it will be a runtime error, if the encoding is not supported.

So, what about adding this exception to commons-lang:

public class WrappingWronglyCheckedExceptionException extends RuntimeException {
...
}

Then, I would know what to fill into my catch-block in such cases.

MediaWiki said: Table "wiki_objectcache" is marked as crashed and should be repaired

My MediaWiki installation suddenly refused to save changes to pages. It just told me something in the lines of:

MediaWikiBagOStuff:_doquery Table 'wiki_objectcache' is marked as crashed and should be repaired

Dammit! A little browsing around hit a german page with the same problem. I am not good at the german language, but I could understand the proposed solution:

truncate table wiki_objectcache

And all worked again.

Sometimes, MySQL just seems so much like a toy-database to me!

Is Maven too Complex and Bloated?

The set of features of maven seems cool, but maybe it is too complex to use in practise. Kind of ironic, when one of the goals was to make it dead-easy to setup builds of common Java artifacts.

Transitive dependencies not found
One common example is when transitive dependencies are not met. More often than I would like, I get into the problem of transitive dependencies of one of my dependencies cannot be found. Latest one was when using CXF, where it failed on finding some JAXB dependency in some specific version.

You could argue, that this is not mavens fault, but the fault of those deploying into the repository. But it appears to happen so often. Why is this? Maybe because it is too hard to do deployment correctly into it.

All the site/report generation crap
From the start, maven has taken on the role of building more than just our sources. With the reports and site plugin, it can generate documentation in html-format from various sources. It can also produce various reports and integrate them into the generated site.

Nice, but... It takes ages to process. It outputs a big load of crap when running, which hides actual problems it might notice on the way. The syntax to write the documentation sources in (xdocs, apt) are crap.

Why not just document on a wiki. Hey! People are already doing that all-over.

When dependencies clash
This can occur in many different forms. One example is what Jacob writes about in "A badly packaged project will break builds". The essence is, that transitive dependencies explodes in complexity. Some project might depend on spring-web-2.0.5 as a fine-grained dependency and another might depend upon a spring-2.0.4, which is a "all of spring" dependency. These are in different versions, and might clash and be incompatible. And maven cannot know what to do about it. It cannot even notice, as the artifactIds, "spring-web" and "spring", are different.

It is nice to be able to just depend on something declaratively, and automatically get a load of needed transitive dependencies with it. But, it is like pissing your pants. It warms right when you are doing it, but it quickly gets cold.

I think the whole dependencies problem is inherently complex. And very hard to put into a build tool for automatic management.

So, what to do?
Sadly, I have no really good advice on what to do then. I know for sure, that I cannot do better myself.

Sometimes, I wonder how far we could come, by doing our builds with:
What do you think?

Saturday, September 01, 2007

Specify artifact details only once with the Maven dependencyManagement element

If you have multi-module maven builds, where sub-poms inherit a parent pom, you can utilize the dependencyManagement element in the parent pom, to only define artifact details once. Here is an except from a parent pom:
<dependencymanagement>
<dependencies>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring</artifactid>
<version>2.0.5</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-mock</artifactid>
<version>2.0.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencymanagement>
The above pom extract does not define dependencies in the project. It sets some defaults, which child-poms inherit. Child-poms will not have the dependencies themselves, unless they explicitly define them in their dependencies element.

In the poms in sub-modules, that inherit this parent pom, you will only need to define the artifacts you depend upon, not their details like version, exclusions, etc. Here is an except from a sub-pom:
<dependencies>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring</artifactid>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-mock</artifactid>
</dependency>
</dependencies>
Using dependencyManagement keeps the version the same over all modules, and reuses other elements like exclusions and scope.