ptg Event Handling in Java When performance is important, Java can be used in place of Groovy for event handling. We dis- cuss Java in more detail in later chapters, but the pattern is similar to Groovy and PHP. You need to create a class with a null constructor to handle the requests, with naming corresponding to the resource. So, we could create java/bookmarks.java like Listing 3.9. Listing 3.9 Java Event Handler public class Bookmarks { public void onGET() { } public void onPOST() { } public void onPUT() { } public void onDELETE() { } } Creating a Client So far, we’ve covered the basics of creating a simple RESTful service. What we need now is a client that end users can use. Earlier we used Poster, which is quite useful for unit testing our ser- vices. However, for some odd reason, end users are not usually very happy formulating JSON messages in Poster. If we were to release our application with Poster as the front-end client, the Human-Computer Interaction people would probably faint. We can create our user interface using three primary technologies: Groovy Templates, PHP, and Dojo. Earlier in this chapter, we learned that, as part of the application directory structure, there are a few client-oriented directories. Of particular interest at this point is the public directory. Groovy Templates Using Groovy templates, we can create a client that accesses the RESTful service on the server side. Groovy templates are very much like JSPs. They embed Groovy code inside HTML. Groovy script elements are surrounded by “<%” and “%>” and expression elements by “<%=” and “%>”. In the public directory, create a file named groovy.gt. We’ll start by simply dis- playing the contents of our bookmark database. To do this, we start by calling the GET method on a connection to our service, as shown in Listing 3.10. 52 Chapter 3 Your First Handler and Beyond Download from www.wowebook.com ptg Creating a Client 53 Listing 3.10 Calling the GET Method Connection.Response resp = Connection.doGET("http://localhost:8080/resources/bookmarks") This connection retrieves a response object. The body of the response object is a String rep- resenting a JSON object, the same JSON object we saw earlier in this chapter. After we have turned the JSON object into a map suitable for iteration, we iterate over the map and output the contents (see Listing 3.11). Listing 3.11 Decode Results and Display resultData = Json.decode(resp.getResponseBodyAsString()) for(bookmark in resultData) { %><tr> <td><%=bookmark.url%></td> <td><%=bookmark.name%></td> <td><%=bookmark.category%></td> <td><a href="?delete=<%=bookmark.id%>">delete</a></td> </tr><% } We could have made the bookmarks into anchors, which would make this little application more useful. It is easier to demonstrate in type by making a simple table. You might have noticed that we’ve added a column in our data to send back a parameter to our Groovy template so that we can handle deletes of bookmarks. When the user clicks a bookmark’s delete link, the page is reloaded, with an extra parameter added. To determine if we’re going to be deleting a bookmark from our database, we check the request and see if the delete parameter is non-null. If the parameter is non-null, we perform the delete and redirect back to our regular view, as shown in Listing 3.12. Listing 3.12 Delete and Redirect if(request.params.delete[]){ Connection.Response resp = Connection.doDELETE( "http://localhost:8080/resources/bookmarks/${request.params.delete[]}") //set the location and the redirect status request.headers.out.Location = "http://localhost:8080/groovy.gt" request.status = 301; } Download from www.wowebook.com ptg To perform the delete, we use the DELETE method and pass the appropriate RESTful URL. Notice that the request.params.delete[] parameter contains the ID of the entry to be deleted so that our URL ends up pointing to an individual resource. Similarly, for the CREATE operation, we create a form element with parameters to pass back to our Groovy template (see Listing 3.13). Listing 3.13 Create Form <form action="groovy.gt" method="get"> <table> <tr> <th>URL*</th> <th>Name*</th> <th>Category</th> </tr> <tr> <td><input type="text" name="url"/></td> <td><input type="text" name="name"/></td> <td><input type="text" name="category"/></td> </tr> </table> <input type="submit" value="Save" /><br />(* = required field) </form> As you can see, this is a very simple form that passes the parameters back to our Groovy template. In the template, we check for the required parameters and POST the new bookmark to the RESTful service (see Listing 3.14). Listing 3.14 Create the New Bookmark if(request.params.url[] && request.params.name[]){ data = [url:request.params.url[], name:request.params.name[], category:request.params.category[]] Connection.Response resp = Connection.doPOST( "http://localhost:8080/resources/bookmarks", Json.encode(data)) //Examine the response code here to see if there are errors. This //should also address the asynchronous nature of the POST, so that //the redirects do not race with the actual create. if("200".equals(resp.getResponseStatus()){ request.headers.out.Location = "http://localhost:8080/groovy.gt" request.status = 301; 54 Chapter 3 Your First Handler and Beyond Download from www.wowebook.com ptg Figure 3.4 Groovy template client Creating a Client 55 }else{ //do error handling } } We collect the data into a map and POST the JSON-encoded map to our RESTful service. Then we redirect the client back to the original page to view the results. Of course, we should do more error checking to make sure all these operations worked well. This code has a bit of a prob- lem in that the redirect sometimes is faster than the database update, so you may need to refresh the page after a delete or a create. Point your browser to http://localhost:8080/groovy.gt. Here’s what it ends up looking like (see Figure 3.4). As you can see, we’re displaying the contents of our initial load. We can add CNN to our bookmark list by typing in the fields. After we press the Save button, we end up seeing what is shown in Figure 3.5. Again, you may have to press Refresh because the database commit is sometimes a touch slower than the redirect. It all depends on your system. You can avoid this refresh if you ensure that the POST/DELETE operation is completed prior to redirecting. We can delete a bookmark simply by pressing Delete (see Figure 3.6). As you can see, we’ve deleted the Groovy bookmark. This is how you can make a simple client to your bookmark RESTful service using Groovy templates. Let’s go back and look at the same thing, but in PHP. Download from www.wowebook.com ptg 56 Chapter 3 Your First Handler and Beyond Figure 3.6 Groovy template client after Delete Figure 3.5 Groovy template client after Add PHP To start using PHP, we have to enable the PHP feature by adding a dependency to the ivy file. You can do that in the same way you did earlier in this chapter. When you do, your ivy.xml will have an additional line: <dependency name="zero.php" org="zero" rev="[1.0.0.0, 3.0.0.0["/> After this feature is enabled, you need to create a new PHP file in the public directory for our PHP code. Let’s call it php.php. Download from www.wowebook.com ptg Creating a Client 57 As with Groovy templates, we start by simply displaying the contents of our bookmark database. To do this, we start by calling the GET method on a connection to our service (see Listing 3.15). Listing 3.15 GET Method in PHP $conn = curl_init("http://localhost:8080/resources/bookmarks"); curl_setopt($conn, CURLOPT_CUSTOMREQUEST, "GET"); curl_setopt($conn, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($conn); curl_close($conn); This connection retrieves a response, which is a string representing a JSON object, the same JSON object that we saw earlier in this chapter. When we have turned the JSON object into an array suitable for iteration, we process each entry and output the contents (see Listing 3.16). Listing 3.16 PHP Decode Result and Display $resultData = json_decode($response); foreach($resultData as $bookmark){ echo "<tr> <td>${bookmark['url']}</td> <td>${bookmark['name']}</td> <td>${bookmark['category']}</td> <td><a href=\"?delete=${bookmark['id']}\">delete</a></td> </tr>"; } As seen previously, we’ve added a column in our data to send back a parameter to our PHP script so that we can handle deletes of bookmarks. To determine if we’re going to be deleting a bookmark from our database, we check the request and see if the delete parameter is non-null. If the parameter is non-null, we perform the delete and redirect back to our regular view (see Listing 3.17). Listing 3.17 PHP Delete and Redirect if(zget('/request/params/delete')){ if(zget('/request/params/delete')){ $conn = curl_init("http://localhost:8080/resources/bookmarks/". zget('/request/params/delete')); curl_setopt($conn, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_setopt($conn, CURLOPT_RETURNTRANSFER, true); curl_exec($conn); Download from www.wowebook.com ptg 58 Chapter 3 Your First Handler and Beyond curl_close($conn); zput('/request/headers/out/Location', 'http://localhost:8080/php.php'); zput('/request/status',301); } To perform the delete, we use the DELETE method and pass the appropriate RESTful URL. Notice that the /request/params/delete parameter contains the ID of the entry to be deleted so that our URL ends up pointing to an individual resource. Similarly, for the CREATE operation, we create a form element with parameters to pass back to our PHP script (see Listing 3.18). Listing 3.18 PHP Create Form <form action="php.php" method="get"> <table> <tr> <th>URL*</th> <th>Name*</th> <th>Category</th> </tr> <tr> <td><input type="text" name="url"/></td> <td><input type="text" name="name"/></td> <td><input type="text" name="category"/></td> </tr> </table> <input type="submit" value="Save" /><br />(* = required field) </form> Again, there is a simple form that passes the parameters back to the PHP script. In the script, we check for the required parameters and POST the new bookmark to the RESTful service (see Listing 3.19). Listing 3.19 PHP Create New Bookmark if(zget('/request/params/url') && zget('/request/params/name')){ $data = array("url"=>zget('/request/params/url'), "name"=>zget('/request/params/name'), "category"=>zget('/request/params/category')); $conn = curl_init("http://localhost:8080/resources/bookmarks"); Download from www.wowebook.com ptg Creating a Client 59 curl_setopt($conn, CURLOPT_RETURNTRANSFER, true); curl_setopt($conn, CURLOPT_POST, 1); curl_setopt($conn, CURLOPT_POSTFIELDS, json_encode($data)); $header = array("Content-type: application/json; charset=iso-8859- 1"); curl_setopt($conn, CURLOPT_HTTPHEADER, $header); curl_exec($conn); curl_close($conn); zput('/request/headers/out/Location','http://localhost:8080/php.php') ; zput('/request/status',301); } We collect the data into an array and POST the JSON-encoded array to our RESTful ser- vice. Then we redirect the client back to the original page to view the results. As mentioned pre- viously, the redirect is sometimes faster than the database update, so you may need to refresh the page after a delete or a create. Point your browser to http://localhost:8080/php.php. It ends up looking exactly like what we saw with the Groovy template. Likewise, the delete and create oper- ations work the same. Dojo WebSphere sMash provides a couple of nifty Dojo-based widgets that help us get a Dojo client up and running very quickly. We use one of those named the DataGrid to show us a table of our bookmarks. To start using Dojo, we have to enable the Dojo feature by adding a dependency to the ivy file. You can do that the same way you did earlier in this chapter. Once you do, your ivy.xml will have an additional line, as follows: <dependency name="zero.dojo" org="zero" rev="[1.0.0.0,1.1.0.0["/> After this feature is enabled, you need to create an HTML page in the public directory named dojo.html. In the newly created HTML file, there are two primary lines of HTML (see Listing 3.20). The first line defines a DataStore, which we use to RESTfully retrieve data. Listing 3.20 Defining a DataStore <span dojoType="zero.resource.DataStore" jsId="bookmarkdata" contextRoot="./resources" resourceCollection="bookmarks"></span> As you can see, we point the DataStore to our RESTful bookmarks service using the resourceCollection attribute, and the DataStore itself takes care of all the details around Download from www.wowebook.com ptg 60 Chapter 3 Your First Handler and Beyond Figure 3.7 Dojo client making the CRUD requests. The second line, as shown in Listing 3.21, uses the DataStore to dis- play our data in a table that has CRUD operations. Listing 3.21 Defining a DataGrid <div dojoType="zero.grid.DataGrid" id="thegrid" visibleFields="url,name,category" store="bookmarkdata" style="width: 500px; height: 300px;"></div> In this line, the DataGrid uses the store attribute to retrieve data to display. We’ve tailored this DataGrid to show only the data columns we’re interested in using the visibleField attrib- ute. Point your browser to http://localhost:8080/dojo.html to take a look at your newly created Dojo client (see Figure 3.7). As you can see, the DataGrid provides all the standard CRUD operations and a nice table format for our data. Download from www.wowebook.com ptg Conclusion 61 Conclusion In this chapter, we’ve taken the first steps toward building real applications with WebSphere sMash. We learned about the application directory layout and how it is structured to make your applications easy to develop and maintain. We learned about how straightforward it is to create RESTful services using ZRM, Groovy, Java, and PHP. Finally, we learned how to create some clients for our REST services. Throughout this book, we’ll revisit and examine, in more depth, many of the parts of what we’ve skimmed over here. Download from www.wowebook.com . charset=iso -8 8 5 9- 1"); curl_setopt($conn, CURLOPT_HTTPHEADER, $header); curl_exec($conn); curl_close($conn); zput('/request/headers/out/Location','http://localhost :80 80/php.php') ; zput('/request/status',301);. Beyond curl_close($conn); zput('/request/headers/out/Location', 'http://localhost :80 80/php.php'); zput('/request/status',301); } To perform the delete, we use the DELETE method and pass. to http://localhost :80 80/php.php. It ends up looking exactly like what we saw with the Groovy template. Likewise, the delete and create oper- ations work the same. Dojo WebSphere sMash provides