Friday, June 24, 2011

Single Threading in Vaadin!

Are you developing a Vaadin application for Google App Engine (or you might not be able to spawn threads for any other reason)? Then this post will help you out in creating a more responsive application. This will especially be helpful if you are trying to do heavy backend tasks (Java code as opposed to the client-side JavaScript code). Well, consider it heavy in GAE terms if it is going to take more than 30 seconds.

What to achieve:
I want to update the UI accordingly during a long backend process (e.g. by updating a progress indicator) and let the user intervene to stop it.

The problem:
Without spawning another thread, modifications to the UI components will not take effect until the backend process finishes.

Assumption:
I will try to use Vaadin's capabilities rather than locking myself into Google's task queue API.

What I have done is creating a custom Echo component that simulates a backend to frontend round trip. I have broken down the long process into small chunks. Now I need to call this component from my backend code after doing each chunk of operation. Echo goes off and returns, on return I will resume the process.

Another place this component can be useful is where you want to disable a button while the handler is still working. This could be achieved easily using another thread, but if you cannot spawn threads this is how you might do it: On the button's click listener disable the button and then send an echo. The button is disabled now and you will continue your process in the backend on the response.

There is complete source code available for the custom component and also a sample application that shows how it can be used. Use this command to check it out on your own machine:

svn checkout http://tinywebgears-samples.googlecode.com/svn/trunk/echosample/ echosample-read-only
or feel free to browse the repository (here).You can use the jar files provided right away or compile it yourself.

Update: If you seek this solution only to disable a button while processing the click, be aware of this change to the Button that will enable you to call button.setDisableOnClick(false). The feature is to be added to Vaadin 6.7 and you might try the nightly build for an early access.

Monday, June 13, 2011

XML-RPC + Maven + Spring

I was lately trying to implement a basic set of services in XML-RPC. Well, it had to be XML-RPC as a architectural design constraint if you are interested why . Other than that I had other requirements as well: It had to be on Spring, must be built by Maven, and most importantly it had to be a WAR file in a container not a standalone application.

Googling around, I came up with a few blog posts providing hints and code snippets. Here are some of them that I actually based my code on:
Salmon Run (07 Feb 2010)
Tomas Salfischberger (28 March 2008)
Perry Nguyen (6 Oct 2006)
Here I am not adding much to what these guys have already said, but instead doing what they could have done to save me hours of trial and error: Providing a complete working example.

The sample application provided here is a Spring based web application that can be hosted in an application server like Tomcat.

You can browse the code in this SVN repository. Alternatively you might try this command to check it out completely from repository:
svn checkout http://tinywebgears-samples.googlecode.com/svn/trunk/xmlrpcsample/ xmlrpcsample

This application also provides a sample Java client that can be used to call the sample service. The client code connects to the server at this pre-configured location:
http://127.0.0.1:8080/xmlrpc-backend-services/xmlrpc/
and then invoke the sample service called 'sampleService.getVersion'.
You might need to change the client code if you deploy in a different configuration.

For those who are intersted, I have also been able to add another view controller and other set of Spring MVC views to serve a web application living besides the XML-RPC services, but I removed those bits in order to keep it simple.

The parts of configuration that tend to go wrong (and took me bloody hours to get them fixed) are web.xml and Spring's beans configuration file. Here is my web.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/META-INF/properties/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

<!-- Spring context -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:WEB-INF/spring/*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Spring webapp -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!-- Welcome file -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

</web-app>



And finally the beans configuration will be as follows:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">


<!-- XML-RPC -->

<!-- XML-RPC Services -->
<bean id="sampleService" class="com.tinywebgears.samples.service.SampleServiceImpl">
</bean>
<!-- Processor Factory -->
<bean id="requestProcessorFactory"
class="com.tinywebgears.samples.xmlrpc.ConfiguredBeanProcessorFactory">
<property name="classBeanMap">
<map>
<entry key="com.tinywebgears.samples.service.SampleService"
value-ref="sampleService" />
</map>
</property>
</bean>
<!-- Controller -->
<bean id="xmlRpcHandler" class="com.tinywebgears.samples.xmlrpc.XmlRpcServerController">
<property name="factory" ref="requestProcessorFactory" />
<property name="mappings">
<props>
<prop key="sampleService">com.tinywebgears.samples.service.SampleService</prop>
</props>
</property>
</bean>


<!-- Dispatcher -->

<bean id="simpleUrlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="mappings">
<props>
<prop key="/xmlrpc/*">xmlRpcHandler</prop>
</props>
</property>

</bean>

<context:component-scan base-package="com.tinywebgears.samples" />

</beans>

Friday, June 10, 2011

Beans Go Crazy

After years of contemplation (!) I finally found the guts to start my techie blog.
Here I will be writing about my software development experiences and provide useful tips and code snippets, like what everyone else does.
You might then ask "why bother"? Yes, you're right. There is something different here. I will provide complete working code if what I talk about is in the code level and more than a simple tip.
Needless to say that Java will be the dominant topic of this blog, well that's why it is called 'Beans Go Crazy', because they most of the times do!
Although every other sensible names I came up with had already been registered a few years ago, having only one 'Hello World' post.


Talk to you soon.