Thursday, September 17, 2009

Subversion – Odd Problems and Funny Solutions

I've been using Subversion and TortoiseSVN since 2005.  They're both great technologies and I'm very happy they exist.  However, I think anyone who's been using them for a while has periodically encountered some weird problems and has had to come up with a few strange (and even funny) solutions.  I certainly have.  In this post, I describe one example.

Earlier this week, a developer I work with saw the following in a TortoiseSVN window when he ran update on a working copy:

Error: Couldn't do property merge 
Error: Unable to make name for 'C:\tempfile'

Not knowing how to proceed, he asked me for help.  We tried my typical first approach: running cleanup via Tortoise on the working copy.  That didn't fix it, so we ran a "Check for modifications" and discovered that there were a few temp files scattered through the directory tree.  We deleted those and tried again.  Still the same message, so on to Google.  I searched for various permutations of the error messages, but was unable to find anything other than code check-in comments for Subversion itself, which appropriately enough uses a Subversion repository.  For some reason, I wish I remember why, we next tried updating just one child directory within the working copy.  It worked!  We tried updating all the other child directories and those worked as well.  So, that suggested that there was something wrong with the Subversion metadata, but only at the top level.  We went into the .svn directory and started browsing through the files.  When we looked at the entries file, we noticed a few lines starting with "incomplete".  I tried moving the entries file out of the .svn directory to a totally different location in the file system, hoping that when we updated or ran another cleanup, the file would simply be recreated.  Unfortunately, with that file missing, the directory was no longer considered by Subversion to be a working copy.  Disappointed, I moved the entries file back into .svn and started thinking about what to do next.  On a whim, the guy I was helping tried updating again and it worked!  Somehow, changing the directory from a valid working copy to an invalid one and back again was enough to fix everything.  Who knew?!

Have any good Subversion/TortoiseSVN troubleshooting stories or troubleshooting tips of your own?  Please leave them in the comments.

Tuesday, August 25, 2009

Curious Concept's Excellent JSON Pretty Formatter and Validator

I just wrote a bit of code using Groovy HTTPBuilder to fetch and parse some JSON content to help answer someone's question on StackOverflow.  When trying to pull some interesting data out of the JSON to display, I realized that it would be much easier for me to understand the structure of the JSON if it were pretty-printed (or pretty-formatted).  When I googled for "JSON pretty format", I found a helpful blog entry pointing me to Curious Concept's JSON Formatter (& Validator).  It's a simple online tool that allows you to paste in either a URL pointing to JSON content or the content itself and display it in either compressed or readable form.  It might not have been very hard to code, but it's extremely useful.  Thanks Curious Concept!

Update: I'm trying out the JSONView Firefox plug-in.  So far it seems to work pretty well.  Even so, I expect I'll continue to use Curious Concept's tool for a while, since I spend a fair amount of time in Chrome.

Friday, August 21, 2009

Merger Madness & One Sample App To Rule Them All

VMware --- SpringSource --- /---G2One
\---CloudFoundry
Terracotta --- Ehcache
Oracle --- Sun


With all the mergers and acquisitions happening in the Java world, I thought I'd suggest a sample app someone could build to bring them all together.

Here it is: a Grails app using an Oracle DB with distributed caching provided by Terracotta and Ehcache, all running in a VMware cloud, with deployment and management handled by CloudFoundry.  I think that covers all the bases.  I have no idea what it will do yet, but let me know if I've missed anything. :)

Note: I actually have a lot of respect for all the technologies and people involved, I'm just feeling a bit overwhelmed with all of the recent consolidation!

Wednesday, August 19, 2009

Interruptible JDBC Statements

I work for a client on a product that makes direct queries against databases via JDBC. A while ago, I added some code so that a user could stop the execution of a series of queries by clicking on a cancel button. Behind the scenes, it interrupts the thread executing the queries. Since that thread checks whether it's been interrupted by calling Thread.currentThread().isInterrupted() before starting to execute each query, no new queries will start once the cancel button was pushed. However, any query that's already started will run to completion before the code discovers that a request to cancel had been made. Recently, my client decided that we should make cancellation more granular and add the ability to stop a query in mid-stream. Looking at the JDBC docs, there's nothing to indicate that any of the relevant methods respond to interrupts (none throw InterruptedExceptions or claim to wrap them in a SQLException), so I had to come up with another way. I settled on an approach where I submit the query as a Callable to an ExecutorService and then block, waiting for the result via Future.get(). If the thread is interrupted while we're waiting, get() throws an InterruptedException, which gives us the chance to call Statement.cancel(). It's pretty simple and works nicely. :)
Here's the code in a somewhat abridged/condensed form (I create the ExecutorService elsewhere using Executors.newCachedThreadPool()):
final String sql = "...<some SQL>...";
final Statement statement = conn.createStatement();
Future<ResultSet> queryFuture =
 execService.submit(new Callable<ResultSet>() {
   @Override
   public ResultSet call() throws Exception {
     statement.execute(sql);
     return statement.getResultSet();
   }
 }
);

ResultSet rs;
try {
 rs = queryFuture.get();
} catch (InterruptedException e) {
 logger.info("Query interrupted - calling Statement.cancel()");
 statement.cancel();
 throw e;
} catch (ExecutionException e) {
 //code to handle or rethrow the exception
}
By the way, if any of the java.util.concurrent classes above are unfamiliar to you, I highly recommend Java Concurrency in Practice by Brian Goetz (et al.). It's an excellent book.