Thursday, July 31, 2008

Flex/Flash Critcisms Addressed

In this blog entry, I intend to outline some of the most common criticisms and concerns regarding Flex that I hear or read from other developers. Because Flex necessarily compiles to Flash, any Flash criticisms or disadvantages are also Flex criticisms or disadvantages.

I will first list some of the most common criticisms and disadvantages correctly or incorrectly associated with Flex (and Flash) and then provide brief detail on things that address these issues. I welcome feedback in the comments section on any criticisms or disadvantages that I have missed and any events or methods that reduce the disadvantage or criticism.

Commonly Cited Flex/Flash Criticisms and Disadvantages
1. License Costs
2. Not Open Source
3. Perception: For Movies and Animation Only
4. Application Load Time
5. Development/Productivity Tools
6. Flash Player Dependence
7. No 64-bit Flash Player
8. No URLs, Histories, or Bookmarks
9. Searchability / Search Engine Optimization
10. Adobe Commitment to Flex
11. Flash Player is Single Threaded
12. Flex is Not a Standard

1. License Costs

For a long-time, one of the most significant criticisms of Flex that prevented developers from adopting it was its licensing costs. In fact, in his now well-known article Hybridizing Java, Bruce Eckel (a well-known Flex evangelist featured in Adobe advertisements for a while) even states that Flex's former licensing costs affected how much he used and wrote about Flex. This movement started with Flex being released for free use outside of commercial products and then moved to a fully free Flex SDK. I still occasionally see developers stating in blogs or on comments on blogs that they won't use Flex because of its licensing costs, but for much of Flex this is simply not the case anymore. There are some "extra" Flex features that still do require license fees for commercial use, but Flex applications can be written without these.


2. Not Open Source

While there are advantages to a product, library, or framework being open source, calling something open source does not necessarily make it better than competing alternatives (witness all the dead open source projects out there) and does not necessarily make it free of cost (free speech versus free beer). Still, there are a growing number of developers who desire "open source" as one of the most significant characteristics of the products and frameworks they choose. For them and even for those of us who prefer open source when it is competitive in other aspects as well, it was good news when Adobe announced the open sourcing of Flex. Major components of Flex 3 (SDK, debugger, etc.) were released as open source. Shortly before Flex 3's release, Adobe also released BlazeDS (especially useful for Flex-to-Java communication) as open source.

There are optional portions of Flex that are still not open source and/or still require licensing fees, but these are not necessary to create fully functioning Flex-based applications.


3. Perception: For Movies and Animation Only

With the issues of licensing costs and not being open source mostly resolved, a common concern (or really more of a question) that I hear from many developers is something along the lines of, "Isn't Flash really only for games, movies, and animation?" and "Can you create an HTML-like web form with Flash?" The answer is that Flex really is "Flash brought to the Java (or other programming language) developer." By this, I mean that the Flash applications many people are familiar with are more likely designed by a specific Adobe product by designers rather than by developers or programmers. Flex provides a rich component set out-of-the-box with the free and open source SDK, adds a couple more components with the for-a-fee FlexBuilder, and there are numerous third-party Flex components sprouting up all over the web. These components include many HTML-like components along with many richer components that rival or even exceed the component sets provided by the many fine JavaScript libraries. If one wants to, one can make a Flex-based application look nearly identical to any HTML/JavaScript application. However, Flex is usually desired for "richer" applications and hence is often used with Rich Internet Applications rather than more traditional HTML/web applications.


4. Application Load Time

As part of the RIA experience, Flex-based applications tend to load more than DHTML applications initially, but then often have reduced reloading and server communication after the initial load. However, this means that a Flex-based RIA can often take longer to load initially than a DHTML-based RIA.

Adobe continues to work on improving the performance of the Flash Player to reduce this disadvantage. The relatively recent announcement of the new Flash Player Caching is very welcome in this area.

There are several tactics Flex developers can take as well to reduce the initial load time. For example, the Flex TabNavigator has a creationPolicy attribute that allows all tabs in the navigator to be loaded at load time (ContainerCreationPolicy.ALL) or have only the initially visible tab loaded (deferred instantiation with ContainerCreationPolicy.AUTO).

Links to other ideas for improved Flex performance are available in the article Flex RIA Performance Considerations Part 1: Getting Started. Part 2 in this same series focuses on application startup.


5. Development/Productivity Tools

Another early criticism of Flex was the lack of IDE and tooling support that Java enjoys. This, of course, is just as deserved and just as common complaint for many other highly useful languages as well. However, Adobe has released FlexBuilder, an Eclipse-based Flex IDE. While Adobe does charge a licensing fee for FlexBuilder and while FlexBuilder (like most IDEs) does have room for improvement, it is also true that FlexBuilder comes with many nice features for making Flex development more productive. Because it is Eclipse-based, it is fairly easy for Java developers familiar with Eclipse to learn and use.

The author of the entry Flex 3 Vs Silverlight and JavaFX - Is Adobe Listening? maintains that Flex "may die on the vine" because it charges for FlexBuilder. As outlined above, the making Flex itself available for free did undoubtedly help increase its adoption, but the cost difference is significant. Flex formerly had license fees costing thousands of dollars while FlexBuilder fees are measured in hundreds of dollars. Still, many IDE vendors do offer free IDEs already (Eclipse, NetBeans, and JDeveloper for example). While I agree the licensing fee required for FlexBuilder must have some impact on Flex's adoption rate, I'm not convinced that it has been or will be as great on the long-term adopters of Flex as maintained in this entry.

For those who don't want to purchase FlexBuilder, there are some alternatives. Because both MXML and ActionScript are text-based, even a simple text editor will work at a minimum level of functionality. Because Flex MXML is an XML grammar, any XML-aware tool can be used to provide some advantages to working with MXML. For example, I have blogged previously about using NetBeans XML support and JEdit's XML support with Flex. One can go even beyond simple XML handling with more specific editors like Spket IDE and Aptana.


6. Flash Player Dependence

Some developers have had such negative experiences with Flash-based applications that they have a hard time even considering Flash (and hence Flex) for their web applications. There are many reasons for this resistance to the Flash Player, including wanting to avoid a proprietary runtime and not liking Flash application experiences in others' applications. The latter point can be partially addressed by considering that just because someone else abuses a language or framework doesn't many I need to. If that was the case, no language or framework would be acceptable because they all get abused by someone.

Related to the proprietary nature of Flash, there are some mitigating conditions to consider. The OpenScreen Project was huge news for Flash running on devices because it is intended to remove restrictions on two major Flash-related specifications (SWF and FLV/F4V) and to remove license fees for both AIR and Flash Player. Another interesting development occurred when Adobe and Mozilla partnered in the Tamarin Project to include the ActionScript Virtual Machine (AVM).


7. No 64-bit Flash Player

While the Flash Player is nearly universally available in 32-bit architectures, it is not available for 64-bit architectures. This has been a particularly loud complaint from Linux users, though Microsoft Vista developers are starting to request a 64-bit Flash Player more actively as well.

This concern can be partially addressed by running the 32-bit Flash Player on the platform, such as on a 32-bit browser running on the platform. In Flash 9 on 64-bit Linux in 2 Commands, James Ward covers how to use the Flash Player on 64-bit Linux. Likewise, Darron Schall has written about running Flash Player on 64-bit Linux platform in Installing Flash Player 9 on 64-bit Linux. Interestingly, James Ward points out in Where is 64-bit Linux Support for Flash Player? that one of the major hold-ups on a 64-bit Linux Flash Player is the need to upgrade the Tamarin project discussed briefly in the criticism above.

UPDATE (24 November 2008): Adobe has announced the release of an alpha version of Flash Player 10 for 64-bit Linux. An excellent review of life in Linux without this release is available in Adobe Starts 64-bit Flash Testing with Linux Alpha. The excitement in the Linux community over this is documented in One More Reason for Linux Lovers to Give Thanks.


8. No URLs, Histories, or Bookmarks

A common complaint about Flex-based RIAs that is really common to even many Ajax-based RIAs is the inability or difficultly involved in letting web users use meaningful URLs in histories and bookmarks. This was easy and expected in static web pages and even in more dynamic web sites that completely reloaded the page after each server request. With Ajax and Flash-based RIAs, these things are not quite so easy now. Just as many of the Ajax/DHTML frameworks have begun to provide support to ease the developer's ability to allow users to use URLs for bookmarking and histories, similar approaches have sprung up for Flex. However, the really good news was Flex 3's support for BrowserManager and deep linking. Approaches of use in this area (including the Flex 3 BrowserManager to perform deep linking) are covered in Flex 3 Features: Deep Linking in Flex 3, Flex 3 BrowserManager, and Flex 2 Applications and Bookmarking 101. Deep linking only works on select browsers (the most significantly used ones though) and takes a little extra effort, but does provide benefits associated with changing URLs in a web application.


9. Searchability / Search Engine Optimization

Another commonly discussed disadvantage of the Flash Player is the inability of search engines to index the binary content of a Flash application. A command work-around has been to developer HTML "wrapper" pages for the SWF applications that includes terms that the search engines can find. This tried and proven method works, but there are even more advancements coming. Google, Yahoo!, and Adobe have announced their combined effort to better index the text content in Flash applications. Considering the dominance of Google and Yahoo! in the search engine business, this is a big deal. In addition, it sounds like this approach will be made available to other search engines in the future if it works out well.


10. Adobe Commitment to Flex

Some of have questioned Adobe's commitment to Flex, especially in light of Adobe's early interest in SVG (Scalable Vector Graphics) followed by seemingly significantly reduced interest in SVG. While I don't work for Adobe and have no knowledge of what they may or may not do, I don't worry much about this particular criticism because Adobe's products still continue to support SVG to a large degree. More importantly, however, it appears to me as an outsider that Adobe has placed significantly more emphasis, time, and resources into Flex. Also, it is only anecdotal observations, but it seems to me that Flex is gaining popularity much more rapidly than SVG did. This is not too surprising because, as much as I like SVG, Flex is in many ways appealing to a wider audience of developers than SVG. The fact that Microsoft and Sun are trying to match Flex with their Silverlight and JavaFX products respectively demonstrates to me that all three of these major players believe there is a future in the RIA application development business.

For a series of articles spelling out obstacles and competitive forces that Adobe faces with Flex, see the three-part series Flash Wars.


11. Flash Player is Single Threaded

I won't write much about this here because Matthew Fabb's blog entry Multi-threading is Coming (Sort of) to Flash Player 10 does such a great job of articulating (based on his attendance at Jim Corbett's Flash Player Internals presentation at FITC) the issue and good news in that area. He describes how Flash's single-threaded architecture can be a limitation in Flash-based (and hence Flex-based) applications and how Flash Player 10 will be providing some multi-threading support.


12. Flex is Not a Standard

I saved the common criticism that I think is most overblown for last. Flex is based on the W3C standard XML specification (for Flex's MXML) and the envisioned ECMAScript standard [ECMA-262 Edition 4] (for Flex's ActionScript 3.0), including support for E4X (ECMAScript for XML).

While DHTML/Ajax can be argued to be based on standards [(X)HTML, CSS, JavaScript or JScript (ECMAScript implementations)], practical implementations are seldom if ever truly completely specification compliant because the most popular web browser does not allow them to be! The respective browser DOMs are a huge source of differences. I have stated before that standards and specifications are only as good as their implementations. As long as the dominant web browser requires developers to write non-standard code, it is difficult for me to understand how Flex with its standards-based MXML and ActionScript is so much less standard than writing DHTML/Ajax implementations. In fact, the heart of many Ajax applications is XMLHttpRequest, which itself has not been a standard (though it is now in-work at the W3C).


It Doesn't Need to Be One or the Other

Before concluding, I think it is important to point out that there is no need to necessarily use Flex/Flash instead of DHTML/Ajax or to use DHTML/Ajax instead of Flex/Flash. They both actually complement one another nicely and provide benefits to each other. An example is the discussion above about putting text in HTML wrappers of Flash applications for searchability benefits. On the other side, Flash can provide much easier approaches to rich interaction than via JavaScript. The combination of Flex and DHTML is so powerful and expected to be so popular that Flex 3 folded in the Flex-Ajax Bridge into the standard Flex SDK.


Conclusion and Request for Feedback

In this blog entry, I've attempted to outline common criticisms and cited disadvantages of Flex (and Flash). Some of these were valid but have been overcome by events. Others are still valid, but most of them have been at least partially addressed with modern advances in Flex and Flash. I like forward to additional concerns being addressed in future releases of Flex and Flash.

I also encourage you to add any other drawbacks or criticism you have from using Flex and Flash in the feedback section along with any approaches you may have used to overcome one of the drawbacks listed here or in the feedback section. Thanks in advance for your input.


Other Resources with Flex/Flash Criticisms

* Flex 3 Versus Silverlight and JavaFX: Is Adobe Listening? [FlexBuilder not free] (24 July 2008)

* Flash Wars: Adobe Fights for AIR with Open Screen Project [Part 3 of 3] (7 May 2008)

* Flash Wars: The Many Enemies and Obstacles of Flash [Part 2 of 3] (6 May 2008)

* Flash Wars: Adobe in the History and Future of Flash [Part 1 of 3] (5 May 2008)

* Flex Versus Ajax (9 July 2006)

* Why Flex 2 Isn't (8 March 2006)

* A Look at Rich Internet Applications (July/August 2004)

* Is Flash Good or Bad?

Saturday, July 26, 2008

JMX Model MBeans with Apache Commons Modeler

In previous blog entries, I demonstrated coding Model MBeans directly (“in the raw”) and using the Spring Framework. In both cases, two primary advantages of Model MBeans (highly descriptive nature and ability to present non-JMX objects as managed JMX resources) were realized. While writing the Java code to construct Model MBean metadata information is not difficult, it is tedious. The Spring Framework significantly eases this effort, but requires a dependency on Spring if the full descriptive nature of the Model MBean is to be realized via Spring’s JMX metadata annotations. For those who want rich descriptions of their Model MBeans, who want to reduce the Java code required to implement Model MBean metadata, and cannot or do not want a Spring dependency, the Apache Commons Modeler may be the appropriate answer.

As its name implies, the Apache Commons Modeler is part of the highly useful and varied Apache Commons project. For this blog entry, I am using Modeler 2.0.1. The Modeler 2.0.1 download includes a JAR file (commons-modeler-2.0.1.jar) and the XML DTD for Modeler XML metadata configuration files (mbeans-descriptors.dtd). The contents of this DTD can be viewed without downloading Modeler at the URL http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd.

I’ll be demonstrating how to register the same SimpleCalculator class as a Model MBean that was used in the previous blog entries with direct Model MBean creation and Spring-based Model MBean creation. For convenience, the SimpleCalculator class is reproduced here.

SimpleCalculator.java

package dustin.jmx.modelmbeans;

/**
* Simple calculator class intended to demonstrate how a class with no knowledge
* of JMX or management can be "wrapped" with ModelMBeans.
*
* @author Dustin
*/
public class SimpleCalculator implements SimpleCalculatorIf
{
/**
* Calculate the sum of the augend and the addend.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @return Sum of augend and addend.
*/
public int add(final int augend, final int addend)
{
return augend + addend;
}

/**
* Calculate the difference between the minuend and subtrahend.
*
* @param minuend Minuend in subtraction operation.
* @param subtrahend Subtrahend in subtraction operation.
* @return Difference of minuend and subtrahend.
*/
public int subtract(final int minuend, final int subtrahend)
{
return minuend - subtrahend;
}

/**
* Calculate the product of the two provided factors.
*
* @param factor1 First integer factor.
* @param factor2 Second integer factor.
* @return Product of provided factors.
*/
public int multiply(final int factor1, final int factor2)
{
return factor1 * factor2;
}

/**
* Calculate the quotient of the dividend divided by the divisor.
*
* @param dividend Integer dividend.
* @param divisor Integer divisor.
* @return Quotient of dividend divided by divisor.
*/
public double divide(final int dividend, final int divisor)
{
return dividend / divisor;
}
}


When using Apache Commons Modeler, most of the work is done in an XML metadata configuration file conforming to the DTD specified above. For this example, that XML file is shown next. The XML element and attribute names are largely self-explanatory and additional information on these can be found within the DTD definition at http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd.

simple-calculator-modeler.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mbeans-descriptors PUBLIC
"-//Apache Software Foundation//DTD Model MBeans Configuration File"
"http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
<mbeans-descriptors>
<mbean id="managedSimpleCalculatorBean"
name="ManagedSimpleCalculatorBean"
description="Applying JMX Model MBean with Apache Commons Modeler"
type="dustin.jmx.modelmbeans.SimpleCalculator">

<descriptor>
<field id="nameField" name="name" value="ModelMBeanInCommonsModeler" />
<field id="descriptorTypeField" name="descriptorType" value="mbean" />
</descriptor>

<operation id="addOperation"
name="add"
description="Integer Addition"
impact="INFO"
returnType="int">
<parameter id="augendParameter"
name="augend"
description="The first parameter in the addition (augend)."
type="int" />
<parameter id="addendParameter"
name="addend"
description="The second parameter in the addition (addend)."
type="int" />
</operation>

<operation id="subtractOperation"
name="subtract"
description="Integer Subtraction"
impact="INFO"
returnType="int">
<parameter id="minuendParameter"
name="minuend"
description="The first parameter in the substraction (minuend)."
type="int" />
<parameter id="subtrahendParameter"
name="subtrahend"
description="The second parameter in the subtraction (subtrahend)."
type="int" />
</operation>

<operation id="multiplyOperation"
name="multiply"
description="Integer Multiplication"
impact="INFO"
returnType="int">
<parameter id="factor1Parameter"
name="factor1"
description="The first factor in the multiplication."
type="int" />
<parameter id="factor2Parameter"
name="factor2"
description="The second factor in the multiplication."
type="int" />
</operation>

<operation id="divideOperation"
name="divide"
description="Integer Division"
impact="INFO"
returnType="double">
<parameter id="dividendParameter"
name="dividend"
description="The dividend in the division."
type="int" />
<parameter id="divisorParameter"
name="divisor"
description="The divisor in the division."
type="int" />
</operation>

</mbean>
</mbeans-descriptors>


My SimpleCalculator-based JMX Model MBeans examples (direct, Spring-based, and now Commons Modeler-based) have all focused on specifying MBean operations and their parameters. To see how to specify other portions of a Model MBean with Commons Modeler, see the "Modeler" section of the article Using Jakarta Commons, Part 2. Note that there have been a few changes since that article was written. The promotion of the Commons project from a sub-project of Apache Jakarta to its own Apache Commons project brought the name change and is a relatively minor change. However, several changes to the API have led to some of the methods used in previous examples being deprecated.

The next class is the main class that reads in the XML metadata configuration file and uses Modeler to register an MBean with the descriptive information provided in the XML file shown earlier. Note that this code explicitly looks up the XML file by name. I could have had Modeler pick up the metadata configuration implicitly by appropriately naming the XML file and including it in the same package as the code, but I chose to use the explicit loading for this example.


package dustin.jmx.modelmbeans;

import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import org.apache.commons.modeler.Registry;

/**
* The purpose of this class is to demonstrate use of ModelMBeans with Apache
* Commons Modeler.
*/
public class CommonsModelMBeanDemonstrator
{
/**
* Main functionality for using Modeler XML metadata to instantiate and
* register a Model MBean with the Platform MBean Server.
*/
public void applyCommonsModeler()
{
final String modelerMetadataFile = "simple-calculator-modeler.xml";
final SimpleCalculator calculator = new SimpleCalculator();
Registry registry = null;
final InputStream modelerXmlInputStream =
CommonsModelMBeanDemonstrator.class.getResourceAsStream(
modelerMetadataFile);

// Use getRegistry(Object,Object) rather than deprecated getRegistry()
registry = Registry.getRegistry(null, null);

// Use instance setMBeanServer method rather than class/static setServer
registry.setMBeanServer(ManagementFactory.getPlatformMBeanServer());
try
{
// The following two methods on Registry (loadMetadata and
// registerComponent) throw the checked and very general Exception,
// which must be captured here..
registry.loadMetadata(modelerXmlInputStream);
registry.registerComponent(
calculator,
"modelmbean:type=commons-modeler", // mbean registered object name
"dustin.jmx.modelmbeans.SimpleCalculator");
}
catch (IOException ioEx)
{
System.err.println(
"ERROR trying to load metadata into Commons Modeler Registry "
+ "from configuration file " + modelerMetadataFile + ":\n"
+ ioEx.getMessage() );
}
catch (Exception ex)
{
System.err.print( "ERROR trying to access metadata file "
+ modelerMetadataFile + ":\n" + ex.getMessage() );
}
}

/**
* Pause for the specified number of milliseconds.
*
* @param millisecondsToPause Milliseconds to pause execution.
*/
public static void pause(final int millisecondsToPause)
{
try
{
Thread.sleep(millisecondsToPause);
}
catch (InterruptedException threadAwakened)
{
System.err.println("Don't wake me up!\n" + threadAwakened.getMessage());
}
}

/**
* Main driver to demonstrate Apache Commons Modeler used with JMX
* Model MBeans.
*
* @param arguments Command-line arguments.
*/
public static void main(final String[] arguments)
{
CommonsModelMBeanDemonstrator me = new CommonsModelMBeanDemonstrator();
me.applyCommonsModeler();
pause(1000000);
}
}


The following three screen snapshots demonstrate how the results look in JConsole.







As the above example has demonstrated, Apache Commons Modeler allows JMX Model MBean metadata to be shifted from hard-coded Java into external XML configuration files. Whether this is an advantage or not is dependent on the situation and developer preferences (some prefer Java coding over XML even for configuration like this). However, it is nice to have an alternative available for those who prefer their Model MBean metadata to be externally configurable.

ADDITIONAL REFERENCES

For additional information on Apache Commons Modeler, see the project’s home page and the previously referenced article Using Jakarta Commons, Part 2. One of the most useful resources for learning to apply Apache Commons Modeler is the Javadoc API documentation for the package org.apache.commons.modeler. This Javadoc-generated documentation is included with the Modeler download and the description for package org.apache.commons.modeler is highly useful in explaining how to use Modeler. Among other interesting pointers, this description specifies how to have Modeler XML configuration found implicitly, how to use manual Java MBean metadata application rather than XML configuration, and which methods of the Modeler API are now preferred and which are now deprecated ("strongly" in some cases).

JMX Model MBeans with Spring Framework

In the creatively named blog entry The JMX Model MBean, I demonstrated with a simple example how the JMX Model MBean enables greater descriptive ability than is available with other JMX MBean types. The simple example also demonstrated that a Model MBean can be applied to an existing class with no knowledge of JMX and without any awareness that it is being exposed via a JMX management and monitoring interface. The one major drawback of Model MBeans that even this simple example demonstrated is the tedious and verbose code needed to build a Model MBean without aid of other tools or frameworks.

In that blog entry, I called out some approaches that can aid in the development of Model MBeans. These include Spring Framework’s JMX support, The Apache Commons Modeler approach, JBoss’s XMBeans, and the use of reflection. In this current blog entry, I will delve into Spring Framework’s support for Model MBeans in greater detail and demonstrate how easy Spring makes it to apply JMX Model MBeans.

By default, Spring’s support for JMX relies upon Model MBeans (though the developer has no need to deal with Model MBeans directly). The reason for this seems clear – the Model MBean allows normal Java classes with no JMX knowledge or awareness to be exposed via a JMX interface. This approach fits Spring’s behavior in other areas. In other words, it seems to be "the Spring way" to use plain Java classes with little or no knowledge of their surroundings and then "wire" them up to their surroundings via external configuration. In this blog entry, I’ll demonstrate how Spring enables Java classes with absolutely no Spring or JMX awareness to be exposed via a JMX interface and how just a little tinkering with the plain Java class via annotations enables the full descriptive power of Model MBeans to be deployed.

Although the JMX Specification (Chapter 4) talks about other potentially useful features of the Model MBean (such as persistence described in section 4.3.4), the two options of the ModelMBean that I most often take advantage of are the Model MBean’s descriptive support and the ability of the Model MBean to expose a non-JMX class in a JMX agent. In Spring, it is almost trivial to obtain this first benefit and expose a class with no awareness of JMX (or even of Spring) as a manageable and monitorable resource. In fact, the "code" needed to do this lies completely in Spring configuration. The following Java code listing contains the class (SimpleCalculator) that has no JMX awareness, but will be exposed via Spring as JMX-accessible. The XML code listing following SimpleCalculator.java shows how Spring is instructed to expose SimpleCalculator as a JMX-accessible resource.

SimpleCalculator.java


package dustin.jmx.modelmbeans;

/**
* Simple calculator class intended to demonstrate how a class with no knowledge
* of JMX or management can be "wrapped" with ModelMBeans.
*
* @author Dustin
*/
public class SimpleCalculator implements SimpleCalculatorIf
{
/**
* Calculate the sum of the augend and the addend.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @return Sum of augend and addend.
*/
public int add(final int augend, final int addend)
{
return augend + addend;
}

/**
* Calculate the difference between the minuend and subtrahend.
*
* @param minuend Minuend in subtraction operation.
* @param subtrahend Subtrahend in subtraction operation.
* @return Difference of minuend and subtrahend.
*/
public int subtract(final int minuend, final int subtrahend)
{
return minuend - subtrahend;
}

/**
* Calculate the product of the two provided factors.
*
* @param factor1 First integer factor.
* @param factor2 Second integer factor.
* @return Product of provided factors.
*/
public int multiply(final int factor1, final int factor2)
{
return factor1 * factor2;
}

/**
* Calculate the quotient of the dividend divided by the divisor.
*
* @param dividend Integer dividend.
* @param divisor Integer divisor.
* @return Quotient of dividend divided by divisor.
*/
public double divide(final int dividend, final int divisor)
{
return dividend / divisor;
}
}


spring-mbean-simple-context.xml


<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="exposedModelMBean"
class="dustin.jmx.modelmbeans.SimpleCalculator" />

<util:map id="exposedMBeans">
<entry key="modelmbean:type=spring-simple" value-ref="exposedModelMBean" />
</util:map>

<bean class="org.springframework.jmx.export.MBeanExporter"
p:beans-ref="exposedMBeans"
p:assembler-ref="assembler" />

<util:list id="manageableInterfaces">
<value>dustin.jmx.modelmbeans.SimpleCalculatorIf</value>
</util:list>

<bean id="assembler"
class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler"
p:managedInterfaces-ref="manageableInterfaces" />

</beans>



The SimpleCalculator class shown above is essentially the same class used in my previous blog entry on Model MBeans done without benefit of Spring. This is far less code than needed in my example of employing Model MBeans without the Spring Framework, but the one disadvantage is that the greater descriptive ability of the Model MBean is not enjoyed in this simple example. This is demonstrated in the following three screen snapshots of JConsole viewing this simple Spring-exposed Model MBean.








The Spring Framework provides a mechanism to provide greater descriptive information to our Spring-exposed Model MBeans. This is done via Spring-specific annotations. The downside of this approach is that the otherwise JMX-unaware and Spring-unaware classes now dependent on Spring-specific JMX-related annotations. However, the benefit of this is great descriptive ability with relative coding ease. The next code listing shows the adapted SimpleCalculatorAnnotated class that is the same class as SimpleCalculator, but with the Spring JMX annotations. The XML needed to configure this class to be exposed via Spring is then shown as well.

SpringCalculatorAnnotated.java


package dustin.jmx.modelmbeans;

import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;

/**
* Simple calculator class annotated with Spring JMX annotations to demonstrate
* using Spring JMX metadata approach. This class uses J2SE 5 annotations, but
* Spring also supports use of Apache Commons Attributes for metadata specification.
*
* @author Dustin
*/
@ManagedResource(
objectName="modelmbean:type=spring-annotated",
description="A simple integer calculator." )
public class SimpleCalculatorAnnotated implements SimpleCalculatorIf
{
/**
* Calculate the sum of the augend and the addend.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @return Sum of augend and addend.
*/
@ManagedOperation(description="Integer Addition")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="augend",
description="The first parameter in the addition (augend)."),
@ManagedOperationParameter(
name="addend",
description="The second parameter in the addition (addend).")})
public int add(final int augend, final int addend)
{
return augend + addend;
}

/**
* Calculate the difference between the minuend and subtrahend.
*
* @param minuend Minuend in subtraction operation.
* @param subtrahend Subtrahend in subtraction operation.
* @return Difference of minuend and subtrahend.
*/
@ManagedOperation(description="Integer Subtraction")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="minuend",
description="The first parameter in the substraction (minuend)."),
@ManagedOperationParameter(
name="subtrahend",
description="The second parameter in the subtraction (subtrahend).")})
public int subtract(final int minuend, final int subtrahend)
{
return minuend - subtrahend;
}

/**
* Calculate the product of the two provided factors.
*
* @param factor1 First integer factor.
* @param factor2 Second integer factor.
* @return Product of provided factors.
*/
@ManagedOperation(description="Integer Multiplication")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="factor1",
description="The first factor in the multiplication."),
@ManagedOperationParameter(
name="factor2",
description="The second factor in the multiplication.")})
public int multiply(final int factor1, final int factor2)
{
return factor1 * factor2;
}

/**
* Calculate the quotient of the dividend divided by the divisor.
*
* @param dividend Integer dividend.
* @param divisor Integer divisor.
* @return Quotient of dividend divided by divisor.
*/
@ManagedOperation(description="Integer Division")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="dividend",
description="The dividend in the division."),
@ManagedOperationParameter(
name="divisor",
description="The divisor in the division.")})
public double divide(final int dividend, final int divisor)
{
return dividend / divisor;
}
}


spring-mbean-metadata-context.xml


<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="exposedModelMBean"
class="dustin.jmx.modelmbeans.SimpleCalculatorAnnotated" />

<bean id="exporter"
class="org.springframework.jmx.export.MBeanExporter"
p:autodetect="true"
p:assembler-ref="assembler"
p:namingStrategy-ref="namingStrategy" />

<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.MetadataNamingStrategy"
p:attributeSource-ref="attributeSource" />

<bean id="attributeSource"
class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />

<bean id="assembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler"
p:attributeSource-ref="attributeSource" />

</beans>


The next three screen snapshots show via screen captures of JConsole how the Spring annotations have allowed the annotated class to provide greater descriptive details to the JMX client. The annotations are far less verbose and are arguably easier to write and maintain than the code I showed in the Model MBean blog entry in which I did not use Spring.







If it is overly burdensome or undesirable to add these annotations to the source class, one can "wrap" the source class with a class that has these annotations. An example of this is shown next. The SimpleCalculatorWrapper class "wraps" the SimpleCalculator class. In this approach, SimpleCalculatorWrapper must know about Spring and Spring’s JMX annotations, but the original SimpleCalculator does not need to be specific to Spring or to JMX.

SimpleCalculatorWrapper


package dustin.jmx.modelmbeans;

import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;

/**
* "Wraps" a SimpleCalculator class so that this wrapper class can be annotated
* with Spring JMX annotations rather than needing to modify the business logic
* Simple Calculator class.
*/
@ManagedResource(
objectName="modelmbean:type=spring-wrapper",
description="A simple integer calculator." )
public class SimpleCalculatorWrapper implements SimpleCalculatorIf
{
private SimpleCalculator simpleCalculator;

/**
* Setter method to set the object that I "wrap."
*
* @param calculator SimpleCalculator that I should wrap.
*/
public void setWrappedObject(final SimpleCalculator calculator)
{
this.simpleCalculator = calculator;
}

/**
* Calculate the sum of the augend and the addend.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @return Sum of augend and addend.
*/
@ManagedOperation(description="Integer Addition")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="augend",
description="The first parameter in the addition (augend)."),
@ManagedOperationParameter(
name="addend",
description="The second parameter in the addition (addend).")})
public int add(int augend, int addend)
{
return simpleCalculator.add(augend, addend);
}

/**
* Calculate the difference between the minuend and subtrahend.
*
* @param minuend Minuend in subtraction operation.
* @param subtrahend Subtrahend in subtraction operation.
* @return Difference of minuend and subtrahend.
*/
@ManagedOperation(description="Integer Subtraction")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="minuend",
description="The first parameter in the substraction (minuend)."),
@ManagedOperationParameter(
name="subtrahend",
description="The second parameter in the subtraction (subtrahend).")})
public int subtract(int minuend, int subtrahend)
{
return simpleCalculator.subtract(minuend, subtrahend);
}

/**
* Calculate the product of the two provided factors.
*
* @param factor1 First integer factor.
* @param factor2 Second integer factor.
* @return Product of provided factors.
*/
@ManagedOperation(description="Integer Multiplication")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="factor1",
description="The first factor in the multiplication."),
@ManagedOperationParameter(
name="factor2",
description="The second factor in the multiplication.")})
public int multiply(int factor1, int factor2)
{
return simpleCalculator.multiply(factor1, factor2);
}

/**
* Calculate the quotient of the dividend divided by the divisor.
*
* @param dividend Integer dividend.
* @param divisor Integer divisor.
* @return Quotient of dividend divided by divisor.
*/
@ManagedOperation(description="Integer Division")
@ManagedOperationParameters({
@ManagedOperationParameter(
name="dividend",
description="The dividend in the division."),
@ManagedOperationParameter(
name="divisor",
description="The divisor in the division.")})
public double divide(int dividend, int divisor)
{
return simpleCalculator.divide(dividend, divisor);
}
}


spring-mbean-wrapper-context.xml

<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="wrappedClass"
class="dustin.jmx.modelmbeans.SimpleCalculator" />

<bean id="exposedModelMBean"
class="dustin.jmx.modelmbeans.SimpleCalculatorWrapper"
p:wrappedObject-ref="wrappedClass" />

<bean id="exporter"
class="org.springframework.jmx.export.MBeanExporter"
p:autodetect="true"
p:assembler-ref="assembler"
p:namingStrategy-ref="namingStrategy" />

<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.MetadataNamingStrategy"
p:attributeSource-ref="attributeSource" />

<bean id="attributeSource"
class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />

<bean id="assembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler"
p:attributeSource-ref="attributeSource" />

</beans>


I won’t show the JConsole view of the wrapper because it appears nearly the same as what was shown for the directly annotated class. The only difference is that the original SimpleCalculator is left untouched by Spring-specific JMX annotations because the wrapper class shields these details from the SimpleCalculator class.

In the annotations examples above, I used the standard Java SE type annotations to provide the JMX Model MBean metadata. Spring also supports using Apache Commons Attributes for this. The Spring approach of specifying JMX ModelMBean metadata via annotations has proven so popular that it now sounds like JMX 2 is very likely to include similar, or at least Spring-inspired, annotation support. The obvious benefit of this would be the ability to enjoy highly descriptive Model MBeans without all the code even when not using Spring.

For completeness, I am including the main Java class that instantiated my three Spring-related examples above: SimpleCalculator without annotations, SimpleCalculator with annotations, and a "wrapped" SimpleCalculator.


package dustin.jmx.modelmbeans;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


/**
* The purpose of this class is to demonstrate use of ModelMBeans with Spring.
*/
public class SpringModelMBeanDemonstrator
{
/**
* Pause for the specified number of milliseconds.
*
* @param millisecondsToPause Milliseconds to pause execution.
*/
public static void pause(final int millisecondsToPause)
{
try
{
Thread.sleep(millisecondsToPause);
}
catch (InterruptedException threadAwakened)
{
System.err.println("Don't wake me up!\n" + threadAwakened.getMessage());
}
}

public static void main(final String[] arguments)
{
String option;
if ( arguments.length < 1 )
{
option = "simple";
}
else
{
option = arguments[0].toLowerCase();
}

ApplicationContext context;
// assume simple example unless metadata or wrapper explicitly requested
if ( option.equalsIgnoreCase("wrapper") )
{
System.out.println("Spring Wrapper Approach");
context = new ClassPathXmlApplicationContext(
"/dustin/jmx/modelmbeans/spring-mbean-wrapper-context.xml");
}
else if ( option.equalsIgnoreCase("metadata")) // metadata example
{
System.out.println("Spring Metadata Approach");
context = new ClassPathXmlApplicationContext(
"/dustin/jmx/modelmbeans/spring-mbean-metadata-context.xml");
}
else // use simple if neither wrapper nor metadata specified
{
System.out.println("Spring Interface Approach");
context = new ClassPathXmlApplicationContext(
"/dustin/jmx/modelmbeans/spring-mbean-simple-context.xml");
}

final SimpleCalculatorIf calculator =
(SimpleCalculatorIf) context.getBean("exposedModelMBean");
pause(1000000);
}
}


I also added an interface, SimpleCalculatorIf, to these examples to make them easily accessible via the same code for any of the three approaches covered in this blog entry. That simple interface listing is shown next.

SimpleCalculatorIf.java

package dustin.jmx.modelmbeans;

/**
* Interface to expose Model MBean via Spring.
*/
public interface SimpleCalculatorIf
{
public int add(final int augend, final int addend);

public int subtract(final int minuend, final int subtrahend);

public int multiply(final int factor1, final int factor2);

public double divide(final int dividend, final int divisor);
}


Spring makes use of JMX easier in general. Because Spring uses Model MBeans anyway for its JMX support, it is easy to apply the descriptive power of the Model MBean to one’s Spring-exposed JMX MBeans using annotations.

See the blog entry Adding Information to a Standard MBean Interface Using Annotations for a method of using annotations processing to provide descriptive detail via Standard MBeans (as opposed to Model MBeans).




UPDATE (7 February 2009): The following section has been added in response to a request in the feedback section. This section demonstrates how to build and run the code examples shown earlier in the blog post.

The Java source files and XML configuration files for Spring shown above can be placed in different locations depending on how the build file is set up. I will provide an Ant build.xml file that generates a JAR file and a script for running the examples. This build file depends on the Java source code files and Spring Framework configuration files being in a directory structure as shown in the next two screen snapshots.

Placement of Java Source Code Files



Placement of Spring Framework XML Configuration Files



As the screen snapshots above demonstrate, I placed the directories and files under a root directory called C:\dustinjmx. The src and config subdirectories hold the Java source code files and Spring XML configuration files respectively. With this structure in place, the following Ant build.xml file can be used to compile the Java source code and assemble a JAR file. This build file also optionally generates a script that can be used to run the Java/Spring examples.

build.xml

<?xml version="1.0" encoding="UTF-8"?>
<project name="SpringModelMBeansExamples" default="all" basedir=".">

<property name="spring.home.dir"
value="C:\\spring-framework-2.5.6" />

<property name="config.dir" value="config" />
<property name="src.dir" value="src" />
<property name="build.dir" value="build" />
<property name="classes.dir" value="${build.dir}/classes" />
<property name="dist.dir" value="dist" />
<property name="jar.name" value="springjmx.jar" />

<property name="command.string"
value="java -cp ${spring.home.dir}/dist/spring.jar${path.separator}${spring.home.dir}/lib/jakarta-commons/commons-logging.jar${path.separator}${dist.dir}/${jar.name} dustin.jmx.modelmbeans.SpringModelMBeanDemonstrator" />
<property name="script.name" value="runIt" />

<target name="-init">
<mkdir dir="${dist.dir}" />
<mkdir dir="${classes.dir}" />
</target>

<condition property="isWindows" value="true">
<os family="windows" />
</condition>

<target name="compile"
depends="-init"
description="Compile Java classes.">
<javac srcdir="${src.dir}"
destdir="${classes.dir}"
classpath="${spring.home.dir}/dist/spring.jar:${spring.home.dir}/lib/jakarta-commons/commons-logging.jar" />
</target>

<target name="jar" depends="compile"
description="Assemble class files and context XML files into JAR.">
<jar destfile="${dist.dir}/${jar.name}"
basedir="${classes.dir}"
includes="**/*.*"
filesonly="true">
<fileset dir="${config.dir}" includes="**/*.*" />
</jar>
</target>

<target name="clean"
description="Clean generated artifacts.">
<delete dir="${dist.dir}" />
<delete dir="${build.dir}" />
</target>

<target name="display-run-command"
description="Shows how to run these examples.">
<echo>
<![CDATA[
Run the assembled executable Spring JMX Demonstration code
with a command like the following:

${command.string} <<<demonstrator_type>>>

where <<<demonstrator_type>>> is one of the following:

simple
wrapper
metadata
]]>
</echo>
</target>

<target name="generate-run-scripts"
description="Generate script to run JMX examples"
depends="generate-windows-run-script, generate-linux-run-script" />

<target name="generate-windows-run-script"
description="Generate run script for Windows"
if="isWindows">
<echo file="runIt.cmd">${command.string} %1</echo>
</target>

<target name="generate-linux-run-script"
description="Generate run script for Linux."
unless="isWindows">
<echo file="runIt.sh">#!/bin/bash${line.separator}${command.string} $1</echo>
</target>

<target name="all" depends="jar, display-run-command"
description="Default target: Compiles Java source and assembles JAR" />

</project>



The location of the Spring Framework should be changed in the build file to point to wherever it is located on the individual machine. The generate-run-scripts target can be called with ant generate-run-scripts to build a script that can then be run to start the examples covered earlier in this blog posting. When the script is run, it should be run with a command-line option of simple, wrapper, or metadata like this: runIt simple.



Once this script has been started, JConsole can be started in a different window by typing "jconsole" on the command line. If JConsole is run on the same machine as the Java application just started, the it should be a local connection that can be selected as shown in the following screen snapshot. Use the MBeans tab to interact with the Java application as shown earlier.

Monday, July 14, 2008

OpenLaszlo 4.1.1 Available for Download

The OpenLaszlo blog has an entry today called OpenLaszlo 4.1.1 Now Available in which it is recommended that anyone who downloaded OpenLaszlo 4.1 "upgrade to release 4.1.1." The blog entry also includes a link to a list of bug fixes in 4.1.1. The OpenLaszlo 4.1.1 Reference is available here and OpenLaszlo 4.1.1 itself can be downloaded here.

Other good news on the OpenLaszlo front is renewed talk about a Laszlo Systems-provided Eclipse-based IDE for OpenLaszlo.

textformat NOT AWOL in OpenLaszlo 4.1

UPDATE (14 July 2008): I am updating this blog entry (striking out certain text and adding other text) to be more accurate in light of Henry's reminder (see comments) about an important part of the migration to OpenLaszlo 4.1. As part of this update, I also added "NOT" to the blog entry's title.

As I was adding tool tips to the OpenLaszlo RSS Reader that I blogged about earlier, I noticed that the hyperlinks to blog entries no longer worked. I turned on the Laszlo debugger and the reason for the absence of hyperlinks in my RSS Reader was made evident as shown in the following screen snapshot (click on image to see larger version).



The debugger shows by the comment "call to undefined function textformat" that something had happened to the textformat object I was previously using. All of the other debugger output is directly due to this not being found.
I confirmed that there is no textformat file in my OpenLaszlo 4.1 installation directory despite it still being listed in the OpenLaszlo 4.1 LZX Reference Manual and being discussed in Chapter 22 of the OpenLaszlo 4.1 Application Developers Guide.


The piece of code that had been using textformat and which was now not serving up HTML links anymore is shown next (as shown in the earlier blog - see that entry for remaining code and context):


<handler name="ontext">
htmlLink = new textformat(); // LzTextFormat is deprecated
htmlLink.setAttribute("url", this.getText());
htmlLink.setAttribute("target", "blank");
this.setHTML(htmlLink);
this.setTextFormat(htmlLink);
</handler>


The code that was now leading to the debugger output error messages is highlighted above.

As Henry points out in the comments to my original version of this blog entry, and as documented in the OpenLaszlo 4.1 Release Notes (see section "Upgrading to OpenLaszlo 4.1"), "user classes are no longer defined as part of the global namespace" and are now instead specified with lz. in front of the user-defined class. Apparently, textformat (or lz.textformat now) fits this description.


The next code listing shows the simple addition of lz. in front of textformat. This was enough to fix the debugger warnings and make the hyperlinks work again.



<handler name="ontext">
htmlLink = new lz.textformat(); // LzTextFormat is deprecated
htmlLink.setAttribute("url", this.getText());
htmlLink.setAttribute("target", "blank");
this.setHTML(htmlLink);
this.setTextFormat(htmlLink);
</handler>


I was also able to get this to work again with the new handler shown next that doesn't use textformat (or lz.textformat) at all:


<handler name="ontext">
<![CDATA[
newUrl = "<a href='" + this.getText() + "' target='_blank'>"
+ this.getText() + "</a>";
this.setText(newUrl);
this.setHTML(true);
]]>
</handler>


In the new handler that doesn't use any form of textformat, because I was building up an HTML anchor tag myself in the JavaScript, I needed to use a CDATA block to tell the OpenLaszlo XML parser to not try to parse this JavaScript. The functionality now works exactly the same in the OpenLaszlo 4.1 environment either using lz.textformat or manually generating HTML.

Related to this, it is exciting to see in the blog entry OpenLaszlo 4.1.1 is Coming and More... that we can expect to see 4.1.1 out soon (probably within a week) to address some issues identified by the OpenLaszlo community. That blog entry also mentions the possible release of OpenLaszlo 4.2 with SWF9 alpha support by the end of July. Finally, the brief text entry Use JavaScript 2 Today with OpenLaszlo mentions the upcoming OpenLaszlo 4.2 release and its support for compilation into various flavors of ActionScript (not surprising in light of support of SWF9).

OpenLaszlo ToolTips

The OpenLaszlo Incubator (<<openLaszloInstall>>\lps\components\incubator) has several useful components and features for developing rich web applications. These include form validators, the rich text editor (Flash runtime only, not DHTML), and tool tips (the subject of this blog entry).

The concept of a tool tip is familiar to just about anyone who has written an HMI in recent years. In HTML, a tooltip can be easily provided using the title attribute and it can be programmatically altered using JavaScript. Similarly, OpenLaszlo allows for static and dynamic setting of tooltips and OpenLaszlo can generally be compiled into JavaScript/DHTML or Flash runtime. In this blog entry, I'll demonstrate how simple it is to add a tool tip to an OpenLaszlo visual component.

This blog entry's example of applying an OpenLaszlo tooltip is trivial and is similar to those shown in the example in the OpenLaszlo blog entry Laszlo Mail Tooltip Contributed to OpenLaszlo and in the blog entry OpenLaszlo: Dynamic Tooltip Text. Here is a full example of OpenLaszlo code with a simple tooltip included.


<canvas title="Very Simple OpenLaszlo ToolTip Example">

<include href="incubator/tooltip/tooltip.lzx" />

<simplelayout axis="y" spacing="10" />

<inputtext id="toolTipInfo" text="Click Button">
<handler name="ontext">
mainButtonToolTip.setAttribute("text", this.getText());
</handler>
</inputtext>
<button id="mainButton" text="Click Me!">
<tooltip id="mainButtonToolTip" text="${toolTipInfo.text}" />
</button>
<button id="secondaryButton" text="No, Click Me!">
<tooltip>This is the secondary button.</tooltip>
</button>

</canvas>


The above source code will not compile with the lzc compiler if the include statement is not specified. This is shown in the next screen snapshot with the message "Unknown tag: tooltip".



With the include line <include href="incubator/tooltip/tooltip.lzx" /> included, the source code above does compile correctly.

The next series of screen snapshots show the tooltips used in the code above in action. The first two screen snapshots show the tool tips that are provided initially for each button and the third screen snapshot demonstrates the changed tool tip for the main button based on the text entered in the input text field.







All three screen snapshots above show the OpenLaszlo tooltip in an SWF8 runtime (now the default runtime in OpenLaszlo 4.1). Of course, OpenLaszlo's support for a DHTML runtime is a compelling feature for many developers. The next single screen snapshot shows the application running in DHTML. The image was captured after the inputtext field was changed to contain the contents "Dustin!".



With the OpenLaszlo tooltip, it is possible to go back to the OpenLaszlo RSS Reader example and add tool tips to that reader. The next screen snapshot shows how this looks when one of the newly added tool tips is displayed.



The OpenLaszlo tool tips are highly useful in providing additional detail to users. Fortunately, they are easy to add as well.

Thursday, July 10, 2008

The JMX Model MBean

In this blog entry, I will be demonstrating the development of a simple Model MBean. In a previous blog entry, I demonstrated some key characteristics of the MXBean. The MXBean is more straightforward to develop and use, but the additional complexity of the Model MBean does bring several benefits.

The two primary benefits that I like to use Model MBeans to achieve are the increased descriptive nature of the Model MBean and the ability to "wrap" non-JMX classes or resources with the Model MBean. The latter advantage is the primary reason that the Spring Framework uses Model MBeans in its JMX support. The Model MBean enables Spring to allow developers to write plain Java classes that Spring can then expose as MBeans by "wrapping" the developed simple objects as managed resources. Spring also illustrates the descriptive nature of the Model MBean. Spring accomplishes this with annotation-based descriptive specification as I discussed in a previous blog entry. In short, the Spring Framework takes advantage of the two most important advantages (in my opinion) of the Model MBean by using them to wrap non-JMX objects and by leveraging their great descriptive ability.

In the remainder of this blog entry, I will show the rather verbose code for handling Model MBeans by hand. I'll also show the extra detail displayed in JConsole thanks to the Model MBean.

The first code listing is for the plain Java class that has no knowledge of JMX or the fact that it will be managed.

SimpleCalculator.java


package dustin.jmx.modelmbeans;

/**
* Simple calculator class intended to demonstrate how a class with no knowledge
* of JMX or management can be "wrapped" with ModelMBeans.
*
* @author Dustin
*/
public class SimpleCalculator
{
/**
* Calculate the sum of the augend and the addend.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @return Sum of augend and addend.
*/
public int add(final int augend, final int addend)
{
return augend + addend;
}

/**
* Calculate the difference between the minuend and subtrahend.
*
* @param minuend Minuend in subtraction operation.
* @param subtrahend Subtrahend in subtraction operation.
* @return Difference of minuend and subtrahend.
*/
public int subtract(final int minuend, final int subtrahend)
{
return minuend - subtrahend;
}

/**
* Calculate the product of the two provided factors.
*
* @param factor1 First integer factor.
* @param factor2 Second integer factor.
* @return Product of provided factors.
*/
public int multiply(final int factor1, final int factor2)
{
return factor1 * factor2;
}

/**
* Calculate the quotient of the dividend divided by the divisor.
*
* @param dividend Integer dividend.
* @param divisor Integer divisor.
* @return Quotient of dividend divided by divisor.
*/
public double divide(final int dividend, final int divisor)
{
return dividend / divisor;
}
}


The next code listing is the Model MBean handling and registration. This is a rather long code listing, indicative of the verbosity of the Model MBean. Note that JMX books have provided frameworks and libraries to reduce this code and Daniel Fuchs shows in his blog entry Dynamic MBeans, Model MBeans, and POJOS... how one could use reflection to reduce Model MBean code. Even so, Model MBeans still require more tedious coding and can be a little more tricky than the Standard MBean or the MXBean. If a developer is using the Spring Framework in their application, then Spring's support of Model MBeans makes these particularly easy to apply. When not using Spring, one might consider the Apache Commons Modeler Component to support Model MBeans. With all that said, here is the code listing.


package dustin.jmx.modelmbeans;

import java.lang.management.ManagementFactory;
import javax.management.Descriptor;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.RuntimeOperationsException;
import javax.management.modelmbean.DescriptorSupport;
import javax.management.modelmbean.InvalidTargetObjectTypeException;
import javax.management.modelmbean.ModelMBean;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import javax.management.modelmbean.RequiredModelMBean;

/**
* The purpose of this class is to demonstrate use of ModelMBeans in the raw.
*/
public class ModelMBeanDemonstrator
{
private MBeanServer mbeanServer;

/**
* Constructor.
*/
public ModelMBeanDemonstrator()
{
this.mbeanServer = ManagementFactory.getPlatformMBeanServer();
}

/**
* Construct the meta information for the SimpleCalculator ModelMBean
* operations and the operations' parameters.
*
* @return
*/
private ModelMBeanOperationInfo[] buildModelMBeanOperationInfo()
{
//
// Build the PARAMETERS and OPERATIONS meta information for "add".
//

final MBeanParameterInfo augendParameter =
new MBeanParameterInfo(
"augend",
Integer.TYPE.toString(),
"The first parameter in the addition (augend)." );
final MBeanParameterInfo addendParameter =
new MBeanParameterInfo(
"addend",
Integer.TYPE.toString(),
"The second parameter in the addition (addend)." );

final ModelMBeanOperationInfo addOperationInfo =
new ModelMBeanOperationInfo(
"add",
"Integer Addition",
new MBeanParameterInfo[] {augendParameter, addendParameter},
Integer.TYPE.toString(),
ModelMBeanOperationInfo.INFO );


//
// Build the PARAMETERS and OPERATIONS meta information for "subtract".
//

final MBeanParameterInfo minuendParameter =
new MBeanParameterInfo(
"minuend",
Integer.TYPE.toString(),
"The first parameter in the substraction (minuend)." );

final MBeanParameterInfo subtrahendParameter =
new MBeanParameterInfo(
"subtrahend",
Integer.TYPE.toString(),
"The second parameter in the subtraction (subtrahend)." );

final ModelMBeanOperationInfo subtractOperationInfo =
new ModelMBeanOperationInfo(
"subtract",
"Integer Subtraction",
new MBeanParameterInfo[] {minuendParameter, subtrahendParameter},
Integer.TYPE.toString(),
ModelMBeanOperationInfo.INFO );

//
// Build the PARAMETERS and OPERATIONS meta information for "multiply".
//

final MBeanParameterInfo factorOneParameter =
new MBeanParameterInfo(
"factor1",
Integer.TYPE.toString(),
"The first factor in the multiplication." );

final MBeanParameterInfo factorTwoParameter =
new MBeanParameterInfo(
"factor2",
Integer.TYPE.toString(),
"The second factor in the multiplication." );

final ModelMBeanOperationInfo multiplyOperationInfo =
new ModelMBeanOperationInfo(
"multiply",
"Integer Multiplication",
new MBeanParameterInfo[] {factorOneParameter, factorTwoParameter},
Integer.TYPE.toString(),
ModelMBeanOperationInfo.INFO );

//
// Build the PARAMETERS and OPERATIONS meta information for "divide".
//

final MBeanParameterInfo dividendParameter =
new MBeanParameterInfo(
"dividend",
Integer.TYPE.toString(),
"The dividend in the division." );

final MBeanParameterInfo divisorParameter =
new MBeanParameterInfo(
"divisor",
Integer.TYPE.toString(),
"The divisor in the division." );

final ModelMBeanOperationInfo divideOperationInfo =
new ModelMBeanOperationInfo(
"divide",
"Integer Division",
new MBeanParameterInfo[] {dividendParameter, divisorParameter},
Double.TYPE.toString(),
ModelMBeanOperationInfo.INFO );

return new ModelMBeanOperationInfo[]
{ addOperationInfo, subtractOperationInfo,
multiplyOperationInfo, divideOperationInfo };
}

/**
* Build descriptor.
*
* @return Generated descriptor.
*/
private Descriptor buildDescriptor()
{
final Descriptor descriptor = new DescriptorSupport();
descriptor.setField("name", "ModelMBeanInTheRaw");
descriptor.setField("descriptorType", "mbean");
return descriptor;
}

/**
* Set the provided ModelMBean to manage the SimpleCalculator resource.
*
* @param modelMBeanToManageResource ModelMBean to manage the SimpleCalculator
* resource.
*/
private void setModelMBeanManagedResource(
final ModelMBean modelMBeanToManageResource )
{
try
{
modelMBeanToManageResource.setManagedResource(
new SimpleCalculator(),
"ObjectReference");
}
catch (RuntimeOperationsException ex)
{
System.err.println(ex.getMessage());
}
catch (InstanceNotFoundException ex)
{
System.err.println(ex.getMessage());
}
catch (InvalidTargetObjectTypeException ex)
{
System.err.println(ex.getMessage());
}
catch (MBeanException ex)
{
System.err.println(ex.getMessage());
}
}

/**
* Create a ModelMBean the "old fashioned" way.
*
* @return ModelMBean created directly without framework.
*/
private ModelMBean createRawModelMBean()
{
RequiredModelMBean modelmbean = null;
try
{
final ModelMBeanInfoSupport modelMBeanInfo =
new ModelMBeanInfoSupport(
SimpleCalculator.class.getName(),
"A simple integer calculator.",
null, // attributes
null, // constructors
buildModelMBeanOperationInfo(),
null, // notifications
buildDescriptor() );
modelmbean = new RequiredModelMBean(modelMBeanInfo);
setModelMBeanManagedResource(modelmbean);
}
catch (MBeanException mbeanEx)
{
System.err.println( "ERROR trying to create a ModelMBean:\n"
+ mbeanEx.getMessage() );
}

return modelmbean;
}

/**
* Register the provided ModelMBean in the MBeanServer using the provided
* ObjectName String.
*
* @param modelMBean ModelMBean to be registered with the MBeanServer.
* @param objectNameString ObjectName of the registered ModelMBean.
*/
private void registerModelMBean(
final ModelMBean modelMBean,
final String objectNameString)
{
try
{
final ObjectName objectName =
new ObjectName(objectNameString);
this.mbeanServer.registerMBean( modelMBean,
objectName );
}
catch (MalformedObjectNameException badObjectName)
{
System.err.println( "ERROR trying to generate ObjectName based on "
+ objectNameString + ":\n"
+ badObjectName.getMessage() );
}
catch (InstanceAlreadyExistsException objectNameAlreadyExists)
{
System.err.println( "ERROR due to ObjectName ["
+ objectNameString + "] already existing: "
+ objectNameAlreadyExists.getMessage() );
}
catch (MBeanRegistrationException badMBeanRegistration)
{
System.err.println( "ERROR trying to register MBean with ObjectName "
+ objectNameString + ":\n"
+ badMBeanRegistration.getMessage() );
}
catch (NotCompliantMBeanException nonCompliantMBean)
{
System.err.println( "ERROR trying to register nonconforming MBean "
+ "with ObjectName of " + objectNameString
+ nonCompliantMBean.getMessage() );
}
}

/**
* Create a ModelMBean in the raw and register it with the MBeanServer.
*/
public void createAndRegisterRawModelMBean()
{
final String rawModelMBeanObjectNameString = "modelmbean:type=raw";
registerModelMBean(createRawModelMBean(), rawModelMBeanObjectNameString);
}

/**
* Pause for the specified number of milliseconds.
*
* @param millisecondsToPause Milliseconds to pause execution.
*/
public static void pause(final int millisecondsToPause)
{
try
{
Thread.sleep(millisecondsToPause);
}
catch (InterruptedException threadAwakened)
{
System.err.println("Don't wake me up!\n" + threadAwakened.getMessage());
}
}

/**
* Demonstate use of ModelMBean.
*
* @param args the command line arguments
*/
public static void main(String[] args)
{
final ModelMBeanDemonstrator me = new ModelMBeanDemonstrator();
me.createAndRegisterRawModelMBean();
pause(1000000);
}
}


When the above code is run, the operations in SimpleCalculator can then be accessed via JConsole as shown in the next four images (click on images to see larger versions). The images demonstrate the descriptive information available for the MBean and for each operation thanks to the Model MBean's extraordinary descriptive abilities. They also show the results of one of the operations.

ModelMBean Descriptive Information Displayed




The Exposed ModelMBean Operations




ModelMBean-Exposed Operation Works




ModelMBean Operation Descriptive Detail




I have attempted to demonstrate the power and flexibility of the ModelMBean. I did not show specification of the metadata for constructors, notifications, and attributes, but they generally follow the same pattern as shown for operations. ModelMBeans are another example of the typical trade-off of greater flexibility for increase complexity. However, there are ways to reduce this complexity as discussed previously. These include use of reflection, use of the Spring Framework, use of the Apache Commons Modeler Component, and use of JBoss XMBeans.

Wednesday, July 9, 2008

VisualVM Included in Java SE 6 Update 7

Luis-Miguel Alventosa announced exciting news: VisualVM 1.0 is now being included in Sun's Java SE 6 implementation as of Update 7. His announcement is available in his blog. VisualVM is a highly useful tool because it consolidates many command-line performance and diagnostic tools that were previously available as separate, non-visual tools in previous versions of Sun's JDK.

I was happy to see Sun include native JAXB support and native annotations processing support in Java SE 6 and even wrote an article for OTN about that. Like VisualVM, JAXB was available for separate download before its inclusion in Java SE 6, but having it integrated in the JDK provided several benefits. Similarly, having a platform JMX agent (introduced in J2SE 5) was also significantly more convenient than using a separate JMX implementation. I expect to realize similar benefits from having VisualVM downloaded as part of the JDK. There is no concern about downloading or configuring VisualVM separately and it can be run simply as %JAVA_HOME%/bin/jvisualvm or $JDK_HOME/bin/jvisualvm (assuming that JAVA_HOME is defined as an environment variable pointing to your JDK 6 Update 7 installation). Because many of us have that directory in our path anyway for convenient use of java, javac, xjc, jconsole, and many other commonly used Java tools, this is especially convenient.

Tuesday, July 8, 2008

NetBeans: Jersey and Tomcat

In my blog entry Project Jersey and Java-Based REST, I used several screen snapshots and some text to illustrate how NetBeans 6.1 can be used with Jersey (the JSR-311/JAX-RS reference implementation) to quickly and easily develop RESTful web services from database tables. The process illustrated there takes advantage of the ability of NetBeans 6.1 (which many other IDEs now have as well) to generate JPA-compliant entity classes from source database tables. Similarly, the ability of NetBeans to automatically generate Jersey artifacts for JPA entities was also used and illustrated.

In the referenced blog entry, I did not talk much about the differences of deployment to Tomcat or to GlassFish or other web server. While much of the process is the same regardless of the server used, the JPA persistence.xml file does need to be altered. In this blog entry, I'll focus on the deploying the JPA-backed Jersey-based RESTful web services on Tomcat.

The default persistence.xml file generated as part of the JPA entity generation process (and based on my wizard settings) is shown next:


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="SimpleJerseyProjectPU" transaction-type="JTA">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<jta-data-source>jdbc/hr</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
</persistence>


The NetBeans-centric article Getting Started with RESTful Web Services on Tomcat points out in the Configuring the Persistence File section how to change that file for Tomcat. In particular, it recommends changing that file to remove the jta-data-source element, to change the transaction-type attribute of the persistence-unit element to RESOURCE_LOCAL, and to specify JPA implementation-specific provider properties in the file. For my Oracle database using TopLink Essentials, the persistence.xml file now looks like this:


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="SimpleJerseyProjectPU" transaction-type="RESOURCE_LOCAL">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<!-- <jta-data-source>jdbc/hr</jta-data-source> -->
<exclude-unlisted-classes>false</exclude-unlisted-classes>

<properties>
<property name="toplink.jdbc.user" value="hr"/>
<property name="toplink.jdbc.password" value="hr"/>
<property name="toplink.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:ORCL"/>
<property name="toplink.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
</properties>

</persistence-unit>
</persistence>


The previously referenced article also pointed out some other useful changes that I needed to make. For example, I copied the libraries specified (except for Derby because I was using Oracle) in the Copying Libraries to Tomcat section to the appropriate Tomcat directories as specified.

During the NetBeans generation process, the web.xml (WEB-INF) file and the context.xml (META-INF) file are generally taken care of automatically.

With the change to the persistence.xml file and the appropriate libraries copied to the appropriate Tomcat directories, it was easy to use NetBeans' "Test RESTful Web Services" feature to have the newly generated web services automatically deployed (to Tomcat in this case because it was my currently selected server) and have a browser-based client access the deployed web services.




In somewhat related news, I found two recently posted blog entries on REST to be particularly interesting. In REST vs REST, Anthony Goubard differentiates between what he calls "Pure REST" (close attention to HTTP operations GET, POST, PUT, DELETE and the JSR 311 approach) and the "RESTful Way" (more traditional HTTP servlet approach with use of GET and/or POST and URL parameters). Anthony then goes on to delineate problems he sees with the "Pure REST" approach.

The second article is REST Anti-Patterns by Stefan Tilkov. The first two of his eight REST anti-patterns are: 1) Tunneling everything through GET and 2) Tunneling everything through POST. (By the way, Stefan's short entry WS-Dilemma is poignant and worth the brief read.)

What these two interesting and useful blog entries demonstrate is that while many people are choosing REST for their web services approach, there is still much disagreement about what qualifies as REST at all, let alone as an efficient REST approach. Although such differences can be distracting at times, I generally prefer this type of discussion and bantering of ideas because I believe it leads to a Darwinian effect (thanks, Bill, for pointing out the application of this term to software development) in the software industry.

Monday, July 7, 2008

Project Jersey and Java-based REST

Project Jersey is the reference implementation of JSR 311 ("The Java API for RESTful Web Services"). The main page states that Jersey is currently available as an "early access" version and cannot transition to 1.0 until the specification it implements (JAX-RS/JSR-311) receives final approval.

There are several highly useful resources provided to learn how to apply Jersey in Java-based web services, especially in the Project Jersey Community Wiki. The REST Web Services Developers Guide is available in both HTML and PDF formats. This 34-page document introduces basic concepts of REST (Representational State Transfer) and covers how to use Jersey to apply REST. The Jersey Getting Started page shows how to create a simple Hello World style REST-based web service. One thing I found particularly interesting about this is that it uses the Lightweight HTTP Server distributed with Sun's implementation of Java SE 6.

Another useful resource on using Jersey with REST is the Enterprise Java Technology Tech Tip Implementing RESTful Web Services in Java.

If you use the NetBeans IDE, two particularly useful articles on using NetBeans 6.0 with Jersey are Getting Started with RESTful Web Services on GlassFish and Getting Started with RESTful Web Services on Tomcat. In the remainder of this article, I will demonstrate how to use NetBeans 6.1 with Jersey and the Oracle database HR schema to generate a RESTful web service.

SIDE NOTE: I started working on this example before discovering the two NetBeans/Jersey articles related to Tomcat and GlassFish described above. However, even after discovering these articles, I decided that it could be worthwhile to publish this blog entry because I am going to use NetBeans 6.1 (the articles use NetBeans 6.0), I am going to use an external Oracle database, and I am going to add different commentary than that available in the two articles hosted on the NetBeans site. However, because the basic Jersey support seems to be largely the same between NetBeans 6.0 and NetBeans 6.1, I am going to try to not repeat much of what is already available in those articles unless the repetition is necessary to make this blog entry flow more smoothly.

The Jersey distribution can be downloaded, but this step is unnecessary with NetBeans 6.1. The snapshot below (click on snapshots to see larger versions) demonstrates the "Jersey (JSR 311) Libraries" library (and its content JARs) that is available with NetBeans and can be included in a project using Jersey.



NetBeans 6.1 includes a plugin for Jersey. This is shown in the next screen snapshot:



With the Jersey library added to my NetBeans 6.1 project and the plugin installation verified, it is time to start developing a simple Jersey-based web service. For this example, I will be using the Oracle HR database schema. When one runs a SELECT table_name FROM user_tables SQL command in SQL*Plus on this schema, the following tables are shown


TABLE_NAME
------------------------
LOCATIONS
COUNTRIES
DEPARTMENTS
REGIONS
JOB_HISTORY
JOBS
EMPLOYEES


With existing database tables like those shown above, it is trivial to generate Java Persistence API (JPA) entity classes from the database tables in NetBeans 6.1.

The next three screen snapshots indicate how simple it is to generate "Entity Classes from Database," to select appropriate tables from which JPA entity classes should be generated, and to specify a package structure for the generated JPA entity classes.







You may have noticed some tables and generated JPA entities in the above screen snapshots that are not normally in the HR schema. These tables are in my schema because I created them and am using them for something else, but they are not significant for this example.

The next screen snapshot shows the generated JPA entity classes as they appear in the NetBeans 6.1 IDE.



The icons with exclamation points in the middle of red circles indicate classes that do not compile with the current NetBeans compiler classpath settings. To address this, I needed to add the TopLink Essentials (JPA 1.0 reference implementation) library to the project. This library is delivered with NetBeans 6.1, so this is a relatively easy task. The next screen snapshot indicates how the addition of the TopLink Essentials library allows the generated entity classes to build properly.



Thus far, NetBeans 6.1 has done most of the heavy lifting. We have not done anything REST or even Web Service specific, but we do have JPA entity classes generated and corresponding to the database tables we started with. The next step is to let NetBeans 6.1 generate the appropriate Jersey-based artifacts to support RESTful web services access of these newly generated entity classes. The next four screen snapshots show how to generate "RESTful Web Services from Entity Classes," how to select the entity classes from which REST/Jersey artifacts should be generated, which Jersey/REST artifacts are to be generated, and the generation of Jersey-based REST web services in action.









When the steps shown in the screen snapshots immediately above are executed, the Jersey-based web services artifacts shown in the next four screen snapshots are generated or set up.

Converters - Convert Between JPA Entities and Jersey Services


Services - Workhorse Classes for Jersey-based REST Web Services Support


Jersey Libraries Automatically Associated with NetBeans Project


NetBeans RESTful Web Services


NetBeans 6.1 has done most of the work to go from database tables to JPA entities and from JPA entities to RESTful Web Services. NetBeans does even more for us by providing an easy testing and monitoring mechanism. By right-clicking on the "RESTful Web Services" icon shown in the last screen snapshot (in NetBeans' Project window) and selecting , a web browser comes up with a basic "Test RESTful Web Services" web page that can be used to test and monitor the running REST-based web services. The next screen snapshot shows a snippet of this using a REST query for employee with employee ID of 170.



There is much to look at in the web page for testing, but my focus here is on the simplicity of the REST-style URL (see Resource toward top of web page), the tabs at the bottom that allow you to see the "raw" XML in addition to the useful Tabular View and HTTP Monitor tabs, and the URL for the WADL (see top left corner).

In this blog, I used NetBeans to create the RESTful web services from JPA entity classes that were generated by NetBeans from an Oracle database schema. I also performed simple testing of my newly generated RESTful web services using NetBeans' automatic support. I intend to follow up with additional blog entries in which I use non-NetBeans clients to contact these RESTful web services.

Wednesday, July 2, 2008

Simple Spring HTTP Remoting Example

I am using this blog entry to demonstrate by simple example the use of the Spring Framework's HTTP Remoting. There are numerous online resources on this subject, so my intention here is to provide an extremely simple but complete demonstration of using Spring's HTTP Remoting with non-browser clients.

The Spring approach to HTTP Remoting allows clients to communicate with the Spring-hosted server code via HTTP without the client code requiring any knowledge of HTTP being used. Instead, the client Java code only "sees" normal business-related Java objects (usually interfaces) rather than HTTP-specific objects.

Spring HTTP Remoting generally requires Spring and Java on both the server side and client side. However, if those two requirements can be met, Spring HTTP Remoting is easily applied.

The following steps allow HTTP communication between Spring-hosted clients and servers. After first briefly outlining the steps, I'll then delve into them in more detail (including code samples).


  1. Create or use an existing Spring bean that typically implements a Java interface.

    This is nothing special to HTTP remoting and is the same step you'd need to take to do most things in Spring (a notable exception is Spring JDBC that does not require any Spring beans to be used).


  2. Create the Spring XML configuration file for associating the bean created in step #1 with a Spring application context.

    As with Step #1, this XML file is nothing particular to Spring HTTP Remoting, but is instead common to nearly all Spring Framework wiring and configuration.


  3. Create or add to web.xml file.

    This third step is the first step that is more particular to Spring HTTP Remoting, but is still generally applicable with Spring MVC framework. This step includes adding the servlet class and URL mappings as one usually uses with Java EE servlets and JavaServer Pages. The most important part of this step is to specify the Spring DispatcherServlet. An optional "link" is also provided in this web.xml file to a context config location where one or more Spring XML application context files are located and used.


  4. Create the Spring-specific servlet context file.

    This XML file looks a lot like a "normal" Spring application context XML configuration file, but its name is prescribed by the convention of servlet name followed by a hypen and the word servlet. In other words, if the servlet was called "somewebthing" in the web.xml file, this Spring servlet configuration file would be called somewebthing-servlet.xml. This file contains the configuration for the HttpInvokerServiceExporter (the piece of this that is particular to the HTTP Remoting covered in this blog entry) and URL mapping information.


  5. Test!

    Although the simple client will be writting without HTTP in mind and will appear to only be using Java objects, it will actually be invoking the service via HTTP. This will be "proven" by running the client without the service deployed and watching for the resulting HTTP error code.




I'll now move onto demonstrating the above steps in greater detail and attempt to illustrate them concretely with code samples.

Step #1: The Bean and Its Interface

This step is no different than defining Java classes and interfaces they implement for use with Spring. The following code listings show the interface (StateCapitalServiceIF) and the implementing class (StateCapitalService) used for this example.

--- StateCapitalServiceIF.java ---

package examples.springhttp;

import java.io.Serializable;

/**
* The State Capital Service interface that the client will use to access
* server-side functionality via HTTP.
*/
public interface StateCapitalServiceIF extends Serializable
{
/**
* Provide capital of state whose name is provided.
*
* @param stateName Name of state whose capital is desired.
* @return Capital of the specified state; null if not found.
*/
public String getCapital(final String stateName);
}


--- StateCapitalService.java ---

package examples.springhttp;

import java.util.Map;

/**
* Implementation of functionality to be run after being called by client via
* HTTP.
*/
public class StateCapitalService implements StateCapitalServiceIF
{
Map statesAndCapitals = null;

public StateCapitalService()
{
}

/**
* Set my states to state capitals mapping.
*
* @param statesAndCapitals States to state capitals mapping.
*/
public void setStatesAndCapitals(final Map statesAndCapitals)
{
this.statesAndCapitals = statesAndCapitals;
}

/**
* Provide capital of state whose name is provided.
*
* @param stateName Name of state whose capital is desired.
* @return Capital of the specified state; null if not found.
*/
public String getCapital(final String stateName)
{
return this.statesAndCapitals.get(stateName);
}
}



Step #2: Spring Application Context Configuration File

I like to keep Spring's HTTP-specific configuration separate from the bean's XML configuration. Therefore, the bean's configuration is exactly like one would see normally with Spring. To configure the StateCapitalService class above, the following configuration is used:

--- spring-http-config.xml ---

<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<util:map id="statesCapitalsMap">
<entry key="Alabama" value="Montgomery" />
<entry key="Alaska" value="Juneau" />
<entry key="Arizona" value="Phoenix" />
<entry key="Arkansas" value="Little Rock" />
<entry key="California" value="Sacramento" />
<entry key="Colorado" value="Denver" />
<entry key="Connecticut" value="Hartford" />
</util:map>

<bean id="stateCapitalService"
class="examples.springhttp.StateCapitalService"
p:statesAndCapitals-ref="statesCapitalsMap" />

</beans>


So far, nothing specific to HTTP Remoting has been done. In fact, the bean, its interface, and its XML application context configuration could all be run by a normal Java SE class like the one shown below:

--- MainServiceAppContext.java ---

package examples.springhttp;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* Demonstrates how Spring bean can be used without any HTTP involvement.
*/
public class MainServiceAppContext
{
public static void printStateInfo(
final StateCapitalServiceIF stateCapitalMapper,
final String state)
{
System.out.println(
"The capital of " + state + " is "
+ stateCapitalMapper.getCapital(state));
}

/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
final ApplicationContext context =
new ClassPathXmlApplicationContext(
"examples/springhttp/spring-http-config.xml" );
StateCapitalServiceIF stateCapitalMapper =
(StateCapitalServiceIF) context.getBean("stateCapitalService");
printStateInfo(stateCapitalMapper, "Alabama");
printStateInfo(stateCapitalMapper, "Colorado");
}
}


Step #3: The web.xml File

This web.xml file is familiar to anyone who has developed a Java EE web application. The web.xml used in this example is shown next.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<display-name>
Simple Spring HTTP Remoting Example
</display-name>

<description>
This is meant as an extremely simple example of using Spring's HTTP
Remoting capability.
</description>

<servlet>
<servlet-name>statesCapitals</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

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

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/examples/springhttp/spring-http-config.xml</param-value>
</context-param>

</web-app>


Step #4: The Servlet Context Configuration File

Because the servlet in this example is named "statesCapitals," a Spring servlet configuration file named statesCapitals-servlet.xml needs to be provided. It is shown next:

--- statesCapitals-servlet.xml ---

<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="httpStateCapitalService"
class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"
p:service-ref="stateCapitalService">
<property name="serviceInterface">
<value>examples.springhttp.StateCapitalServiceIF</value>
</property>
</bean>

<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/statesCapitals">httpStateCapitalService</prop>
</props>
</property>
</bean>

</beans>


Step #5: Testing It

We need to configure the client to communicate via HTTP with our server-side application. The configuration for this is contained in spring-http-client-config.xml for this example and is shown next:

--- spring-http-client-config.xml ---

<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="stateCapitalProxyService"
class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl">
<value>http://localhost:8080/SpringHTTPExample/statesCapitals</value>
</property>
<property name="serviceInterface">
<value>examples.springhttp.StateCapitalServiceIF</value>
</property>
</bean>

</beans>


The client code that uses the above XML to bootstrap a Spring container and call the server-side code via HTTP is in the class HttpClient and that code is shown next:

--- HttpClient.java ---

package examples.springhttp.client;

import examples.springhttp.StateCapitalServiceIF;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* This class demonstrates a client of a Spring HTTP-exposed service and shows
* how the client interacts with the server as if using normal Java objects
* rather than using anything HTTP specific.
*/
public class HttpClient
{
public static void printStateInfo(
final StateCapitalServiceIF stateCapitalMapper,
final String state)
{
System.out.println(
"The capital of " + state + " is "
+ stateCapitalMapper.getCapital(state));
}

public static void main(final String[] arguments)
{
final ApplicationContext context =
new ClassPathXmlApplicationContext(
"examples/springhttp/client/spring-http-client-config.xml");
final StateCapitalServiceIF stateCapitalService =
(StateCapitalServiceIF) context.getBean("stateCapitalProxyService");
printStateInfo(stateCapitalService, "Colorado");
printStateInfo(stateCapitalService, "Alabama");
}
}


When the server-side code is built into a WAR and deployed to Tomcat or other web server, the above client will connect to it successfully and print out the capitals of Alabama and Colorado as shown in the next screen snapshot:



If the server-side application is undeployed or the web server is turned off, the client prints a 404 ("Not Found") HTTP status code indicating it is not available and proving that HTTP is being used. This is shown in the next screen snapshot.



The Packaging

I have displayed the contents of all the files above, but the packaging of them can be a little tricky. This section shows the contents of various JARs and the WAR I used to run the above examples.

--- SpringHTTPExample.war ---
This is the WAR file I deployed to Tomcat:

102 Thu Jul 03 23:25:54 MDT 2008 META-INF/MANIFEST.MF
1218 Thu Jul 03 23:13:42 MDT 2008 WEB-INF/web.xml
1505 Thu Jul 03 23:25:56 MDT 2008 WEB-INF/lib/SpringHTTPExample-web.jar
52915 Thu Jul 03 23:25:56 MDT 2008 WEB-INF/lib/commons-logging.jar
2832933 Thu Jul 03 23:25:56 MDT 2008 WEB-INF/lib/spring.jar
385822 Wed Jan 09 13:24:06 MST 2008 WEB-INF/lib/spring-webmvc.jar
1099 Thu Jul 03 22:33:04 MDT 2008 WEB-INF/examples/springhttp/spring-http-config.xml
1143 Thu Jul 03 23:25:42 MDT 2008 WEB-INF/statesCapitals-servlet.xml


In the above WAR, three of the JARs in the WEB-INF/lib are Spring-provided. Besides those, the remaining content of the WAR consists simply of the web.xml file shown above, the statesCapitals-servlet.xml file shown above, the spring-http-config.xml file shown above, and a JAR file called SpringHTTPExample-web.jar, whose contents are shown next.

--- SpringHTTPExample-web.jar ---

102 Thu Jul 03 23:25:54 MDT 2008 META-INF/MANIFEST.MF
1011 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/StateCapitalService.class
205 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/StateCapitalServiceIF.class


The contents of the JAR above consist simply of the bean class and the interface it implements, both of which are shown above.

--- SpringHTTPClient.jar ---
The contents JAR used to test the HTTP-exposed service are shown now:

102 Thu Jul 03 23:25:54 MDT 2008 META-INF/MANIFEST.MF
205 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/StateCapitalServiceIF.class
1618 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/client/HttpClient.class
954 Thu Jul 03 23:25:54 MDT 2008 examples/springhttp/client/spring-http-client-config.xml


The above client JAR includes the compiled version of the client class shown above along with the spring-http-client-config.xml configuration file shown above. Perhaps the most interesting thing to note here is that the interface class included in the server JAR also needs to be in the client JAR. This makes sense, of course, because it is that interface the client code uses as a proxy to the server side.

Conclusion

In this blog entry, I have included all the code (Java and XML) necessary to build and run a simple example that uses and illustrates Spring's HTTP Remoting capabilities. I did not cover every nuance of this feature and did not explicitly discuss some of the associations between various configuration files. There are several good resources on Spring's HTTP Remoting that do this. I instead attempted to illustrate complete code for a simple Spring HTTP Remoting example without referencing work on similar Spring remoting solutions. (Because Spring treats remoting very consistently, many good books and tutorials cover HTTP support with references to the other protocols supported.) I am including some references to these other resources related to Spring HTTP remoting below.

Other Resources

* Section 17.4 ("Exposing Services Using HTTP Invokers") of Spring Framework 2.5 Reference Manual

* Best of Both Worlds Remote Services with Spring HTTP Invoker

* A Case for Lightweight Remoting (Part 2): Spring to the Rescue

Tuesday, July 1, 2008

Big News in the OpenLaszlo Community: 4.1 and 500k

There have been two major OpenLaszlo announcements in the last two days (yesterday and today) as recorded at http://swik.net/OpenLaszlo. It was announced today that one-half million copies of OpenLaszlo have been downloaded.

While 500,000 downloads is a significant milestone for the OpenLaszlo project, an even bigger announcement for many of us was made a day earlier when it was announced that OpenLaszlo 4.1 is now available and is the recommended released of OpenLaszlo. This is exciting news for anyone who has been waiting for OpenLaszlo's DHTML support to move out of beta Frankly, I was surprised at this release because I assumed that it would still be a while before 4.1's release due to recent interest in OpenLaszlo support of Flash Player 9.

Although the big news associated with OpenLaszlo 4.1's release is its DHTML support, it is also worth noting that "preliminary" support for Flash Player 9 has also been included. Other welcome news includes the observation that OpenLaszlo 4.1 addresses over 800 bugs. The current download page indicates the particular web browser/operating system combinations on which OpenLaszlo 4.1 has been qualified.

The OpenLaszlo 4.1 Release Notes contain additional details and information regarding this release. For example, these Release Notes point out that the button for compiling using preliminary Flash 9 support has been removed from the developer console. However, an OpenLaszlo developer can still choose to compile to Flash 9 using the
lzr=swf9 Laszlo Runtime parameter. The Release Notes also link to the document "Runtime Differences," which documents runtime differences between DHTML and SWF/Flash.

Another piece of recent good news for OpenLaszlo applications is the announcement of SWF searchability. One of the common complaints against Flash-based applications is their reduced ability to support engine optimization. A common approach has been to include text in the HTML "wrapper" pages of Flash applications, but this new approach should provide developers of Flash applications with much greater power and flexibility in search engine support. For now, this increased Flash searchability seems limited to Google and Yahoo! search engines, but my guess is that these two are by far the most heavily used of the search engines.