Saturday, January 9, 2010

Cross-Platform Desktop Application Frameworks: Which One to Choose?


Desktop applications aren't dead yet, in my opinion. I still prefer email client, Twitter client, IM client, office apps, and many others on the desktop instead of using my web browser for that.

There are several desktop application frameworks for your development appetite, all with its own strengths and weaknesses. Which one is the best?

Java Desktop Application Frameworks


When looking at desktop application frameworks in Java, obvious choices are:
Java applications run on all major desktop platforms. It potentially runs on advanced mobile platforms, such as Nokia's Maemo, Intel's Moblin, and Google's Android.

I personally think Eclipse RCP is more powerful than NetBeans', and I'm not alone. You can see that from its usage on many commercial applications: SpringSource Tool Suite and JBoss Developer Studio among those.

The slight downside of Java is the user need to have Java Runtime installed. There are many ways to make this part of user experience much smoother.

C++ Desktop Application Frameworks


You can also go native, with C++ your choices are:
I have some experience with Qt development, and it's quite pleasant. Qt applications run on all desktop operating systems equally well, with initial support for Maemo, Symbian S60, and Windows Mobile (WinCE) mobile devices.

Most, if not all, KDE applications use Qt. Examples include the high profile Amarok music player, Kontact organizer, and KOffice desktop suite. Which proves Qt as suitable for complex applications.

Current Symbian devices can already run Qt apps with additional Qt runtime. Nokia featurephones and smartphones sometime in 2010 will have Qt support out-of-the-box.

Mozilla RCP is a higher-level framework than Qt, and powers an impressive portfolio of Firefox, Thunderbird, Sunbird, Songbird, Firefox Mobile (Fennec), and ActiveState Komodo.

Hybrid Web/Desktop Application Frameworks


If you love Web Technologies, these tools may be interesting to you:
Both alternatives have a similarity: they allow you to write applications with HTML, JavaScript, and CSS, with some proprietary JavaScript API for native functionality.

Titanium has an interesting advantage: apps can be run on iPhone and Android devices with Titanium Mobile.

Your code is potentially reusable for a web application frontend.

What about Mono?


I intentionally left out CLR (Common Language Runtime), more popularly known as the Microsoft .NET Framework. It's Java's most fierce competitor.

.NET has varying degrees of support in different platforms. Windows has the best support, followed by Linux and Mac OS X using Mono implementation, then Windows Mobile devices with .NET Compact Framework.

If you develop using Visual Studio 2010 (in Beta as of this writing), for example, you app will most likely not run under Linux. Add to that the continuing licensing issues. So I don't consider it "cross platform enough".

Anyway, I loved the C# programming language.

So, The Answer is...?

My conclusion is, it depends on your use case. I have a few suggestions though:
  • If it's a complex desktop application, go with Eclipse RCP. It will be more maintainable in the long term, and your Java code should be reusable.
  • If any of these is important to you: reusing code across platforms, Nokia devices, you love C++, you want as native as possible, seamless installation, small footprint; go with Qt.
  • If you love working with web technologies, and/or your application deals more with fluid user experience than processing data locally; go with Titanium Desktop.
What's your preferred framework?

Get Started with Eclipse RCP

To get started developing rich desktop applications with Eclipse RCP, grab the book Eclipse Rich Client Platform, Second Edition.

Friday, January 8, 2010

Unfuddle Mylyn Connector for Eclipse IDE

Unfuddle is an excellent source code hosting and online project management tool. It has a nicely done bug ticketing system, but I wanted something much cooler, a Mylyn Connector for Unfuddle.

Mylyn is an Eclipse plugin that makes it easy to create and edit tasks (or issues/tickets/bugs whatever you call it) right inside the Eclipse IDE. Mylyn also allows the developer to work locally (offline), and the changes can be synchronized with the remote task repository when online.

I work in Java primarily with SpringSource Tool Suite, which has Mylyn built-in. It made me sad that I seldom use Mylyn while working with Unfuddle-hosted projects... but that's old news.

Fortunately for me and all of you, Andronic Trandafir this morning brought good news that Unfuddle has developed the Unfuddle Mylyn Connector. They're running limited tests with some customers, and I'm lucky enough to have that privilege.

Unfuddle Plugin Installation on SpringSource Tool Suite


Installation couldn't be easier, just copy that plugin JARs into the Eclipse dropins folder, then restart Eclipse.

I was using SpringSource Tool Suite 2.3.0, the installation was flawless. Unfuddle plugin was immediately installed, no plugin conflicts whatsoever. This is quite a feat on Unfuddle developers' part because SpringSource Tool Suite is a very complex IDE.

Experience of Unfuddling in Mylyn


Setup Task Repository:



Synchronizing tickets from Unfuddle to Mylyn:


Editing a Ticket:


Want It?


At the time of this writing, Unfuddle Mylyn Connector is still in beta testing phase. Post your request in Unfuddle Community Forums to see if you can get a copy.

Unfuddle Mylyn Connector has been released. Check out their blog post announcing this plugin.

Installing Voxeo Prophecy 9 on Ubuntu Karmic Koala 9.10

Voxeo Prophecy is an IVR (Interactive Voice Response) speech server supporting VoiceXML, ccXML, SCXML, SIP, and related standards.

Prophecy only officially supports Red Hat Enterprise Linux (RHEL), but with some tweaks, it can be configured to run on Ubuntu.

Installing Voxeo Prophecy on Ubuntu


After you download Voxeo Prophecy, you need to do some preparation steps:
  1. Create symbolic links for supporting libraries:
    sudo su
    ln -s /lib/libssl.so.0.9.8 /lib/libssl.so.6
    ln -s /lib/libcrypto.so.0.9.8 /lib/libcrypto.so.6
    ln -s /usr/lib/pm-utils/functions /etc/init.d/functions
    ln -s /lib/libcap.so.2 /lib/libcap.so.1
  2. Still as root, install Voxeo Prophecy:
    ./prophecy-9.0.38536.0-small-tts-ds-vm.bin
    The installation should finish successfully, although with "some errors.":
    The installation of Voxeo Prophecy is finished, but some errors occurred during the install.  Please see the installation log for details.

  3. If you have a license, copy license.xml to /opt/voxeo/config.
    If you don't have a license yet, follow instructions to run Voxeo Prophecy below and get a license as soon as possible. If your Voxeo Prophecy trial installation license expires, you will not be able to generate a license automatically and must contact Voxeo support to get a license. (believe me, I've been there)
  4. Create the /var/lock/subsys directory:
    mkdir -p /var/lock/subsys

Prophecy is now installed on your Ubuntu system.

Starting Voxeo Prophecy on Ubuntu


To run Prophecy, you cannot use "prophecy start". You need to run these commands manually:
sudo su
/etc/init.d/voxeo-vdirectory start
/etc/init.d/voxeo-vmc start
/etc/init.d/voxeo-vsipmethod start
/etc/init.d/voxeo-vserver start
/etc/init.d/voxeo-vxml start

Shutting Down Voxeo Prophecy on Ubuntu


To stop/shutdown Prophecy, run these commands:
sudo su
/etc/init.d/voxeo-vxml stop
/etc/init.d/voxeo-vserver stop
/etc/init.d/voxeo-vsipmethod stop
/etc/init.d/voxeo-vmc stop
/etc/init.d/voxeo-vdirectory stop

Uninstalling Voxeo Prophecy


Uninstallation process is still the same, run the following commands:
sudo su
/opt/voxeo/Uninstall/Uninstall_Voxeo_Prophecy
rm -rf /opt/voxeo

Why Voxeo Prophecy?


You might be wondering what an IVR server is doing on a Spring/Java EE blog.

I feel that this information could be useful to others, and I can't find a better place to publish it. :-)

Who knows maybe you're also working with IVR?

Thursday, January 7, 2010

Best Java IDE: SpringSource Tool Suite

There are abundant choices of Java IDEs. My work on Java is mainly Spring web application development. Obviously, my choice goes to: SpringSource Tool Suite.



SpringSource Tool Suite is basically Eclipse IDE Java or Java EE edition with the following additional features preinstalled:
The only additional feature I must install afterwards is Subclipse for Subversion integration. I wonder why SpringSource left it out (intentionally?)

Of course, there are alternatives:

Want Tail with GUI on Windows (and Linux and Mac)? MakeLogic Tail!

I usually do my Java development on Ubuntu (Linux) and tail is my best friend. Tail is a console tool to follow real-time updates on a file, for example the Apache Tomcat log file. However, in Windows, I don't have the "luxury" of tail

MakeLogic Tail, a GUI/visual Tail utility, comes to save my day! It is a Java application so it also runs on Linux and Mac OS X and other Java-supported platforms.



If you want the "real tail", alternatives are:

Monday, January 4, 2010

Event Notification Framework with Spring Integration 2.0

Spring Integration is SpringSource's library for implementing Enterprise Integration Patterns in a Java application. I'm going to demonstrate how to use Spring Integration as an event notification framework.

I'll use the example in my previous article, Advanced Event Notification Framework with Apache Camel. In short, we're going to make a Sensor publish notification events to two Displays.

Fortunately, there is very minimal code change required to implement it using Spring Integration. My code was much more portable than I thought. ;-)

The complete application source can be downloaded/explored from: http://github.com/ceefour/eventfx.si

Tweaking Listener Interfaces


I had made a minor portability mistake before, annotating the listener interfaces with Camel-specific annotations. We can leave them out, as we can configure Spring Integration to work with POJO classes, without any annotations. (FYI, Apache Camel does too)

SyncListener.java becomes:

package com.soluvas.samples.eventfx.si;

import java.util.EventListener;

public interface SyncListener<E, R> extends EventListener {

 R update(E event);
}

AsyncListener.java becomes:

package com.soluvas.samples.eventfx.si;

import java.util.EventListener;

public interface AsyncListener<E> extends EventListener {

 void notify(E event);
}

Spring Context Configuration


The most major change is the Spring Context Configuration file.

<?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:si="http://www.springframework.org/schema/integration"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
  http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">

 <context:component-scan base-package="com.soluvas.samples.eventfx.si" />

 <bean class="com.soluvas.samples.eventfx.si.Sensor">
  <property name="sensorSyncListener">
   <si:gateway id="sensorSyncListener" service-interface="com.soluvas.samples.eventfx.si.SyncListener"
    default-request-channel="Sensor_SensorEvent_sync" />
  </property>
  <property name="sensorAsyncListener">
   <si:gateway id="sensorAsyncListener" service-interface="com.soluvas.samples.eventfx.si.AsyncListener"
    default-request-channel="Sensor_SensorEvent_async" />
  </property>
 </bean>
 <bean id="display1" class="com.soluvas.samples.eventfx.si.Display">
  <property name="name" value="Sony(sync)" />
 </bean>
 <bean id="display2" class="com.soluvas.samples.eventfx.si.Display">
  <property name="name" value="Samsung(async)" />
 </bean>
 
 <si:channel id="Sensor_SensorEvent_sync" />
 <si:publish-subscribe-channel id="Sensor_SensorEvent_async" />

 <si:service-activator input-channel="Sensor_SensorEvent_sync" ref="display1" method="update" />
 <si:chain input-channel="Sensor_SensorEvent_async">
  <si:delayer default-delay="1200" />
  <si:service-activator ref="display2" method="notify" />
 </si:chain>
 
</beans>

The differences between this Spring Integration version with the Apache Camel version are:
  1. CamelProxyFactoryBean's are replaced with si:gateway beans, which has a more concise syntax.
    Camel 2.2.0 will support similarly concise camel:proxy element that can be used outside camelContext element.
  2. Endpoint URIs are replaced with explicit declaration of Spring Integration Channel beans. Here I use direct channel (si:channel) for sync events and publish-subscribe channel (si:publish-subscribe-channel) for async events.
    I think the the explicit publish-subscribe channel in Spring Integration is very useful. In Apache Camel 2.1 and earlier, the only way to do this is to use multicast. In Apache Camel 2.2, the SEDA component will have a multipleConsumers option that provides a lightweight publish-subscribe mechanism (dynamic multicasting).
  3. I specify the "routing" to Display service-activators using the Spring XML DSL. Apache Camel's Spring DSL feels much more powerful.

The Main Application


The main application, App.java, can't get any simpler:

package com.soluvas.samples.eventfx.si;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
 public static void main(String[] args) {
  new ClassPathXmlApplicationContext("META-INF/spring/*.xml");
 }
}

I'm using Spring Integration 2.0 with Spring Framework 3.0 for this project. For those who are curious, here's the project's Maven pom.xml :

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.soluvas.samples</groupId>
 <artifactId>eventfx.si</artifactId>
 <packaging>jar</packaging>
 <version>0.0.1-SNAPSHOT</version>
 <name>eventfx.si</name>
 <url>http://maven.apache.org</url>
 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.integration</groupId>
   <artifactId>spring-integration-core</artifactId>
   <version>2.0.0.M2</version>
  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
 <repositories>
  <repository>
   <id>spring-milestone</id>
   <name>Spring Portfolio Milestone Repository</name>
   <url>http://s3.amazonaws.com/maven.springframework.org/milestone</url>
  </repository>
 </repositories>
</project>

Event Notification Framework with Spring Integration 2.0 in Action


The app now runs exactly same as the Camel Event Notification example. Here's the application output log:

Jan 5, 2010 3:00:19 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@12a54f9: startup date [Tue Jan 05 03:00:19 WIT 2010]; root of context hierarchy
Jan 5, 2010 3:00:19 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from file [/home/ceefour/Sandbox/eventfx.si/target/classes/META-INF/spring/eventfx-si.xml]
Jan 5, 2010 3:00:20 AM org.springframework.integration.config.xml.DefaultConfiguringBeanFactoryPostProcessor registerErrorChannelIfNecessary
INFO: No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
Jan 5, 2010 3:00:20 AM org.springframework.integration.config.xml.DefaultConfiguringBeanFactoryPostProcessor registerTaskSchedulerIfNecessary
INFO: No bean named 'taskScheduler' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created.
Jan 5, 2010 3:00:20 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2f0df1: defining beans [sensorSimulator,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.integration.internalDefaultConfiguringBeanFactoryPostProcessor,com.soluvas.samples.eventfx.si.Sensor#0,display1,display2,Sensor_SensorEvent_sync,Sensor_SensorEvent_async,org.springframework.integration.handler.ServiceActivatingHandler#0,org.springframework.integration.config.ConsumerEndpointFactoryBean#0,org.springframework.integration.handler.DelayHandler#e06940,org.springframework.integration.handler.ServiceActivatingHandler#1aae94f,org.springframework.integration.handler.MessageHandlerChain#0,org.springframework.integration.config.ConsumerEndpointFactoryBean#1,nullChannel,errorChannel,org.springframework.integration.handler.LoggingHandler#0,org.springframework.integration.endpoint.EventDrivenConsumer#0,org.springframework.integration.channel.MessagePublishingErrorHandler#0,taskScheduler]; root of factory hierarchy
Jan 5, 2010 3:00:21 AM org.springframework.scheduling.concurrent.ExecutorConfigurationSupport initialize
INFO: Initializing ExecutorService  'taskScheduler'
Jan 5, 2010 3:00:21 AM org.springframework.integration.endpoint.AbstractEndpoint start
INFO: started org.springframework.integration.gateway.SimpleMessagingGateway@1fe571f
Jan 5, 2010 3:00:21 AM org.springframework.integration.endpoint.AbstractEndpoint start
INFO: started si:gateway#1c5fde0
Jan 5, 2010 3:00:21 AM org.springframework.integration.endpoint.AbstractEndpoint start
INFO: started org.springframework.integration.gateway.SimpleMessagingGateway@cf710e
Jan 5, 2010 3:00:21 AM org.springframework.integration.endpoint.AbstractEndpoint start
INFO: started si:gateway#19e8329
Jan 5, 2010 3:00:21 AM com.soluvas.samples.eventfx.si.SensorSimulator initialize
INFO: Sensor simulator initialized.
Jan 5, 2010 3:00:21 AM com.soluvas.samples.eventfx.si.Display initialize
INFO: Display Sony(sync) created.
Jan 5, 2010 3:00:21 AM com.soluvas.samples.eventfx.si.Display initialize
INFO: Display Samsung(async) created.
Jan 5, 2010 3:00:21 AM org.springframework.scheduling.concurrent.ExecutorConfigurationSupport initialize
INFO: Initializing ExecutorService 
Jan 5, 2010 3:00:21 AM org.springframework.integration.endpoint.AbstractEndpoint start
INFO: started org.springframework.integration.config.ConsumerEndpointFactoryBean#0
Jan 5, 2010 3:00:21 AM org.springframework.integration.endpoint.AbstractEndpoint start
INFO: started org.springframework.integration.config.ConsumerEndpointFactoryBean#1
Jan 5, 2010 3:00:21 AM org.springframework.integration.endpoint.AbstractEndpoint start
INFO: started org.springframework.integration.endpoint.EventDrivenConsumer#0
Jan 5, 2010 3:00:23 AM com.soluvas.samples.eventfx.si.Sensor updateText
INFO: updateText: Something happens at 3:00:23 AM
Jan 5, 2010 3:00:23 AM com.soluvas.samples.eventfx.si.Display update
INFO: [Sony(sync)] is updated: 'Something happens at 3:00:23 AM'
Jan 5, 2010 3:00:23 AM com.soluvas.samples.eventfx.si.Sensor fireSensor
INFO: Response: Sony(sync) received Something happens at 3:00:23 AM
Jan 5, 2010 3:00:23 AM org.springframework.integration.endpoint.AbstractEndpoint start
INFO: started org.springframework.integration.endpoint.EventDrivenConsumer@1be2893
Jan 5, 2010 3:00:24 AM com.soluvas.samples.eventfx.si.Display notify
INFO: [Samsung(async)] is notified: 'Something happens at 3:00:23 AM'
Jan 5, 2010 3:00:25 AM com.soluvas.samples.eventfx.si.Sensor updateText
INFO: updateText: Something happens at 3:00:25 AM
Jan 5, 2010 3:00:25 AM com.soluvas.samples.eventfx.si.Display update
INFO: [Sony(sync)] is updated: 'Something happens at 3:00:25 AM'
Jan 5, 2010 3:00:25 AM com.soluvas.samples.eventfx.si.Sensor fireSensor
INFO: Response: Sony(sync) received Something happens at 3:00:25 AM

Which One Is More Powerful?


Technically speaking, I think Apache Camel is more powerful than Spring Integration. And this is not just a "feel", see the Spring XML above to see it for real.

For simpler purposes, both Apache Camel and Spring Integration do their job very well.

For more complex purposes, currently they have their own strengths and weaknesses.

Apache Camel allows you to refer to endpoints either by name ("ref") or by URI (though an endpoints must specify a URI), and creating an endpoint automatically just by referring to its URI. Spring Integration can only refer to a channel by name, and useful (i.e. non-direct) channels need to be created explicitly.

Apache Camel routes are extremely flexible, and can be specified in a variety of DSLs. With Spring Integration it's either basic routing or custom processing. Spring Integration has XML DSL and annotations, that Apache Camel also has.

Spring Integration's concept of publish-subscribe channel is more convenient than Apache Camel's.

Learning More on Enterprise Integration


Spring Integration is all about decoupling messaging between components, which is part of enterprise integration. If you want to learn more about enterprise integration, I heartily recommend the book Enterprise Integration Patterns.

Advanced Event Notification Framework with Apache Camel


Let's build an Event Notification Framework using Apache Camel... Second Edition.

I've demonstrated how to do event notification with Apache Camel before. But the classes were hard-coupled to Camel URI endpoints.

This time, I have these goals in mind:
  • Decoupled. The event source and listener(s) must be as decoupled as possible, but in a good way that it's not too complex.
  • As POJO as possible. Event sources, event classes, and event listeners need not import the event framework classes/interfaces. Annotations may be used.
See also: Event Notification with Spring Integration