Saturday, February 28, 2009

Locating The Classpath Definition Used in Java Code

In a previous blog posting, I listed some "everyday problems" Java developers will often face and included some ideas and links related to addressing these issues. One of the focal points of that post was Java classpath issues. One tool that I neglected to mention in that post (but will be adding belatedly when I add a link to this post) is use of Java security-related classes to identify where the class definition used in a Java application comes from on the classpath.

The ability to identify the source of a class definition in a Java application is an especially useful tactic when one knows or has reason to suspect that a particular class is defined twice on the classpath, possibly with different definitions. In general, the first definition of a class found on the classpath is the one used, but this technique can verify the class definition being used or can be useful when there is a very large classpath that makes it difficult to identify all instances of a particular classpath entry.

As discussed in How to Determine Where Your Java Class is Actually Located, Where's That Class Coming From?, How to Know from Which JAR Your Class is Loaded From, Where Did That Class Come From?, Where to Find JARs?, and J2SE Security, the Java SE Security model provides a convenient mechanism for identifying the source (JAR or .class file) of a class definition used in a Java application. This approach involves getting the ProtectionDomain from a class's Class and using that ProtectionDomain to obtain a CodeSource which provides a URL to the source of that particular class definition.

I will include the full code a little later, but here is a sample of code focused on using these Security APIs to get class definition information.


/**
* Provides the name of the classpath entry that provides the class definition
* of the provided object.
*
* @param objectInQuestion Object for which classpath source of instance is
* desired.
*/
public static final String getClassPathSource(final Object objectInQuestion)
{
final StringBuilder builder = new StringBuilder();
final Class clazz = objectInQuestion.getClass();
final ProtectionDomain protectedDomain = clazz.getProtectionDomain();
final CodeSource codeSource = protectedDomain.getCodeSource();
if (codeSource != null)
{
builder.append("CodeSource: ").append(codeSource.toString());
builder.append(Constants.NEW_LINE);
final URL url = codeSource.getLocation();
builder.append("URL: ").append(url.toString());
}
else // codeSource == null
{
builder.append("CodeSource for ")
.append(clazz.getCanonicalName())
.append(" is null.");
}
return builder.toString();
}


As the code listing above shows, it is a relatively straightforward process to use get a particular object's Class to obtain a ProtectionDomain from which a CodeSource can be obtained. The CodeSource provides the getLocation() and toString() methods that make it really easy to display the classpath locations from which the class definition came.

The code snippet above can be used in a class such as the ClassPathIdentifier class shown next.

ClassPathIdentifier.java


package classpathidentifier;

import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;

/**
* This class reports what entry in the classpath provides the definition of
* the provided Object.
*/
public final class ClassPathIdentifier
{
/** This class is not intended for public consumption. */
private ClassPathIdentifier() {}

/**
* Provides the name of the classpath entry that provides the class definition
* of the provided object.
*
* @param objectInQuestion Object for which classpath source of instance is
* desired.
*/
public static final String getClassPathSource(final Object objectInQuestion)
{
final StringBuilder builder = new StringBuilder();
final Class clazz = objectInQuestion.getClass();
final ProtectionDomain protectedDomain = clazz.getProtectionDomain();
final CodeSource codeSource = protectedDomain.getCodeSource();
if (codeSource != null)
{
builder.append("CodeSource: ").append(codeSource.toString());
builder.append(Constants.NEW_LINE);
final URL url = codeSource.getLocation();
builder.append("URL: ").append(url.toString());
}
else // codeSource == null
{
builder.append("CodeSource for ")
.append(clazz.getCanonicalName())
.append(" is null.");
}
return builder.toString();
}

/**
* Test method to demonstrate use of this functionality.
*/
public static void main(final String[] arguments)
{
if (arguments.length < 1)
{
System.err.println("You must provide a fully qualified Class name.");
System.exit(-1);
}
final String classForSource = arguments[0];
if (classForSource.isEmpty())
{
System.err.println("You must provide a valid string for class path/name.");
}
System.out.println("You provided class of " + classForSource + " ...");

try
{
final Class clazz = Class.forName(classForSource);
final Object object = clazz.newInstance();
System.out.println("Source: " + getClassPathSource(object));
}
catch (ClassNotFoundException classNotFoundEx)
{
System.err.println("Could not find class " + arguments[0]);
}
catch (InstantiationException instanceEx)
{
System.err.println("Unable to instantiate instanceof " + classForSource);
}
catch (IllegalAccessException illegalAccessEx)
{
System.err.println("Illegal Access trying to instantiatite " + classForSource);
}
}
}


It is not exciting, but I include the code listing for the Constants class next for completeness.

Constants.java


package classpathidentifier;

/**
* Constants used in simple example demonstrating one way to determine the
* classpath entry from which a particular instance was specified.
*/
public class Constants
{
/** This constructor is not intended for public consumption. */
private Constants() {}

public final static String NEW_LINE = System.getProperty("line.separator");
}


For this example, I am also using a basic class called SomeClass, which is defined next.

SomeClass.java


package classpathidentifier;

public class SomeClass
{
/** An integer. */
private final int someInt;

/** Some String. */
private final String someString;

/**
* Constructor accepting arguments to populate an instance of me.
*/
public SomeClass(final int newInt, final String newString)
{
this.someInt = newInt;
this.someString = newString;
}

/**
* Provide my integer value.
*
* @return My integer value.
*/
public int getSomeInt()
{
return this.someInt;
}

/**
* Provide my String value.
*
* @return My String value.
*/
public String getSomeString()
{
return this.someString;
}

/**
* Provide String representation of me.
*
* @return My String representation.
*/
@Override
public String toString()
{
final StringBuilder builder = new StringBuilder();
builder.append("Some Int: ").append(this.someInt).append(Constants.NEW_LINE);
builder.append("Some String: ").append(this.someString);
return builder.toString();
}
}


With all of the classes defined above, it is time to turn to an executable class that can drive out use of these APIs. The relatively simple Main class demonstrates the approach of using Class->ProtectionDomain->SourceCode->getLocation() to determine the original source on the classpath of that class's definition.

Main.java


package classpathidentifier;

/**
* Main class that is separate from ClasspathIdentifier class, but uses that
* class.
*/
public class Main
{
/** My instance of SomeClass. */
private SomeClass someClass = new SomeClass(5, "Five");

/** No-arguments constructor doesn't do anything exciting. */
public Main() {}

/**
* Provide access to my instance of SomeClass.
*
* @return My instance of SomeClass.
*/
public SomeClass getSomeClass()
{
return this.someClass;
}

/**
* Main function for running me.
*
* @param arguments Command-line arguments; none expected.
*/
public static void main(final String[] arguments)
{
final Main me = new Main();
printString(ClassPathIdentifier.getClassPathSource(me));
printString(ClassPathIdentifier.getClassPathSource(me.getSomeClass()));
printString(ClassPathIdentifier.getClassPathSource(me.getSomeClass().getSomeInt()));
printString(ClassPathIdentifier.getClassPathSource(me.getSomeClass().getSomeString()));
}

/**
* Print provided String.
*
* @param stringToPrint String to be printed.
*/
private static void printString(final String stringToPrint)
{
System.out.println(Constants.NEW_LINE);
System.out.println(stringToPrint);
}
}


This class demonstrates how this approach works on different classes. When I run this Main class as part of a JAR, the output appears as shown below.



As the above screen snapshot demonstrates, the getLocation() method (and the toString()) provide a URL to the JAR file from which the class was found. The command at the top of the output window shows that this class was indeed in the JAR because that JAR is the only item on the classpath.

The next screen snapshot shows execution of the Main class using the classes directory in the classpath rather than using a JAR.



In this case, we can see that the source of the classpath entries was the directory rather than a JAR file. What happens when both (the JAR and classes directory) are on the classpath? The next screen snapshot demonstrates this with the JAR first and then with the directory first.



The last screen capture indicates that whatever class definition appears first on the classpath (when reading from left to right) is the one used by the class loader for that application.

Finally, you may have noticed that the classes Integer and String from the core Java API have null values for CodeSource.

Conclusion

There are situations when a mismatch of class definitions or multiply defined class definitions cause runtime headaches. In such cases, an approach like that demonstrated in this blog posting can be useful and provide some relief.

Thursday, February 26, 2009

Software Development Atrocities Committed in the Name of Flexibility

Although it is difficult to measure and quantify, most of us have heard and do believe that flexibility is an important part of software development. There are numerous advantages gained from software that is designed and implemented to be flexible and adaptive. However, I think it is worth asking, "Can we have too much of a good thing?"

The human body, in some situations, can indeed have too much flexibility. I think the same is true for software. In this blog posting, I will explain why I believe that we as software developers sometimes allow the desire for extreme flexibility to overshadow more important software characteristics.


Benefits of Flexible Software

There are several benefits to flexible software that have made this flexibility desirable to software developers.

Software Maintenance Benefits

It is a generally accepted observation that software maintenance costs significantly exceed development costs. Therefore, it is sensible to want to make the software as adaptive and flexible to bug fixes and other maintenance activities as possible.

Software Modifications/Enhancement Benefits

Another generally accepted observation in the software development world is that requirements and customer desires can and do change. Again, flexible software is key to dealing with this likely scenario.

Software Reuse Benefits

Advertised benefits of software reuse can sometimes be difficult to realize without significant cost because the original software is not flexible enough to be easily reused outside of its very narrow initial application. The idea here is that one can increase the reusability of one's software by making it more flexible.


Drawbacks of Developing Flexible Software

Software flexibility is generally a desirable characteristic because of the benefits described above. However, this flexibility is often far from free and, in some cases, can even be a detriment.

Higher Initial Cost of Flexible Software

In some cases, it can be significantly more difficult (and correspondingly more expensive) to introduce the desired flexibility into the developed software. In the extreme case, it is definitely cheaper to initially hard-code values all over the place, but we have all learned (usually through hard experience) that the costs of doing this are so great that we should take the time to use properties, XML, or other more dynamic values for our software. This is a case where the flexibility does come at a higher initial cost, but almost always "pays for itself" in the long term. This situation is one in which long-term benefits seem to dwarf the initial higher cost of more flexible software. However, not all situations are the same and there are situations where the long-term benefits may not justify or even cover the initial costs.

YAGNI

Software development projects have a notoriously bad record for not completing on time or on budget. There are several explanations for this as eloquently called out in the software development classic The Mythical Man-Month, but certainly one part of this is the desire we seem to have to add features and flexibility that will likely not need or only remotely may need. Extreme Programming introduced the term "You Aren't Gonna Need It" (YAGNI). This well-known term essentially serves as a reminder that we should not waste time and effort on things that we will never need. As the blog posting Using YAGNI Responsibly reminds us, this does not mean that we should shortchange long-term benefits like flexibility. Instead, we should be more realistic about the ratio of costs to benefits.

Greater Difficulty to Understand

Flexibility can sometimes make the software more difficult to understand or use initially. This occurs when certain techniques that make software more flexible also happen to create more classes, interfaces, and other pieces of code that must be understood.

Less Practical Use

Although appropriately chosen flexibility can increase the overall usefulness of a piece of software, too much or inappropriate flexibility can actually have the opposite effect. For example, a framework or library that is supposed to help improve development productivity will not likely be successful in that goal if it is as flexible as the programming language upon which it is based. To be useful, the framework usually needs to make some assumptions and limit some flexibility.


Examples of Flexibility Gone Wrong

Using Java String Rather than Java Enum for a Constant

A specific example that I have repeatedly observed in which the desire for flexibility has blinded experienced developers is overuse of the Java String. We had to wait a long time to get a Java enum, but the wait was worth it. It is painful to see the enum go unused even in situations screaming for its use. When I ask a developer why he or she is not using an enum rather than a String when the range is finite, the usual answer is something like "It is more flexible. What if I find myself needing to add a new value down the road?" This answer effectively implies that the benefit of being able to add an arbitrary String at any point in the future is worth more than the type safety, readability, comparison performance, and other benefits of the enum. This actually might be the case if the range of values changes frequently or is so large that it feels like it is not finite, but I have heard this argument multiple times for small sets of finite and fixed data with no obvious changes or additions in the near future or in the future at all.

Wide-Open SQL Statements

You don't have to work in software development with databases long to realize the dangers of using dynamic SQL in applications. While allowing any arbitrary string to be executed against the database is certainly more flexible, it is also far more dangerous and unpredictable. In fact, errors related to this kind of thinking are included in the CWE/SANS Top 25 Most Dangerous Programming Errors. Although it seems obvious that one should not do this, it is an example where enthusiasm for extreme flexibility could lead one astray and blind him or her to the downsides.


The Flexibility Continuum

Because flexibility in software is generally a desirable quality, the tricky part is knowing how much flexibility to add to a piece of software for long-term benefits without running up extraordinary costs or creating something too complex to maintain or use. Part of the difficulty is that the appropriate degree of flexibility is difficult to identify because it depends on context and because it depends on the often unpredictable future. Experience improves our ability to predict when the extra effort to add flexibility will pay off, but we cannot expect to always be correct. Sometimes, we will plan more flexibility than is actually needed while at other times we may wish we had spent a little more time making our application more flexible. Still, I think it is better to use our best engineering judgment when deciding how flexible to be than to blindly go to one extreme (no flexibility) or the other (complete flexibility at all cost).

In general, "throw-away" code such as demonstration code or prototypes will require less flexibility while larger and longer-term applications will require much greater flexibility. The longer an application is in production and use, the more likely that users will want new features and changes. Frameworks and libraries intended to be used by applications tend to need much greater flexibility than end applications that are not intended to be used as part of another application. Even with these guidelines, deciding on the exact level of flexibility for a given software project is still difficult due to the largely unforeseeable future events

It seems that sometimes we see extremism in which the developer does not believe in any flexibility, hard codes everything, doesn't design for extensibility, and generally makes software nearly impossible or extremely costly to even slightly enhance. However, the opposite extreme is to spend undue time and effort to obtain unnecessary flexibility and to sacrifice other software benefits to obtain that flexibility.


Flexibility's Best Uses

Where we choose to apply flexibility is an important consideration. Flexibility tends to be most useful if it is at an architecture or design level. Low-level code is almost always easier and cheaper to change than architectural concepts. Many good practices will naturally lead to greater flexibility while at the same time delivering other benefits. For example, modularity can make code easier to understand while at the same time increasing code's flexibility. Extensibility can be a benefit now and in the future. In fact, extra effort to justify additional flexibility is easiest to justify when we can realize benefits of that flexibility both now and in the long-term.

The worst time to expend significant resources on flexibility is when that proposed flexibility has minor and unlikely benefits now or in the future. What is especially frustrating is when one exerts significant time and effort for a level of flexibility that is truly unattainable or unrealistic, but wastes time and effort trying to achieve it anyway.


Conclusion

It is generally a good idea to design and implement our software to be extensible, maintainable, and flexible. However, even flexibility can be taken to an extreme where we spend inordinate amounts of time, money, and effort to design and write the software features that may never be needed and we may even end up with something too flexible to be used practically. Software development is filled with trade-offs and the degree of flexibility we should employ in our applications is a trade-off with the amount of time and resources to spend to gain that degree of flexibility.

Flexibility is a necessary characteristic of any software application of long term significance, but the desire for extreme flexibility does not justify ignoring all other desirable software characteristics. Depending on the context, duration, and future use of a software application, flexibility can be anywhere from a highly desirable characteristic to a necessary characteristic. However, flexibility must not be the excuse for over-engineering, over-designing, or over-complicating an application; or the excuse for indulging in a software development guilty pleasure; or for making a software project go over time and budget. Above all, the ability to easily change our software for something that might happen in the future should not limit our ability to deliver what is needed and desired today.

Monday, February 23, 2009

Small Java 7 Language Changes

Project Coin is the name of the OpenJDK work covering small language changes for Java SE 7. The current Java.net poll question asks which of the proposed Project Coin features is most interesting. I often like to gauge the interests of the Java developer community based on these poll questions and their results. In this case, I am not going to analyze the results because, at the time of this writing, the vote total is just over 100. Instead, I am going to describe what each of the proposed features are and what my own level of interest in each is.

The choices to vote for to answer the question of which Project Coin feature is most interesting are: switch statement support for Strings, ability to catch multiple exceptions with the same catch clause, using type parameters for more concise constructors, call methods with exotic names, bracket notation for collections, and any feature not already listed. I will now briefly summarize each of these features and state my own level of interest in each feature.


Strings in Switch Statements

There was a time when I really wanted this feature. In fact, I have even written about this feature in the ActionScript language and compared it to Java. This feature is less important to me now that we have the powerful and typesafe enum. That being said, I know several Java developers who prefer Strings because of greater flexibility. For them, switching on String would help them avoid long if-then-else blocks.

For me, I generally find that I only really use switch for things that are finite and for which individual differences are more frequent than similarities. In other words, in many cases, if something needs such flexibility that it is better supported by Strings than by Enums, then it is typically the case that I don't need to switch on individual values anyway.

Many people have expressed interest in having the ability in Java to switch on Strings. Accounts of this interest are available in Java Switch Statements Should Allow Strings, Not Just Ints, A Switch on String Idiom for Java, Java String Switch, and Switch on String in Java.

In the end, I have a slight preference toward the ability to switch on Strings, but the emphasis is on slight.


Multi-Exception Catch

This is another "small change" that many Java developers have requested. For example, the blog posting Wanted: Multiple Exception-type Catch Blocks talks about why this would be useful. This feature is described in Alex Miller's section on the Improved Catch Clause.

I have run into the situation more than once when it would be nice to catch multiple exceptions and handle them with the same exception handling code. I have found this to be especially true when using older libraries and frameworks that make use of large sets of checked exceptions. For example, in working with Remote JMX, there are many common checked exceptions one encounters. The developer is usually forced to either catch a very general exception to handle all of them or to list each one out individually to handle them differently. Being able to combine two or three closely-related JMX exceptions in the same handling block would be handy.

Even with the benefits described above, this is still a feature for which I only have a slight preference. With the trend toward unchecked exceptions except for things that can really be expected to be handled, I have run into this problem far less. Also, there seems to be a trend for frameworks to use exception hierarchies and I can often catch the parent exception for general exception handling for that API or framework.


Bracket Notation for Collections

This feature refers to the ability to reference a particular item in a Collection with square brackets similar to how Arrays are accessed. Shams Mahmood makes a persuasive argument for a similar feature (instantiation of a collection like an array) in his blog posting My Java 7 Wishlist Regarding Collections. In the blog posting Double Brace Intialization, Isa Goksu describes how double curly braces apply an anonymous inner class and obtain a similar effect. He also points out multiple issues with this approach. The Java Idioms site covers this double brace initialization approach in even greater detail.

The argument for the ability to treat Collections more like arrays is that this syntax is easier and more concise. According to this argument, Collections would be even more widely accepted and used instead of arrays if Collections had this array-like syntax. This is another feature that could be handy, but I only have slight preference for.


Concise Constructors with Type Inference

This feature would allow the compiler to understand the generic types being used in a constructor based on the newly instantiated object's data type rather than necessarily needing to redeclare the generic type as we do today. The pain associated with this redundant type information is lessened by today's powerful IDEs. That being said, it also seems sensible that a statically typed language like Java could take advantage of the fact that it knows the generic type on the left side of the equals sign to imply what static types are used on the right hand side of the equals sign.

It's become a tiresome theme, but this is another feature that I won't mind having, but also won't lose any sleep over not having. Again, I have only a slight preference for the addition of this feature.


Exotic Method Name Calling

The aim of this feature request is for Java to allow methods to be called in non-Java languages. Many of these non-Java languages allow their methods to have characters not supported in Java method names. While this would be of the least benefit to me in the short-term, I could see this feature providing the greatest long-term benefit as it is likely that we'll see the trend toward mixed language use continue to grow.


Conclusion

It is not surprising that "small language changes" tend to be, for me at least, also smaller in terms of enthusiasm and excitement. Of course, I also don't have strong feelings from a negative perspective on these small changes. If all of them were implemented, I would occasionally benefit. If none of them were implemented, I'd only occasionally miss them.

One other observation that can be made from looking at these Project Coin changes is that many of them meant more to me in the past, but the passage of time and improving language features have reduced my degree of interest in these features. The long-awaited arrival of the Java enum, the rise of the powerful Java IDEs, and other advancements have reduced the urgent need for these changes to some degree. The one exception to this is the exotic method name support, a feature for which need is actually relatively new and is likely to grow rather than diminish.

The final personal observation from this is that, at least for the small things, the Java language is very mature and there are very few small things that I have a strong longing for. In other words, I'm pretty happy with the Java programming language generally.

Tuesday, February 17, 2009

Day-to-Day Java Development Tools and Techniques

There are some common things that are useful to know in many day-to-day Java development activities. It is especially helpful for someone new to Java development to know where to find this information, but I have found bookmarking these sources to be useful even as I have gained experience developing Java applications. Because one of the primary purposes for me writing a blog is to provide myself with an easy way to find things I am looking for, I am using this blog posting to collect some of these sources of information that I frequently use for Java development in one place. Because these items are related to the development of Java applications rather than to source code, it is not surprising that many of the items are specific to the JVM I am using.


Java Processes: jps

There are many times in Java development when it is important to know which Java processes are running. More specifically, I find myself needing the process ID of Java applications for running other tools against those processes or for terminating processes. There are several Sun JDK development tools, but one of my favorites is the jps tool (JVM Process Status Tool). This "experimental" tool lists the Java processes running on the target HotSpot JVM. As I previously blogged, my favorite use of this tool is jps -lm.


JVM Arguments

Java Application Launcher

The environment a Java application runs in can be significantly tweaked via the use of JVM arguments. In addition, JVM arguments allow for different levels of monitoring and analysis of the executing Java application. The command java -help lists the standard options (standard across different JVM implementations) for the Java application launcher. The command java -X can be used to see the Java application launcher's non-standard (X for extension specific to that JVM) arguments. In the HotSpot JVM, some frequently used extension arguments are -Xms and -Xmx for initial Java heap size and maximum Java heap size respectively.

The -Xbootclasspath option can be used to either prepend (/p) or append (/a) resources to the bootstrap classpath.

If you wish to detect which JVM arguments your currently running Java application is using, you can use the ManagementFactory.getRuntimeMXBean().getInputArguments() call as described in Accessing JVM Arguments from Java. This technique takes advantage of Platform MXBeans available since J2SE 5 (custom MXBeans support was added in Java SE 6).

Two useful sources of information on the JVM parameters available when using Sun's JVM are A Collection of JVM Options and Charles Nutter's Favorite Hotspot JVM Flags. Both of these resources list and describe some/all of the not-recommended-for-the-casual-developer double X arguments (-XX) that are available.

Java Compiler

The javac Java compiler also has command-line arguments that can be of great use. Like the java application launcher, the javac compiler that comes with the Sun Java SDK includes both standard options and non-standard/extension options. These options are displayed in a manner consistent with that used for the application launcher. Non-standard options include bootstrap classpath append and prepend options, setting of endorsed standards path, setting of directory of installed extensions, and enabling and disabling of specific warnings (-Xlint options including -Xlint:path).


Warnings

-Xlint

The warnings reported by the Java compiler can be very useful in identifying things that either may be larger current problems than one realizes or could easily turn into more significant problems. Sun's javac compiler allows one to take relatively granular control of which warnings are enabled and disabled using -Xlint (all warnings are reported when this is used by itself). Specific warnings can be reported by providing the type of warning after the -Xlint: notation. If no reports of warnings are desired (other than those the Java Language Specification requires), the notation -Xlint:none is used.

@SuppressWarnings

One can use the @SuppressWarnings annotation introduced with J2SE 5 to mark in code the warnings that should not be reported when the code is compiled. However, a natural question is which specific warnings can be suppressed in-code using this annotation. It turns out that this is compiler-specific. For Sun's compiler, the available warnings that can be suppressed with @SuppressWarnings are listed here and here.


Java Classpath Issues

Classpath Basics

The Java classpath can be one of the most confusing things for a new Java developer. The classpath can become a complicated mess even for experienced developers when different issues arise due to different classloader behaviors, the presence of slightly different versions of libraries on the classpath, and incorrectly typed classpaths. Fortunately, there are several tools to help understand and better work with the classpath.

For those just learning Java and Java classpaths, a good starting point is to read Elliotte Rusty Harold's articles Managing the Java Classpath (Windows) and Managing the Java Classpath (Unix). These articles provide a good overview of the options one has for setting a classpath, why dynamically setting the classpath is preferred over using an environment variable, and provides the basics of how classpaths work with Java packages.

Because the Sun Java compiler will ignore an entry on the classpath that it cannot resolve, it is easy to think that one has correctly typed in a classpath entry even if it is incorrectly typed. The -Xlint:path extension option instructs the Java compiler to report any classpath entries that cannot be resolved.

The JARs, .class files, and other resources specified on a command-line classpath using -classpath or -cp are typically not the only resources on an application's classpath. Other sources of classpath information that must be considered include the standard Java classpath (for standard Java classes), jre/lib/ext, and jre/lib/endorsed (uses bootstrap classpath). In addition classpaths may be different when using an IDE and are different when using web servers and application servers (classpath is typically determined by the contents of the WAR file and EAR file in those cases).

ClassNotFoundException Versus NoClassDefFoundError

One thing that can be a little tricky when first learning Java is distinguishing between the ClassNotFoundException and the NoClassDefFoundError. The Javadoc API documentation for each of these explains their use and why they might occur. In most cases, the easy way to differentiate between the two is that the ClassNotFoundException indicates that a class needed for compilation cannot be found on the classpath and a NoClassDefFoundError indicates that the matching class that was found at compile time cannot be found at runtime. This differentiation between compile time and run time can be useful in figuring out when the classpath entry is missing.

It is also interesting to note that while ClassNotFoundException is a checked exception extending Exception directly, NoClassDefFoundError is actually an Error rather than an Exception. Note that ClassNotFoundException can actually be encountered during runtime in a variety of situations such as the runtime on-the-fly compilation of JavaServer Pages, reflection, and, as the API states, "when an application tries to load in a class through its string name." Generally speaking, the causes of NoClassDefFoundError are more diverse and difficult to resolve than those of ClassNotFoundException.

Some interesting and in-depth articles on class loading are available in the Demystifying Class Loading Problems series. Other references regarding the difference between these two exceptions are available at Difference Between ClassNotFoundException and NoClassDefFoundError, What is the Difference Between ClassNotFoundException and NoClassDefFoundError?, Java Fanatics: NoClassDefFoundError versus ClassNotFoundException, and ClassNotFoundException and NoClassDefFoundError.

UPDATE (2 March 2009): Identifying an Instance's Original Classpath Definition

UPDATE (2 March 2009): This subheading and entire paragraph have been added since the original post. Some of the NoClassDefFoundErrors one might run into can be traced to multiple definitions of the same class on the classpath with slight differences. One way to see which class definition a loaded class is using is described in another blog post of mine.



System Properties

Java provides some standard properties that can be used for several different benefits. An often used property from this set include line.separator for a platform-independent reference to a new line. It is not easy to remember all of the available system properties, especially those that are not used often. Fortunately, several resources either list these or provide code examples of how to see a list of them. For example, Java Standard System Properties lists them, How to Print All the Java System Properties demonstrates how to programmatically list them, and Java: System Properties both demonstrates how to get the properties via code and lists them. The Javadoc-based API documentation for System.getProperties() lists the system properties that are always available. I've even been known to blog on properties before.

The Platform MXBean RuntimeMXBean provides a RuntimeMXBean.getSystemProperties() method that can be used to see the system properties as well.


View Swing GUI's Hierarchy with CTRL-SHIFT-F1

A nifty trick with Swing-based applications is the ability to use CTRL-SHIFT-F1 to see the Swing GUI's hierarchy. This is further demonstrated and explained in the Tech Tip Ctrl-Shift-F1 in Swing Applications.


serialver

The command-line serialver tool is useful for generating servialVersionUID attributes on classes that implement the Serializable interface. I have blogged previously on the serialver tool.


jar Tool and JAR Files

jar Tool

With the prevalence of IDEs and Ant and Maven for building Java code, it is easy to forget about the jar command. However, knowledge of the jar command can be useful for writing and running simple tests and examples. One of jar's characteristics that makes it most useful is the fact that it uses the ZIP compression format and uses similar syntax to the tar command. The versatile jar command can even be used to display the contents of an Adobe AIR .air file.

Executable JAR Files

JAR files can be made executable so that they can be run with a command line java -jar someJar.jar without the need to specify classpath information or the main executable class in the JAR. The classpath and the main class to execute do not need to be explicitly stated because they are embedded in the executable JAR's manifest file with the Class-Path and Main-Class name/value pairs respectively. There are a few details to be aware of when using executable JARs (such as specifying the class path entries via directories relative to the location of the executable JAR file) and these details are covered in the blog posting Executable Jar File in Java.

JAR Manifest File Information

You can place essentially any name/value pair in a manifest file on its own line. While virtually any names and values can be used, there are some standard and accepted manifest name/value pairs one might wish to use. These include Class-Path, Main-Class, package version information (Specification-Title, Specification-Version, Specification-Vendor, and implementation equivalents). The Manifest file is also used to seal packages in JAR files. See also the Wikipedia entry on Manifest File for more details.


JVM JMX Instrumentation

The JVM itself has been instrumented with Java Management Extensions (JMX) support since J2SE 5. This provides valuable information regarding the JVM and applications running in the JVM. Sun provides JConsole (since J2SE 5) and VisualVM (since Java SE 6 Update 7) with their SDK for easy developer monitoring of the JVM and its deployed applications.

Platform MXBeans have been provided with the Sun JVM since J2SE 5 and provide a wide variety of details regarding the JVM. Platform MXBeans provide information on JVM topics such as thread contention, operating system details, memory analysis, and logging management. As described earlier, the RuntimeMXBean provides interesting information such as the classpath in effect, the boot classpath, system properties, and JVM vendor and specification details. The available Platform MXBeans are described in greater detail in Using the Platform MBean Server and Platform MXBeans.

Java EE application servers also provide information via JMX.


UPDATE (18 February 2009) Generating a Stack Trace

UPDATE (18 February 2009) Eyal Lupu reminded me (see feedback) of a very handy tool during debugging (especially when processes are hanging). Forced generation of a stack trace with a SIGQUIT, CTRL+\, or CTRL-BREAK (Windows) is described in greater detail in An Introduction to Java Stack Traces.


Documentation

Some of the Java documentation resources that I use most often include the overall JDK 6 Documentation (includes links to many of the other documents referenced in this blog posting), the Java SE 6 API documentation, the Java EE 5 API documentation, and specialized documentation such as the Spring Reference Manual and the Oracle Technology Network JPA Annotations Reference. Perhaps my favorite tool for finding useful documentation is the Google search engine.

Saturday, February 14, 2009

Classic Movie Quotes Applied to Software Development



UPDATE (9 March 2009): This posting has been referenced and quoted in the CNN Entertainment article You Talkin' to Me? Film Quotes Stir Passion.




In this blog posting, I look at some classic movie quotes that can apply to software development. In several cases, I have actually heard them used in software development situations. In general, these movie quotes are from movies I like (or at least have seen) and can be applied to software development. It is not all that surprising that the movie quotes that we all seem to be able to relate to also relate specifically to software development.


1. "What we've got here is failure to communicate."

This quote from 1967's Cool Hand Luke (#11 in AFI's Top 100 Quotes) summarizes one of the most common problems facing software developers. Problems with communication can plague all stages of software development from learning customer requirements to development to testing to product delivery. In fact, a large percentage of the most significant problems I have seen in large software development projects can be traced back in some degree to a break-down in communications. These include things like redundant work being done, interfaces and contracts not being met, misunderstandings about requirements and expected functionality, etc.


2. "You're gonna need a bigger boat."

This quote (#35 in the AFI Top 100 Quotes) from the 1975 movie Jaws was the perfect quote for representing this movie. Jaws is a fantastic suspense movie with an understated, Hitchcock-like building of suspense throughout the movie mingled with briefly intense scenes and highlighted with John Williams' famous and famous two-note music. This quote seems understated at first glance, but really does sum up the plight of the main characters and their dangerous situation with this greatest of Great Whites. It also serves as a great transition from the extraordinary fear built up through imagination of what the shark must look like to new scenes where the shark is visible.

We often run into our own situations like this in software development. We often find ourselves needing more memory, more disk space, more bandwidth, or more of other types of resources to do our jobs and to maintain customers' experiences. There are numerous well-known and real-life examples of this including the inability to purchase Colorado Rockies World Series tickets and the initial server overload for JavaFX 1.0 downloads.


3. "Show me the money!"

This quote from the 1996 movie Jerry Maguire (#25 in AFI's Top 100 Quotes) is one most of us can easily relate to. With current economic times like they are, this may mean more than ever to us. The fact that money is at the root of so much that is motivating is also a reason that it is likely that the "free speech" part of open source will remain as important or more important than the "free beer" part of open source in the future. While there are many great open source products that are used without charge, many significant open source projects are run by organizations that (not undeservedly) expect to earn some revenues from their association with these products and related services. Examples include SpringSource, Sun, and many others.

This quote almost makes up for the other well-known quote in that movie: "You had me at 'hello'" (#52 in AFI Top 100 Quotes).


4. "A person is smart. People are dumb, panicky dangerous animals and you know it."

The 1997 movie Men in Black is full of great quotes including this one. Edwards (soon to be Jay) is asking Kay why the secret Men in Black don't tell the ordinary people of Earth about the aliens living among them. This quote is Kay's explanation and it often applies in software development as well.

It is easy in our rush to stay current and relevant to make poor choices that we would not do individually when given the opportunity to think rationally about the situation. The rush to apply EJB 1.x/2.x where it wasn't needed is one example of this.

Terms such as mob mentality, herd behavior, and peer pressure largely have negative connotations because they often imply allowing poor judgment based on group thinking to override potentially clearer and superior individual judgment. I have written in a previous blog posting about The Lemming Effect and The Emperor's New Clothes Effect in software development. Both of these dysfunctional software development motivations are related to negative group think.


5. "Houston, we have a problem."

This is a momentous quote (#50 in AFI's Top 100 Quotes) in a terrific movie (1995's Apollo 13) based on real events (the actual Jim Lovell quote was "Houston, We've had a problem."). It is now used all the time to indicate a (usually) less serious problem than when it was originally used. For example, see this completely unrelated example. Because software and hardware surprises us all the time and then we throw our own human-caused errors into the mix, we seem to get many opportunities to apply this quote. The calm coolness portrayed by Tom Hanks in the movie and the power of many dedicated engineers in Houston working on the problem are a reminder of how best to solve problems and are an inspiration. Lovell has called that Apollo 13 mission "a successful failure."


6. "I had to keep digging ... without a shovel."

This quote comes from the 1985 movie Fletch. It sometimes feels like we in the software development community find ourselves in situations in which we are tying to identify and resolve a nasty bug without the appropriate tools. This can be especially likely in cases such as runtime logic errors, in multi-threaded environments, and when using languages that are too new (or too old) to have good debug tool support.


7. "My Precious"

With the exception of a few things that really bothered me (most notably the mistreatment of Faramir's character as having seemingly less integrity than in the books), I generally enjoyed the 2001-2003 adaptation of J.R.R. Tolkein's The Lord of the Rings trilogy. I thought that the character Gollum was particularly well done. The movie version of Gollum wanted The One Ring as badly as the book version did in my imagination.

In software development, it is good to take ownership of things, have pride in what we do, and instill craftsmanship into our work. However, we can take it too far to where we refuse to admit anything is wrong with what we've done or insist ours is the only way to go. If I work long and hard on piece of code and later find out that it is either being replaced by an alternative or not being used altogether, it is easy to start acting greedily and with distrust like Gollum. It is not easy being told your brainchild is ugly, but sometimes it just might be. This quote earned #85 in AFI's Top 100 Quotes.


8. "You fell victim to one of the classic blunders."

The complete quote (not listed in the header due to its length) from the 1987 movie The Princess Bride is: "You fell victim to one of the classic blunders. The most famous is: 'Never get involved in a land war in Asia.' But, only slightly less well known is this: 'Never go in against a Sicilian, when death is on the line!'"

It is difficult to think of a movie with more quote-worthy lines than this one. I chose this particular quote from this movie because we are all aware of some of the classic software development blunders such as copying and pasting identical code in multiple places, hard-coding values, swallowing exceptions rather than handling them, etc., but there continues to be enough people committing these blunders to lead to numerous blog postings, articles, and discussions on the blunders. Steve McConnell has collected three dozen higher-level classic blunders in his Classic Mistakes Enumerated.


9. "I think all you need is a small taste of success, and you will find it suits you."

I have blogged before about the importance of confidence in software development. In this quote from the 1985 movie Better Off Dead, Monique is explaining to the rather pathetic Lane the importance of having a little success to gain confidence and a real desire to work to achieve more of the same success. This seems like good advice for all of us, but I think it is especially useful for new software developers. It can be overwhelming to start working with much more experienced software developers, but a small taste of success early on can be very helpful and lead to a long career full of successes. This is also a reminder to more experienced and senior developers that we can help those who are new to development to get a taste of success.

This is another quote-filled movie with "I want my two dollars" not the least among them.


10. "Frankly, my dear, I don't give a damn."

This quote, which earned the top spot in AFI's Top 100 Quotes occurs at a point in the 1939 epic Gone with the Wind when it is very easy to understand this sentiment coming from the Rhett Butler character. It is equally easy to sometimes find ourselves feeling the same way. In fact, it is sometimes good to give up worrying about the littlest of things and let some things go. In particular, I have seen situations in which someone with no formal power but high degrees of expert power continually fight against those with formal power (such as managers and clients). These are almost always losing causes.

While valid discussions and even technical disagreements are useful in coming to the best solutions, there are times when the fight is not worth the cost. This is especially true in situations where multiple recommendations are sufficient and it is only a matter of which one is slightly preferable to the others. I have witnessed numerous situations in which the debate and delay in beginning implementation of a solution has taken ten times longer than the difference of development time between two competing options.

I have observed that effective software developers do care deeply about their work and the product they create. That being said, the most effective of these effective software developers also know when to pick their battles and when to just let it go because it's not worth it.

Another Gone with the Wind quote that fits well is Scarlett's words, "After all, tomorrow is another day!" (#31 on AFI Top 100 Quotes). This is good advice because bad things often aren't as bad the next day as they are the day they happen.


Conclusion

In this blog posting, I have looked at the quotes from ten different movies that apply to software development even though none of the movies listed were specifically focused on computers or software development. In fact, while I enjoy many of the computer-oriented movies such as War Games (1983), it is also true that many of these are completely unrealistic and the computer is often the bad guy. If nothing else, I hope to use this blog posting to prove to others that watching movies is not a waste of time. I'm going with the story that watching movies actually makes me a better software developer. It's time now to go watch Star Wars. May the force be with me (#8).

Thursday, February 12, 2009

Thankful for User Groups

As the Rocky Mountain Oracle Users Group (RMOUG) Training Days 2009 was wrapping up, I couldn’t help but think about this event that the RMOUG volunteers pull off each year. That thought naturally led to thoughts of other users groups that I have benefited from and to a renewed appreciation for the volunteers that make these user groups successful. As I blogged about previously, I believe that Java-related users groups are one of the Java resources that were missed in this article on resources for newer Java developers. These user groups can provide significant benefit to more experienced developers as well.

RMOUG’s annual Training Days conference provides an example of what many user groups could become, but only at the cost of countless volunteer hours. This year’s edition of Training Days was the 18th version (my tenth time attending and eighth time presenting). While all the editions that I have attended have been full of insightful speakers and informed colleagues and fellow attendees, there has been a definite increase in recent years in the number of “big names” presenting at RMOUG Training Days. Dan Norris, a well-known Oracle DBA himself, commented on this in his blog.

When I look at RMOUG’s success in turning this local/metro conference into a regional success and then into a national success and now into an international success, I believe there are some lessons learned regarding what it would take other user groups to get to this point. RMOUG Training Days attracts some of the biggest names in the World of Oracle.


Consistency over Time

One explanation for RMOUG’s success in attracting the heavy hitters of the Oracle world is the long tradition of its successful conferences. The consistency of the conference to provide quality training related to Oracle at a very low cost has led to a well-deserved reputation that seems to grow each year.


Hours and Hours of Volunteer Activity

Another reason that RMOUG has been so successful is the dedicated volunteers that make the organization run. I see this too in the people who run other local users groups, but RMOUG seems to enjoy the benefits of more of these people being actively involved. I put much effort and significant hours into preparing for my RMOUG Training Days presentations. However, I realize that even the volunteers who do not present may spend that many hours on the organization. Furthermore, many of the board members and other most active volunteers also present.

Speakers who are consultants and/or authors do often have at least an outside chance of some monetary gain from speaking; they may be able to indirectly advertise their consulting services or books to the audience that is interested in that topic. However, many volunteers have no expectations of this type of compensation either because they don’t provide consulting services or because they don't have a book or because they are not in a position to advertise that if they did. That being said, it is also worth noting that most consultants and authors would likely not present if the sole purpose of presenting was financial gain. There are usually easier ways to achieve that. Typically, they also want to present to share their knowledge.


Don’t Forget the Locals

While it is a huge benefit to have the prominent Oracle experts present and share ideas, I believe that the strongest user groups rely heavily on the local practitioners as well. For one thing, it is often the local practitioners who provide consistent quality over time to get the attention of non-local experts. It is also the local practitioners who can attend regular meetings that are not as large or well-attended as Training Days. Of course, no user group can succeed without the countless hours provided by the local volunteers. Finally, there is a really nice personal touch to knowing people in the field who live and work in the same general area. It is also worth noting that user groups in metropolitan areas with strong technology sectors enjoy locals who are well-known experts.


Don’t Forget the Little People

As mentioned before, it is a particular benefit of Training Days to meet and hear presentations from some of the most well-known people in the Oracle community. However, I have heard some remarkably thought-provoking presentations from people who are not well-known. In fact, even with a large number of well-known experts attending, a conference as large as RMOUG Training Days requires interesting local practitioners to provide the wide breadth and depth of topics.


The Significance of Sponsors

Sponsors can also make a user group meeting or conference more successful. Sponsors typically pay for the right to advertise and that offsets some of the cost to the participants. The usual trade-off model applies here: more advertising means lower costs to the end user.


Nothing Is Free

I have attended many great presentations in conjunction with several local users groups, but RMOUG definitely seems to be the most successful in terms of participants and clout. I believe that RMOUG’s success has not come easily or without significant sacrifice. The sacrifice of time, resources, and sharing of talents and knowledge by many dedicated individuals has helped RMOUG and its annual training extravaganza to become what it is today.

Monday, February 9, 2009

Flex: Proxied HTTPService and REST

My article Java EE and Flex: A compelling combination, Part 2 was published on JavaWorld last week. In that article, I briefly discussed some of the extra features that BlazeDS adds to HTTPService beyond what is support with Flex's HTTPService out of the box without BlazeDS.

I have previously blogged on some of these advantages of HTTPService with BlazeDS. In this blog posting, I plan to focus on something outside of the scope of both the article and previously blog posting: how BlazeDS allows the Flex HTTPService to be used with HTTP methods other than GET and POST.

In the JavaWorld article, I wrote the following: "Another advantage of using HTTPService in conjunction with BlazeDS is that you can use HTTP methods beyond GET and POST (the only two supported in HTTPService without the proxy service)." I will use the remainder of this blog posting to expand on this and illustrate this with examples.

To illustrate the differences between HTTP methods supported by non-proxied HTTPService (out-of-the-box without BlazeDS) and proxied HTTPService (with BlazeDS), I have put together a very simple Flex application that connects to a back-end HTTP-exposed server using both non-proxied and proxied HTTPService clients. The main MXML source code for this simple illustrative example is shown next.

FlexHttpClient.mxml


<?xml version="1.0" encoding="UTF-8" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:dustin="components.*"
width="800" height="500"
applicationComplete="invokeServer('GET');">

<mx:Script>
import mx.controls.Alert;
import mx.events.ItemClickEvent;
import flash.events.MouseEvent;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.utils.ObjectUtil;

include "includes/HttpMethodHandling.as";
include "includes/ResponseCodeHandling.as";
</mx:Script>

<mx:HTTPService id="httpServiceProxied"
useProxy="true"
resultFormat="object"
destination="DefaultHTTP"
fault="faultHandler(event);"
result="proxiedResultHandler(event);">
<mx:request>
<id>5</id>
</mx:request>
</mx:HTTPService>

<mx:HTTPService id="httpService"
useProxy="false"
resultFormat="object"
url="http://localhost:8080/RESTfulFlex/httpServer"
fault="faultHandler(event);"
result="nonProxiedResultHandler(event);">
<mx:request>
<id>5</id>
</mx:request>
</mx:HTTPService>

<mx:HTTPService id="httpServiceResponseCodes"
useProxy="false"
resultFormat="object"
method="GET"
url="http://localhost:8080/RESTfulFlex/responseCodes"
fault="responseCodesFaultHandler(event);"
result="resultCodeHandler(event);">
<mx:request>
<requestedCode>{desiredHttpCode.text}</requestedCode>
</mx:request>
</mx:HTTPService>

<mx:HTTPService id="httpServiceResponseCodesProxied"
useProxy="true"
resultFormat="object"
method="GET"
destination="DefaultHttpResponseCode"
fault="responseCodesFaultHandler(event);"
result="proxiedResultCodeHandler(event);">
<mx:request>
<requestedCode>{desiredHttpCode.text}</requestedCode>
</mx:request>
</mx:HTTPService>

<mx:TabNavigator id="tabs" width="750" height="450">
<mx:Panel id="mainPanel"
title="Flex HTTPService Demonstrated"
label="HTTPService Demonstrated">
<mx:Form>
<dustin:ProxySelectorFormItem label="To Proxy or Not To Proxy?"
selectorHandler="setProxyStatus" />
<mx:FormItem label="Select HTTP Method">
<mx:RadioButtonGroup id="method" itemClick="invokeHttpMethod(event);"/>
<mx:RadioButton groupName="method" id="get" label="GET"/>
<mx:RadioButton groupName="method" id="post" label="POST"/>
<mx:RadioButton groupName="method" id="put" label="PUT"/>
<mx:RadioButton groupName="method" id="remove" label="DELETE"/>
<mx:RadioButton groupName="method" id="options" label="OPTIONS"/>
<mx:RadioButton groupName="method" id="trace" label="TRACE"/>
</mx:FormItem>
<mx:FormItem label="HTTP Method Invoked">
<mx:Label id="serviceResults" />
</mx:FormItem>
</mx:Form>
</mx:Panel>
<mx:Panel id="responseCodePanel"
title="HTTP Response Codes"
label="HTTP Response Codes">
<mx:Form>
<dustin:ProxySelectorFormItem
label="Proxied?"
selectorHandler="setResponseCodesProxyStatus" />
<mx:FormItem label="Desired Return Code">
<mx:TextArea id="desiredHttpCode" />
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Submit Desired Response Code"
click="invokeHttpResponseCodes(event);"/>
</mx:FormItem>
<mx:FormItem label="Returned Text">
<mx:Text id="returnedHttpResponse" />
</mx:FormItem>
</mx:Form>
</mx:Panel>
</mx:TabNavigator>

</mx:Application>


The above MXML file contains most of the layout for the simple application and includes the configuration of the proxied and non-proxied instances of HTTPService. You may have noticed that there are actually four instances of HTTPService. Two instances are the proxied and non-proxied instances for testing the different HTTP methods while the other two instances are the proxied and non-proxied instances used to test handling of HTTP response codes. I will not cover the latter two in this post, but plan to cover response code handling in a future post.

I intentionally placed the static layout MXML code in the file above. I factored the event handling code, written in ActionScript, into two separate files that are included by the MXML code above. These two ActionScript files are shown next.

HttpMethodHandling.as

/** true if proxied service is to be used; false otherwise. */
[Bindable] private var proxiedService:Boolean = false;

/**
* Invoke HTTPservice with HTTP method specified by parameter.
*
* @param httpMethod HTTP method to be used.
*/
private function invokeServer(httpMethod:String):void
{
if (proxiedService)
{
httpServiceProxied.method = httpMethod;
httpServiceProxied.send();
}
else
{
httpService.method = httpMethod;
if (httpMethod == "POST")
{
const dummyObject:Object = { "key" : "value" };
httpService.send(dummyObject);
}
else
{
httpService.send();
}
}
}

/**
* Handler for HTTP method selected from radio button group
*
* @param event Event associated with clicking of radio button to select HTTP
* method.
*/
private function invokeHttpMethod(event:ItemClickEvent):void
{
serviceResults.text = "Loading ...";
const selectedHttpMethod:String = event.currentTarget.selectedValue;
invokeServer(selectedHttpMethod);
}

/**
* Handler for radio button group used to determine if proxied or non-proxied
* HTTPService is to be used.
*/
private function setProxyStatus(event:ItemClickEvent):void
{
const proxyStatus:String = event.currentTarget.selectedValue;
proxiedService = (proxyStatus == "BlazeDS Proxied");
}

/**
* Fault handler for faults encountered during a service call.
*
* @param event Fault Event needing to be handled.
*/
private function faultHandler(event:FaultEvent):void
{
serviceResults.text = "Failure trying to access service.\n"
+ event.fault.faultString + "\n" + event.fault.faultDetail;
}

/**
* Results handler for result of proxied HTTPService invocation.
*
* @param event Result Handler for proxied HTTPService call.
*/
private function proxiedResultHandler(event:ResultEvent):void
{
serviceResults.text = ObjectUtil.toString(httpServiceProxied.lastResult);
}

/**
* Results handler for result of non-proxied HTTPService invocation.
*
* @param event Result Handler for non-proxied HTTPService call.
*/
private function nonProxiedResultHandler(event:ResultEvent):void
{
Alert.show("Non-Proxied Result Handler Accessed!");
serviceResults.text = ObjectUtil.toString(httpService.lastResult);
}



ResponseCodeHandling.as


/** true if proxied service is to be used; false otherwise. */
[Bindable] private var responseCodesProxiedService:Boolean = false;

/**
* Handler for invoking of response codes service.
*
* @param event Event associated with clicking of radio button to submit
* response code.
*/
private function invokeHttpResponseCodes(event:MouseEvent):void
{
returnedHttpResponse.text = "Loading ...";
if (responseCodesProxiedService)
{
httpServiceResponseCodesProxied.send();
}
else
{
httpServiceResponseCodes.send();
}
}

/**
* Handler for radio button group used to determine if proxied or non-proxied
* HTTPService is to be used for response code service.
*/
private function setResponseCodesProxyStatus(event:ItemClickEvent):void
{
const proxyStatus:String = event.currentTarget.selectedValue;
responseCodesProxiedService = (proxyStatus == "BlazeDS Proxied");
}

/**
* Results handler for result of service call for HTTP response code.
*
* @param event Result Handler for non-proxied response code reply.
*/
private function resultCodeHandler(event:ResultEvent):void
{
returnedHttpResponse.text =
"SUCCESS: " + ObjectUtil.toString(httpServiceResponseCodes.lastResult);
}

/**
* Results handler for result of service call for HTTP response code that is
* based on a proxied call.
*
* @param event Result Handler for proxied response code reply.
*/
private function proxiedResultCodeHandler(event:ResultEvent):void
{
returnedHttpResponse.text =
"SUCCESS: " + ObjectUtil.toString(httpServiceResponseCodesProxied.lastResult);
}

/**
* Fault handler for faults encountered during a service call on the
* response codes service.
*
* @param event Fault Event that needs to be handled.
*/
private function responseCodesFaultHandler(event:FaultEvent):void
{
returnedHttpResponse.text = "ERROR: Failure trying to access service.\n"
+ event.fault.faultString + "\n" + event.fault.faultDetail;
}



The MXML file and two ActionScript files shown above constitute the client side of this example. Now, a HTTP-exposed server side is required to complete the example. This is implemented using a Java servlet. The servlet, which passes back a simple String indicating that a particular HTTP method has been called, is shown next.

SimpleHttpServer.java


package dustin.flex.rest;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Logger;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
* Simplistic Java EE server-side application intended for demonstration of
* Flex HTTPService capabilities with and without BlazeDS.
*
* @author Dustin
*/
public class SimpleHttpServer extends HttpServlet
{
/** Set up java.util.Logger. */
private static Logger LOGGER =
Logger.getLogger("dustin.flex.rest.SimpleHttpServer");

/**
* Servlet method responding to HTTP GET methods calls.
*
* @param request HTTP request.
* @param response HTTP response.
*/
@Override
public void doGet( HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
LOGGER.warning("[DUSTIN] doGet() Accessed!");
final PrintWriter out = response.getWriter();
final String requestId = request.getParameter("id");
out.write("GET method (retrieving data) was invoked with ID " + requestId + "!");
}

/**
* Servlet method responding to HTTP POST methods calls.
*
* @param request HTTP request.
* @param response HTTP response.
*/
@Override
public void doPost( HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
LOGGER.warning("[DUSTIN] doPost() Accessed!");
final PrintWriter out = response.getWriter();
out.write("POST method (changing data) was invoked!");
}

/**
* Servlet method responding to HTTP PUT methods calls.
*
* @param request HTTP request.
* @param response HTTP response.
*/
@Override
public void doPut( HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
LOGGER.warning("[DUSTIN] doPut() Accessed!");
final PrintWriter out = response.getWriter();
final String requestId = request.getParameter("id");
out.write("PUT method (inserting data) was invoked with ID " + requestId + "!");
response.setStatus(HttpServletResponse.SC_CREATED);
}

/**
* Servlet method responding to HTTP DELETE methods calls.
*
* @param request HTTP request.
* @param response HTTP response.
*/
@Override
public void doDelete( HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
LOGGER.warning("[DUSTIN] doDelete() Accessed!");
response.setStatus(HttpServletResponse.SC_OK);
final PrintWriter out = response.getWriter();
final String requestId = request.getParameter("id");
out.write("DELETE method (removing data) was invoked with ID " + requestId + "!");
}

@Override
public String getServletInfo()
{
return "Provide examples of HTTP methods invoked by clients.";
}
}



With this servlet in place, we can now look at the differences between HTTP method handling for HTTPService with and without BlazeDS. I will be using GlassFish to host all server-side code shown in this blog posting.

Without BlazeDS (or similar proxy server support), the Flex HTTPService only supports the GET and POST methods. I previously blogged about even the POST in a non-proxied HTTPService being treated like a GET in some cases. The example code above does use a body in the POST request to ensure that it is treated like a POST. As the following screen snapshots indicate, all of the other major HTTP methods (PUT, DELETE, OPTIONS, TRACE) are treated as GET methods. POST is treated like a POST.

Non-Proxied HTTPService GET



Non-Proxied HTTPService POST



Non-Proxied HTTPService PUT



Non-Proxied HTTPService DELETE



Non-Proxied HTTPService OPTIONS



Non-Proxied HTTPService TRACE





In the non-proxied HTTPService examples illustrated above, all of the HTTP methods were treated as GET except for the POST method. As stated earlier, even that can be treated as a GET if no body is included in the request.

The next series of screen snapshots show the same HTTPService calls as before, but with a BlazeDS proxy used now.

Proxied HTTPService GET



Proxied HTTPService POST



Proxied HTTPService PUT



Proxied HTTPService DELETE



Proxied HTTPService OPTIONS



Proxied HTTPService TRACE




The results shown in the sample Flex client for BlazeDS-proxied HTTPService instances are more interesting than the non-proxied counterparts. The GET and POSt work the same for both proxied and non-proxied, but the other HTTP methods have different results in the proxied versions than in the non-proxied versions. In the screen snapshots of the results of the TRACE and OPTIONS calls, I took advantage of the Flex Label feature that displays an automatic truncation tip when the contents of the Label are larger than the label and no tooltip is provided for the Label. We can see that when BlazeDS is used, HTTPService can "see" the options returned by the server and can see the traced route.

The results for PUT and DELETE are not quite as encouraging. While we see "null" in the text field, all is not lost. The result handler is called when the HTTP PUT or DELETE invocation returns, but the text does not get populated. Also, we can see that the PUT and DELETE are being called when we look at the GlassFish log as shown in the next screen snapshot.



In the GlassFish log record shown immediately above, log record number 300 represents the GET initially performed when the Flex application's applicationComplete event is triggered. Log record 301 is the explicit non-proxied GET and log record 302 is the explicit non-proxied POST. Log records 303 through 306 are the PUT, DELETE, OPTIONS, and TRACE non-proxied calls treated like GETs. Log record 307 is the BlazeDS-proxied GET and log record 308 is the BlazeDS-proxied POST. Log record 309 and log record 310 are clearly the proxied PUT and DELETE calls as evidenced by the WARNING text. This also proves that the server-side doPut() and doDelete() methods were in fact invoked.

It is nice to be able to use Flex's HTTPService with BlazeDS to use a more complete range of the standard HTTP methods. I would like to find out if there is a way to return a non-null body from PUT and DELETE calls so that the REST-inspired concept of Hypermedia as the Engine of Application State (HATEOAS) might be more fully realized for those two HTTP methods.

As mentioned earlier, BlazeDS also makes HTTPService more useful by improving its handling of HTTP response codes similarly to how it improves HTTPService's handling of HTTP method differentiation. I hope to cover this BlazeDS-improved handling of HTTP response codes in a future blog post.


Addition (March 2010)

Christian Junk pointed out that I had not included the piece of MXML code defining ProxySelectorFormItem. That code is shown next and this sample comes from a file called ProxySelectorFormItem.mxml.


<?xml version="1.0" encoding="utf-8"?>
<mx:FormItem xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:dustin="components.*">
<mx:Script>
<![CDATA[
[Bindable] public var selectorHandler:Function;
[Bindable] public var proxiedLabel:String = "BlazeDS Proxied";
[Bindable] public var nonProxiedLabel:String = "Not Proxied";
]]>
</mx:Script>

<mx:RadioButtonGroup id="proxyStatus" itemClick="{selectorHandler(event)}"/>
<mx:RadioButton groupName="proxyStatus" id="proxy" label="{proxiedLabel}" />
<mx:RadioButton groupName="proxyStatus" id="nonproxy" label="{nonProxiedLabel}" />

</mx:FormItem>



Conclusion

BlazeDS allows Flex developers to use a wider range of HTTP methods. This is one of the many advantages that BlazeDS offers for proxied HTTPService when compared to non-proxied HTTPService.


Additional Resources

There are several good blog postings on using Flex with HTTP and REST. A particularly insightful resource is the StackOverflow thread Is It Feasible to Create a REST Client with Flex?.