Dustin's Pages

Wednesday, February 24, 2010

Many Java developers are not fond of Java's standard APIs for handling Dates and Calendars. In fact, it is difficult to think of examples from the Java standard APIs that better illustrate the mistake of allowing ultimate and mostly unused flexibility to result in an unnecessarily high degree of pain for the vast majority of users of the API. One of the things a Java developer using Calendar may need to do is specify a particular TimeZone. The specification of a TimeZone is done via String-based TimeZone IDs. This blog post demonstrates getting these String-based IDs with both Java and Groovy.

The TimeZone class provides a static method for getting an array of the Strings representing recognized TimeZone IDs. The availability of this method, TimeZone.getAvailableIDs(), allows a developer to programmatically access TimeZone IDs supported by the current JRE release or via Timezone Updater. I have blogged previously on the value of using simple Java tests. The next code listing is an example of just that and provides the available set of TimeZone IDs for a given environment.

The above Java code is relatively simple and it does the job of providing the valid TimeZone IDs available to me in a given environment, but Groovy can be even simpler to use in situations such as this one. The next code listing is a simple Groovy script for printing out these values.

displayTimeZoneIds1.groovy

println Arrays.toString(TimeZone.availableIDs)

Wow! It doesn't get much simpler than that. Groovy allowed me to drop the class declaration, the main method declaration, both java.util imports, and even simplified the "meaty" line from the Java code. It turns out that it actually does gets even easier, however, as shown in the next version of the Groovy-based script.

displayTimeZoneIds2.groovy

println TimeZone.availableIDs

The second version of the Groovy script dropped use of Arrays.toString(Object) because it is unnecessary when using Groovy arrays. Now that's super simple: println TimeZone.availableIDs

The static method Arrays.toString(Object[]) was necessary in the Java example to avoid seeing the default Object.toString() implementation for the array of Strings that would look something like this: [Ljava.lang.String;@3e25a5 where the [ indicates an array, the L indicates a reference type (not primitive), java.lang.String is obviously the class name of the elements of the array, and the @3e25a5 represents the "unsigned hexadecimal representation" of the object's hash code.

With things so simple, it seems like it's a good time to add some additional functionality. We'll do one more very simple thing that will dramatically improve the readability of our output. The third version of the Groovy script leverages Groovy's closure support to easy iterate over the String array and print each element of the array (each TimeZone ID) on its own line and without the array delimiting square braces ([]).

Before finishing this example, I would like to do one more thing to make the returned set of TimeZone IDs easier to manage. It can be difficult to find what I'm looking for in this list and I'd rather see it in sorted form.

displayTimeZoneIds4.groovy

TimeZone.availableIDs.sort().each {println it}

That's all there is to it -- there's nothing sordid about that. I don't show it here, but running that single line script will return the available TimeZone IDs without the array syntax, with each ID on its own line, in an alphabetically sorted order.

Conclusion

This blog post had two primary purposes. One purpose was to demonstrate another practical example of where Groovy can greatly simplify use of basic Java APIs, especially when simply trying to learn about something new or get a listing of options available in a given environment. A second purpose was to demonstrate how to find out which TimeZone IDs are available, though this was really more of an excuse to demonstrate the sleekness of Groovy.

Thursday, February 18, 2010

Several blog posts related to Rocky Mountain Oracle Users Group (RMOUG) Training Days 2010 have started appearing and some of the presenters have made their slides available for download. In this blog post, I collect links to some of those blog posts and presentation slides after briefly summarizing my own experience.

I enjoyed presenting "RESTful Java" and "Applied Groovy: Scripting for Java Development" at this year's (2010) edition of RMOUG Training Days. The audiences for these presentations were small (approximately 10 in the REST presentation and 20 to 30 in the Groovy presentation), but the people in attendance were attentive and asked great questions. I have always believed, and have heard many other speakers also say, that the types of questions from the audience is a good type of feedback on how well the presentation went. Some of the questions were so insightful and useful that I plan to blog on the answers to those questions in future blog posts.

The URLConnection class and its child HttpURLConnection class provide many useful methods for accessing details regarding a HTTP connection. These are easily obtained from a call to URL.openConnection(). This is demonstrated in the next Groovy code listing.

The response code and message are included in the output shown in the above screen snapshot. In all three cases, the response code and message are 200 and OK respectively. The content length of -1 is the value provided by the getContentLength method when (according to the Javadoc) "content length is not known."

In the example above, I used the convenience methods provided for "certain header fields [that] are accessed frequently" (see URLConnection Javadoc description). Because many more header fields are included in responses, it can be useful to find out what these are and see their values. This is demonstrated in the next code sample.

The simple Groovy script above uses the GDKMap.each method that acts on closures and prints out the field values for each header field. The output from running this script against the same three URLs as before is shown next.

This output shows that there are some differences in the fields returned by each of the three URLs in response to the implicit GET request.

The combination of Groovy, Groovy GDK, URL, and HttpURLConnection make it easy to generate a quick and dirty HTTP client. This can be useful in testing HTTP-exposed services including HTTP-based REST services.

In my previous blog posts on JAX-RS and REST, I have often used RESTClient as the client for testing my deployed services. RESTClient provides a nice graphical user interface and is easy to use. However, if I only need command line test, Groovy is one easy option.

With Groovy, it is easy to take advantage of Java's URI and URL classes. Groovy makes it even easier to use these than in traditional Java because the Groovy GDK-provided String class provides the very convenient toURI() and toURL methods. This is such an easy process that it's actually easier to demonstrate it than to attempt to describe it. So, here is an example in two lines of Groovy code (really one line if you don't count the shebang line):

The URL incorporated in the String in the above code points to a JAX-RS-powered REST-based web service I discussed in a previous blog post. The simple service behind that URL returns a "movie of the day" for the month and date given by the two integers at the end of the URL. When the above Groovy code is executed, the output appears as shown in the next screen snapshot.

That simple Groovy code of one real executable line leveraged the power of the Groovy GDK's String and a standard Java class to easily provide the text provided by the resource at the other end of the URL. It doesn't get any easier than that.

The next example is slightly more interesting, but still only requires a small number of lines of Groovy code:

Because Java's URL class provides significantly more details than just the text available from accessing that URL, this information is readily accessed in a Groovy script. An example of some of this additional information being retrieved is shown in the next code listing and associated output screen snapshot.

In this post, I have demonstrated how easy it is to mix the best of Groovy with the best of Java to put together a very simple client for accessing HTTP-exposed services such as one finds in many REST applications. I didn't even get to the URL.openConnection() method here, but this method opens up a great deal more information that might be useful for simple testing tools when using HTTP-exposed services.

Monday, February 15, 2010

HTTP Status Codes are a big part of the HTTP protocol that most of us have seen countless times in our web browsing and development. We are used to seeing 404 (Not Found), 200 (OK), and so forth. Because HTTP is often closely tied with REST style applications, it is not surprising that JAX-RS provides tremendous support for returning appropriate HTTP responses from REST-based web services. In this blog post, I look at the tip of the iceberg in terms of JAX-RS support for HTTP-based service responses.

The code listing that follows would not generally be a useful piece of functionality, but it is used here to demonstrate how easy it is with JAX-RS to generate HTTP responses with specific HTTP status codes.

I use RESTClient as an easy client tool to demonstrate this simple JAX-RS web service in action. The next two screen snapshots show what RESTClient sees (and what any other client would see) in terms of responses to certain provided URIs (shown at top of GUI).

JAX-RS also makes it easy to turn encountered exceptions into HTTP response codes indicating the error. The next piece of code demonstrates this.

/** * Return an exception-based HTTP response based on the provided number * indicating a particular exception to be used. The HTTP method PUT would * normally likely not be the method used for this type of operation, but * it makes it easy to differentiate from the other method in this class * already tied to @GET and also accepting a single String. * * There are four cases in which a particular exception is used to build the * response and that exception and a particular Response.Status are provided, * telling the JAX-RS provider which HTTP status to tie to that particular * thrown exception. In the default/general case when one of the first four * are not used, no specific Response.Status is used, so the general 500 * Internal Server Error will be returned to the client along with the' * exception's stack trace as the body. * * @param exceptionNumberType A number used to determine which type of * exception is used for the basis of the response. * @return Response based on the described exception type. */ @PUT @Path("/{exceptionNumberType}") @Consumes("text/plain") public Response causeException( @PathParam("exceptionNumberType") final int exceptionNumberType) { Exception exception; Status status = null; switch (exceptionNumberType) { case 1 : exception = new NullPointerException("1. Null Encountered."); status = Status.NOT_FOUND; break; case 2 : exception = new IllegalArgumentException("2. Bad argument"); status = Status.PRECONDITION_FAILED; break; case 3 : exception = new RuntimeException("3. Runtime Exception"); status = Status.BAD_REQUEST; break; case 4 : exception = new NumberFormatException("4. Bad Numeric Format"); status = Status.NOT_ACCEPTABLE; break; default : exception = new Exception("General Exception"); } throw status != null ? new WebApplicationException(exception, status) : new WebApplicationException(exception); }

I included some verbose comments on this method to describe how it behaves in greater detail. This method primarily demonstrates how the WebApplicationException is useful in turning Java exceptions into HTTP responses. I only use two of this exception's eight constructors in this example, but they demonstrate the difference between providing a particular HTTP Response.Status with the exception (and counting on the JAX-RS provider to place the results of Response.Status.getReasonPhrase() in the response body) or allowing the JAX-RS provider to associated a Response.Status with the exception (500) and showing the entire stack trace of the exception.

This difference is demonstrated in the next three screen snapshots. Two are of exceptions for which a particular (largely nonsensical here and only meant to illustrate how to do this) HTTP status code is associated with the exception and one is for the case where the JAX-RS provider assigns 500 implicitly and puts the exception's stack trace in the response body rather than the Response.Status.getReasonPhrase().

In this post, I have attempted to demonstrate how easy JAX-RS makes it to specify HTTP responses based on regular and exceptional conditions. I have only touched on a small part of the extensive JAX-RS support for building appropriate responses.

There is a part of me that likes to try things just to see what happens. If I read something that says, "Never do this," I have a hard time not doing just that thing if I believe doing so comes at no significant cost. There can be value to this approach when I learn about the results associated with an improper action and can then more readily recognize the underlying cause when I inadvertently cause the same problem myself or see a colleague dealing with the same effects. In this blog post, I look at how JAX-RS 1.1 (specifically the Jersey implementation) handles some of the "don't do that" rules related to resource methods.

One JAX-RS Resource Method Designation Per Java Method

JAX-RS literature warns that only one JAX-RS method designation annotation is allowed per method in a Java class resource. In other words, I should only be able to apply @GET or @POST or @PUT or @DELETE to a method, but never apply more than one of them to the same method. This actually seems sensible, but it prevents some of the "trickery" one commonly saw in servlet applications where the doPost and doGet methods were set up so that one called the other or they both called the same piece of code.

To find out what the negative consequences are of specifying multiple JAX-RS method designators on the same method, I took the method addMovieOfTheDay from my previous blog post (JAX-RS and the REST Uniform Interface) and added the @POST annotation on top of its existing @PUT annotation. The altered code is shown next:

Two JAX-RS Method Designation Annotations for a Single Method

/** * Add a new entry or update an existing entry representing a movie of the day. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ @PUT @POST @Path("/{month}/{date}/{title}") @Consumes("text/plain") @Produces("text/html") public String addMovieOfTheDay( @PathParam("month") final Integer month, @PathParam("date") final Integer date, @PathParam("title") final String title) { final Map<Integer, String> moviesOfTheMonth = MOVIE_OF_THE_DAY.get(month-1); if (moviesOfTheMonth != null) { moviesOfTheMonth.put(date, title); } return generateAddedMovieHtml(title); }

The above code compiles without incident. This is not surprising because, as the JAX-RS 1.1 specification states (Section 3.3 Resource Models, emphasis added), "A request method designator is a runtime annotation that is annotated with the @HttpMethod annotation." However, when I try to deploy it following the steps outlined in my blog post JAX-RS with Jersey: An Introduction, I see an error in the GlassFish v3 web-based Administrative Console. A screen snapshot of that is shown next.

The output states that an IllegalStateException has been thrown and suggests seeing the logs for additional details. There is a very lengthy stack trace in the logs, but the most significant piece of it is this:

[#|2010-02-14T19:43:38.495-0700|SEVERE|glassfishv3.0|com.sun.jersey.server.impl.application.WebApplicationImpl|_ThreadID=25;_ThreadName=Thread-1;|A (sub-)resource method, public java.lang.String rmoug.td2010.rest.MovieOfTheDay.addMovieOfTheDay(java.lang.Integer,java.lang.Integer,java.lang.String), should have only one HTTP method designator. It currently has the following designators defined: [@javax.ws.rs.PUT(), @javax.ws.rs.POST()]|#]

With the context of the situation in mind, this is pretty straightforward: "only one HTTP method designation" is allowed for a resource method and the method "[addMovieOfTheDay(Integer,String)] currently has the designators ... @PUT ... @POST [defined]." Okay, so that is bad. Note to self: The advice to only use one method designator per class resource method should be heeded.

As I wrote this post, I verified that NetBeans 6.8 continues the tradition of creating new Java servlets with the automatically generated doPost and doGet methods calling the same protected method (processRequest in NetBeans 6.8, though I seem to recall this method had a different name previously, such as doProcess()). I decided the next thing to try was annotating two separate methods with respective annotations, but have them call the same underlying method. My assumption was that this would work fine. The code for this is shown in the next listing.

Two Designators/Two Methods But with Single Common Method

/** * Add a new entry or update an existing entry representing a movie of the day. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ @PUT @Path("/{month}/{date}/{title}") @Consumes("text/plain") @Produces("text/html") public String addMovieOfTheDay( @PathParam("month") final Integer month, @PathParam("date") final Integer date, @PathParam("title") final String title) { return addMovie(month, date, title); }

/** * Add a new entry or update an existing entry representing a movie of the day. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ @PUT @Path("/{month}/{date}/{title}") @Consumes("text/plain") @Produces("text/html") public String addMovieOfTheDayPost( @PathParam("month") final Integer month, @PathParam("date") final Integer date, @PathParam("title") final String title) { return addMovie(month, date, title); }

/** * "Common" method for adding/updating a movie of the day that is intended * to support PUT and POST. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ private String addMovie(final Integer month, final Integer date, final String title) { final Map<Integer, String> moviesOfTheMonth = MOVIE_OF_THE_DAY.get(month-1); if (moviesOfTheMonth != null) { moviesOfTheMonth.put(date, title); } return generateAddedMovieHtml(title); }

This code compiles without incident because I appended "Post" to the method name of the added method. However, I "forgot" to change the annotation to @Post for the new method and this became obvious when I tried to deploy to GlassFish. I saw the same general error as before in the console, but the logs had details on the new problem:

This SEVERE-level log message is telling us that the two methods annotated with @PUT are ambiguous because they have the same URI path and same MIME type. One of these needs to be different to allow the JAX-RS provider to differentiate them. For our purposes, I simply change the new method addMovieOfTheDayPost to have the @POST annotation rather than the @PUT annotation.

Method Intended for POST Annotated with @POST

/** * Add a new entry or update an existing entry representing a movie of the day. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ @POST @Path("/{month}/{date}/{title}") @Consumes("text/plain") @Produces("text/html") public String addMovieOfTheDayPost( @PathParam("month") final Integer month, @PathParam("date") final Integer date, @PathParam("title") final String title) { return addMovie(month, date, title); }

The code again compiles and even deploys this time. I don't show it here, but using RESTClient to access the resource via PUT and via POST works for both HTTP methods. In short, it does appear that one can delegate functionality from two different Java methods associated with different HTTP methods to the same common method.

The last thing I wanted to try in this area was having one method call the other rather than two methods calling a third, common method. To try this, I changed the method added for POST support to simply call the method for PUT:

POST-Supporting Method Calling PUT-Supporting Method

/** * Add a new entry or update an existing entry representing a movie of the day. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ @PUT @Path("/{month}/{date}/{title}") @Consumes("text/plain") @Produces("text/html") public String addMovieOfTheDay( @PathParam("month") final Integer month, @PathParam("date") final Integer date, @PathParam("title") final String title) { final Map<Integer, String> moviesOfTheMonth = MOVIE_OF_THE_DAY.get(month-1); if (moviesOfTheMonth != null) { moviesOfTheMonth.put(date, title); } return generateAddedMovieHtml(title); }

/** * Add a new entry or update an existing entry representing a movie of the day. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ @POST @Path("/{month}/{date}/{title}") @Consumes("text/plain") @Produces("text/html") public String addMovieOfTheDayPost( @PathParam("month") final Integer month, @PathParam("date") final Integer date, @PathParam("title") final String title) { return addMovieOfTheDay(month, date, title); }

This approach compiled successfully, deployed successfully, and I was able to invoke both the PUT-supporting and POST-supporting Java methods successfully. So, the approach of having one method directly call the other seems to work as well if a developer wants to get around the limitation of not having multiple HTTP method designations on the same Java method.

Only Public Methods Allowed as Resource Methods

Section 3.3.1 ("Visibility") of the JAX-RS 1.1 specification states: "Only public methods may be exposed as resource methods. An implementation SHOULD warn users if anon-public method carries a method designator or @Path annotation."

Let's see what happens with Jersey in this situation.

To test this one out, I change the just-added method supporting POST to be package scope by removing its public modifier.

Package-level @POST-annotated Method

/** * Add a new entry or update an existing entry representing a movie of the day * via HTTP POST. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ @POST @Path("/{month}/{date}/{title}") @Consumes("text/plain") @Produces("text/html") /*public*/ String addMovieOfTheDayPost( @PathParam("month") final Integer month, @PathParam("date") final Integer date, @PathParam("title") final String title) { return addMovieOfTheDay(month, date, title); }

In this case, the code compiles and the WAR deploys without apparent incident, but things go less smoothly when a client attempts to use POST to add/change a movie. The package-level method is not available and this is made evident in the RESTClient GUI as shown in the next screen snapshot.

As the above image demonstrates, an HTTP response code of 405 ("Method Not Allowed") is returned when there is no public method associated with the specified HTTP method. As the specification suggests, Jersey does warn of this condition with the following WARNING-level logged statement:

[#|2010-02-14T21:13:31.226-0700|WARNING|glassfishv3.0|com.sun.jersey.server.impl.application.WebApplicationImpl|_ThreadID=28;_ThreadName=Thread-1;|A sub-resource method, java.lang.String rmoug.td2010.rest.MovieOfTheDay.addMovieOfTheDayPost(java.lang.Integer,java.lang.Integer,java.lang.String), MUST be public scoped otherwise the method is ignored|#]

Conclusion

The messages Jersey logs related to problems associated with resource method designations are relatively clear and straightforward. That is good news because it means that when these errors are unintentionally caused, they are more likely to be readily identified and addressed.

The "uniform interface" concept is obviously important to REST and is a driving force behind the design of HTTP methods. JAX-RS provides sophisticated annotations-based support for providing uniform interfaces to clients from regular Java classes. The main intent of this post is to briefly cover how JAX-RS makes it easy to write Java classes that provide this uniform interface.

Nearly all REST-based applications "happen" to be HTTP based as well, but it is often emphasized that HTTP is not absolutely required to implement a REST-based application. Still, HTTP and REST often do go together, so it is not surprising that the JAX-RS-provided annotations @GET, @DELETE, @POST, and @PUT closely mirror in name the respective HTTP methods GET, DELETE, POST, and PUT. Note that JAX-RS also provides @OPTIONS and @HEAD annotations.

In my blog post JAX-RS with Jersey: An Introduction, I demonstrated use of the @GET annotation in conjunction with fellow JAX-RS annotations @Path and @PathParam. Only data retrieval (hence the "GET") was shown in that post. In this post, I expand upon (and change) the MovieOfTheDay class I used in that post to support creation/insertion of new data, updating of existing data, and deletion/removal of data.

As I stated in the previous post, I use an (slightly modified for this post) internal static map to emulate what would normally be a datastore such as a database. This piece of code is shown next.

final Map<Integer, String> aprMovies = new ConcurrentHashMap<Integer, String>(); aprMovies.put(25, "Raiders of the Lost Ark"); aprMovies.put(26, "Indiana Jones and the Temple of Doom"); aprMovies.put(27, "Indiana Jones and the Last Crusade"); aprMovies.put(28, "Indiana Jones and the Kingdom of the Crystal Skull"); MOVIE_OF_THE_DAY.put(Integer.valueOf(Calendar.APRIL), aprMovies);

The above code snippet sets up an underlying data store with the movies of the day. The MovieOfTheDay class represents a resource and its class declaration is shown in the next code listing. The @Path annotation is significant because it tells the JAX-RS provider that this class represents a resource.

MovieOfTheDay.java Fragment: Class Declaration with @Path

/** * Simple class that provides a movie for the provided month and day of that * month. */@Path("/movies")public class MovieOfTheDay{// . . .}

By specifying "/movies" as an argument to the @Path annotation, I am instructing the JAX-RS provider that this class represents a resource accessible in part by the URI portion "/movies".

With the @Path annotation provided on the class level, methods can be defined for the JAX-RS provider to tie to the uniform interface. The next code snippet demonstrates this for GET. There are actually two methods annotated with the @GET annotation. The first method, getMovieUsage(), simply returns a String specifying how the other GET method can be used. The other GET method is called getMovieOfTheDay(Integer,Integer) and it provides the movie of the day for the day provided as the two integer parameters (month and date in that month).

MovieOfTheDay.java Fragment: Two GET Methods

/** * This method provides a "usage" string related to retrieving movie of the * day information. * * @return String describing how to access movie of the day information. */ @GET @Path("/") @Produces("text/plain") public String getMovieUsage() { return "To see the movie of the day, provide URL with month and day: " + "\thttp://localhost:8080/rest/resources/movies/<<month>>/<<day>>"; }

/** * Obtain the movie of the day as indicated by the provided month and date. * * @param month Month for which movie of the day is desired. * @param date Date for which movie of the day is desired. * @return Title of the movie of the day for provided month and date. */ @GET @Path("/{month}/{date}") @Consumes("text/plain") @Produces("text/html") public String getMovieOfTheDay( @PathParam("month") final Integer month, @PathParam("date") final Integer date) { final Map<Integer, String> moviesOfTheMonth = MOVIE_OF_THE_DAY.get(month-1); final String movieOfTheDay = moviesOfTheMonth != null ? moviesOfTheMonth.get(date) : "Fletch Lives!"; return movieOfTheDay != null ? generateSelectedMovieHtml(movieOfTheDay, month, date) : generateSelectedMovieHtml("Fletch", month, date); }

The @Path annotation was used on this entire class and then was again used in the previous code sample to annotate the two GET methods to add more to the overall path. In the first case, the usage method's path is defined simply as "/", meaning that it remains the same path as to the overall class. The second GET method, however, has an @Path annotation with "/month/date" specified as an argument. This means that the JAX-RS provider should match this method with a URI containing the class-level @Path's URI portion concatenated with this method's @Path's URI portion: movies/{month}/{date}. The curly braces indicate that the value is a placeholder. In this case, the {month} and {date} are placeholders for Integers (the types of the two parameters to the method that are annotated with @PathParam annotations that tie them directly to the placeholder names).

The code for the other methods on this HTTP-based uniform interface is similar @DELETE annotation makes it obvious which method is associated with deletion of a resource. In my case, I'm using the method associated with the @PUT annotation for both insert/create (new) behavior and for update/modify (change to existing) behavior. There has been controversy in the REST community about how closely (if at all) HTTP methods in HTTP-based REST applications should apply to the CRUD concept (Create/Read/Update/Delete) with the particularly contentious point being the relationship of HTTP methods PUT/POST to the CRUD operations of UPDATE/CREATE.

Returning to the subject of JAX-RS and the uniform interface, here is a code snippet with the appropriate JAX-RS annotations for deleting and inserting/updating movies of the day.

MovieOfTheDay.java Fragment: DELETE and PUT Methods

/** * Remove the movie of the day for the day whose month and date are provided * as parameters. * * @param month Month of date for which movie is to be removed. * @param date Date for which movie is to be removed. * @return String representing movie of the day information was deleted. */ @DELETE @Path("/{month}/{date}") @Consumes("text/plain") @Produces("text/html") public String deleteMovieOfTheDay( @PathParam("month") final Integer month, @PathParam("date") final Integer date) { final Map<Integer, String> moviesOfTheMonth = MOVIE_OF_THE_DAY.get(month-1); String movieRemoved = ""; if (moviesOfTheMonth != null) { movieRemoved = moviesOfTheMonth.remove(date); } return generateDeletedMovieHtml(movieRemoved); }

/** * Add a new entry or update an existing entry representing a movie of the day. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ @PUT @Path("/{month}/{date}/{title}") @Consumes("text/plain") @Produces("text/html") public String addMovieOfTheDay( @PathParam("month") final Integer month, @PathParam("date") final Integer date, @PathParam("title") final String title) { final Map<Integer, String> moviesOfTheMonth = MOVIE_OF_THE_DAY.get(month-1); if (moviesOfTheMonth != null) { moviesOfTheMonth.put(date, title); } return generateAddedMovieHtml(title); }

The code shown to this point in this post illustrates use of JAX-RS annotations @GET, @DELETE, and @PUT to expose methods in the Java class as methods roughly equivalent respectively to reading/retrieving, deleting, and adding/updating. Before moving onto screen snapshots showing these simple examples in action, I provide the entire class (including the example snippets above and the helper utility methods called from the examples above) here in one listing for convenience.

final Map<Integer, String> aprMovies = new ConcurrentHashMap<Integer, String>(); aprMovies.put(25, "Raiders of the Lost Ark"); aprMovies.put(26, "Indiana Jones and the Temple of Doom"); aprMovies.put(27, "Indiana Jones and the Last Crusade"); aprMovies.put(28, "Indiana Jones and the Kingdom of the Crystal Skull"); MOVIE_OF_THE_DAY.put(Integer.valueOf(Calendar.APRIL), aprMovies);

/** * This method provides a "usage" string related to retrieving movie of the * day information. * * @return String describing how to access movie of the day information. */ @GET @Path("/") @Produces("text/plain") public String getMovieUsage() { return "To see the movie of the day, provide URL with month and day: " + "\thttp://localhost:8080/rest/resources/movies/<<month>>/<<day>>"; }

/** * Obtain the movie of the day as indicated by the provided month and date. * * @param month Month for which movie of the day is desired. * @param date Date for which movie of the day is desired. * @return Title of the movie of the day for provided month and date. */ @GET @Path("/{month}/{date}") @Consumes("text/plain") @Produces("text/html") public String getMovieOfTheDay( @PathParam("month") final Integer month, @PathParam("date") final Integer date) { final Map<Integer, String> moviesOfTheMonth = MOVIE_OF_THE_DAY.get(month-1); final String movieOfTheDay = moviesOfTheMonth != null ? moviesOfTheMonth.get(date) : "Fletch Lives!"; return movieOfTheDay != null ? generateSelectedMovieHtml(movieOfTheDay, month, date) : generateSelectedMovieHtml("Fletch", month, date); }

/** * Remove the movie of the day for the day whose month and date are provided * as parameters. * * @param month Month of date for which movie is to be removed. * @param date Date for which movie is to be removed. * @return String representing movie of the day information was deleted. */ @DELETE @Path("/{month}/{date}") @Consumes("text/plain") @Produces("text/html") public String deleteMovieOfTheDay( @PathParam("month") final Integer month, @PathParam("date") final Integer date) { final Map<Integer, String> moviesOfTheMonth = MOVIE_OF_THE_DAY.get(month-1); String movieRemoved = ""; if (moviesOfTheMonth != null) { movieRemoved = moviesOfTheMonth.remove(date); } return generateDeletedMovieHtml(movieRemoved); }

/** * Add a new entry or update an existing entry representing a movie of the day. * * @param month Month for the movie of the day. * @param date Day of the month for the movie of the day. * @param title Title of the movie of the day. * @return HTML excerpt for movie of the day entry status. */ @PUT @Path("/{month}/{date}/{title}") @Consumes("text/plain") @Produces("text/html") public String addMovieOfTheDay( @PathParam("month") final Integer month, @PathParam("date") final Integer date, @PathParam("title") final String title) { final Map<Integer, String> moviesOfTheMonth = MOVIE_OF_THE_DAY.get(month-1); if (moviesOfTheMonth != null) { moviesOfTheMonth.put(date, title); } return generateAddedMovieHtml(title); }

/** * Generate snippet of HTML related to selection of a movie. * * @param movieTitle Title of movie selected. * @param movieMonth Month in which this was movie of the day. * @param movieDay Day on which this was movie of the day. * @return HTML describing selected movie of the day. */ private String generateSelectedMovieHtml( final String movieTitle, final int movieMonth, final int movieDay) { final String movieOfTheDayBody = "<p>The movie of the day for " + movieMonth + "/" + movieDay + " is '" + movieTitle + "'.</p>"; return generateHtmlTemplate("Movie of the Day", movieOfTheDayBody); }

The first screen snapshot demonstrates running RESTClient with the method exposed via HTTP GET that provides usage information.

The next screen snapshot demonstrates the other GET-exposed method. This method provides an actual movie of the day.

In the previous two screen snapshots, the GET HTTP method was used as shown by the checked GET bullet. The next screen snapshot shows a movie of the day being added. In this case, the PUT radio bullet is checked on REST Client. The URL changes here to include a movie title.

I needed to specify the space in the movie title ("Mission Impossible") with %20 in this case. In a realistic, programmatic REST client, I'd make sure either the client framework or my own code ensured that spaces were translated for users rather than relying forcing the client to handle these %20 representations.

To call the deletion method, I simply need to change the HTTP method selected in the RESTClient GUI to "DELETE" and return to the URI with month and date integers. This is shown in the next screen snapshot.

If I run RESTClient GET with the same URI at this point, I'll get a message back saying that the movie of the day is Fletch because that is the default I use for any dates on which no movie of the day is assigned (and I had just deleted the movie assigned to that day).

JAX-RS supports REST in many more ways besides its making it easy to tie custom methods to specific HTTP methods, but I wanted to focus on how JAX-RS enables the uniform interface concept via the standard HTTP methods in this post. In future posts, I plan to consider how JAX-RS further helps with an HTTP-based REST application by handling other items such as content types and responses.