Thursday November 30, 2006 Scott Leberknight
Today I needed to install Subversion on my Macbook running OS X and was following Dan Benjamin's excellent instructions for accomplishing this task. The main difference was that I wanted to install the latest and greatest (as of today) version of Subversion, which is 1.4.2. Dan's instructions covered 1.3.1 and a co-worker was able to install SVN just fine using those instructions and the older version. I started following the instructions, substituting 1.4.2 for 1.3.1. Everything was going nicely until the configure, at which point I received an error stating "no suitable apr found". The following is the full output.
configure: Configuring Subversion 1.4.2
configure: creating config.nice
checking for gcc... gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ANSI C... none needed
checking how to run the C preprocessor... gcc -E
checking build system type... i386-apple-darwin8.8.1
checking host system type... i386-apple-darwin8.8.1
checking target system type... i386-apple-darwin8.8.1
checking for egrep... grep -E
checking whether ln -s works... yes
checking for a BSD-compatible install... /usr/bin/install -c
checking for static Apache module support... no
checking for Apache module support via DSO through APXS... no - Unable to locate /usr/include/httpd/mod_dav.h
==================================================================
WARNING: skipping the build of mod_dav_svn
--with-apxs or --with-apache must be used
==================================================================
configure: Apache Portable Runtime (APR) library configuration
checking for APR... no
configure: WARNING: APR not found
The Apache Portable Runtime (APR) library cannot be found.
Please install APR on this system and supply the appropriate
--with-apr option to 'configure'
or
get it with SVN and put it in a subdirectory of this source:
svn co \
http://svn.apache.org/repos/asf/apr/apr/branches/0.9.x \
apr
Run that right here in the top level of the Subversion tree,
then run autogen.sh again.
Whichever of the above you do, you probably need to do
something similar for apr-util, either providing both
--with-apr and --with-apr-util to 'configure', or
getting both from SVN with:
svn co \
http://svn.apache.org/repos/asf/apr/apr-util/branches/0.9.x \
apr-util
configure: error: no suitable apr found
Oops.
I searched around Google a bit to see if anyone else had encountered (and solved) this problem. Didn't find much so I decided to go ahead and follow the suggestion to install Apache Portable Runtime and then try the configuration again. In case you run into the same problem, here are the modified instructions I used to build SVN 1.4.2 for OS X. Thanks to Dan for the original instructions, and I hope the modified ones will help you out too. Admittedly I did not think too much about exactly why I needed apr and was interested in just getting it to work. So if I've done something stupid by installing apr please feel free to post a comment and let me know!
One last note is that the following commands contain my username, sleberkn, so of course you'll need to substitute your username, or follow Jason's suggestion to use $HOME instead. Before just trying these commands, first read Dan's entire post so you have all the prerequisites, such as setting your PATH correctly!
cd ~/Desktop mkdir src cd src curl -O http://subversion.tigris.org/downloads/subversion-1.4.2.tar.gz tar xzvf subversion-1.4.2.tar.gz curl -O http://mirrors.24-7-solutions.net/pub/apache/apr/apr-1.2.7.tar.gz tar xvzf apr-1.2.7.tar.gz curl -O http://mirrors.24-7-solutions.net/pub/apache/apr/apr-util-1.2.7.tar.gz tar xvzf apr-util-1.2.7.tar.gz cd apr-1.2.7 ./configure --prefix=/Users/sleberkn/Desktop/src/subversion-1.4.2 make make install cd .. cd apr-util-1.2.7 ./configure --prefix=/Users/sleberkn/Desktop/src/subversion-1.4.2 --with-apr=/Users/sleberkn/Desktop/src/subversion-1.4.2 make make install cd .. cd subversion-1.4.2 ./configure --prefix=/usr/local --with-openssl --with-ssl --with-zlib --with-apr=/Users/sleberkn/Desktop/src/subversion-1.4.2 --with-apr-util=/Users/sleberkn/Desktop/src/subversion-1.4.2 make sudo make install
Assuming all that worked, verify your installation.
which svn svn --version
The output from the above commands should show the Subversion is installed in /usr/local/bin. My output looked like this.
nic-sleberkn:~/Desktop/src/subversion-1.4.2 sleberkn$ which svn /usr/local/bin/svn nic-sleberkn:~/Desktop/src/subversion-1.4.2 sleberkn$ svn --version svn, version 1.4.2 (r22196) compiled Nov 30 2006, 17:47:45 Copyright (C) 2000-2006 CollabNet. Subversion is open source software, see http://subversion.tigris.org/ This product includes software developed by CollabNet (http://www.Collab.Net/). The following repository access (RA) modules are available: * ra_svn : Module for accessing a repository using the svn network protocol. - handles 'svn' scheme * ra_local : Module for accessing a repository on local disk. - handles 'file' scheme
Recently I came across a couple of pretty interesting things in Java 5. The StringBuilder class was introduced in Java 5 as an unsynchronized version of the rather ubiquitous StringBuffer class which has been around for ages, and which the beginner Java programmer soon learns about the first time a more experienced Java developer sees his code littered with string concatentation using the '+' operator. The reason StringBuilder was introduced (I am guessing) is that you almost never need synchronization when building up a string, or at least I've never had multiple threads building a string at the same time! So the StringBuilder class is pretty much identical to StringBuffer except its methods are not synchronized.
Another new feature Java 5 introduced is covariant return types, which permits an overriding method to return a more specialized type than the overriden method. Some good examples I've seen include this and this. In a nutshell, suppose you want to override the clone() method for a Person class. The clone() method in Object can only return, well, Object. Prior to Java 5 your overridden clone() method in Person would also have to return Object and a cast would be required. But now you can do this:
@Override
protected Person clone() throws CloneNotSupportedException {
...
}
So now there is no cast required since the overriden clone() can return the type you want - Person. This is a nice feature in general, but the thing I came across that was more interesting was the inheritance relationship between StringBuffer, StringBuilder, and AbstractStringBuilder. StringBuffer and StringBuilder both extend AbstractStringBuilder and use covariant return types in overridden methods. For example, here are the definitions of the append(String) methods for these three classes:
public AbstractStringBuilder append(String str) {
....
}
public synchronized StringBuffer append(String str) {
...
}
public StringBuilder append(String str) {
...
}
So what's cool about this is that the parent class defines the append() method to return an object of the parent type AbstractStringBuilder but the subclasses overriding this method can restrict the return type so that no casts are required. StringBuilder's append() method can return StringBuilder and StringBuffer's append() method can return StringBuffer. I found it interesting that the methods were not marked with the @Override annotation - maybe that would have been a gargantuan task to retrofit all existing code using the annotation?
But even though the covariance is cool, what was even more interesting is that AbstractStringBuilder is not a public class, as described by David Flanagan. It is defined as:
package java.lang;
// imports
abstract class AbstractStringBuilder implements Appendable, CharSequence {
...
}
So it is actually a package-private, or default - or whatever you call it - accessible class that is not visible to code outside the package. If you read the JavaDocs, they say both StringBuilder and StringBuffer extend Object, not AbstractStringBuilder! I guess JavaDoc figures what you don't know can't hurt you, right? This is interesting because I don't think I've ever seen a case where a superclass wasn't as visible as its subclasses, and David points out this is the first time he is aware it has happened (I assume in the JDK he means). I don't know if I necessarily think this is a good design, but I suppose it is an interesting way to limit who can create subclasses of an abstract class. Normally I've always wanted to openly permit subclasses of abstract classes as that is generally the point, i.e. the abstract class provides some base functionality that subclasses then must customize and extend. But if you for whatever reason need to restrict subclassing an abstract class, this is as good a way as any I suppose.
This past week I started adding a new set of features to a legacy EJB 2.x application that I wrote circa-2002 and which follows Core J2EE Patterns to the letter. In a nutshell, that means there are Struts Actions which call Business Delegates that delegate to Stateless Session Beans which in turn execute straight "Fast-Lane Reader" JDBC or talk to CMP Entity Beans with local interfaces. Whew! This is the first time in about three years that any new features have been requested for this application. Up until now it has been humming along nicely, though trying to migrate it to WebLogic 8.1 from WebLogic 7.0 was somewhat of a challenge with changed WebLogic deployment descriptor settings I needed to track down.
The new features are relatively minor, or at least they would be in a modern architecture using Spring, Hibernate, a more modern web framework than Struts, AJAX, etc. To add the new features as rapidly as possible - a week or two at most is what I was aiming for - I decided to stick to the existing architecture. The main reason I chose this path was internal consistency within the application, so there was not a mishmash of legacy and modern technologies which would undoubtedly make maintenance more difficult. The secondary reason is that I thought it would actually be faster to stick to the way it had originally been implemented, rather than try to introduce a bunch of new technologies that facilitate faster development. Whether it would have been faster to integrate newer technologies I'll never know as I am committed at this point and have implemented a fair chunk of the new features in the past few days.
But, what I've learned is just how slow and tedious using the legacy EJB 2.x architecture really is, especially now that I've done several projects using Spring, Hibernate, et. al. After all, I just want to implement a simple JDBC query and display it in a browser, right? Not with EJB 2.x! Dealing with JNDI lookups manually, obtaining and handling JDBC connections, rollbacks in Stateless Session Beans on exceptions, writing Business Delegates that essentially do nothing at all but "hide" RemoteExceptions and delegate to Session Beans and more, has really made me appreciate just how much easier things have become with the more lightweight frameworks supporting the Buzzwords-du-Jour such as IoC, Dependency Injection, Transparent Persistence, etc. This includes Spring, Hibernate, the new Java Persistence API (JPA), Ruby on Rails, and a lot more.
I now know exactly why it took me nine months to write the original version of this application back in 2002 using EJB 2.x technology. For a project of similar size and scope I'd estimate no more than three months and maybe less using modern frameworks in 2006. Probably even less if you are among those lucky enough to use Rails. So what's the point of all this? I think mainly that there has been a consistent progression towards lighter weight frameworks that just let you get your job done in a more efficient and less invasive manner. And also why DRY always results in faster development, more maintainable code, and more fun developing.

