Main

April 17, 2007

Developing Software in a Fast Company

I've been working at MobiTV for nearly 3 months, and have been able to make a noticeable impact in the PCTV project during my stay. This is a very fast paced business (Internet/mobile video delivery) with highly compressed product delivery schedules. This virtually eliminates the possibility for big up-front design that has been possible on some of the government projects I was involved in with SRA.

This is not the first time I've worked for a company with high expectations and little time. While working on a very small start-up in 2003 with my friends Tim & Ben, we relied on Extreme Programming (XP) techniques to manage deliverables and keep product quality high. It worked very well for us, and instilled in me the importance of writing and running developer unit-tests. It had a profound effect on how I approached writing software - thinking of requirements in terms of unit-tests is a major paradigm shift.

For most junior (& many senior) programmers, the idea of writing developer unit-tests is quickly dismissed because they have too much work to do on production code and can't space the time. What they don't realize is that the act of writing unit-tests enforces their understanding of what the requirements are for production code, and saves them time because they end up writing only enough code required to make the tests pass. Also, having unit-tests to verify functionality increases a developer's confidence in the code and reduces the amount of time spent in the debugger during development time, integration testing, and QA testing.

Recently, my teammates and I at MobiTV have applied and benefited from the use of XP and unit-testing while developing the latest release of PCTV. We achieved 80% test-coverage of our code, and encountered merely 10 defects during the QA cycle (more than 100 had been reported in the previous release). We also finished the development phase 3 weeks ahead of schedule. Management has taken notice at the dramatic improvement in quality and reduction in development time that resulted from unit-testing and test-driven development.

Lately, I've been working on a new version of our PCTV front-end web application. I have used the StrutsTestCase library to conduct unit-testing of Struts Actions, which is an area often overlooked when writing unit-tests. StrutsTestCase makes it easy to test form validation and Action invocation for applications that use Struts. It also includes support for the Spring and Tiles frameworks, both of which we're using. The only downside is that StrutsTestCase doesn't appear to be actively maintained, though it works well with the Struts 1.3.8 library that we're using.

December 20, 2006

Keyword 'final' in Java

I've been a strong advocate of the 'final' keyword in the Java language. It's an effective way of communicating to both humans and machines (the compiler & JVM) that a class/method/field/variable cannot be modified or extended. A while ago, I had a heated discussion with a former co-worker regarding the necessity of the 'final' keyword in variable declarations because he felt they were unnecessary and cluttered up the code. My opinion on the issue is that the readability of code can be addressed easily by choosing a coding-style that suits your tastes, and that producing code with ambiguous behavior can be extremely difficult to correct and is very error-prone. I recently found a great web page that explains why the 'final' keyword is so valuable. It's a worthwhile read, if that's your thing.

September 1, 2006

Tomcat Support for the AJP Communication Protocol

I've been working on a case where a customer is trying to deploy our product in a fairly common server configuration that relies on the Apache web server to accept HTTP requests, and one or more Tomcat server instances on the back-end to process those requests. There are generally two options for choosing how the Tomcat and Apache servers communicate:


  • HTTP Reverse-Proxy - by far, the simplest, though the least efficient

  • AJP/13 - a binary protocol for handled by connectors on the Apache (mod_jk) and Tomcat (Coyote AJP connector) servers

So, the customer is trying to use AJP/13 for communication between the two. Configuring the two systems is simple; however, AJP is not very well-suited for real-time communications. The Documentum component I work on, UCF, establishes a communications channel between client and server and requires that the server be able to transmit pieces of an HTTP response over an extended period of time. The AJP connector included with Tomcat buffers HTTP responses until a sufficiently large (~8 kilobytes) amount of data is accumulated or the Servlet is finished, at which point the connector flushes the buffer to a socket connection between Apache and Tomcat. In our case, the server should transmit the small "heartbeat" messages to the client in the HTTP response instead of buffering them. While the messages are buffered in Tomcat, the client thinks that the server is dead.

I've arrived at the conclusion that Tomcat's AJP connector does not work well for real-time applications that have the requirement of being able to send small chunks of an HTTP response to a client. This might not be the case with other application servers, though I was able to verify this behavior in the Tomcat application server because the source code is made available to the public. I haven't seen any evidence that the AJP protocol does not support the transmittal of partial HTTP responses. Rather, it's just Tomcat's connector implementation that imposes this limitation.

I'm left with the option of using Apache as a simple reverse-proxy with the mod_proxy connector module. This problem would not exist if the Tomcat AJP connector provided a configuration parameter to indicate that responses should not be buffered before being flushed to the socket.

July 20, 2006

Testing Software that Runs on Other Software

Recently I've been working on porting some code that used a home-grown HTTP client connector to use the HTTP client connector facilities present in Java 1.4+. Some of the outstanding advantages of using the built-in HTTP client connector is that transport encoding (chunked streaming versus fixed-content-length transfers) and forward-proxy authentication is handled automatically behind the scenes.

During my development, I've been using our suite of unit tests to verify the correctness of my work. The tests are implemented using the JUnit test framework and can be run from within my IntelliJ development environment. I've been using the Jetty Servlet container to host our server-side application during testing. Jetty includes a light-weight HTTP server.

At one point, I had all of the unit tests passing and decided to perform functional testing using the full-blown web application in the Tomcat Servlet container. I quickly learned that something was wrong when I began seeing an EOFException reported in the Tomcat server log. I had been using Java's default HTTP Content-Type header field value (application/x-www-form-urlencoded), which the Tomcat Coyote HTTP connector recognized. Tomcat attempted interpret our proprietary communication protocol rather than simply pass it through. I then specified that the Content-Type should be application/octet-stream (the default type according to the HTTP 1.1 RFC) and was successful in testing against Jetty and Tomcat. The problem was that Jetty had ignored the Content-Type HTTP header in our requests, while the Tomcat Coyote HTTP connector did not. Tomcat was correct in this case and has honored the HTTP 1.1 specification more closely than Jetty, in my experience.

Most developers are encouraged to distrust user input because it introduces unpredictability into the execution of a software program. But what I've learned in this and other projects is that no software program works in isolation. If you're writing software for Windows, then you're dependent on the behavior of the Windows Operating System (OS). And the Windows OS is dependent on the third-party hardware drivers and firmware it uses to interact with the computer's hardware devices. And if you're working on software that communicates over a computer network (i.e. the Internet), then anything can happen.

So, simply distrusting user input is not enough to ensure correct operation of a software program. The vagueness of relatively simple communications protocols like HTTP still provide a lot of room for interpretation. The only way to ensure a high degree of compatibility is to test as many hardware, software, and input permutations as possible. An EMC VMWare virtualization appliance is an excellent platform for such testing, in my opinion :)

May 29, 2006

"Getting Things in Order" Web App

I've been working on a Java-based web application titled "Getting Things in Order". It's a project-planning application that uses a lot of the concepts described in David Allen's geek-friendly book "Getting Things Done". I'm using a lot of open-source tools in the process: Eclipse, Apache Tomcat, Linux, the Spring Framework, and many others.

Some of the features I've got in place are:


  • Uses a relational database (I'm using MySQL) to store application data.

  • Supports multiple users with separate project/action data.

  • Administration of users, and the designation of users capable of administration duties.

  • The ability to create, edit, and delete Projects (composed of one or more Actions).

  • The ability to create, edit, and delete Actions, which are atomic tasks.

  • A main page that summarizes a user's Projects and the next Action for each.

I've made a lot of progress in the last two weeks, and it wouldn't have been possible without the assistance of the Spring Framework. It does a wonderful job of simplifying the creation of complex websites. I hope to incorporate AJAX behaviors soon with the aid of the Direct Web Remoting (DWR) library.

May 15, 2006

Sun Java Plug-in Allows Expired Certificates

At work, we ran into a problem where older releases of our product incorporate a Java Applet that's digitally-signed with a certificate about to expire in a few weeks. The role of digital-signatures is to verify the authenticity and integrity of electronic information based on the shared-trust of a certificate-authority (CA), such as Verisign or Thawte. Most CA's issue certificates that are valid for at most two years because the quality of the trust relationship between the CA and the organization seeking a certificate degrades over time. To combat this (& to sustain the CA's business model), the certificate must be renewed at regular intervals.

So, we needed to determine what behavior to anticipate from our customers when our certificate expires. I set the system clock forward on a VMware image of Windows XP and experimented with the Java Plug-in versions 1.4 and 1.5. To my surprise, the Applet functioned without any warnings when the certificate had already been imported into the plug-in keystore. And when the certificate was not in the keystore, the normal certificate acceptance dialog was presented with just an additional warning message about the expiration status of the certificate.

This puzzled me since the plug-in should honor the expiration of certificates by treating code bearing their signature as untrusted. I googled the subject and learned that the Sun JSSE stops verifying the certificate chain once it encounters a certificate it trusts. In the case where the certificate has been imported into the plug-in keystore, this occurs immediately and the CA certificates aren't consulted. Still, the expiration date of the certificate could be enforced regardless of the keystore-status. But this is not the case.

This represents a minor security vulnerability since it implies that all certificates issued to an organization can be viewed as "active". The private keys of expired certificates must be guarded in the same manner as non-expired certificates. This translates well to the old-world of corporate letterhead. Most companies are careful not to leak unused paper stock bearing the company's letterhead since it may be used to impersonate someone from the company. Similarly, the private keys for expired certificates should be destroyed or stored safely so that they may not be used under false pretenses. Failure to do so could result in the distribution of malicious software bearing an innocent organization's name, resulting in possible legal and economic damages.

I also learned that the Sun Java Plug-in 1.5 supports a time-stamp property in digital signatures that honors any code signed by a certificate at a time when the certificate was active, even if it is now expired. This makes sense for organizations looking to extend the use of their signed-code. It relies on the use of a time-stamping authority who can vouch that the signature was generated on the date/time indicated. This sounds like an interesting idea, but I think it works in opposition to the CA-model where the currency of a certificate is used as a measure of trust.

May 6, 2006

Spring Framework for Java, What a Delight!

I began working on a project I set aside about 6 months ago that includes a Java Web Application programmed with the Spring Framework. I am mostly interested in getting some experience with technologies that I don't use in my 9-5 job. The new territory I'm covering (or re-visiting, actually) is web page design (yikes, I'm a engineer!) and database schema design.

I'm using the Spring Framework to create a Model-View-Controller (MVC) architecture, and have found that it ties together with back-end and presentation technologies very nicely. It took me a while to learn the lingo of Java Servlet development since I haven't ventured beyond XML Web Services and client-server development in a couple of years.

Once I had the routine down, cranking out code and GUIs was progressing at a lightning-pace! I could easily get the functionality of the project done in a weekend. An since the Java Server Pages (JSPs) are using the model data in a super-decoupled way, changing the look-and-feel of the web site should be really easy. I would hate to design a large interactive web-site with anything besides Spring.

May 3, 2006

BEA Weblogic and HTTP 1.1 Chunked-Encoding

A customer issue I am dealing with at work involves the use of HTTP 1.1 chunked transfer-encoding on the BEA Weblogic 8.1 application server (SP3, in this case). Chunked transfers offer a very efficient method of transferring large amounts of data since they allow the payload to be broken up into manageable chunks of data. The alternative is to transfer the entire payload in a single message (expensive since it needs to be buffered in memory), or programmatically divide the payload into pieces for sequential transmission (difficult, requires a non-standard protocol between receiver and sender).

So, HTTP 1.1. chunked encoding is being used by our product to transfer large files between the client and server. It should work fine, except that it relies on the application server/web server to have implemented the HTTP 1.1 protocol correctly. I've come to learn that BEA's Weblogic 8.1 application server has the poorest implementation, by far.

The most aggregious offense is that client requests using a fixed content-length (alternative to chunked transfer-encodings) will occasionally receive a response that uses chunked transfer-encoding. This would be like asking someone to call you back on the phone, but instead they write you a letter. Fortunately, our client doesn't make much of a distinction between the encoding used; rather, it just cares that a response is provided.

Additionally, there is a bug in Weblogic 8.1 (S-31186) where use of chunked transfers in a cluster will result in buffering of the HTTP response. Buffering of communications for an undetermined amount of time doesn't work for real-time applications like ours. It appears that disabling the use of chunked transfers altogether in the server's config.xml might solve the problem, but that's a horrible compromise to make.

However, if a system sits between the client and application server, it's possible that the system would be confused by the mismatch in encodings. I've noticed that when an Apache HTTP server is configured as a reverse-proxy (a common setup that limits web traffic to a DMZ) a chunked response can be buffered by the HTTP server for as long as 9 minutes. This is long enough for the client to time-out and disconnect under the assumption that the server is unreachable. This has resulted in more than a few headaches as I've tried to remedy the situation.

So, I have one point to make: protocols and standards exist to make communication easier. Deviation from protocols (i.e. slang) results in conversations that can be difficult to understand. Companies such as BEA wouldn't write a press-release composed in slang. So, why would they release their core product with a half-ass implementation of a communication protocol? People are building products and basing their success on the quality of products like BEA Weblogic. How about a little professionalism? Please?

April 26, 2006

TrustDecider for Verifying JAR Files

I've been working on an approach for verifying Java JAR files at runtime in Java 1.3+ environments. Unfortunately, I've noticed a serious lack of information with regards to what verification facilities are provided with Java and to what extent they do their job.

One of the most promising tools I've come across is the TrustDecider class. It is available to all Applets in JRE 1.3+ (plugin.jar), and to all Java Web Start applications in JRE 1.5+ (deploy.jar). In my case, I have a digitally-signed Java Applet that downloads digitally-signed content which must be verified programmatically at runtime. TrustDecider provides a method called isAllPermissionGranted that returns a boolean value indicating whether certificates associated with a CodeSource (JAR file) have AllPermissions privileges, which is to say that they are trusted.

In JRE 1.3, the TrustDecider class has the full-name sun.plugin.security.TrustDecider; however, in JRE 1.5, the full-name is com.sun.deploy.security.TrustDecider. Locating the appropriate implementation of the class can be accomplished with Java's Reflection capabilities.

To verify the integrity of an archive, you must enable verification when constructing the JAR instance, and then actually read each entry in the JAR to trigger verification of the entry's digital signature(s). The last part is not so obvious to people, since it seems like just constructing the JAR instance with verification enabled should be enough.

To verify the authenticity of each archive entry, you can invoke the isAllPermissionGranted method in TrustDecider. The user's Java keystore will be accessed by the TrustDecider class to determine if the certificate is already trusted. If not, the user will be presented with a dialog prompting them if they trust the certificate subject and signer. They will then have the option to approve the certificate for that invocation, or all future invocations. Problem solved!

As a word of warning, the TrustDecider class is part of the com.sun.* and sun.* packages and is not guaranteed to work in any version of Java. It should be used at your own risk.

Here's a method that verifies a JAR file using the TrustDecider class:

private boolean checkArchivePermissions(File file)
    {
        if (null == file || !file.exists() || !file.getName().endsWith(".jar"))
        {
            return false;
        }

        Class trustDeciderClass;
        try
        {
            trustDeciderClass = Class
                    .forName("com.sun.deploy.security.TrustDecider");
        }
        catch (ClassNotFoundException e)
        {
            System.out.println("Trying Plugin TrustDecider...");
            try
            {
                trustDeciderClass = Class
                        .forName("sun.plugin.security.TrustDecider");
            }
            catch (ClassNotFoundException ee)
            {
                System.err.println("TrustDecider not found, cannot verify archive");
                return false;
            }
        }

        Object trustDecider;
        Method verifyMethod;
        try
        {
            trustDecider = trustDeciderClass.newInstance();
            verifyMethod = trustDeciderClass.getMethod(
                    "isAllPermissionGranted", new Class[]
                    { CodeSource.class });
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }

        JarFile jarFile = null;

        try
        {
            // attempt to load a Java class from the JAR
            jarFile = new JarFile(file, true);
            Enumeration fileEntriesEnum = jarFile.entries();

            while (fileEntriesEnum.hasMoreElements())
            {
                JarEntry je = (JarEntry) fileEntriesEnum.nextElement();

                if (je.isDirectory())
                {
                    continue;
                }

                // Verify the integrity of the file against the digest
                InputStream is = null;
                try
                {
                    is = jarFile.getInputStream(je);
                    JarUtilities.getDataFromZipInputStream(is);
                }
                finally
                {
                    if (null != is)
                    {
                        is.close();
                    }
                }

                // Verify that the certificates used to assert the integrity are trusted
                if (!je.getName().startsWith("META-INF"))
                {
                    Certificate[] certs = je.getCertificates();
                    CodeSource cs = new CodeSource(file.toURI().toURL(), certs);
                    if (!Boolean.TRUE.equals(verifyMethod.invoke(trustDecider,
                            new Object[]
                            { cs })))
                    {
                        System.err.println("Not Trusted: " + jarFile.getName());
                        return false;
                    }
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != jarFile)
            {
                try
                {
                    jarFile.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }

        return true;
    }

March 23, 2006

Java PluginClassLoader

I recently researched a means for verifying the integrity and authenticity of Java archive programmatically within a Java Applet. In my case, I had an Applet that was digitally-signed and trusted by the client. The Applet downloaded and executed Java bytecode packaged in JAR files. Before loading the downloaded code, I wanted the Java Applet to verify the digital signatures of the archives using the Java Plugin's certificate-management features.

I learned that there is a ClassLoader implementation called PluginClassLoader, and is provided in Java Runtime Environments version 1.3 or better. The PluginClassLoader is an extension of the URLClassLoader and can be used only in the context of the Java Plugin. Once a JAR file has been registered with a PluginClassLoader instance, the classloader will verify that the JAR's classes loaded by it are signed by certificates trusted by the user and/or in the browser keystore.

Here is some code that, when run as an Applet, will verify the integrity of an arbitrary JAR file in its path:

String jarFileName = ...
if (file.exists() && 
	file.getName().endsWith(".jar") && 
	classLoader instanceof PluginClassLoader) 
{
	try {
		// add the JAR to the ClassLoader's context
		((PluginClassLoader)classLoader).addLocalJar(file.toURL());
		
		// attempt to load a Java class from the JAR
		JarFile jarFile = new JarFile(file, false);
		Enumeration fileEntriesEnum = jarFile.entries();
		while (fileEntriesEnum.hasMoreElements()) 
		{
			JarEntry entry = (JarEntry) fileEntriesEnum.nextElement();
			if (entry.getName().endsWith(".class"))
			{
				String className = entry.getName().replace('/', '.').replace('\\', '.').replaceFirst(".class", "");
				System.out.println("Verifying with class: " + className);
				
				// Use the PluginClassLoader to load an arbitrary class from 
                                // the archive, triggering verification
				Class.forName(className, false, classLoader);
				verified = true;
				break;
			}
		}
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

March 17, 2006

Java Security Manager

I recently needed to address a problem where I have a digitally-signed Java Applet running in a web browser, and the Applet creates a new native Java process to handle application operations once the Applet goes out of scope. Considering that trust is transitive, the Java application process should propagate the Applet's trust relationship established with the user.

So, I researched strategies that would ensure the Java application process checked the trustworthiness of the components used by the new Java application process. Java 2 includes a Security Manager feature which is responsible for restricting access to resources based on trust relationships established with Principals. To ensure that all Java application components used in the Java application process are trusted by the user (or their system administrator), I added a property to the Java command line invoking the default Java Security Manager:

java -Djava.security.manager -jar foo.jar

This ensures that all application resources must be trusted by the user, with that trust usually being established by way of digitally-signed JARs. Effectively, the Java application process will be run with the same restrictions placed on a Java Applet running in a web browser.

March 2, 2006

Java Native Interface (JNI) and Experiments in Pain

One of my recent objectives has been to integrate logging messages from a C library invoked using JNI with the logging services in the Java application. So, the path of execution is: Java to C, then C to Java. The intense intermingling of C and Java scared me at first, which was perfectly appropriate as a I would come to learn.

Providing a means of invoking C library function from Java is pretty easy. Simply define native methods in your Java class, compile the C header from the compiled Java byte-code, and develop your C functions to match those in the header. The C functions include a JNI Environment (type JNIEnv*) parameter which provides a reference to the Java runtime environment within the scope of the calling thread. The JNI Environment variable is the hub of activity in JNI world, so it's tempting to want to keep a global reference to it. But this is something you should never do, especially when it's possible that your C library will be accessed by more than one thread. I learned this the hard way...

Here's an example drawn from my work that illustrates how to make this work. When the C library is loaded by the Java application, I invoke a native method (C function) called init which sets a global variable to reference the Java Virtual Machine. This reference can be used to get a handle to the environment associated with the current thread. Very useful. Here's what the init function looks like:

// Here's the global variable for the JavaVM
JavaVM* jvm = NULL;

// global variable for the logger instance - MUST - be released in destructor to avoid 
// memory leaks
jobject logger = NULL;

JNIEXPORT void JNICALL Java_com_foo_Bar_init
  (JNIEnv *env, jobject obj)
{
	jclass loggerClass = (*env)->FindClass(env, "com/foo/LoggerFactory");
	jmethodID loggerConstr = (*env)->GetStaticMethodID(env, loggerClass, "getInstance", 
            "()Lcom/foo/ILogger;");
	logger = (*env)->CallStaticObjectMethod(env, loggerClass, loggerConstr);
	logger = (*env)->NewGlobalRef(env, logger);

	(*env)->GetJavaVM(env, &jvm);	
}

// Resonsible for deleting references to Java objects made by global variables.
void EXPORT_LIB_DESTRUCTOR destroy()
{
	JNIEnv *env = NULL;
	(*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_2);
	
	if (env && logger)
	{
		(*env)->DeleteGlobalRef(env, logger);
	}		
}

I have C function called getEnvironmentVariable, which has a handle to the JNI Environment. The JNI Environment reference is not in scope when the function lookupVar is called:

JNIEXPORT jstring JNICALL Java_com_foo_Bar_getEnvironmentVariable
  (JNIEnv *env, jobject obj, jstring var)
{
	const char *varName = (*env)->GetStringUTFChars(env, var, NULL);
	if (varName == NULL) {
		return NULL;
	}
	const char *envVal = lookupVar(varName);
	if (envVal == NULL) {
		return NULL;
	}
	jstring retval = (*env)->NewStringUTF(env, envVal);
	(*env)->ReleaseStringUTFChars(env, var, varName);
	return retval;
}

The lookupVar function may need to access logging facilities in Java. I've provided a log function which uses the jvm global variable to get a reference to the JNI Environment for the current thread:

void log (char *msg) {
	JNIEnv *env = NULL;
	(*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_2);
	if (env) {
		jstring stringMsg = (*env)->NewStringUTF(env, msg);
		loggingMethod = (*env)->GetMethodID(env, loggerClass, "debug", 
                   "(Ljava/lang/String;)V");
		(*env)->CallVoidMethod(env, logger, loggingMethod, stringMsg);
		(*env)->DeleteLocalRef(env, stringMsg);
	}				
}

This should provide a fairly complete example of how to use JNI to call back into a Java application from C without having a handle to the JNI Environment information. Here are some good resources I came across along the way:

February 25, 2006

Working with Java New I/O (NIO)

A project I've been working on lately has involved restricting access to a registry file that might be used by concurrent Java processes. There is a distinction between threads and processes: multiple threads function within the scope of a single process, and multiple processes function within a single computer. Concurrent access to a resource by threads can be limited with Java's synchronization features. But limiting concurrent access by processes has, until Java 1.4, been unavailable.

Java runtime environments (JREs) version 1.4 or better feature an addition to the API called "New I/O", or NIO. Developers can use NIO to restrict access to a file not just by other Java processes, but by any native processes running on the computer. It is significant that Sun has taken advantage of the file locking facilities on each operating system (Windows, Mac, Solaris, etc.) to make NIO work. Because operating systems differ in their features and behavior, it is worth noting that the file locking features in NIO may function a bit differently across operating systems.

NIO features a concept called "Channels" which offer the ability to lock an entire file, or even portions of a file. Channels do not provide any support for restricting access to a locked file by concurrent threads; rather, this must be handled by the developer using thread synchronization.

Based on my experiences, NIO offers some very powerful block I/O and file locking features, but takes a while to understand within the broad scope of the Java language. Hopefully more tutorials and supporting documentation will be provided in the near future so that new and seasoned Java developers can take advantage of its many features.

December 20, 2005

Java 1.4.2 Plug-in on Fedora Core 4

Lately I've been using several Linux distributions to test a Java Applet used in Documentum's Unified Client Facilities (UCF). I've tested Red Hat Enterprise 3 and Fedora Core 4 using Firefox 1.0.7 and the Java plug-in (1.4.2_09 and 1.5_05). In my testing, the Applet failed to load on Fedora Core 4 using JRE 1.4.2; however, JRE 1.5 on Fedora Core 4 worked fine.

The Applet is embedded in an HTML page using the standard "code" tag. The browser HTML engine encounters the tag and informs the Java plug-in that it has some work to do. The Java plug-in then attempts to download and execute the code archive referenced in the tag. The 1.4.2 plug-in was reporting an inability to download the Applet archive from the web server. I verified that the URL of the Applet archive (JAR file) was accessible through the browser. It was, so there was no reason that the Java plug-in should report an error while trying to download the archive. I was puzzled.

I googled the problem a bit and learned that it stems from the IPv6 support in the Java 1.4.2 plug-in. The JRE tries to create an IPv6 socket to the system hosting the JAR file, but screws up somewhere along the line and reports that the connection failed. It looks like the Java 1.5 plug-in might need to be the minimum requirement for browser-based Linux clients.

Here are some of the links I found documenting the bug in JRE 1.4.2:
JRoller posting
Sun Bug Entry

December 7, 2005

Java Applets and Assumed Identity

As part of a new assignment at work, I've been experimenting with the use of user-configured MIME types to load external content from a Java Applet. Specifically, I want a Java Applet to trigger to loading of an arbitrarily-typed file in the appropriate application. This means opening Word for a Word document, Excel for a spreadsheet, etc.

Applets are a weird thing. They have an odd security model that assumes the User can accurately make the distinction between "friend" and "foe". Most Applets are assumed to be "foes", which is fine for most situations. Loading files in helper applications requires "friend" status according to the default security policy. This can be achieved by signing the archive used to convey the Applet with a digital certificate. The certificate can be signed by a Certificate Authority (CA), or by an unverified individual (self-signed certificate).

The rub is that the user is required to make the distinction between a certificate that has been registered with a CA, and a certificate that was generated by a potentially-malicious individual. The distinction is often a subtle one to the user. And the consequences of letting a malicious Applet run can be significant.

Our commercial product uses a certificate that has been registered with a CA, so this won't be a problem. But I'm reminded of the fragility of the security model and how much it relies on user-sophistication.

October 10, 2005

Creating 'Calendar' Instances with Betwixt

At work, I'm currently developing a prototype for mapping between legacy and modern messaging data structures. The modern data structures are actually JAX-RPC Web Service stubs generated from a Web Services Description Language (WSDL) document. The JAX-RPC reference implementation generates attributes of type java.util.Calendar to represent XML Schema 'datetime' elements. This is fine, exception that Calendar is not a valid Java Bean since it lacks a public default constructor.

This is normally not a problem, since a new instance of Calendar can be had by invoking 'Calendar.getInstance()'. However, I'm using Betwixt to load an XML document into the JAX-RPC stubs, and Betwixt assumes that the data structures are all Java Beans with default constructors. Betwixt chokes onces it tries to create a new instance of Calendar to hold date/time information.

So, I sought out a solution to configure Betwixt to construct Calendar appropriately. It turns out that Betwixt is lacking in documentation, or at least, well-organized documentation. I eventually figured out a good way to address the problem.

Create a class (i.e. CalendarCreator):

public class CalendarCreator implements ChainedBeanCreator

  public CalendarCreator() { }

  public Object create(ElementMapping mapping, ReadContext context, BeanCreationChain chain)
  {
    if (Calendar.class.equals(mapping.getType()))
    {
      return Calendar.getInstance();
    }

    return chain.create(mapping, context);
  }

}

Then, associate the CalendarCreator with the Creator Chain used by the BeanReader when reading your XML document:

BeanReader beanReader = new BeanReader();
beanReader.getXMLIntrospector().getConfiguration().setUseBeanInfoSearchPath(true);

// add Calendar creator to chain
BeanCreationList chain = BeanCreationList.createStandardChain();
chain.insertBeanCreator(1, new CalendarCreator());
beanReader.getReadConfiguration().setBeanCreationChain(chain);

This will result in the CalendarCreator instance being consulted regarding attributes of type Calendar. I'm sure that this approach can be applied to any class that needs to be constructed in a manner other than just with the default constructor.

September 11, 2005

Using Betwixt to Aid in Unit Testing

One problem I'm facing at work is the labor-intensive process of composing complex data structures for use in unit testing. Sure, I can consolidate a lot of the object contruction in the JUnit setup method; however, it still amounts to a lot of code and remains hard to visualize the overall object structure. So, I need a better way to compose my test data structures.

Enter Betwixt, a tool I'm looking to use in another problem domain for Java object (de)serialization. In this case, I can represent my test data structure content as an XML document and use Betwixt to populate the structures. Similarly, the end-result test data structures can be deserialized to XML and validated using a simple String comparison. If the structure changes or I want to alter the test data, I simply need to edit the XML document. This is easier to conceptualize and maintain. I now realize that the approach is very similar to how the dbunit tool uses XML document instances to set up databases before and after running unit tests.

September 6, 2005

Translating Document Representations Using Betwixt & XSLT

One of my current tasks at work is to develop a mechanism for supporting our legacy transfer record (TR) formats while developing new XML-RPC web services. This is a bit of a challenge since the TR formats are composed of fixed-width strings (read: not XML). So, how can you map between non-XML and XML documents?

I stumbled upon an interesting project in the Jakarta Commons site called "Betwixt". Betwixt is designed to serialize and de-serialize JavaBean compliant objects to-and-from XML documents. This is all possible thanks to the magic that is "reflection". And because it's relying on reflection, Betwixt does not need to have any hints as to the structure of the JavaBeans.

So, I came up with the idea of using our existing TR parser/generator classes to represent the TR strings as JavaBeans, serialize their contents to XML, apply an XSLT template to transform the document structure into something compatible with the XML-RPC web service stubs, and then de-serialize the XSLT output into the stubs. The reverse applies, too. This sounds like a lot of work, but really it's not. I only need to write an XSLT to translate between the TR and XML-RPC stub structures. Betwixt handles the serialization and de-serialization operations on the JavaBeans in just a few lines of code. The alternative would be to have a Java class manually map between the two structures, which is error-prone and difficult to maintain.

I think that there is going to be a huge demand for these kinds of translation services in the future. In our case, we want to support a new XML-RPC interface while having the ability to route all legacy clients to the new interface without any TR interface changes. This is the beauty of code-by-interface programming.

September 3, 2005

Developing with the Spring Framework

I've been experimenting with the Spring Framework lately while developing a strictly-for-fun web application. I have been really frustrated with the invasiveness of the Struts Framework in past years. Fortunately, Spring has none of these flaws. It works on two core principles: Dependency Injection, and Aspect-Oriented Programming (AOP).

Dependency Injection has radically changed how I approach Object-Oriented Programming (OOP). It relies on classes defining what they want, and allowing the Spring Framework to give it to them. This is different from standard Java programming in that traditionally classes would concern themselves with both constructing and using their dependencies. With Spring, classes are concerned only with using their dependencies. Hence, their dependencies are "injected".

Spring handles Dependency Injection (DI) through XML descriptors that are loaded by the Spring Container at runtime. This provides a great way to alter the behavior of application processing classes simply by changing how their dependencies are built and assigned through the descriptor files. A key component of DI is the use of interfaces to describe the operations & data available to users of a component. If consumers of the component use DI and program to the component interface, the component implementation is open to change and substitution with little or no modification to the consumers.

I'm currently reading the "Spring in Action" book from Manning Press. It's a well-written overview of the Spring Framework, and is a great companion to the wonderful documentation included with the Spring distribution.

walls2_cover150.jpg

August 19, 2005

JAX-RPC Handlers

I am using the JAX-RPC 1.1 Reference Implementation (RI) at work to expose operations in a business processing system we're building as XML Web Services. I've been building XML Web Services for several years, and have used numerous APIs to perform Object-XML (O-X) binding (notably, JAXM and JAXB). I wanted to use JAX-RPC on this project to take advantage of the automated WSDL generation and generation of serialization components from existing Java classes.

One nice feature of JAX-RPC is the support for Handlers, which follow the Intercepting Filter design pattern. The 1.1 specification support SOAP protocol handlers, while the 1.2 specification makes a further distinction between Logical and Protocol Handlers. I like the idea of being able to plug Handlers in series to perform functions like logging, auditing, and security operations.

In this case, I was trying to create my first Handler which would restrict access to the service to trusted hosts. This is pretty simple in principle: inspect the ServletRequest for the remote address and verify that it is trusted.

I had a hell of a time finding documentation on how to specify server Handlers. I finally got it straightened out. I needed to modify the config.xml file used by the wscompile process. Here's what the config.xml looked like when I was done (names changed to protect my employer):

<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
  <service name="MyService" targetNamespace="urn://MyService/wsdl" 
                   typeNamespace="urn://MyService/types" packageName="foo">
    <interface name="foo.MyService" servantName="foo.MyServiceImpl"/>
    <handlerChains>
      <chain runAt="server">
        <handler className="foo.handlers.TrustedHostsHandler"/>
      </chain>
    </handlerChains>
  </service>
</configuration>

Then, the TrustedHostsHandler class overrode the handleRequest method in the Handler interface in order to inspect the remote host's IP. Here are the relevent sections:

public class TrustedHostsHandler extends GenericHandler {
  private static final String SERVLET_CONTEXT_CLASS = 
    "com.sun.xml.rpc.server.http.HttpServletRequest";
  private HandlerInfo config;

  public TrustedHostsHandler() {
  }

  public void init(HandlerInfo config) {
    assert null != config : "HandlerInfo argument was unexpectedly null";
    this.config = config;
  }

  public QName[] getHeaders() {
    return config.getHeaders();
  }

  public boolean handleRequest(MessageContext msgContext) {
    assert null != msgContext : "MessageContext argument unexpectedly null";

    ServletRequest req = 
        (ServletRequest) msgContext.getProperty(SERVLET_CONTEXT_CLASS);
    assert null != req : "ServletRequest unexpectedly null";

    boolean result = false;
    String remoteAddress = req.getRemoteAddr();

    if ((null != remoteAddress) && isTrusted(remoteAddress)) {
      result = true;
    }

    return result;
  }
}

August 4, 2005

Tivo Java Apps

I've been able to download programming listings and software updates for our Tivo since we purchased and configured an 802.11g wireless adapter on it. It's the only way to go, in my opinion - if only because we don't have a standard phone line (the only other means for obtaining Tivo content).

But another great feature of the Tivo 7.1 software is the ability to interact with the Tivo box(es) over the LAN. Tivo has sponsored a great Sourceforge project called the Tivo Home Media Engine (HME) which allows developers to produce Java applications that can be discovered and invoked through the Tivo interface. Rendezvous is used for discovery, which makes service discovery automatic. Pretty cool. I'd like to develop some apps in the near future.