Monday, October 27, 2008

Learning Wicket

I'm always on the lookout for different ways of doing the things I'm familiar with. Once in a while, I learn a better way of doing things. Even if I don't, I find that it helps me realize what I like and dislike about the techniques that I'm used to.

Take creating web applications for example. I'm familiar with JSF, both with and without Seam. Overall, I would say that I agree with the ideas behind JSF, but in practice it is not easy to be productive in developing a medium to large sized web app. It seems like some things that should be very easy to do are difficult, but maybe that's just me. Seam adds a bit more complexity, but helps overall. To the JSF world of managed beans, Seam adds ways to manage the rest of your objects called scopes. This is a good idea on paper, but feels a bit like using global variables (albeit with managed lifecycles).

So I decided to give Wicket a try. What stood out to me right away is the simplicity of it. There's very little configuration, and no XML other than web.xml (which makes me realize how much I dislike having stuff like page navigation in an XML file). Each page template corresponds to one Java class. Also, there is no EL or OGNL so your markup is sure to have no logic whatsoever, which is great for those of us who prefer to code in Java. That's the bottom-line benefit that I see with Wicket: everything happens in Java code. Which means you get all of the benefits of writing Java code in an IDE from debugging to refactoring, etc. I haven't tried it, but I've read that it's easy to use alternative JVM languages such as Scala and Groovy instead, if you are so inclined.

Wicket is very friendly to the web designer because it does not invade the markup, so the designer can see what they are getting without firing up a web container. For now, I haven't seen any Wicket components which look good "out of the box" (translation: you probably need a web designer). However, there is no reason why there couldn't be such component libraries for Wicket. That will come with increased adoption, if it happens. After all, creating a component library in Wicket means putting your classes and markup in a JAR file, so it couldn't be easier.

Some minor gripes I have with Wicket are that the markup has to stay in sync with your Java class (but all web frameworks I have used also have this problem), it can sometimes add junk to your URLs after a form submit (maybe there's a way around that). Also, there's quite a bit of casting when using version 1.3, but they are adding generics to version 1.4 which should minimize that. Overall, I'm very impressed.

Resources:

Wednesday, March 12, 2008

Ideal command prompt


In setting up my new laptop, I've been experimenting with different command prompt settings in bash. Here is what I've settled on for now (click for a more clear image). It's simple, yet gives me all of the information I need in a format that is easy for the eye to parse. That's because the text color of the full path is inverted from your other colors.

If you are interested in using/tweaking it:
export PS1="\u:\[\e[0;07m\w\e[m\]> "

What's your ideal PS1? Here's a how-to article. It's written with Linux in mind, but the information applies to pretty much any environment where bash is present (OS X, Unix, Cygwin, etc.).

EDIT: My original post did not wrap the color code in \[ and \] which caused the first line wrap to overwrite the current line. Fixed!

Tuesday, March 11, 2008

Rantings of a recent Mac convert

I ordered a new MacBook Pro (Penryn w/ multi-touch) which arrived last Monday (which probably explains my lack of posting since then). Although I do have a bit of experience with OS X and actually do my programming at work on a Mac mini (I'm in the minority here), this is my first purchase of any Apple product (which means I don't own an iPod - *gasp*).

The Desktop OS Wars


As far as OSes are concerned, I don't mind Windows, but I find that it gets in my way sometimes. That is fine for most people because they know the workarounds (e.g. reboot, re-install every 6 months...). To me, this is a waste of time since other OSes don't have this problem. This observation is mostly from XP and previous versions, but based upon what I've heard about Vista, I don't expected much better. Also, the lack of a robust terminal/shell (with things like adequate scripting) is completely inexcusable when the competitors run bash and the like.

Linux is a rock-solid OS. It dominates the server environments, and rightly so. The problem is the desktop user experience. The average computer user cannot be expected to survive here, and even the most technically savvy users often find themselves searching through forum posts for hours on how to overcome some hurdle or another. Driver support is non-existent for the most part. The installation process is flawed for the vast majority of distros (one exception is Ubuntu and the like). Also, while package management is great, there are often packages that are missing and/or outdated, so it loses much of its utility. Granted, Linux in general (and Ubuntu in particular) are making great strides in this area, but the progress is too little, too late.

That brings me to OS X. I think Apple's really gotten it right. Take something solid (BSD - though modified with a very different kernel) and put a nice UI on top of it, and that's exactly what they've done. I have a terminal session (bash) open 90% of the time when I'm programming, which is indispensable. I never payed much attention to aliasing or font rendering before, but I can't help but notice how much better everything looks. Some of that has to do with the top-notch (read: expensive) displays that Apple uses, but at work I've used the same (non-Apple) display on Windows, Linux and OS X and there is a clear difference.

Final Thoughts


I have to say, I am very impressed with my MBP so far. It does everything I want it to, without any of the quirks that are present in other hardware/OS configurations. I think this is due to the relatively small number of available hardware configurations for Macs. This puts Apple in the unique position of being able to test every possible hardware configuration - they know it works. I've heard from other Mac users that "everything works", but I don't think I really believed them or understood the implications of that statement. Now I get to experience it firsthand, and it's refreshing.

Anyhow, I hope to get back to posting more Scala stuff soon, and maybe something about Java for a change.

Saturday, February 23, 2008

ARM Blocks in Scala, Part 3: The Concession

Update: Here's a better approach to Automatic Resource Management in Scala.

After a couple of attempts (part 1, part 2) at implementing Automatic Resource Management in Scala, I've decided not to "reinvent the wheel" here. I will defer instead to the implementation found in Scalax. I did not know about their ManagedResource class before my first post (many thanks to the commenters who pointed me there), and if I had known about it I may not have made the attempt. I'm glad I did, however, because it gave me a chance to improve my Scala skills. I'm not "there" yet, though, as I still find myself writing Java-like code in Scala. When I catch myself doing so, I am usually able to refactor it into the Scala style, which ends up being more compact and elegant. Come to think of it, that is why I recommend ManagedResource over my approach. I would say mine is the Java-like approach, while ManagedResource is more elegant and more consistent with Scala style.

Let's look at the same example from my first two posts using ManagedResource:


def createReader = ManagedResource(new BufferedReader(new FileReader("test.txt")))
def createWriter = ManagedResource(new BufferedWriter(new FileWriter("test_copy.txt")))

//copy a file, line by line
for(reader <- createReader; writer <- createWriter) {
var line = reader.readLine
while (line != null) {
writer.write(line)
writer.newLine
line = reader.readLine
}
}



Why is ManagedResource better?
It may be clear from the example, but let's discuss what it is that makes the usage of ManagedResource cleaner than the previous approach. ManagedResource uses for-comprehensions, and that alone solves many of the problems I encountered. For example, I had the problem of being able to define and initialize a resource and still being able to reference it inside of the block of code. For that reason, I had to define an initialization function (in part 2), but "for" takes care of this nicely: for(a <- ManagedResource(new SomeResource())) .... It also takes care of the many-resources problem elegantly, without using varargs: for(a <- createA; b <- createB; ...). In short, "for" seems like the right tool for the job.

That being said, I think ManagedResource does have some room for improvement. For example, consider the following code segment:


def createReader = ManagedResource(new BufferedReader(new FileReader("test.txt")))
def createWriter = ManagedResource(new BufferedWriter(new FileWriter("test_copy.txt")))

try {
//copy a file, line by line
for(reader <- createReader; writer <- createWriter) {
try {
var line = reader.readLine
while (line != null) {
writer.write(line)
writer.newLine
line = reader.readLine
}
} catch {
case e: IOException => println("Exception thrown while copying: " + e.getMessage)
}
}
} catch {
case e: IOException => println("Exception thrown upon open or close: " + e.getMessage)
}


As you can see, we have total control inside of the block of code, but if an exception occurs while initializing or disposing we have no way of knowing which of the two steps was the culprit. This is probably not an issue most of the time, but I could see a possible need for handling exceptions in initialization differently from exceptions in disposal. Maybe this can be improved (it would have to be non-intrusive for the more common, general case), or maybe some level of control must be sacrificed.

Also, at the time of writing, ManagedResource exposes methods for opening (initializing) and closing (disposing) a resource: "unsafeOpen" and "unsafeClose". These cannot be called from within the block of a for-comprehension, but I see no need to make them public, "protected[control]" should be the maximum visibility - if that. Making them public is a mistake because it allows for the same type of resource leaks we set out to quash. In fact, anyone who is calling these methods externally requires more control over where and when resources are initialized and disposed, and should not be using ManagedResource to begin with. If there is a legitimate reason for exposing these methods, I would like to see it.

Overall, however, I have to congratulate Scalax (Jamie Webb in particular) for getting it right. Scalax is still in a very early stage, so maybe the concerns addressed here will be addressed by the time it is ready for release. These concerns are relatively minor anyway, so I recommend using ManagedResource as is.

Friday, February 15, 2008

ARM Blocks in Scala, Part 2

Update: Here's a better approach to Automatic Resource Management in Scala.

I didn't plan on writing a follow-up to my first post on ARM Blocks in Scala, but I think I will be able to improve upon some things. I don't plan on any future posts on this topic, but I will not hesitate to do another one if sufficient progress can being made.

Here's where we left off with Arm:


object Arm {
type CloseType = { def close() }

def manage(resources: CloseType*)(block: => Unit)
(implicit exceptionHandler: (Exception) => Unit) = {
try {
block
} finally {
resources.foreach( resource => {
try {
resource.close()
} catch {
case e: Exception =>
try {
exceptionHandler(e)
} catch {
case fatal: Throwable => fatal.printStackTrace() //last resort
}
}
})
}
}
}


Motivation

I chose to write a follow-up because of a couple of important omissions that I made in my previous post. The first and foremost is that of resource initialization (as "helium" pointed out). The problem is that resource initialization happens outside of the scope of the Arm.manage method. This violates the principle motivation for ARM Blocks by forcing the developer to correctly handle resource disposal in the case that one or more resources is initialized successfully and others are not.
For example:

val reader = new BufferedReader(new FileReader("test.txt"))
val writer = new BufferedWriter(new FileWriter("test_copy.txt"))

If reader initializes successfully and writer does not, reader needs to be closed. This is exactly the type of problem we were trying to avoid with ARM Blocks in the first place. I didn't have a solution for this problem at the time, but I forgot to mention it in my post - a mistake on my part.

Secondly, I didn't mention how an exception within the block of code itself should/would be handled. This means that one would have to wrap the entire call to Arm.manage in a try/catch block in order to handle any exceptions that may occur inside the block itself. Not ideal.

In this post, I hope to address these two concerns. The solution I present here is by no means the best solution, and I am confident it can be improved upon as well.

For starters, let's take care of the first issue, which is the easier of the two:

object Arm {
type CloseType = { def close() }

def manage(resources: CloseType*)(block: => Unit)
(implicit exceptionHandler: (Exception) => Unit) = {
try {
try {
block
} catch {
case e: Exception => exceptionHandler(e)
}
} finally {
resources.foreach( resource => {
try {
if (resource != null)
resource.close()
} catch {
case e: Exception =>
try {
exceptionHandler(e)
} catch {
case fatal: Throwable => fatal.printStackTrace() //last resort
}
}
})
}
}
}

Here we reuse the existing exception handler function. This is more convenient that declaring two different exception handlers, but has the issue of knowing if the exception being handled occurred upon closing or in the block itself. We will correct this after we address the second issue.

The issue of initialization is a more complicated one. The approach taken here is to define an initialization function, much like our exception handling function. It should be implicit as well in the case that resources have already been initialized and no initialization is necessary. Here's an attempt:

object Arm {
implicit def defaultInitializer() = {}
implicit def defaultExceptionHandler(e: Exception) = {}

type CloseType = { def close() }

def manage(resources: (() => CloseType)*)(block: => Unit)
(implicit initializer: () => Unit, exceptionHandler: (Exception) => Unit) = {
try {
try {
initializer()
block
} catch {
case e: Exception => exceptionHandler(e)
}
} finally {
resources.foreach( resource => {
try {
val value = resource()
if (value != null)
value.close()
} catch {
case e: Exception =>
try {
exceptionHandler(e)
} catch {
case fatal: Throwable => fatal.printStackTrace() //last resort
}
}
})
}
}
}

Here we define a default initializer as well as a default exception handler. Defining the exception handler is not really necessary because of the implicit identity function in Scala's Predef, but defining the default initializer may be helpful. In Arm.manage, the initialization and exception handling functions are included in the list of implicit parameters. Only one such list is allowed in the Scala language and it is required to be the last list of params. Also, if we are to use an initialization function, the resources themselves cannot be passed as arguments because it will be call-by-value (i.e. in Arm.manage, they will remain uninitialized). Instead, we use call-by-name and accept an arbitrary number of functions that return resources - remember that methods are functions in Scala. This is a necessary change, but adds a bit of clutter when it comes to usage. We will save an example until later because of a deficiency in this implementation.

In this version of Arm.manage, when an exception occurs and our handler is called, we have no idea if the exception happened in initialization, in the block of code, or when trying to close the resources.

Let's address this issue:

object Arm {
abstract class ManagementException(val cause: Exception) extends Exception(cause) {
override def getCause() = cause
}
class InitializationException(cause: Exception) extends ManagementException(cause)
class ExecutionException(cause: Exception) extends ManagementException(cause)
class ClosingException(cause: Exception) extends ManagementException(cause)

implicit def defaultInitializer() = {}
implicit def defaultExceptionHandler(e: ManagementException) = {}

type CloseType = { def close() }

def manage(resources: (() => CloseType)*)(block: => Unit)
(implicit initializer: () => Unit, exceptionHandler: (ManagementException) => Unit) = {
try {
var executeBlock = true

try {
initializer() //initialize the resources
} catch {
//forward exceptions to the handler
case e: Exception =>
executeBlock = false //do not continue if initialization fails
exceptionHandler(new InitializationException(e))
}

if (executeBlock) {
try {
block // execute the block
} catch {
//forward exceptions to the handler
case e: Exception => exceptionHandler(new ExecutionException(e))
}
}
} finally {
//close all of the resources properly
resources.foreach( resource => {
try {
val value = resource()
if (value != null)
value.close()
} catch {
case e: Exception =>
try {
exceptionHandler(new ClosingException(e))
} catch {
case fatal: Throwable => fatal.printStackTrace() //last resort
}
}
})
}
}
}

So now, our exception handler signature takes a ManagementException, which has the original exception as its cause - accessable by e.cause or e.getCause(). We know, based on the type of ManagementException, where it is coming from. Instead, we could define three different exception handling methods, but I think it's easier to use if we only have to define (at most) one exception handler.

Let's see an example:

var reader: BufferedReader = null
var writer: BufferedWriter = null

def getReader() = reader
def getWriter() = writer

def initResources() = {
reader = new BufferedReader(new FileReader("test.txt"))
writer = new BufferedWriter(new FileWriter("test_copy.txt"))
}

def handle(e: ManagementException) = {
e match {
case ie: InitializationException =>
println("Failed to initialize: " + ie.getCause())
case ee: ExecutionException =>
println("Could not copy files: " + ee.getCause())
case ce: ClosingException =>
println("Failed to close a resource: " + ce.getCause())
}
}

//copy a file, line by line
manage(getReader, getWriter) {
var line = reader.readLine
while (line != null) {
writer.write(line)
writer.newLine
line = reader.readLine
}
} (initResources, handle)

This one passes the methods for initialization and exception handling as explicit parameters.

Here's the same example with a different approach:

var reader: BufferedReader = null
var writer: BufferedWriter = null

implicit def initResources() = {
reader = new BufferedReader(new FileReader("test.txt"))
writer = new BufferedWriter(new FileWriter("test_copy.txt"))
}

implicit def handle(e: ManagementException) = {
e match {
case ie: InitializationException =>
println("Failed to initialize: " + ie.getCause())
case ee: ExecutionException =>
println("Could not copy files: " + ee.getCause())
case ce: ClosingException =>
println("Failed to close a resource: " + ce.getCause())
}
}

//copy a file, line by line
manage(() => reader, () => writer) {
var line = reader.readLine
while (line != null) {
writer.write(line)
writer.newLine
line = reader.readLine
}
}

This one uses implicit defs for our initialization and exception handling functions. For this to work, we cannot import the implicit defs of these functions from Arm because they would conflict. I should point out that if you provide one function explicitly, you have to provide the other explicitly as well. Also, this example defines getters for reader and writer "inline".

Room for Improvement

The new syntax is not nearly as easy to read as the original. This concession was necessary, though, for the sake of completeness. The problem of an exception thrown from the handler still remains from the first post, as well.

A couple of readers pointed me toward scalax, which provides a ManagedResource class which provides the same functionality using for-comprehensions. I took a look at it and it looks pretty well done, but I haven't yet had an opportunity to use it so I can't comment on how it works in practice. I would be interested to see an example of this which manages more than one resource.