te-code logo

Source code for the real world™ Java | .NET
What is TE-Code?

TE-Code is the name of a collection of libraries available under a liberal BSD-derived Open Source license, originally written by Andrew S. Townley in Java and Python, but later expanded to .NET using the C# language.

Why would I want to use this library?

There are a lot of libraries out there, but I haven't been able to find one that solves some of the basic issues that this one does. The majority of the code in this library has been tested in real, live production applications in use on a daily basis. I actively continue to use this code where ever I can, so that if it breaks, it will affect me as soon as (and hopefully before) it affects anyone else.

To get a better feel for the capabilities, see the documentation for some examples. However, highlights of the main features of this library are:

Command Line Argument Parsing

I spend a lot of time writing CLI applications in a variety of languages. One of the C libraries that I liked best was libpopt from RedHat. When I migrated away from C and C++, I tried to find a version in Java that did what I wanted. At the time, I found a couple of libraries (including Java Popt, Greg White's DDJ article and JArgs), but none of them really did what I wanted.

Also, as I wrote more and more of these things, I decided that the traditional approach to handling the command line arguments could be improved by applying OO techniques. Eventually, I applied the Gang of Four Command pattern and ended up with something which I'm finally more-or-less happy with. I think that if you have to write programs to handle command-line arguments, you will soon appreciate the OO approach over using more traditional mechanisms, including the Jakarta CLI library.

Configuration Setting Handling

Another thing that I have needed with nearly every program I've written is a way to provide overridable configuration settings. This happens all the time because there are usually at least 3 levels of configuration in any sizable application:

  1. Individual user settings
  2. System-wide default values normally set during installation
  3. Built-in, hard-coded default values

In most programs, you want the settings available to the user to be the union of items 1-3, but allow them to change or override any settings contained in 2-3 which are appropriate.

Support for this functionality has been part of the library from the beginning. As of the initial .NET work and the 3.0.0-pre1 release, this functionality has been expanded and generalized allowing more control over the configuration settings and selective writes to either items 1 or 2.

Filtering and Sorting

The library also includes classes that allow you to create complex filters which may be applied to any of the standard Java Collections framework classes. Supplied classes allow for logical AND, OR and NOT operations to be created based on either specific filter checks or on dynamic property value checking (at the moment, the properties are limited to one level, however by using the Jakarta Commons Beanutils, this limitation can be easily addressed).

The sorting aspects allow you to order the values in the collection based on complex sort specifications. When used with the filter classes, you can build complex queries and order the results in a similar manner to the facilities provided by SQL. Together, these facilities provide an implementation of the Query Object pattern as defined by Martin Fowler in his book Patterns of Enterprise Application Architecture.

Delimited Text File Processing

The library contains a set of classes to abstract the boilerplate code used to process delimited text files to allow the developer to concentrate on what to do with the data.

Persistence Layer Utilities

The notable item in this package is the QueryHandler class. This class provides a facility similar to the DB API in Python allowing you to more easily execute SQL without having to set up all of the boilerplate code.

For example, if you wanted to easily perform processing of the SQL query:

select fname, lname from customer where customer_id = ?
you could do something similar to the following:
public void findCustomerById(long cust_id)
{
	QueryHandler query = new QueryHandler(_myConnFactory);
	query.addQueryListener(this);

	// you would use an external source for the SQL
	String sql = SQLProvider.get("find_customer_by_id");
	query.execute(sql, new Object[] { new Long(cust_id) });
}

public void nextRow(QueryEvent event)
{
	ResultSet rs = event.getResultSet();
	String lname = rs.getString("lname");
	String fname = rs.getSTring("fname");

	System.out.println(lname + ", " + fname);
}

The management of the connection, the preparation of the SQL and the processing of the result set are all handled by the instance. Again, the idea here is to reduce the amount of boiler-plate code you have to write as well as not having to worry about mapping the query parameters to the specific statement.

Parts of this package came from earlier work with the Jaxor persistence framework. The library also has specific support for some earlier Jaxor releases as extensions, so as to not directly introduce a dependency if you don't need it (and I doubt it works with the current version of Jaxor, anyway).

Internationalization & Localization (I18N & L10N) Tools

As part of the library implementation, an idiom is provided to enable the efficient localization of any text messages in the application. This facility goes beyond the standard Java Properties class capabilities, allowing you to write code as follows:

public void someMethod()
{
	System.out.println(Strings.get("sTitle"));
	System.out.println(Strings.format("fSomeMessage"
			new Object[] { "arg1", "arg2" }));
}

This technique is based on something that I a saw in the Jakarta Tomcat source code, but it has been expanded to use the same inheritance principles used by the configuration system so that you don't have to continually define the same strings over and over again for different packages.

General-purpose Swing Classes

The Swing capabilities consist of additional UI classes for a status bar and an about box along with a way to easily implement a background task which sends status information to a monitor object. There is also a highly-extended Metal theme mechanism which gives much more control over the themes and allows the application to extend the values of the them in a consistent manner.

Another aspect of this package is the ability to define the UI in terms of resources. There is currently only one implementation based on property files, but the mechanism is general enough to be extended to XML or something else. The existing implementation is based off the original Notepad example shipped with the first releases of Swing.

Project Version Information

One of the things I always try to do is include an awareness of version information into a project's source. This is just good practice and allows you to easily identify which version of a product you are running.

Using the idioms in the project's build.xml and the Version.java.in source file, you can easily add version tracking information into your projects. For .NET projects, I have created an NAnt task which essentially does the same thing, but without having to jump through quite as many hoops.

Run-time Application Tracing

This facility was one of the first to be added and has been with me for most of my career in one form or another. The point of this part of the library is to allow enough instrumentation to be useful for run-time problem diagnosis.

The main difference between TE-Trace and Jakarta's Log4j is this library is focused solely on application tracing. To me, application logging is a different beast altogether, and for that I use Log4j. However, the key differences of TE-Trace is the support for the different "maturity levels" of a particular class. This means that what you get initially with a trace level of 10 may not be what you will get after the code is more mature and the developer increments the maturity level.

Another way to look at it is imagine that you had the DEBUG level of Log4j divided up into as many sub-levels as you needed. The biggest problem with using only DEBUG is that after a while, there is so much information in the output that it becomes unusable. I know you can filter the output with Log4j, but I don't think that you should have to do that. The developers know which classes are more mature, so they should be able to indicate this fact during implementation. Once this has been done, the user/administrator sets the output level they wish to see. All of the "mature" code isn't cluttering up the trace log, but if you want it, you can still get it by using a higher trace level.