Martin Probst's weblog

API usability

March 7, 2008, 7:51 p.m. — 0 comments

Alex on API usability

Sun is definitely bad on the developer usability part. Really.

Eh Alex, when was the last time you had to use C++/MFC or similar?

Or use some random Ruby functionality from the standard library, trying to find the documentation for it?

Or actually do something in JavaScript, with the awkward set of interpreters, and no proper documentation for any libraries?

There are certainly issues with Java (and in particular a lot of the Java libraries), but it's certainly not that bad. Though I sympathize with your frustration, I know that very well ;-)

Shell script to restore .svn directories in Mac OS X Bundles

Feb. 11, 2008, 3:57 p.m. — 1 comment

Checking in Mac OS X bundles, such as the files created by Pages.app or Keynote, into Subversion breaks, as Pages removes the metadata directories ('.svn') Subversion uses to keep track of file status.

Pretty annoying, and it doesn't seem to get fixed very soon. Following various links I found a script by Daniel Sadilek that recovers the missing .svn directories. While the script from the blog article itself doesn't work with directories that contain whitespace, the one posted in the comments by "Percy" does.

Basically you edit your checked-in bundle using Pages/Keynote/..., then run 'svnrecover ', and afterwards you can check your stuff in.

I modified it a bit to better handle folder switches by using pushd/popd, so I'm reproducing it here:

#!/bin/bash
IFS="
"

# must be dir!
if [ ! -d "$1" ]; then
  echo "Path is not a directory."
  echo "Usage: $0 [bundle directory]"
  exit 1
fi

# get info
dir=`dirname "$1"`
base=`basename "$1"`

# go to dir
pushd "$dir">/dev/null

# prefix
prefix="tmp"
prefixi=1

# does it exist?
while [ -x "$prefix.$base" ]; do
  prefix="tmp$prefixi"
  prefixi=$(( prefixi + 1 ))
done

# move to temp
echo "* moving to temp location..."
mv "$base" "$prefix.$base"

# update
echo "* svn update..."
svn update -q "$base"

# check to make sure it's a dir!
if [ ! -d "$base" ]; then
  echo "Updated path is not a folder! Restoring original!"
  mv "$prefix.$base" "$base"
  exit 2
fi

# go to dir
echo -n "* moving .svn directories"
pushd "$base" >/dev/null

# find .svn dirs
for foo in `find . -type d -name .svn`; do
  if [ -d ../"$prefix.$base"/"`dirname "$foo"`" ]; then
    # only move it if the folder exists in the modified version
    mv "$foo" ../"$prefix.$base"/"`dirname "$foo"`"
    echo -n "."
  fi
done

popd >/dev/null
echo

# replace
echo "* replacing..."
rm -Rf "$base"
mv "$prefix.$base" "$base"
popd >/dev/null
echo "* done."

Silent errors from JSTL

Jan. 31, 2008, 4:15 p.m. — 0 comments

The JavaServer Pages Standard Tag Library appears to have a habit of silently failing to work.

Boring technical details

Today I ran into a very nice issue: I tested and coded my webapp against Tomcat 6.0 with a version 2.5 web.xml. Deploying this on Tomcat 5.5 on the target system seemed to work: no errors, database was filling from webservice, Spring worked, I could access webpages, etc. But due to the niceness of JSTL a c:choose statement containing an EL expression was always false, so the page always came up with no content. Very nice to debug, as no error or anything shows up and the developer of course assumes some failure to load data.

End of the story: JSTL silently fails if the web.xml version tag and Tomcat combination doesn't fit JSTLs expectations. I needed to change my web.xml to 2.4.

Slightly less boring rant

Another example of really great software: include a versioning scheme, but don't give any errors if versions don't match, but rather silently fail.

While Java has it's deficiencies, I'm beginning to think that much could be fixed by replacing the totally broken toolchain (yes, Maven, Tomcat & Co.; I'm looking at you!) with proper software.

My current hit list would be:

And there's still a lot missing on that list.

The JVM is an awesome platform, and Java as a language is totally tolerable, and most of the platforms/libraries even sound rather sane in theory, but are a real pain to work with in practice. It's interesting to see that a small group of Ruby guys was able to craft a tool chain that's much easier to use in so little time, with no big vendor support. I think Java web applications are looking for some sort of a Rails like renovation, or they will fade into irrelevance.

SOAP with Axis, 4D and something called multiRefs

Jan. 25, 2008, 10:47 a.m. — 1 comment

SOAP really totally sucks. I just wasted several hours trying to access a certain Webservice using Axis. The server is apparently implemented using 4D.

It turns out that by default Axis (at least 1.x) uses a feature called "sendMultiRefs". This turns regular, unsuspecting messages into this:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:SomeAction xmlns:ns1="some-namespace" 
        soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <SID xsi:type="xsd:string">some param1</SID>
      <startID href="#id0"/>
    </ns1:SomeAction>
    <multiRef xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
      id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
      xsi:type="xsd:int">some param2</multiRef>
  </soapenv:Body>
</soapenv:Envelope>

The fun thing is that this happens somewhere really deep down in the Axis code - if you debug the Axis message send, all you see of the SOAP message is a regular message (without that multiRef abomination), even when you get down really close to the HTTP socket send. I found this in the end using Wireshark/Ethereal to inspect the actual packages.

Now what happens is that 4D silently drops/ignores the second parameter and apparently sets the value of that input parameter to 0. It doesn't give any error whatsoever, thanks. Additionally, due to the close coupling to the programming language, the implementation cannot make out if the parameter is not present or set to zero, because it comes out as an int value.

There are a lot of questions here. Why does Axis use a bizarre encoding scheme, that is known to cause problems with a variety of platforms, where it's totally superfluous? It even makes the messages larger.

And why is this multiRef thing there, anyways? The only thing I can find about it on www.w3.org is a mention that it's included in SOAP 1.2, but not in SOAP 1.1. I can't find any mention of it in the spec itself, though. It only appears to be useful for serializing Object graphs that are self-referencing.

Why a messaging protocol needs something like that, which is totally linked to the complex semantics different meanings of identity in different programming languages etc., is beyond me. And actually most people don't seem to implement it anyways...

It's quite frustrating to use all this complex, bizarre stuff when all you'd really need is a webservice that takes 1 parameter and returns some XML-encoded list, i.e. http://foo/bar?startID=x.

Tomcat startup timeouts in Eclipse

Jan. 21, 2008, 6:44 p.m. — 1 comment

Today starting Tomcat from Eclipse using WTP suddenly stopped working for me. Tomcat would start up all fine and nice, but then after some time Eclipse would complain that Tomcat didn't come up properly and kill it again. The strange thing: everything was actually working, and I could access the webapp with a browser.

After some intense digging I found out that Eclipse tries to connect to Tomcat via HTTP to find out if it works. I then found out using netstat -Af inet that Eclipse was indeed connecting to localhost:8080, and Tomcat was accepting the connection, but then apparently nothing happened. Eclipse kept spamming Tomcat with new connections, and after some time it hit the timeout:

Active Internet connections
Socket   Proto Recv-Q Send-Q  Local Address      Foreign Address    (state)
       0 tcp4       0      0  127.0.0.1.8080     127.0.0.1.50349    ESTABLISHED
       0 tcp4       0      0  127.0.0.1.50349    127.0.0.1.8080     ESTABLISHED
       0 tcp4       0      0  127.0.0.1.8080     127.0.0.1.50348    ESTABLISHED
       0 tcp4       0      0  127.0.0.1.50348    127.0.0.1.8080     ESTABLISHED
       0 tcp4       0      0  127.0.0.1.8080     127.0.0.1.50347    ESTABLISHED
       0 tcp4       0      0  127.0.0.1.50347    127.0.0.1.8080     ESTABLISHED
       0 tcp4       0      0  127.0.0.1.8080     127.0.0.1.50346    ESTABLISHED
       0 tcp4       0      0  127.0.0.1.50346    127.0.0.1.8080     ESTABLISHED
       0 tcp4       0      0  127.0.0.1.8080     127.0.0.1.50345    ESTABLISHED
       0 tcp4       0      0  127.0.0.1.50345    127.0.0.1.8080     ESTABLISHED
       0 tcp4       0      0  127.0.0.1.8080     127.0.0.1.50344    ESTABLISHED
       0 tcp4       0      0  127.0.0.1.50344    127.0.0.1.8080     ESTABLISHED
       0 tcp4       0      0  127.0.0.1.8080     127.0.0.1.50343    ESTABLISHED
       0 tcp4       0      0  127.0.0.1.50343    127.0.0.1.8080     ESTABLISHED
       ... and so on ...

No idea why this was exactly happening, but I fixed it by deleting all server related configuration from my workspace. That is, delete all Tomcat related configuration, exit Eclipse, and then within your workspace:

rm -r .metadata/.plugins/*server*

Of course this is just cargo cult programming, but it fixed my problem.

Why is String.format() static?

Jan. 16, 2008, 11:01 a.m. — 0 comments

I really wonder why they made java.lang.String.format(String format, Object... args) a static method. Compare:

String message = String.format("Failed to quizzle the fibble: %s", fibble);

with:

String message = "Failed to quizzle the fibble: %s".format(fibble);

The latter isn't only more object-oriented (static methods are in effect global procedures), it's also less typing.

MacHeist software bundle

Jan. 15, 2008, 8:57 a.m. — 0 comments

MacHeist offers a software bundle consisting of a set of nice Mac OS X applications for 49$. While I certainly won't need some of the applications, this includes Snapz Pro X, which itself costs 69$ standalone. Other apps include Pixelmator, CoverSutra and CSSEdit, so this is definitely worth looking at.

"Optimized for writes"

Jan. 7, 2008, 9:08 a.m. — 0 comments

Priceless @ dive into mark:

“What is that?” she exclaimed.

“It’s all the paperwork we’ve collected this year.”

“In one big pile?”

“It’s a perfectly good system. It’s just optimized for writes.”

Spring MVC / web framework. not so l33t

Dec. 20, 2007, 1:03 p.m. — 2 comments

I'm currently digging into the Spring framework a bit and just finished walking through the step-by-step tutorial. It creates a simple application that displays a list of products, and then allows you to increase the price of all of them. The price increase is validated and persisted in an HSQL database.

Behold the line counts:

      23 ./.classpath
      23 ./.project
      33 ./bin/test-context.xml
      16 ./build.properties
     308 ./build.xml
       5 ./db/create_products.sql
       2 ./db/load_data.sql
       1 ./db/server.sh
       0 ./db/test.lck
     151 ./db/test.log
      17 ./db/test.properties
      10 ./db/test.script
      39 ./src/springapp/domain/Product.java
      23 ./src/springapp/repository/InMemoryProductDao.java
      48 ./src/springapp/repository/JdbcProductDao.java
      11 ./src/springapp/repository/ProductDao.java
      20 ./src/springapp/service/PriceIncrease.java
      53 ./src/springapp/service/PriceIncreaseValidator.java
      11 ./src/springapp/service/ProductManager.java
      29 ./src/springapp/service/SimpleProductManager.java
      36 ./src/springapp/web/InventoryController.java
      46 ./src/springapp/web/PriceIncreaseFormController.java
      37 ./test/springapp/domain/ProductTests.java
      45 ./test/springapp/repository/JdbcProductDaoTests.java
     100 ./test/springapp/service/SimpleProductManagerTests.java
      26 ./test/springapp/web/InventoryControllerTests.java
      33 ./test/test-context.xml
       2 ./war/index.jsp
      54 ./war/WEB-INF/applicationContext.xml
       3 ./war/WEB-INF/classes/jdbc.properties
      12 ./war/WEB-INF/classes/messages.properties
      18 ./war/WEB-INF/jsp/hello.jsp
       5 ./war/WEB-INF/jsp/include.jsp
      30 ./war/WEB-INF/jsp/priceincrease.jsp
      34 ./war/WEB-INF/springapp-servlet.xml
      33 ./war/WEB-INF/web.xml
    1337 total

So apart from telling me that either I or Spring are indeed totally 1337, how on earth do they justify this? To be fair, it's about 200 lines less if you don't calculate the DB log and the Eclipse specific files, but still, well over 1000 LOC for that?

What's even worse is the number of concepts you have to understand. Apart from the probably ok Java and SQL stuff - why do we need a build file that says essentially "do as usual", but on >300 lines? And in the particular funny ant style - lots of <property name="src.dir" value="src"/>. When did this change the last time? Why do we need a JSP taglib for even the most basic stuff? Separate setup for the application server for each tiny project? Three separate properties files? Lots of copying jars around?

And then all the XML configuration. >150 LOC not counting the build file. With gems like this:

      <property name="driverClassName" value="${jdbc.driverClassName}"/>
      <property name="url" value="${jdbc.url}"/>
      <property name="username"  value="${jdbc.username}"/>
      <property name="password" value="${jdbc.password}"/>

Isn't that the kind of stupid, repetitive task we created computers for?

Repeated bloat

And it's not just the one-time setup. Creating the form to increase prices with, i.e. a simple form to enter exactly one integer requires these five(!) components. The PriceIncreaseFormController (50 LOC), the PriceIncrease class to hold the integer(!) (20 LOC), the PriceIncreaseValidator (50 LOC), the priceincrease.jsp (30 LOC), and the XML configuration to glue it all together with 10 lines. That's 160 lines of code for one simple form, without the code that actually performs the operation or any tests.

Loosely coupled XML

Something else that bugs me is the looseness of this thing. Not as in loose coupling, but as in "loose and falls apart". Spring uses Java, a static, compiled, type checked language. This static-ness results in less expression, but usually better performance and earlier-caught errors. So far so good. But then we outsource half of our application logic into XML configuration files, with no checks at all. With an abundance of unchecked references to Java classes, field names, hard coded and duplicated URLs and so forth.

The benefits of a compiled language like Java are effectively eliminated by this. Typos in XML files will create NullPointerExceptions at runtime, refactoring doesn't work anymore and the code cannot be understood as is anymore, but only through reading several XML files. This dispersion of single concerns into lots of files really scares me.

A better framework?

I wonder if this mess is simply due to Java or if there is a better way of doing this. I have seen references to Spring's annotation based configuration, maybe that helps a bit. Even in static Java it should be possible to do better, with some reflection and by-convention magic.

Java closure syntax with a dash of Smalltalk

Dec. 18, 2007, 12:24 p.m. — 0 comments

I just came across a curious paragraph in the Closure Syntax Proposal for Java 7 by Gilad Bracha, Neal Gafter, James Gosling, and Peter von der Ahé, on page 8:

We are also experimenting with generalizing this to support an invocation syntax that interleaves parts of the method name and its arguments, which would allow more general user-defined control structures that look like if, if-else, do-while, and so on.

This doesn't play well with the return statement being given a new meaning within a closure; it returns from the closure instead of the enclosing method/function. Perhaps the return from a closure should be given a different syntax:

^ expression;

Note the Smalltalk-ish "^" return symbol, with the reference to interleaving method name parts and arguments before. I first thought this was an insider joke, but they seem to be serious about that ;-)

Other than that the proposal is really nice, I think. It fits very well into the existing Java syntax - the new blocks are simply blocks as they always have been, and the syntax for nested functions looks exactly like regular Java methods. They also seem to have made up their minds about the necessary type system changes.