Here in the Here and Now

It’s easy for software companies to focus on the next release; it’s new and improved and the blush is still on the bloom. And it’s not Scoble’s job to help customers employ the current release. But when facing your customers, “Not my department” doesn’t go very far. The answer should be “let me get someone to help you with that.”

The Microsoft bloggers are covering topics that they’re passionate about. That’s the way that it should be. But either there are no microsofties passionate about the current tools, or they’re not being encouraged to get into the game. I’d like to believe that it’s the latter, that consulting and training want to help and are being held back. But it’s up to Microsoft to prove it.

Microsoft may be focused on the future. But most of us are focused on the here and now.

Getting Started with OpenEJB

Simple is good. But working in Java can get to be complicated. Which is why I’ve started exploring OpenEJB, an open source, modular, configurable, and extendable EJB Container System and EJB Server. OpenEJB peels away some of the obfusticating java infrastructure and gets down to the bare code.

“Hello World” is the canonical beginning program, and the EJB version comes as a Stateless Session Bean. The bean is 99% boilerplate, so I’ll skip that and go straight to the ant build file. But everything is included in the zip distribution.

Before we get started, I assume that you are familiar with ant. If you don’t, then may I suggest that you start with my Ant tutorials. Just in case there is a version specific problem, here is my Java Software configuration. And windows users are forewarned that there is one required change [that I know of].

My build file starts out with some property assignments. You must change the OPENEJB property to reflect the location of your OpenEJB distribution. The remaining properties should be fine. Note that I’m using two properties for the EJB jar file, JarName and BeanJar – JarName is the jar basename and BeanJar is a location bound to the full path.

1
2
3
4
5
6
7
<property name="src-dir"  location="src" />
<property name="obj-dir" location="obj" />
<property name="TALK" value="false" />
<property name="DEBUG" value="true" />
<property name="OPENEJB" location="/Projects/Java/openejb" />
<property name="JarName" value="hello.jar" />
<property name="BeanJar" location="${JarName}" />

Next, I define three classpaths. The first classpath is used to compile the driver class and the Session Bean class and interfaces. The second classpath is used when executing against a remote server. And the third classpath is used when executing against a local server. The execution classpaths were determined by trial and error and may be missing a jar file or two.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<path id="classpath.base">
<pathelement location="${obj-dir}" />
<pathelement location="${OPENEJB}/lib/ejb-2.0.jar" />
</path>
<path id="classpath.runRemote">
<path refid="classpath.base" />
<pathelement location="${OPENEJB}/dist/openejb_client-0.9.2.jar" />
<pathelement location="${OPENEJB}/dist/openejb-0.9.2.jar" />
</path>
<path id="classpath.runLocal">
<path refid="classpath.base" />
<fileset dir="${OPENEJB}/dist" includes="*.jar" />
<pathelement location="${OPENEJB}/lib/log4j-1.2.1.jar" />
<pathelement location="${OPENEJB}/lib/jta_1.0.1.jar" />
<pathelement location="${OPENEJB}/lib/jca_1.0.jar" />
<pathelement location="${OPENEJB}/lib/castor-0.9.3.9.jar" />
<pathelement location="${OPENEJB}/lib/castor-0.9.3.9-xml.jar" />
<pathelement location="${OPENEJB}/lib/xercesImpl-2.0.2.jar" />
<pathelement location="${OPENEJB}/lib/jakarta-regexp-1.1.jar" />
<pathelement location="${OPENEJB}/lib/idb_3.26.jar" />
</path>

Targets to build the object directory, compile the java source into the object directory, and clean it all up.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<target name="init">
<mkdir dir="${obj-dir}" />
</target>
<target name="compile" depends="init">
<javac srcdir="${src-dir}"
destdir="${obj-dir}"
debug="${DEBUG}"
>

<classpath refid="classpath.base" />
</javac>
</target>
<target name="clean-compile">
<delete verbose="${TALK}" dir="${obj-dir}" />
</target>

A target to build our EJB jar file. Note that it includes both the object code and the META-INF directory. And the companion target to clean up.

1
2
3
4
5
6
7
8
9
10
11
12
<target name="jar" depends="compile">
<jar destfile="${BeanJar}">
<fileset dir="${obj-dir}"
includes="org/**" />

<fileset dir="${src-dir}"
includes="META-INF/**"
/>

</jar>
</target>
<target name="clean-jar">
<delete verbose="${TALK}" file="${BeanJar}" />
</target>

A couple of targets to deploy the jar file to OpenEJB. In the deploy-check target, we use the uptodate task to compare the deployed jar in ${OPENEJB}/beans to our local jar and set the deploy.notNeeded property for the deploy target. Note that ${BeanJar} is a location and early bound to the full path name, and ${JarName} is a normal property represents the jar basename.

The deploy target executes the openejb deploy command unless deploy.notNeeded is set in the deploy-check target. This build file uses the unix executable script, openejb.sh. Changing to openejb.bat should work on windows, but I haven’t tested it. We use the following deploy options:

  • -a: automate deployment as much as possible.
  • -c: copy the jar rather than move (-m).
  • -f: force the move/copy, overwriting an existing jar with the same name.
1
2
3
4
5
6
7
8
9
10
11
<target name="deploy-check">
<uptodate property="deploy.notNeeded"
targetfile="${OPENEJB}/beans/${JarName}"
srcfile="${BeanJar}"
/>

</target>
<target name="deploy" depends="jar,deploy-check" unless="deploy.notNeeded">
<exec dir="${OPENEJB}" executable="${OPENEJB}/openejb.sh">
<arg line="deploy -a -c -f ${BeanJar}"/>
</exec>
</target>

And a pair of targets for execution against a remote and a local OpenEJB server. The choice between local and remote servers is defined by the Properties object used in creating the InitialContext object. We provide the appropriate properties as system properties.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<target name="remote" depends="deploy">
<java classname="HelloDriver"
fork="true">

<classpath refid="classpath.runRemote"/>
<sysproperty key="java.naming.factory.initial"
value="org.openejb.client.RemoteInitialContextFactory" />

<sysproperty key="java.naming.provider.url" value="127.0.0.1:4201" />
<sysproperty key="java.naming.security.principal" value="me" />
<sysproperty key="java.naming.security.credentials" value="me" />
</java>
</target>

<target name="local" depends="deploy">
<java classname="HelloDriver"
fork="true">

<classpath refid="classpath.runLocal"/>
<sysproperty key="openejb.home" value="${OPENEJB}" />
<sysproperty key="java.naming.factory.initial"
value="org.openejb.client.LocalInitialContextFactory" />

</java>
</target>

The HelloDriver class with our main program. The build file supplies the OpenEJB properties as system properties and the code just passes them on to the InitialContext constructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import org.acme.*;

import java.util.Properties;
import java.rmi.*;
import javax.ejb.*;
import javax.rmi.*;
import javax.naming.*;


public class HelloDriver
{


public static void main( String[] args )
{

try {
InitialContext ctx = new InitialContext( System.getProperties() );
Object obj = ctx.lookup( "Hello" );
HelloHome home = (HelloHome)
PortableRemoteObject.narrow( obj,HelloHome.class );

Hello hello = home.create();
System.out.println( hello.hello() );
}
catch ( NamingException ne ) {
ne.printStackTrace();
}
catch ( CreateException ce ) {
ce.printStackTrace();
}
catch ( RemoteException re ) {
re.printStackTrace();
}
}

}
//
// $Id: HelloDriver.java,v 1.1.1.1 2004/01/26 19:26:08 dwight Exp $
//

Now we can deploy the Bean to OpenEJB:

1
$ ant deploy
Buildfile: build.xml

init:
    [mkdir] Created dir: /Projects/Learn/OpenEJB/hello/obj

compile:
    [javac] Compiling 4 source files to /Projects/Learn/OpenEJB/hello/obj

jar:
      [jar] Building jar: /Projects/Learn/OpenEJB/hello/hello.jar

deploy-check:

deploy:
     [exec] --------------SUPPORT INFO-------------
     [exec] Darwin 6.8 Darwin Kernel Version 6.8: Wed Sep 10 15:20:55 PDT 2003;
                                         root:xnu/xnu-344.49.obj~2/RELEASE_PPC 
     [exec] Using JAVA_HOME:     /usr/bin/..
     [exec] Using OPENEJB_HOME:  /Projects/Java/openejb-0.9.2
     [exec] .
     [exec] OpenEJB Deploy Tool 0.9.2    build: 20030605-0409
     [exec] http:/\/openejb.sf.net

     [exec] This jar contains the following beans:
     [exec]   Hello


     [exec] -----------------------------------------------------------
     [exec] Deploying bean: Hello
     [exec] -----------------------------------------------------------

     [exec] ==--- Step 1 ---==

     [exec] Auto assigning the ejb-name as the deployment id for this bean.

     [exec] Deployment ID: Hello
     [exec] ==--- Step 2 ---==

     [exec] Auto assigning the container the bean will run in.

     [exec] Container: Default Stateless Container

     [exec] -----------------------------------------------------------
     [exec] Done collecting deployment information!
     [exec] Creating the openejb-jar.xml file...done
     [exec] Writing openejb-jar.xml to the jar...done

     [exec] Congratulations! Your jar is ready to use with OpenEJB.

     [exec] If the OpenEJB remote server is already running, you will
     [exec] need to restart it in order for OpenEJB to recognize your bean.

     [exec] NOTE: If you move or rename your jar file, you will have to
     [exec] update the path in this jar's deployment entry in your 
     [exec] OpenEJB config file.



BUILD SUCCESSFUL
Total time: 22 seconds

Execute against a Remote Server (Don’t forget to start the OpenEJB Server).

1
$ ant remote
Buildfile: build.xml

init:

compile:

jar:

deploy-check:

deploy:

remote:
     [java] Hello, World!



BUILD SUCCESSFUL
Total time: 9 seconds
And execute against a Local Server.

$ ant local
Buildfile: build.xml

init:

compile:

jar:

deploy-check:

deploy:

local:
     [java] OpenEJB 0.9.2    build: 20030605-0409
     [java] http:/\/openejb.sf.net
     [java] Hello, World!



BUILD SUCCESSFUL
Total time: 1 minute 4 seconds

Download the code for this OpenEJB Stateless Session Bean and get started on something a bit more substantial.

Disclaimer: I don’t claim to be an expert on OpenEJB. Please send comments and corrections.

Google Leeches

This may be a sign that I’ve become a have rather than a have not, but I control the flow of GoogleJuice from this site. Make a good contribution to the conversation and I’ll send some your way. But I’m not going to automatically allow comments, trackbacks, and referers to steal it away. I agree with Simon Willison, if the cost of eliminating spam is the loss of some Google ego then [it is] well worth paying. And the sooner we stamp it out, the sooner we can move on to more rewarding endeavors.

Why Use Standalone Comment and Trackback Servers?

My motivation in developing Standalone Comment and Trackback Servers for Radio Userland was to improve my weblog performance and to minimize my external dependencies. Radio Userland renders static html pages and has very good server performance with three exceptions: the comment count, the trackback count, and the statistics web bug.

When your Radio Userland weblog is slow, the culprit is usually the comment and/or trackback counters. The static page is quickly delivered, but page rendering has to wait for the counter javascript from the comment and trackback servers. Switching to standalone servers can provide a more consistent response and eliminate long delays. The statistics web bug can also be slow, but your browser can render the page while it’s waiting on the web bug.

Go Panthers

I was going to be neutral during this Super Bowl – but my brother reminded me that there are only 2 degrees of separation between myself and the Carolina Panthers. My friend Pete Brown was on the football staff at Fork Union Military Academy. While at Fork Union, Pete got to know the Richardson family (founder/owner of the Panthers). So for the purposes of this Super Bowl, I’m a Southerner.

Standalone Comments and Trackback for Radio Userland

I’m pleased to announce the availability of Standalone Comments and Trackback for Radio Userland. This release refactors my previous Standalone Trackback package to support standalone comments. You might be interested in this package if you: host your own Radio Userland weblog, know some perl, and want to improve the performance of your weblog.

Requirements

  • Web Server capable of running cgi scripts
  • Perl with the following Perl Modules:
    • File::Spec
    • Storable
    • CGI
    • CGI::Cookie I believe that these are core modules as of Perl 5.6.0.

14 May: Updated to allow comment editing.

Bloggers, Start Your Directories

Scoble is thinking about building a directory of blogs. I think that he should go for it. In fact, I think that everyone should build a directory of RSS feeds. Because there are some interesting things to be done with the data once we attain critical mass. I’d love to see the most popular feeds on a topic or feeds that are popularly believed to straddle multiple topics.

I used to worry about standardizing names, but now I believe that it’s a self correcting problem. We may start out with chaos, but names should autocorrelate once the results are compiled and published. People want their votes to count, and they will shift toward comformity to insure that they will.

No mod_gzip here

James Robertson remarks on the paucity of sites supporting conditional get and gzip compression – I’m guilty as charged.

I have a fairly typical hosting plan: charged for disk space and bandwidth above my base allocation with all CPU cycles included. Since my bandwidth usage is comfortably below my base allocation, there is no motivation for me to conserve. And since it would shift usage from a metered resource (bandwidth) to an unmetered resource (CPU cycles), there is no motivation for my host to provide mod_gzip.

Weblog software should have the option to generate both a normal and a gzipped RSS feed. Then we could turn on gzip content encoding and apache would serve the gzipped version when appropriate. This swaps between two metered services and doesn’t require a change to the billing model. I think that hosting providers could buy into that.

PS: That’s a pretty old link. I have no idea whether gzip content encoding is still supported.

The Itch You Just Can't Scratch

People may be agents of change. But that gee-whiz software you’re developing is just a tool – and while tools may enable change, people will make the change happen. When you’re evangelizing new tools, you’re looking for people with an itch they just can’t scratch. And once you show them how to scratch that itch, you can own them for life.

Yesterday, StartupSkills.com posted on understanding the early market and visionaries. Sometimes visionaries will buy into your product vision. But sometimes they’ve had the itch for years, wrestling with its application and ramifications, but unable to give it a good scratch. They’re the ones who will run with your product while others are taking baby steps. And they’ll take your product to the next level.

Until weblogs came around, there were people with something to say and no good way of saying it. Weblogs gave those people a way to scratch that itch. Previously, I dissed the prospect of CEO weblogs – they just don’t have the itch. But those same CEO’s preside over companies full of people eager to scratch. They’re the ones who can transform the company relationship with customers.