Creating a tar.gz with commons-compress

Recently I needed to take a Linux-only Java application and make it work on Windows. One of the things I had to do was remove a lot of calls to command line utilities. One of those was where we used tar to create a tar.gz of a directory structure. Googling around for creating a tar.gz in Java quickly pointed me to the commons-compress project. The problem was that there was very little documentation and no full examples to go off of. I ended up getting this code working and below is an example. In this example you will see two Java methods that are heavily documented and use together will allow you to create a .tar.gz of a directory. Of course, this example could be made better and is simple for brevity. Enjoy.

/**
 * Creates a tar.gz file at the specified path with the contents of the specified directory.
 * 
 * @param dirPath The path to the directory to create an archive of
 * @param archivePath The path to the archive to create
 * 
 * @throws IOException If anything goes wrong
 */
public static void createTarGzOfDirectory(String directoryPath, String tarGzPath) throws IOException {
    FileOutputStream fOut = null;
    BufferedOutputStream bOut = null;
    GzipCompressorOutputStream gzOut = null;
    TarArchiveOutputStream tOut = null;
 
    try {
        fOut = new FileOutputStream(new File(tarGzPath));
        bOut = new BufferedOutputStream(fOut);
        gzOut = new GzipCompressorOutputStream(bOut);
        tOut = new TarArchiveOutputStream(gzOut);
 
        addFileToTarGz(tOut, dirPath, "");
    } finally {
        tOut.finish();
 
        tOut.close();
        gzOut.close();
        bOut.close();
        fOut.close();
    }
}
 
/**
 * Creates a tar entry for the path specified with a name built from the base passed in and the file/directory
 * name.  If the path is a directory, a recursive call is made such that the full directory is added to the tar.
 * 
 * @param tOut The tar file's output stream
 * @param path The filesystem path of the file/directory being added
 * @param base The base prefix to for the name of the tar file entry
 * 
 * @throws IOException If anything goes wrong
 */
private static void addFileToTarGz(TarArchiveOutputStream tOut, String path, String base) throws IOException {
    File f = new File(path);
    String entryName = base + f.getName();
    TarArchiveEntry tarEntry = new TarArchiveEntry(f, entryName);
 
    tOut.putArchiveEntry(tarEntry);
 
    if (f.isFile()) {
        IOUtils.copy(new FileInputStream(f), tOut);
 
        tOut.closeArchiveEntry();
    } else {
        tOut.closeArchiveEntry();
 
        File[] children = f.listFiles();
 
        if (children != null) {
            for (File child : children) {
                addFileToTarGz(tOut, child.getAbsolutePath(), entryName + "/");
            }
        }
    }
}

The example could easily be tested by creating a static main method that looks like this:

...
/**                                                                                                                                                                                                   
 * Application entry point.                                                                                                                                                                           
 *                                                                                                                                                                                                    
 * @param args The command line arguments.                                                                                                                                                            
 */
public static void main( String[] args )
{
    createTarGzOfDirectory("/Users/jwhitlock/some_directory", "/tmp/some_directory.tar.gz");
}
...

And there you have it...a complete example of how to use commons-compress to create a .tar.gz of a directory.

Simple Emacs Window Persistence

So I've been using Emacs for a long time now but most recently, I've started using the new NextStep/Cocoa support for Mac OS X. Basically, it replaces the old Carbon support with OS X's newer Cocoa APIs. The reason for doing this was an attempt to find an OS X Emacs application instead of using the terminal emacs implementation. Nothing was wrong with the terminal version but I wanted to have more flexibility, specifically with OS X's Spaces feature. One of the first things I noticed was, well, every time I opened Emacs.app, I had to reposition and resize my Emacs window because the maximize button didn't consume all available screen real estate. That being said, I whipped up a very simple alternative using Emacs Lisp (elisp). Below are the two elisp functions, one to persist your window geometry at Emacs close and another to load the geometry at Emacs startup, and the hooks to wire the functions up to the necessary hooks to have it all work:

;; Custom functions/hooks for persisting/loading frame geometry upon save/load
(defun save-frameg ()
  "Gets the current frame's geometry and saves to ~/.emacs.frameg."
  (let ((frameg-font (frame-parameter (selected-frame) 'font))
        (frameg-left (frame-parameter (selected-frame) 'left))
        (frameg-top (frame-parameter (selected-frame) 'top))
        (frameg-width (frame-parameter (selected-frame) 'width))
        (frameg-height (frame-parameter (selected-frame) 'height))
        (frameg-file (expand-file-name "~/.emacs.frameg")))
    (with-temp-buffer
      ;; Turn off backup for this file
      (make-local-variable 'make-backup-files)
      (setq make-backup-files nil)
      (insert
       ";;; This file stores the previous emacs frame's geometry.\n"
       ";;; Last generated " (current-time-string) ".\n"
       "(setq initial-frame-alist\n"
       "      '((font . \"" frameg-font "\")\n"
       (format "        (top . %d)\n" (max frameg-top 0))
       (format "        (left . %d)\n" (max frameg-left 0))
       (format "        (width . %d)\n" (max frameg-width 0))
       (format "        (height . %d)))\n" (max frameg-height 0)))
      (when (file-writable-p frameg-file)
        (write-file frameg-file)))))
 
(defun load-frameg ()
  "Loads ~/.emacs.frameg which should load the previous frame's geometry."
  (let ((frameg-file (expand-file-name "~/.emacs.frameg")))
    (when (file-readable-p frameg-file)
      (load-file frameg-file))))
 
;; Special work to do ONLY when there is a window system being used
(if window-system
    (progn
      (add-hook 'after-init-hook 'load-frameg)
      (add-hook 'kill-emacs-hook 'save-frameg)))

All you have to do is get this into your ~/.emacs file and things just work. What you'll notice is after you have this code in place, open Emacs, reposition your window and resize its geometry. Next time you open Emacs, it should remember the last window geometry/location.

Known Issues

  • This implementation does not work for new Emacs windows spawned from a running Emacs (If you know a hook I could use so that opening a new window will run load_frameg, let me know.)

Apple's New iPad: Beautiful, innovative and a let down

Apple's "latest creation" event held today unveiled the iPad. The iPad is Apple's tablet, the latest product from the mind of Steve Jobs. It seriously is one of the most beautiful pieces of technology I've ever seen. The problem for me is that beauty only goes so far. My opinion of the iPad is a mixed bag of praise and disappointment, which is likely not Apple's fault but my own dream not coming true.

So I don't end this blog post on a sour note, let's start with my disappointments. When we first heard of Apple's event to be held on the 27th of January, 2010 I started thinking of a MacBook replacement. When the iPad was unveiled, I saw a more refined and much larger iPod Touch. I already have an iTouch so why would I want another one? Sure it's bigger, beautiful and there are some applications for it that have been redesigned for the iPad. Sure it could potentially become a primary system for business executives and designers but I'm not a designer or someone that lives in email/internet/documents/photos only. I'm a software developer. I can't run Eclipse, XCode or anything that I do day to day on that pad so it's awesome form factor is of no benefit to me. I don't have an ebook reader so it could fill that niche but I read books just fine on my iTouch and MacBook. I got myself excited about an Apple NetBook or laptop replacement and instead I got a newer, bigger iTouch. The problem with this is that some of the big complaints about the iPhone/iTouch like no multitasking/background applications, no built-in camera, etc. There is some good news about this that I'll mention below.

My complaint is really a nit and most could say I did it to myself. I just can't help but see the iPad as a bigger iTouch that only serves as an ebook reader since I never bought a Nook or Kindle. But honestly, those are my only complaints. The iPad's form factor and design is breathtaking and based on the software suite available, I can see this device being the go to device for designers and business executives. The iPad comes with the usual business suite of apps you have on the iPhone but redesigned specifically for the iPad. Simplistic applications like Calendar, Contacts and Mail on the iPhone/iTouch have been redesigned for the iPad so that the user experience is like nothing you've ever seen. Seeing the iPad's software in action is truly a site to behold. Apple really knows how to create touch-based user experiences that do not hinder.

One of the biggest surprises today was the iPad's price point. People expected a device costing roughly $1K but the base model is only $499. All iPads comes with WiFi (802.11 a/b/g/n), Bluetooth, Flash drives for storage, microphone, built-in speakers, a 1GHz Apple A4 processor, a 1024-by-768-pixel resolution at 132DPI screen and it all fits in a 7.47"x9.56", 0.5" thick form factor. (For more information on pricing and technical specifications, go here: http://www.apple.com/ipad/specs/) It's amazingly compact and it's multitouch display was impressive during the keynote. (One of the first things people noticed was the lack of a built-in camera. The good news is this can be remedied by plugging an external camera into the device.) The iPad is even said to have 10 hours of battery life. Wow! Since I feel like I can't do the hardware justice, let's move on.

As expected, this device runs the iPhone (3.2) operating system. This means that an iPhone application can run directly on this device. As a matter of fact, not only does the iPhone App Store's 140K+ applications run on the iPad, they can be resized on the iPad to utilize the extra screen real estate. Also as expected, there is a version of iTunes so buying multimedia will be possible with the device. What's new is that there is a third store on the device called iBooks, which is an ebook store. All of this is great news for iPad owners because you can utilize a large list of great applications in the App Store on the iPad on day one. This is very exciting news.

In the end, the iPad is a huge hit, especially among those that can see using it in their daily life. The innovative software delivered with the device is stunning but being able to install iPhone applications means that many will be able to replace their iTouch with this device if it makes sense for them. I'm not sure I'll be buying one but it isn't because the device isn't worth my money, I just think the device was designed for a different type of user.

Snow Leopard is a liar, Java 1.5 is NOT installed

Over the weekend I finally took the plunge to upgrade to Snow Leopard. The system is definitely snappy and I'm loving it. Well, now that the system is back at the state I need it to be in for my various development efforts, I began trying to compile some Java that's used at work, which requires Java 1.5.x (The reason for this is the use of pre-JDBC 4.0 APIs) So I start compiling and I keep getting errors about classes not being abstract and also not implementing necessary methods. I start thinking: Well, I told the build script to use Java 1.5 so I shouldn't be running into this. I start digging around and I see that Java 1.5 and Java 1.5.0 JavaVM framworks on Snow Leopard just symlink to 1.6. WHAT?!? Are you eff-ing serious? Not only is Java 1.5 not installed but Snow Leopard tries to fool you into thinking it is. (Yes, I know I could had looked at /Applications/Utilities/Java Preferences.app and figured this out but being a developer, I look for framework locations manually.) No wonder my code isn't compiling...it needs Java 1.5 and while it appears I told my build script to use 1.5.x, it's really using 1.6.x. Great...

I'm not going to attempt to document how to fix this. Many others have done so and googling "Snow Leopard Java 1.5" will get you what you want. I just can't believe this is the way Apple wants to behave. Why can't the latest Xcode include a *real* version of Java 1.5 at least? Ugh...EPIC FAIL!!!

Review: Motorola Droid from Verizon

Well, I've not done this in a while but I bought the latest toy the day it came out and this time around, it was the Motorola Droid from Verizon Wireless. I was very excited about this primarily because I could get a good smartphone on Verizon that ran on the Google Android platform. Well, after having the phone for the past three days, I am very pleased with the phone's hardware and the Android 2.0 operating system running the device. (For the complete hardware specifications, visit the Motorola Droid site. For the new features of the Android 2.0 platform, visit the Android 2.0 Highlights page.) As you probably have heard, people call this phone "The iPhone Killer" and in some ways, I agree but I also have just as many discrepancies in this statement, but not because of the phone's hardware or core operating system. What makes the phone so good and yet, not an iPhone killer? Let's find out.

The first thing most notice about the phone is its impressive hardware list:

  • Arm® Cortex™ A8 processor running at 550 mHz
  • 16 GB microSD (pre-installed and upgradable to 32 GB)
  • 3.7" WVGA, touch-screen display
  • Physical QWERTY keyboard
  • 5.0 MP camera with 4x digital zoom, flash and capable of doing DVD quality video
  • WiFi (B and G) access
  • Accelerometer
  • Proximity, ambient light and eCompass sensors
  • Many more...

This is one of the most powerful phones, from a hardware perspective, released to date. Using the phone, you'll see how nicely all of this hardware comes into play. First thoughts are how responsive the UI is to touches and gestures. I'm yet to run into a situation where my Droid hangs, becomes unresponsive or "lags" when using it. The next thing I notice is the keyboard. While I've heard many people complain about the keyboard, I've not had any problems with it. It's responsive and not as small as people say. You'll also notice that when you take pictures, they are very clear. Don't expect DSLR quality out of it but the built-in camera does shoot as well as a comparable digital point-and-shoot camera which should make for good on-the-go pictures for Facebook, Twitter and other social services that run on Droid. To keep from writing a full blown dissertation on the Droid, below is a quick list of short hardware features that got my attention:

  • A full-sized, 3.5mm headphone jack means no more proprietary headsets and the ability to reuse existing headphones when listening to music
  • The built-in speaker is very clear and more than loud enough to listen to music
  • USB charger is great to have because you can charge anywhere
  • 4 physical buttons on the display make browsing much easier
  • The back of the Droid has raised parts at each end to keep the phone from getting scratched and to protect the camera on the back

Well, the Droid's hardware is impressive for sure but how usable is the phone? Well, let me say that the Android platform is very, very nice. It's intuitive, easy on the eyes and Android includes many of the necessary applications that you'd need out of the box to transform your phone into the ultimate business tool. From what I can tell, Verizon didn't make any big changes to the Android platform, which is good because many others and myself were worried about how "bastardized" Android would be on a Verizon phone. When you start using your
Droid, you'll notice that the expected applications are there:

  • Email clients (Gmail and regular)
  • Calendar
  • Web browser
  • Android Market
  • Maps
  • Etc...

You should also expect to see others like the Amazon MP3 Store, YouTube and others. Do you use Google services like Gmail, Google Calendar, Google Voice or any other Google service? If so, you'll be glad to know that the Droid's Google integration is flawless. Attach your Google account to your Droid and your calendar, email and contacts are instantly available and bi-directionally synchronized. What about turn-by-turn directions? Tired of having another device in the car? Well, the Droid offers turn-by-turn directions natively and it's implementation is very solid. If you can't find something you need already pre-installed, open the Android Market and look around there. Most of the included applications are top-notch and "just works".

Unfortunately, the Android's included applications and Android Market applications are where I think the chance of the Droid being "The iPhone Killer" diminishes. Sure, there are great applications on the Droid and there are great applications on the Android Market but in the end, there are not nearly as many high-quality applications available for the Droid. I feel like the quality of the included applications on the iPhone are of higher quality than their Droid equivalent. For example, the email application on Droid does not properly delete POP3 emails and you cannot choose which folders in IMAP correspond to their Droid email equivalent, like what IMAP folder should be used for deleted mail. It just seems the depth of control/configurability is lacking in many cases. The good news is that the Android is open source and these problems will ultimately be fixed. iPhone killer? Maybe not but do not let that take away from the awesome handset that it is.

One last, brief thing is that I've traveled a bit since I got the phone, primarily up and down the I-25 highway within Colorado, and I've never had reception or call quality issues. I also haven't seen the 3G icon disappear, unless I was using the fast WiFi when I was at home just to save unnecessary 3G usage. For most, they forget about the carrier when evaluating a phone and in the Droid's case, I think Verizon's network is a very important selling point.

In the end, the Droid is an amazing smartphone. It runs the highly-regarded Android operating system, which includes many high-quality applications, and has some very powerful hardware. While the Droid isn't an iPhone killer yet, it sure could be with a more refined set of included applications and variety/quality in the Android Market. So for the general populous, I wouldn't call the Droid an iPhone killer but I sure have no desire to own an iPhone anymore.

Movie Review: Law Abiding Citizen

Well, I've officially given my first public review of a movie. I don't know if this will turn into a side project or hobby but it was really fun trying to take a movie I saw for pleasure and put together a meaningful review. If you're interested in reading my first public movie review, which happens to be a review of Law Abiding Citizen, please visit http://bit.ly/1tWyJR.

Blogs are suffering and it's Twitter's fault

While I'm not proud of it, my blog has been suffering the last few months. Sure, I can blame my work load, my family time, my social life and a multitude of other things but in the end, I'm going to blame Twitter. For those of you that do not know, Twitter is the phenomenal social networking tool that is like a mini-blog and instant messenger mixed together in 140 character chunks. Sounds cool huh? So, if it sounds like something cool, you might be wondering why I'd blame Twitter right?

Well, the truth of the matter is that my blog has always been an information portal. Whenever I would find something new, interesting or anything that I felt would be great to share, I would whip up a blog entry. And since proliferating useful information is the purpose of a blog, this is probably what the rest of you do as well. But now that Twitter is here, I'm having trouble with that blog cycle and it's primarily because of time.

The average blog entry for me is about an hour. I have to create code snippets, cross link, think of useful verbiage to throw in and then craft the blog entry. I can produce the same net effect in Twitter in a few seconds. My personal opinion of why it's so much easier is that Twitter REQUIRES that you break down your message into an easy to consume chunk called a tweet. Since you only have 140 characters for your message, you can only say so much and end up being brief and to the point. The only real time consumer in Twitter is shortening your urls, which most Twitter clients like Tweetie and TweetDeck handle for you or have built-in features for. So either I can spend a minute tops via Twitter or I can go through the whole hour+ it takes for a full-fledged blog entry. What sounds best for an employee, father, husband, entrepreneur, open source developer with little/no extra time? I'll take the easy effort, quick turnaround, global impact approach please: Twitter.

Yes, there are times where a full-fledged blog entry is better suited, like when you want to write an article or blog about something original. In that case, you'll end up writing your entry and then posting a tweet to reach the masses quickly. Reason being is Twitter is viral. You post a tweet and you instantly have alerted N number of people. Your followers, followers of any hashtag you used in you tweet or just people reading the public timeline. You've instantly told the world of your new blog entry. Marketing has never been easier.

In the end, I blame you Twitter for making it so easy to reach so many people and for making the effort required to do so miniscule. And because of this, my blog is suffering. Sure, you've done nothing wrong but in the end, it's much easier for me to blame you instead of myself. Besides, this was a creative way to plug your awesome service.

Subversion 1.5.7 and Subversion 1.6.4 Fix Security Issue

On August 6th, the Subversion project released a security advisory that alerted the public that any Subversion client/server <= 1.5.6 and <= 1.6.3 could be attacked by a DoS and arbitrary code execution as a result of a buffer overflow. As a result, Subversion 1.5.7 and Subversion 1.6.4 have been released to address the security issues outlined in the CVE-2009-2411 security advisory mentioned earlier.

As the maintainer of the Subversion Universal Binary for OS X, I have also released updated binaries for Subversion 1.5.7 and Subversion 1.6.4. Below are their download locations:

Please upgrade your Subversion clients/servers if you can and if you have any requests/comments/troubles with the Subversion Universal Binary for OS X, please report them to the SVNBinaries project.

Using negative patterns for Subversion's svn:ignore property

Using Subversion's svn:ignore versioned property is pretty straight forward. Use a line-delimited list of patterns you want Subversion to not interest itself in. Here is an example to tell Subversion to ignore all files ending in .abc and .def:

svn propset svn:ignore "*.abc
*.def" .
property 'svn:ignore' set on '.'

(Note: On Windows, multi-line commands like the one above do not work. You need to use "svn propedit svn:ignore ." and then use the editor to add the two lines to the property value.) Like I said earlier, pretty straight forward. But what if you wanted to say something like: Hey Subversion...will you please ignore all files not ending in .xyz? Looking up the svn:ignore property in the Subversion book, linked to above, you will not find any mention of negation syntax. So it's not as simple as throwing in a "!*.xyz" into your svn:ignore property value. Well, after doing a little digging in the Subversion sources, and the mention in the Subversion book, you see that Subversion uses the fnmatch function to do its bidding. After looking around the internet for more information on what exactly fnmatch supports, I started playing around and I found a juicy little tidbit that will do exactly this. Here is an example:
svn propset svn:ignore "*[!x][!y][!z]
*.xyz?*" .
property 'svn:ignore' set on '.'

Yes...it's a little verbose but it works. The idea is to take any character of the extension, enclose it in square brackets behind an exclamation symbol. Just to make sure this sinks in, if you wanted to ignore all but .html files for a directory, here is an example:
svn propset svn:ignore "*[!h][!t][!m][!l]
*.html?*" .
property 'svn:ignore' set on '.'

There you have it. You can use this negation approach anywhere in the pattern, not just the end as the examples have shown. Maybe I can convince Mike Pilato to include this in the book...

Finding Where You Doubly Released a Cocoa Object's Memory

So while working on CocoaREST, I was just about to commit an enhancement to support file uploading, like to update your Twitter profile picture, and I kept spawning a crash with the following error:

objc[<pid>]:FREED(id): message release sent to freed object="<memory_address>"

After scouring the code, I couldn't figure out where I was doubly releasing memory. Hitting up Google, I found the following: http://iphone-crack-addict.blogspot.com/2009/06/debugging-objc17695-freedid-message.html. This article helped introduce me to a few really good environment variables I could set that would allow me to identify where I was creating this problem. Here are the environment variables:

With these two set to "YES" in your executable's Arguments tab, you then have the ability to figure out where you're doubly releasing an object's memory using in gdb:

shell malloc_history <pid> <memory_address>

(Note: To set these environment variables, double-click the executable in Xcode's Executable's group, click the Arguments tab and then add the variables.) And there you have it. Thanks go out to the The Journey of an iPhone Developer blog for helping me extend my Xcode/Cocoa knowledge.

Syndicate content