2010-02-24

Scala 2.8 Showcase - Collections

I would like to present some of the new features of Scala 2.8 which is a 2.8.0 Beta 1 at the moment of writing of this article.

Instead of programming dummy code I decided to implement some methods of computing square roots - but don't worry, just the simple ones. You don't have to dive in maths to understand code samples - in fact, in this article I won't really touch the square root part (I might a bit in the following articles).

This application uses a bit of Design by Contract principles and it does not use unit tests as the specs library doesn't support Scala 2.8 at the moment. Update 2010-02-26: At this moment the specs library already supports Scala 2.8. Thanks to Eric for pointing it out! You can get specs for Scala 2.8 here.

In this article I will mostly focus on...

Scala Collections


The Scala Collections have been improved since the previous stable release.

There are three packages now, scala.collection.mutable (mutable collections), scala.collection.immutable (immutable collections), scala.collection.generic (generic collections). Almost all types of collections exist in all three forms (but not all of them; namely, there is no immutable Buffer, why would there be). The official Scala collections PDF document also presents this neat and informative diagram:

Traversable
                  |
                  |
              Iterable
+-----------------+-------------------+
|                 |                   |
Map              Set                 Seq
|                 |                   |
|             +-----+-------+         |
SortedMap    SortedSet  BitSet        |
                                      |
                                      |
               +-----------+----------+
             Buffer  Vector  LinearSeq

A bit of introduction


Now I'm going to show you a few code examples. These are nothing but simple calls of standard Scala collections methods with a bit of explanation. This is by no means a full list of methods; the list of available methods is way too long. Please refer to the official Scala collections PDF document for more information.

As I mentioned before, the program calculates the square root using two methods:
  • Bisecting intervals - continuous estimations until a satisfactory result is found; for instance, when looking for a square root of 30, you can start looking for the solution between 5 (5 * 5 = 25 < 30) and 6 (6 * 6 = 36 > 30)
  • Babylonian method aka Hero's method

For the example sake I provided the list of numbers to calculate square root of as a collection and then played a bit with it using Scala collections methods. Let's see some examples.

Creating mutable and immutable collections


// Immutable:
val data = Set(1.0, 0.0, 1.0/4, 9.0, 16.0, 10000.0, -1.0)
Here we create a set using (behind the scenes) its apply (read more about the apply method on Jack Cough's blog) method. This is an immutable set because that's the one imported by default. What if we want a mutable set instead?

Well, one way is to specify the class name together with its package:
var mutableSet = scala.collection.mutable.Set(5.0)
mutableSet += 6.0

The second line also demonstrates how to add elements to a mutable set; you can remove them the same way.

mutableSet -= 6.0
println(mutableSet)
And it prints:
Set(5.0)
BTW, what this set really is is a scala.collection.mutable.HashSet.

Operations


Let us now define two methods that will serve as predicates:

def negative(x: Double) = x < 0
def equalsNumber(equalTo: Double)(x: Double) =
    equalTo == x
The first one returns true if the given argument is less than zero. The second one is more interesting - it is a curried function. You can read more about curried functions on Daniel Spiewak's blog. Let's see them in use.

// Immutable:
val data = Set(1.0, 0.0, 1.0/4, 9.0, 16.0, 10000.0, -1.0)
val dataOnlyPositive = data filterNot negative
println(dataOnlyPositive)
Here the negative method is used as a predicate given to the filter method (defined for the Iterable trait) which, as you can guess, filters the collection according to the predicate and returns the result which here is caught in a set called dataOnlyPositive. The result is:
Set(0.0, 1.0, 0.25, 9.0, 16.0, 10000.0)

Let's see a few more methods:
assert(dataOnlyPositive subsetOf data)
assert(!(data subsetOf dataOnlyPositive))

assert(dataOnlyPositive exists equalsNumber(9.0))

The first two calls demonstrate the subsetOf operation which checks whether the first set is a subset of the other.

The third call uses our curried function - because the exists operation accepts a predicate that expects only one parameter, we provide it one - the partial function equalsNumber(9.0). In other words, equalsNumber(9.0)(x) is itself a function that expects one argument (x). To further clarify, see the code example:

def equalsNumber(equalTo: Double)(x: Double) =
    equalTo == x

def equalsNine(x: Double) = equalsNumber(9.0)(x) // Here.
assert(!equalsNine(12))
assert(equalsNine(9))

Imports renaming


If you don't like this:

var mutableSet = scala.collection.mutable.Set(5.0)

... you can always use imports renaming, a feature that is not available in Java.

import scala.collection.mutable.{Set => MSet}

And now the previous call becomes:

var mutableSet = scala.collection.mutable.Set(5.0)

Iterating over a set


One last example is iterating over a set.

dataToProcess map {
  case (x: Double) => printf(
            "Calculating square root for %f.\n", x)
     printf("untilInRange(0.1) condition: %.3f\n",
          BisectingIntervalsMethod.approximate(x,
               SatisfactionFunctions.untilInRange(
                          0.1)))
     printf("untilInRange(0.01) condition: %.3f\n",
          BisectingIntervalsMethod.approximate(x,
               SatisfactionFunctions.untilInRange(
                          0.01)))
     printf("untilInRange(0.0001)) condition: %.3f\n",
          BisectingIntervalsMethod.approximate(x,
             SatisfactionFunctions.untilInRange(
                          0.0001)))
}

Conclusion


There is a lot more to collections in Scala, so I suggest once again that you should read the official Scala collections PDF document.

Download sample code for this article (the Babylonian method is not implemented yet; it will be for the next article)

Scala 2.8 Showcase


  1. Scala 2.8 Showcase - Collections
  2. Scala 2.8 Showcase - Arrays
  3. Scala 2.8 Showcase - Specialized Types

2010-02-18

Artifactory 2.2.1 + Hudson + Maven

Artifactory 2.2.1 and Hudson - error


I have just recently updated my Artifactory from version 2.0.7 to version 2.2.1 and immediately my release builds done from Hudson using the Hudson Release Plugin started failing with a nasty error message (line breaks added manually for readability).

ERROR: Error deploying artifact:
Resource to deploy not found: File:
http:/*/artifactory/libs-releases-local/*/0.1.24-SNAPSHOT/
console-0.1.24-SNAPSHOT.pom does not exist

org.apache.maven.artifact.deployer.ArtifactDeploymentException: Error deploying artifact: Resource to deploy not found: File: http://*/artifactory/libs-releases-local/*/0.1.24-SNAPSHOT/console-0.1.24-SNAPSHOT.pom does not exist
at org.apache.maven.artifact.deployer.DefaultArtifactDeployer.deploy(DefaultArtifactDeployer.java:94)
at hudson.maven.reporters.MavenArtifactRecord.deploy(MavenArtifactRecord.java:119)
at hudson.maven.reporters.MavenAggregatedArtifactRecord.deploy(MavenAggregatedArtifactRecord.java:79)
at hudson.maven.RedeployPublisher.perform(RedeployPublisher.java:96)
at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:19)
at hudson.model.AbstractBuild$AbstractRunner.perform(AbstractBuild.java:582)
at hudson.model.AbstractBuild$AbstractRunner.performAllBuildStep(AbstractBuild.java:563)
at hudson.maven.MavenModuleSetBuild$RunnerImpl.post2(MavenModuleSetBuild.java:594)
at hudson.model.AbstractBuild$AbstractRunner.post(AbstractBuild.java:528)
at hudson.model.Run.run(Run.java:1221)
at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:304)
at hudson.model.ResourceController.execute(ResourceController.java:88)
at hudson.model.Executor.run(Executor.java:122)
Caused by: org.apache.maven.wagon.TransferFailedException: Resource to deploy not found: File: http://*/artifactory/libs-releases-local/*/0.1.24-SNAPSHOT/console-0.1.24-SNAPSHOT.pom does not exist
at org.apache.maven.artifact.manager.DefaultWagonManager.putRemoteFile(DefaultWagonManager.java:283)
at org.apache.maven.artifact.manager.DefaultWagonManager.putArtifact(DefaultWagonManager.java:160)
at org.apache.maven.artifact.deployer.DefaultArtifactDeployer.deploy(DefaultArtifactDeployer.java:80)
... 12 more
Caused by: org.apache.maven.wagon.ResourceDoesNotExistException: File: http://*/artifactory/libs-releases-local/*/0.1.24-SNAPSHOT/console-0.1.24-SNAPSHOT.pom does not exist
at org.apache.maven.wagon.providers.http.LightweightHttpWagon.put(LightweightHttpWagon.java:168)
at org.apache.maven.artifact.manager.DefaultWagonManager.putRemoteFile(DefaultWagonManager.java:244)
... 14 more

It normally helps to see the Artifactory system log. Here is what I found in mine:

2010-02-18 13:48:10,732 [http-8000-3] [WARN ] (o.a.r.j.StoringRepoMixin:543) -
IO error while trying to save resource libs-releases-local:
*/0.1.15-SNAPSHOT/console-0.1.15-SNAPSHOT.pom'':
The target deployment path '*/0.1.15-SNAPSHOT/console-0.1.15-SNAPSHOT.pom'
does not match the POM's expected path prefix '*/0.1.16-SNAPSHOT'.
Please verify your POM content for correctness and make sure the source path is a valid Maven 2 repository root path.

But that's easy to fix with the following command:

-Dartifactory.maven.suppressPomConsistencyChecks=true

You should pass it to your server that runs Artifactory.

However, I also found this:

2010-02-18 13:48:10,732 [http-8000-3] [ERROR] (o.a.j.l.SessionLockEntry:266) -
Immutable item /repositories/libs-releases-local*/0.1.15-SNAPSHOT/console-0.1.15-SNAPSHOT.pom has local modifications that will be ignored.

I found this call in the Artifactory source code but that didn't really give me any clues...

Anyway, the release builds were still failing and luckily I managed to find a workaround.

The workaround


The workaround is a simple operation to be done in Hudson actually (not in Artifactory). In your project configuration there might be two check boxes:
  • Deploy artifacts to Maven repository
  • Deploy artifacts to Artifactory

The workaround for this issue is: uncheck both check boxes. Easy does it.

2010-02-12

Scala - Design by Contract

Design by Contract


Design by Contract (DbC) (aka Programming by Contract) is an approach to developing and engineering software. With Design by Contract programmers should define formal specifications for modules, and those specifications are called contracts. There are basically three types of contracts.

  • Preconditions - requirements for the module to run correctly (must be true before it is invoked)
  • Postconditions - the results that the module guarantees (must be true after it is invoked)
  • Invariants - these conditions must be true before and after the module runs

In other words, preconditions are asking yourself - what does my module expect?
Postconditions - what does my module guarantee?
Invariants - what does my module maintain?

Because you guarantee certain conditions to be true as long as your requirements are satisfied - it is a very formal way of designing software and may help you write formal proofs of correctness for your software using for instance Hoare logic - would you believe?

But seriously, the technique can prove very useful and promises making debugging to be a lot easier, due to the fail-hard principle which means that if the preconditions are not met (i.e. any of them isn't) - it all crashes, perhaps with a big boom, but providing the developer with useful information regarding the failure.

Design by Contract is a bit similar to defensive programming, but it differs in that the module is not responsible for figuring out what went wrong and why - it just fails when the preconditions are not met (which is probably a bit easier). Enough introduction.

Design by Contract in Scala - precondition


Although Scala does not provide support for Design by Contract as such, we can still implement it without having to use any external libraries and in quite an elegant fashion.

Let's not wait any longer and see some code!

package me.m1key.dbc

class Account(b: Int) {
    
    private var balance = b
    
    printf("Creating a new account with balance: %d\n", balance)
    
    require(balance >= 0.0, "Balance must be > 0 and is: %d".format(balance))
    
    
    def debit(amount: Int) = {
        printf("Debitting: %d ", amount)
        balance -= amount
        printf(", balance: %d\n", balance)
    }
    
    def credit(amount: Int) = {
        printf("Adding credit: %d ", amount)
        balance += amount
        printf(", balance: %d\n", balance)
    }

}

Here we can see a simple Account class that you create by providing it an initial amount (b: Int). Because I did not use val/var keywords, this field is not accessible from the outside, which is good as we don't want anyone messing around with the balance in ways other than the debit/credit methods.

The code below class declaration but above the methods - we assign the initial value to a private variable balance. It is not accessible from the outside world. It will hold the actual balance that we will modify (b: Int is a val, we cannot change its value).

The next two lines (printf and require) are what you would call constructor code in Java. Printf just prints some useful info to the console (for the example sake), and then - please welcome the require method of the Scala Predef object which is automatically imported by the compiler for you convenience. The Predef object defines or imports items like String (the Scala version), collections, exceptions, Pair, Triple and more useful stuff.

Now, what the require method does here is it makes sure that balance is greater than or equal 0. Otherwise - fail hard, you get an exception:

val account11 = new Account(-1) // Error

Creating a new account with balance: -1
Exception in thread "main" java.lang.IllegalArgumentException: requirement failed: Balance must be > 0 and is: -1
    at scala.Predef$.require(Predef.scala:117)
    at me.m1key.dbc.Account.<init>(Account.scala:9)
    at me.m1key.dbc.Launch$.main(Launch.scala:11)
    at me.m1key.dbc.Launch.main(Launch.scala)

We only make the check when the object is created, thus this is a precondition. At this point, you can further modify the balance and set it to negative numbers without any exceptions - which we shall fix. By the way, you can put the require method anywhere you want, not just in this particular place.

Note - why use Int for representing money and not double?


Good question. To find out, look at this code and compare what you think it should return with what it actually does (you're going to have to run it yourself).

def x: Double = 2.00
        def y: Double = 1.90
        println(x - y)

Design by Contract in Scala - postcondition


Let us fix this problem. Let us add a postcondition that will verify the balance to be debited.

def debit(amount: Int) = {
        printf("Debitting: %d ", amount)
        assume(balance - amount >= 0.0, "This debit amount exceeds current balance: %d".format(amount))
        balance -= amount
        printf(", balance: %d\n", balance)
    }

Here we check whether the balance stays above or at 0 before we even subtract.

Note that we used assume and not require like we did for the precondition. These two methods are basically the same except that assume throws an AssertionError while require throws an IllegalArgumentException. Therefore assume is more natural for postconditions while require is more natural for preconditions.

Drawbacks


The drawback is that there is no way to disable these checks - if you don't comment them out, they will stay and run in production code.
Update 2010-02-13: As duyn kindly pointed out, this is not entirely true. As of Scala 2.8 the elidable annotation is available and it means that whatever is annotated with it - can be removed from the compiled code (with a command similar to scalac -Xelide-methods-below=1000; I got it from Scala docs). And, the assume method is indeed annotated with it, so it can be disabled for production code (as well as the assert method). However, the require method is not annotated, which means it stays in the code unless you comment it out.
Thanks duyn for your helpful remark!

Now, like I previously said, the require method stays in the code. This may not be acceptable for performance reasons, but also you may not like your code to fail-hard. You might be developing a service that should just run (for example, see Scala Actors).

The two methods - assume and require are very simple. Their limitation is that they only accept simple expressions. So, if you are looking for more flexibility, you may look at the Ensuring class (it accepts functions as predicates).

Conclusion


Design by Contract is an interesting approach, however it has pretty much been replaced these days by Test Driven Development and probably for good reasons (TDD is said to be more flexible and natural). On the other hand, an important thing to notice is that TDD and DbC are not necessarily mutually exclusive, so you might as well try using a combination of both.

Download source code for this article

PS. You can find an interesting way of implementing DbC in Scala on this Scala Wiki page.

2010-02-11

REST with Spring 3.0, Spring MVC and Dojo. Part 5 - DELETE

In the fifth part of the series (which is also the last one, at least for now) we will take a look at the DELETE part.

DELETE, as its name suggests, is for deleting items and it is done by ID which means you don't need to send the entire object to the server via REST.

Operation REST method Sample URI
Return item(s) GET /books (all books)
/books/ (all books)
/books/12 (one book with ID = 12)
Create a new item POST (you pass the ID in the object itself)
/books
/books/
Update an item PUT (you pass the ID in the object itself)
/books
/books/
Delete an item DELETE /books/12 (book with ID = 12)

The Spring MVC controller part


@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public void handleBookDelete(HttpServletResponse response,
            @PathVariable("id") Long bookId) throws IOException {
        BooksBean booksBean = Factory.getBooksBean();
        try {
            booksBean.deleteBook(bookId);
        } catch (BookNotFoundException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }

This is a delete action - the RequestMapping method is DELETE, as you can see. When the book does not exist - we throw a 404, like we did in the previous example.

The Dojo part


function deleteBook(bookId) {
    var deferred = _request("xhrDelete", {
        url: "http://localhost:8080/restsample-0.0.1-SNAPSHOT/rest/books/" +
            bookId + ".json",
        handleAs: "json"
    });
    deferred.addCallback(this, function(value) {
        alert("Book deleted.");
    });
    deferred.addErrback(this, function(value) {                
          alert("Error while deleting book: "  + value);
    });
}

This is Dojo code - simple JavaScript very similar to what we did before. It uses the xhrDelete method, that's it.

Conclusion


This is the end of the series, for now. What else is there to possibly improve or cover?
  • Error handling - something more automatic then writing to response with sendError.
  • Validation - still an open bug at Spring JIRA.
  • Your ideas?
I hope the information here will be helpful to someone!

Links


Download source code for this article

  1. REST with Spring 3.0, Spring MVC and Dojo. Part 1 - GET
  2. REST with Spring 3.0, Spring MVC and Dojo. Part 2 - GET from Dojo perspective
  3. REST with Spring 3.0, Spring MVC and Dojo. Part 3 - POST and JSR-303 validation
  4. REST with Spring 3.0, Spring MVC and Dojo. Part 4 - PUT (updating objects)
  5. REST with Spring 3.0, Spring MVC and Dojo. Part 5 - DELETE

2010-02-10

REST with Spring 3.0, Spring MVC and Dojo. Part 4 - PUT (updating objects)

In the fourth part of the REST/Spring 3.0/MVC/Dojo series we will take a look at the update case, which is done with PUT in REST. Please check out the table below:

Operation REST method Sample URI
Return item(s) GET /books (all books)
/books/ (all books)
/books/12 (one book with ID = 12)
Create a new item POST (you pass the ID in the object itself)
/books
/books/
Update an item PUT (you pass the ID in the object itself)
/books
/books/
Delete an item DELETE /books/12 (book with ID = 12)

PUT for update is very similar to POST for create. There are two differences and one of them will make this part interesting: one is that we pass the actual ID of the object to update (not really interesting), the other is the case when the object to update does not exist in the system (interesting as we will send 404 back to the user).

What happens if the object does not exist? We want to throw an exception, but a regular exception thrown and not caught while handling gives a 500 (Internal server error) on the client side. But that's not what we want. What do we want? Well, since the object was not found, we want to give the client a 404. But first, let's look at the controller.

Handling PUT with Spring MVC


@RequestMapping(value = "/books", method = RequestMethod.PUT)
    public BookTO handleBookUpdate(HttpServletResponse response,
            @RequestBody @Valid BookTO bookTO) {
        BooksBean booksBean = Factory.getBooksBean();
        return booksBean.updateBook(bookTO);
    }

So, this is a sample action. As you can see, the RequestMapping value is identical to the one from the POST (create) action. Not a problem - the method is now PUT. We also have the RequestBody and Valid annotations known from the previous part.

OK, let's look at the Dojo part!

Handling PUT from the client perspective - Dojo


function updateBook(bookId, bookName) {
    var bookToUpdate = {
            "id":bookId,
            "name":bookName
    };
    var actualContent = dojo.toJson(bookToUpdate);
    
    //Save.
    var deferred = this._request("rawXhrPut", {
        url: "http://localhost:8080/restsample-0.0.1-SNAPSHOT/rest/books.json",
        handleAs: "json",
        putData: actualContent,
        headers: { "Content-Type": "application/json"}
    });
    deferred.addCallback(this, function(value) {
        alert("Updated! " + value.bookTO.id + ", " + value.bookTO.name);
    });
    deferred.addErrback(this, function(value) {                
          alert("Error: "  + value);
    });    
}

Nothing very cool here - except that we use Dojo rawXhrPut instead of xhrPut and putData instead of postData.

Throwing an exception that ends up as 404


Finally, let's look at the exception handling so that we get a 404.

@RequestMapping(value = "/books", method = RequestMethod.PUT)
    public BookTO handleBookUpdate(HttpServletResponse response,
            @RequestBody @Valid BookTO bookTO) throws IOException {
        BooksBean booksBean = Factory.getBooksBean();
        try {
            return booksBean.updateBook(bookTO);
        } catch (BookNotFoundException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return new BookTO();
        }
    }

This code catches a BookNotFoundException. If the problem occurs, it writes a 404 to response and returns an empty object.

This is by no means perfect. An ideal way would be to be able to throw the exception without having to worry about writing a 404. This is something that perhaps Spring MVC could handle. I am not aware of such possibility.

Also, we return an empty object. This is definitely better than null, but it might be better to return an empty object more explicitly (a static EMPTY_BOOK field of an Empty final class - just an idea). It does not matter much in our case as client's processing will have to handle a 404 error anyway and will not even get to handle this empty object.

Why not just throw the exception and let the exception itself write a 404? I tried it and it does not work on JBoss (and it works perfectly on WebSphere), it turns out.


In the next and last part we will look at deleting.

Links


Download source code for this article

  1. REST with Spring 3.0, Spring MVC and Dojo. Part 1 - GET
  2. REST with Spring 3.0, Spring MVC and Dojo. Part 2 - GET from Dojo perspective
  3. REST with Spring 3.0, Spring MVC and Dojo. Part 3 - POST and JSR-303 validation
  4. REST with Spring 3.0, Spring MVC and Dojo. Part 4 - PUT (updating objects)
  5. REST with Spring 3.0, Spring MVC and Dojo. Part 5 - DELETE

2010-02-06

REST with Spring 3.0, Spring MVC and Dojo. Part 3 - POST and JSR-303 validation

In the third part of the series we will take a look at handling POST requests from REST in Spring MVC, and also at validation. And - not just any validation but JSR-303 validation! There's a trick to it though, I have to be honest. I will explain this later.
We will also look at sending POST requests with Dojo.

You need Java 6 for this and I am also using JBoss 6.0.0.M1.

POST requests are the C in CRUD. What it means is you use it to create new items. Please see this little table.

Operation REST method Sample URI
Return item(s) GET /books (all books)
/books/ (all books)
/books/12 (one book with ID = 12)
Create a new item POST (you pass the ID in the object itself)
/books
/books/
Update an item PUT (you pass the ID in the object itself)
/books
/books/
Delete an item DELETE /books/12 (book with ID = 12)

As you can see, in the POST or PUT case we are not passing the ID. Instead, we will pass the entire object! Spring MVC makes it possible for us to retrieve the object straight from REST and does all the binding for us.

Also, some of the URIs are identical across the methods. That's perfectly correct - it's the method (POST, PUT) that makes the distinction. You don't have to do any additional handling in your controller methods (actions).

Let us take a look at the controller then. The code should be familiar by now.

@RequestMapping(value = "/books", method = RequestMethod.POST)
    public BookTO handleBookSave(HttpServletResponse response,
            @RequestBody @Valid BookTO bookTO) {
        BooksBean booksBean = Factory.getBooksBean();
        return booksBean.saveBook(bookTO);
    }

First, notice the RequestMapping annotation and the URI that it handles (/books). Second, notice the method - it's POST which means it's supposed to handle the create case.

It's a controller method which means it's an entry point to handle REST requests and - as promised - it already retrieves an object! How does it happen? Well, that's thanks to the RequestBody annotation. It does auto-binding for us and also does type validation.

What is the Valid annotation for? It tells Spring to do JSR-303 on that object when binding. It uses Hibernate constraints, to be precise (the previously mentioned type checking is independent of this and happens with or without the Valid annotation). Please take a look at this TO object that we validate and note the validation annotations needed for JSR-303.

import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.Length;

public class BookTO {
    // ...
    @NotNull @Length(min = 20)
    public String getName() {
        return name;
    }
}

See? It's pretty easy. But... Yeah, there's a problem with it - it doesn't work. That's right, it doesn't work. What's the problem with it? Take a look at the controller code. We have two annotations on the method argument (@Valid and @RequestBody) and when combined, Spring ignores the Valid annotation. It's a bug and it has already been submitted to Spring JIRA. Let's hope this get resolved when Spring 3.1 comes out; I'm keeping my eye on it.

Let's also look at the Dojo part of the story.

function saveBook(bookName) {
    var newBook = {
            "name":bookName
    };
    var actualContent = dojo.toJson(newBook);
    
    //Save.
    var deferred = this._request("rawXhrPost", {
        url: "http://localhost:8080/restsample-0.0.1-SNAPSHOT/rest/books.json",
        handleAs: "json",
        postData: actualContent,
        headers: { "Content-Type": "application/json"}
    });
    deferred.addCallback(this, function(value) {
        alert("Saved! " + value.bookTO.name);
    });
    deferred.addErrback(this, function(value) {                
          alert("Error: "  + value);
    });    
}

We first create an object to pass - the fields have to match the TO object fields (the names have to be the same).

Then we use dojo.toJson to convert this object to a JSON string.

Next, we call our RESTful service. Notice the method - it's rawXhrPost as we need it raw for binding to work. We also pass the object (well, it's a string at this point) as postData. For PUT requests we will use, you guessed it, putData.

And that's all! Download the sample code for this article if you wish.

  1. REST with Spring 3.0, Spring MVC and Dojo. Part 1 - GET
  2. REST with Spring 3.0, Spring MVC and Dojo. Part 2 - GET from Dojo perspective
  3. REST with Spring 3.0, Spring MVC and Dojo. Part 3 - POST and JSR-303 validation
  4. REST with Spring 3.0, Spring MVC and Dojo. Part 4 - PUT (updating objects)
  5. REST with Spring 3.0, Spring MVC and Dojo. Part 5 - DELETE

2010-02-05

Superiority by Arthur C. Clarke

Superiority is a short hard science fiction story written by Arthur C. Clarke and published in 1951. Although it describes an arms race, I believe it to be very relevant to the modern software engineering world.

Soon after publication 'Superiority' was inserted into the Engineering curriculum of MIT - to warn the graduates that the Better is often the enemy of the Good - and the Best can be the enemy of both, as it is always too late. -- Arthur C. Clarke ([ACC, p. 395]).

Have you ever heard of the better being the enemy of the good (attributed to Voltaire)? Have you ever heard of overengineering?

In the story a captured general reveals the reason for his failure. His army had everything, had technological advantage, financial advantage - and yet lost to a seemingly weaker army. Why? Read this shorty story and find out why - and how surprisingly relevant it is in the software world today.

Read it now or purchase it somewhere on the Internet (I own this edition) or at your favorite book store.

Bibliography:
[ACC] Arthur C. Clarke - The Collected Stories, ISBN 978-1-85798-323-4.

You can help me maintaining this site by buying this item:
The Collected Stories Of Arthur C. Clarke (Gollancz S.F.)