John Topley's Weblog

A picture of some pens

July 2004 Article Archive


Summer Madness

Friday, 30 July 2004

It looks like the silly season is upon us again. Respected PC Magazine columnist John C. Dvorak writes about Windows' security problems and implores Microsoft to spend some of its billions of dollars on fixing its software. Nothing wrong with that, good idea.

However, I think Microsoft already spend rather a lot of money on Windows development. Then he writes about how the development of Windows NT was rushed—I wouldn't call five years rushed—and says that compromises were made. Well of course compromises were made! It's not possible to create anything of any significance without making compromises. There are design trade-offs involved and the burden of having to be compatible with programs developed whilst many of the Windows NT developers were still at school. Any engineer knows that a good engineer is one who can find the best compromises.

Next, Dvorak goes on to write possibly the stupidest sentence that I've read all year: “But with $30 billion, couldn't a new architecture be designed that would break the OS into 10,000 parts, each of which could be coded in a few months, then put back together?” Slaps forehead! There's so much wrong with this question, that I barely know where to start, but I'll give it a go.

First of all, throwing money at a problem is not an automatic guarantee of success. Microsoft already have the lion's share of the brightest people in the industry and there's only so many of those to go around. And the ones they do have are almost certainly working flat out.

Secondly, it's generally acknowledged that rewriting from scratch is a bad idea, because you're throwing away accumulated knowledge. How would you even begin to specify 10,000 components that must collaborate to form a whole that would be able to run existing Windows software? Those components would have at least 10,000 ways of interacting with each other, and the real figure would be much, much higher. You would spend a lifetime on integration testing alone.

Moreover, how would you capture the essence of the good aspects of Windows whilst eliminating the bad? The product has evolved over twenty one years, something that cannot be short-circuited in a few months. Why doesn't Dvorak address these questions in his column? May I suggest a far better read about Windows security and security in general.

In another shining example of idiocy, Amazon e-mailed me this week to tell me that I recently purchased products related to website development, programming or databases. Evidently they're not quite sure which it is.

The e-mail went on to speculate that I might have my own website and would I be interested in joining their Associates Programme? The thing is, I'm already a member and have been since I started this site. They are aware of this, because they hassle me each quarter and ask me to select one of their byzantine payment structures. I guess they've yet to discover targetted marketing and joined up systems.

top | link | comments ()


Jakarta Struts De-Mystified Part 2

Saturday, 17 July 2004

Last time I introduced this series of articles and the Web Forum application, and I explained what would and would not be covered. This time I'm going to cover the persistence and business object layers, and we'll roll our sleeves up and cut some code.


Persistence Layer

The persistence layer in the Web Forum application is deliberately very simple. There are two database tables, one for posts and another for users. The posts table stores topics and their replies. The users table stores the details of the registered users of the application. These tables are accessed using data access objects (DAOs), which are just Java objects that perform simple object-relational mapping. In other words, they take a Java object and persist its contents into a table and vice-versa.

My DAOs have the appropriate SQL statements embedded in them, although this probably isn't good practice because database administrators like such things to be externalised so they can tune them. I have also created an abstract superclass for all my DAOs, which contains utility methods that obtain a JDBC connection from a data source and close database resources etc.

This is the schema for the posts table:

FieldTypeNullableKeyExtra
PostIDint(10) unsignedPrimaryAuto increment
SubjecttextYes
ReplyCountint(10) unsigned
UserIDint(10) unsigned
CreationDatedatetime
Messagetext
ParentIDint(10) unsigned

—The most interesting feature of this table is the ParentID column. This links replies back to their parent topic. The Subject column is null when a post is a reply and not a topic. I'm storing the number of replies to each topic in a ReplyCount column. Technically this is redundant because it could be calculated, but I'm storing it because MySQL doesn't currently support nested SQL SELECT statements.

The CreationDate column originally auto-updated, but I changed this because the date and time of the original topic were getting updated to the current date and time whenever a reply was added to that topic.

This is the schema for the users table:

FieldTypeNullableKeyExtra
UserIDint(10) unsignedPrimaryAuto increment
Usernamevarchar(8)
Passwordvarchar(16)
Forenamesvarchar(64)
Surnamevarchar(64)
CreationDatedate

The MySQL SQL script to create these tables is in src/sql/create_tables.sql. This script can be run from a query window in MySQL Control Centre. Note that it assumes the existence of a database named webforum. Also, because we're not creating the functionality to create new topics in this article, you'll have to manually insert some test data so that you have some topics to display.


Business Object Layer

I didn't have to do much thinking to come up with the business objects in the application, as they're pretty obvious. There are classes for individual posts and users, as well as collections of posts and users. The class model—excluding the Struts classes—is shown below:

A section of the Web Forum class model. Click to view the entire model.
A diagram of the Web Forum class model

—Some of these classes—such as UserCookie—will be covered later in the series. As can be seen from the class model, a Posts class contains a collection of Post objects at runtime, and features methods for retrieving this collection and for adding a new post. The Post class itself has attributes corresponding to the columns in the posts table, and overloaded constructors which are invoked depending upon whether the post is a topic or a reply. Accessors and mutators (getters and setters) are not shown on the class model.

The Users class contains a collection of User objects at runtime, and features methods for retrieving this collection and for adding a new user. In fact, I made the getUsers method deprecated after I discovered that I'd coded it but didn't actually call it from anywhere! The User class has attributes mirroring the columns in the users table, as well as a convenience getDisplayName method that returns the user's forenames and surname with a space character in the middle.


Project Structure

The organisation of the source code folder tree is shown on the left.

The source code folder tree.
A picture of the source code folder tree shown in Windows Explorer

Java source code files go under src, and the Java package hierarchy is rooted at com.johntopley.webforum. The public_html folder corresponds to the root of the web application.

I always put JSPs under pages because then they can be protected by the web container using J2EE declarative security. Anything in public_html and its sub-folders really should be regarded as public.

I also like to separate the Struts configuration files out into a config folder, although usually you'll see them stored directly under WEB-INF.

The application entry point is public_html/index.jsp, which is declared as a welcome file in the web.xml web application deployment descriptor. Let's take a look at index.jsp:

<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>
<%@ page session="false" %>
<logic:redirect forward="ViewTopics" />

—All this page does is transfer control to the Struts framework, because if we're going to use a framework then we want to be using it as soon as possible. Struts ships with a number of JSP tag libraries (taglibs) and here we're using the logic taglib, which handles the conditional generation of output text, looping over object collections and application flow management. In this case the redirect tag performs an HTTP redirect for us to a Struts logical URL. More about that in a moment.

One thing to note about the Web Forum application is that I'm using the Servlet 2.3 specification syntax for referencing the taglibs using URIs, rather than referring to TLD files in the web.xml file. This is documented in section 5.4.3 of The Struts User's Guide.


The Heart Of Struts

The heart of Struts is the config/struts-config.xml file. This file defines the flow of the application and tells Struts which classes to use for what. The Struts ActionServlet is a controller class that reads this file and receives all incoming requests for the web application. The ActionServlet needs to be configured as a servlet in the web.xml file:

<servlet-name>action</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
  <init-param>
    <param-name>config</param-name>
    <param-value>/WEB-INF/config/struts-config.xml</param-value>
  </init-param>
  .
  .
  .

The main part of the struts-config.xml file covered by this article is:

<struts-config>
  <global-forwards>
    <forward name="ViewTopics" path="/ViewTopics.do"/>
  </global-forwards>

  <action-mappings>
    <action
      path="/ViewTopics"
      type="com.johntopley.webforum.controller.__
        action.ViewTopicsAction"
      scope="request">
      <forward
        name="Topics"
        path="/WEB-INF/pages/topics.jsp"
      />
    </action>
  </action-mappings>
</struts-config>

—Struts introduces a layer of indirection into web applications because it uses logical URLs. This means that the address you see in the browser's address bar does not correspond to the physical location of that resource on the web server. This allows developers to easily move resources around without breaking things. The Struts name for the association of a logical name with a resource is an ActionForward, often just called a Forward. The Struts configuration file contains a global-forwards section that allows Forwards to be configured that are available throughout a Struts application. These are effectively the application's entry points.

Another key Struts concept is the Action class. Actions are simply Java servlets, so anything a servlet can do, an Action class can do. Actions are used to process requests for specific URLs. Generally they should act as a thin layer around the business objects layer, which does the real work.

Actions are referred to by Action Mappings, which again, are logical URLs. The Struts convention is that Action Mappings end with .do. The web.xml file needs to be configured so that the Struts ActionServlet is used to process any URL matching the pattern *.do, as shown here:

<servlet-mapping>
  <servlet-name>action</servlet-name>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>

Flow Of Events

To recap where we've got to, the index.jsp page redirects to the ViewTopics global ActionForward, and this passes control to the /ViewTopics Action. Struts knows which Action class to invoke because the type attribute in the Action Mapping gives the fully-qualified name of the associated Java class, which must inherit from org.apache.struts.action.Action, and must have an execute method with the following signature:

public ActionForward execute(ActionMapping mapping,
          ActionForm form,
          HttpServletRequest request,
          HttpServletResponse response) throws Exception

—The mapping parameter is an ActionMapping object representing the ActionMapping that invoked this Action. The form parameter is used if an HTML form is associated with the request. This topic will be covered later in this series. The request and response parameters highlight the fact that an Action class is just a specialisation of a servlet.

The Web Forum application uses a BaseAction abstract class that inherits from the org.apache.struts.action.Action class mentioned earlier. The other Action classes within the application inherit from BaseAction, so it serves as an extension point where functionality common to all Action classes can be added if required. This should be considered good practice.

Important: Action classes should not use instance variables, as they are not thread-safe. State should be shared by being passed as parameters to methods.

This is the execute method in ViewTopicsAction.java:

public ActionForward execute(ActionMapping mapping,
          ActionForm form,
          HttpServletRequest request,
          HttpServletResponse response) throws Exception
{
  request.setAttribute(KeyConstants.POST_LIST_KEY,
    new PostsDAO().getTopics());

  return mapping.findForward(ForwardConstants.TOPICS_PAGE);
}

—A new PostsDAO object is instantiated and its getTopics method called. This method uses the following SQL statement to query the posts table:

SELECT  p.PostID, p.Subject, p.ReplyCount, p.UserID, p.CreationDate
FROM  Posts p
WHERE  p.ParentID = 0
ORDER BY  p.CreationDate DESC

—The SQL WHERE clause ensures that only topics are selected. The getTopics method returns an instance of the Posts class i.e. an ordered collection of Post objects. This instance is stored in the HTTP request under the key referred to by the KeyConstants.POST_LIST_KEY constant. The JSP that displays the list of topics will use this Posts object stored in the request. Finally, the findForward method of the ActionMapping class is invoked. This takes a String parameter that is the name of a Struts Forward to pass control to. The ForwardConstants class contains all of the Forward names used within the Web Forum.

As well as global ActionForwards, Struts also has local ActionForwards. These are simply Forwards that are local in scope to a single Action Mapping. In other words, they are not globally visible within the application.

Important: Struts gives precedence to local ActionForwards over global ActionForwards.

A local Forward is used within the /ViewTopics Action Mapping to hold a reference to the JSP that displays the list of topics:

<forward name="Topics" path="/WEB-INF/pages/topics.jsp"/>

—After lots of indirection, we finally have a physical path to a page! Although topics.jsp is included with the source code downloads so you can see the list of topics, I'll leave the explanation of how it works until next time.


Configuring The MySQL Data Source

Before the application can be run using JDeveloper, a data source for the MySQL database needs to be created, using the steps given below:

  1. Copy mysql-connector-java-3.0.11-stable-bin.jar to <JDEVHOME>/jdk/jre/lib/ext.
  2. Add a global data source named WebForumDS to <JDEVHOME>/jdev/systemX.X.X.X.XXXX/oc4j-config/data-sources.xml as shown below:
<data-source
  name="WebForumDS"
  location="jdbc/WebForumCoreDS"
  ejb-location="jdbc/WebForumDS"
  xa-location="jdbc/xa/WebForumDS"
  inactivity-timeout="30"
  class="com.evermind.sql.DriverManagerDataSource"
  connection-driver="com.mysql.jdbc.Driver"
  username="username"
  password="password"
  url="jdbc:mysql://localhost:3306/webforum?autoReconnect=true"
/>

Source Code Downloads

To reduce the download sizes, I've split the Struts JAR files that go into WEB-INF/lib into a separate download.


Next Time

This installment has been quite a lot longer than I'd anticipated, but we've covered a lot of important ground. Next time we'll take a look at how the Topics page works and we'll add the code that allows the user to click on a topic to view that topic and any replies to it.

top | link | comments ()


Reality Metaphor

Saturday, 10 July 2004

I've just had a strange thought. Imagine what it would be like if you took the desktop metaphor popularised by MacOS and Windows and turned it inside out and applied it back to real life.

Your desk would be inside a manilla folder, which itself was inside a filing cabinet drawer. The surface of your desk would be covered with a picture of some clouds or maybe something a bit more personal, and in the corner would be a wastebasket. In the other corner would be the filing cabinet that your desk was in. In other words, your desk would exist in a quantum state whereby it simultaneously contained a filing cabinet and was contained by it. Also on your desk would be pieces of paper referring you to documents stored in your filing cabinet.

Some people would have desks that were four or eight times larger than average. In spite of all this extra room, they'd only be able to work within a regular desk-sized area at any one time.

You would need a different pair of glasses in order to be able to read each different type of document you had, and a different pen to write them. Sometimes you'd get documents from others that you couldn't read because you didn't own the appropriate glasses. Other times, you'd need to upgrade your glasses in order to be able to read the document.

All of this is extreme of course, but you often have to take things to extremes to discover their inadequacies. The basic desktop metaphor hasn't changed a great deal in the thirty-odd years since it was invented. All that's really improved has been the quality of the graphics.

top | link | comments ()


Marketeers Can't Count

Thursday, 01 July 2004

What the blazes is going on with software version numbers? Sun have just announced that the next version of Java is going to be branded as Java 5 and not Java 2. So instead of J2SE 1.5 and J2EE 1.5—I'm ignoring the Micro Edition because my mobile phone doesn't have a JVM—we're going to have J2SE 5 and J2EE 5.

R-i-g-h-t. So that's Java 2 Enterprise Edition, version five, or if you prefer, the fifth version of Java 2. Java 1.2 was rebranded as the Java 2 Platform because it tripled the size of the platform (from 504 classes to 1520 according to my copy of Java In A Nutshell). So Java 1.3 must have been the second version of Java 2, 1.4 was the third version and now 1.5 is the fourth…oh damn, it's all gone wrong. If Sun were to follow what they did previously, then surely it would become the Java 3 Platform, but I guess there's no fun to be had there.

How many Java programmers who are fully au fait with the intricacies of generics will now fail the HR filter because they are “only” certified for the Java 2 platform and not Java 5? People are going to get confused. Heck, I'm confused and I know how to use a Struts Multibox!

Of course it's not just Sun who are guilty of manipulating version numbers for marketing purposes. All of the major software companies do it. Last week I upgraded from Oracle JDeveloper 9.0.3 to 9.0.4 and was surprised to see that it was actually JDeveloper 10g:

Hey everyone, it's JDeveloper 10g!
A picture of the Oracle JDeveloper 9.0.4 splash screen

Fantastic! Now I can use all those great grid computing features that Oracle have added to JDeveloper. Then I checked the about box:

…or is it?
A picture of the Oracle JDeveloper 9.0.4 about box

—Oh my! I've been conned, it's only a 9i release and who wants that now that 10g is out? An Oracle employee tried to rationalise it to me by saying that the software is part of the 10g suite, but I wasn't convinced. I thought I'd installed an IDE, not a bathroom. Does anybody understand Oracle version numbers? I find it hard enough getting to grips with the fact that Oracle offer multiple versions of the same software for download, but that's to do with trying to keep the development environment and application server in step.

Microsoft are past masters of the version number lottery. Who can forget when Word jumped from version 2.0 to version 6.0. Now there were a lot of new features in Word 6.0, and they were proper features, not just the enterprise or collaboration tinsel that we've been getting since Word 97. I think the real reason for the change was to enable WinWord to catch up with Mac Word, which did have the intervening versions.

Windows NT launched at version 3.1, the official reason being synergy with Windows 3.1, the cynical reason being because everybody knows that Microsoft software generally isn't very good until the third version. However, Microsoft's master stroke was the rebranding of Windows 4.0 (Chicago) to Windows 95, thus instantly ensuring that you were a nobody if you were running last year's Windows. Unfortunately, they soon discovered that Windows 95 became last year's Windows and users became confused because they were waiting for Windows 96 or Windows 97. I have actually heard someone tell a help desk person that they were running Windows 97. I didn't have the heart to intervene and point out that they were using Office 4.2 on Windows 95. I bet you thought I was going to say Office 97 then, didn't you? I'm sticking to how it actually was.

Now we've ended up at Windows XP via the naff-sounding Windows 2000. I actually like the name Windows XP and it avoids the model year problem. I think that truly the most fascinating thing about Windows Longhorn just might be the name. I hope Microsoft come up with a good one.

Look, version numbers really aren't difficult. You increment the major version for a major new release and the minor version for a less significant or maintenance release. One of the odd things about odd numbered versions is that oddly, they're often viewed with the odd amount of affection. Windows 3.0 broke Windows—in so many ways—and Windows 5.0 a.k.a Windows 2000 is widely regarded as a good version. Delphi programmers love Delphi 3.0 and Delphi 5.0. You have to be careful not to go too high with your numbers though, because although that implies maturity, it also implies bloat. For years Borland JBuilder was the Java IDE to have, but as soon as the version number started climbing, its reputation waned. Maybe that was because Borland brought out a new JBuilder seemingly every fortnight, whilst my beloved Delphi was left to wither on the vine.

When the version number gets too high you have to switch to letters. “XP” has been the preferred combination for a while now, but it's recently become passe. The latest buzzword is “tiger”. Apple's pre-emptive strike against Windows Longhorn is codenamed Mac OS X Tiger, and who can forget that Java 1.5—I'm so sorry, Java 5—was also a tiger. What will they think of next?

top | link | comments ()

home | archive | kb | media | about | contact | accessibility
Copyright © 2003 - 2005 John Topley. Made with CityDesk.