• No results found

Implementing Dynamic HTTP Validation

In document Ajax Patterns And Best Practices pdf (Page 127-133)

Implementing dynamic HTTP validation is not that difficult if static HTTP validation has been implemented, because static HTTP validation provides a base for dynamic HTTP validation. When implementing dynamic HTTP validation, the LibrarianSaveToStorage is kept identical as is the use of the Decorator pattern. What changes is the implementation of the Builder pattern: the class LibrarianSaveToFile is replaced with LibrarinHTTPValidation, and the class

Book has some additional properties.

What is different in this instance of using the Decorator pattern is that the

LibrarianHTTPValidation class is used to figure out whether LibrarianSaveToStorage has to be called. Additionally, LibrarianSaveToStorage is a bit misnamed because when using dynamic HTTP validation LibrarianSaveToStorage is used for both retrieval and saving of data.

Modifying the Decorator Pattern Implementation

In the static HTTP server validation, the Decorator pattern was used. For the dynamic HTTP server validation, the implementation LibrarianHTTPValidation is used to manage the hash codes of the individual book instances:

public class LibrarianHTTPValidation implements Librarian { private Librarian _next;

private String _etag;

public LibrarianHTTPValidation(String etag, Librarian next) throws InstantiationException {

if( _next == null) {

throw new InstantiationException("Next element cannot be null"); }

_next = next; _etag = etag; }

public Book checkOutBook(String isbn) throws Exception { if(isSameState( _etag, isbn)) {

Book book = new Book();

book.assignHashCode(Integer.parseInt( _etag)); book.setISBN( isbn);

return book; }

else {

return _next.checkOutBook( isbn); }

}

public void checkInBook(Book book) throws Exception { saveHashCode(book);

_next.checkInBook(book); }

}

In the instantiation of the LibrarianHTTPValidation, the constructor has two parameters. The first parameter identifies the ETag, and the second parameter is the next Librarian instance,

which is LibrarianSaveToStorage. The method checkOutBook has an incomplete method

isSameState that is used to test whether the input etag parameter and the to-be-retrieved book instance associated with the isbn number are identical. The method isSameState is incomplete because the way that the cross-referencing of the client-supplied ETag identifier and the current hash code value is done depends on how the old hash code value is stored. It’s an implementation detail that is beyond the scope of this book.

If the method isSameState indicates that the state has not changed, Book is instantiated and the hash code is assigned to the input ETag value. The instantiated value is returned. If the method isSameState indicates that the state has changed, then the checkOutBook is delegated to the next Librarian instance (_next.checkOutBook).

In the implementation of checkInBook, a call is made to an incomplete method implemen- tation, saveHashCode. The incomplete method saveHashCode saves the current hash code value and its associated unique ISBN identifier. After the values have been saved, the next Librarian

instance is called to persist the value to the underlying storage mechanism.

To instantiate the new Decorator pattern structure, the Builder pattern has to be modified and would appear similar to the following:

public class LibrarianBuilder {

public static Librarian create(String etag) throws InstantiationException {

if(etag != null && etag.length() > 0) {

return new LibrarianHTTPValidation(etag, new LibrarianSaveToStorage()); }

else {

return new LibrarianSaveToStorage(); }

} }

The modified method create requires a parameter that is passed in etag from the client. If the etag value is null, the class LibrarianSaveToStorage is instantiated without any parameters, indicating that either the content sent to the client is called for the first time or HTTP validation is not used. If there is an etag value and its length is greater than zero, a validation using

LibrarianHTTPValidation is performed. The class LibrarianSaveToStorage is still instantiated, but the instance is a parameter to the constructor of LibrarianHTTPValidation, and both instances are chained together.

Putting It All Together

In dynamic HTTP validation, it is necessary to implement multiple HTTP verbs. In the example, the verbs GET and PUT are implemented. Note that the same code used for PUT could also be used for

POST to make the servlet HTML form-friendly.

The implementation of the hash code calculation has been shown in the “Architecture” section and will not be reiterated because doing so would provide no value. The hash code would be calculated on the state of the object that is saved to a file or a relational database.

public class ValidationLibrarianServlet extends HttpServlet { protected void doGet(HttpServletRequest req, ➥

HttpServletResponse resp)

throws javax.servlet.ServletException, ➥

java.io.IOException {

String isbn = getISBNFromURL(req.getRequestURI()); try {

String etagvalue = req.getHeader("If-Match"); Librarian librarian = ➥

LibrarianBuilder.create(etagvalue); Book book = librarian.checkOutBook(isbn); if(etagvalue != null && book.hashCode() == ➥

Integer.parseInt(etagvalue)) { resp.setStatus(304, "Not modified"); return; } resp.setHeader("ETag", Integer.toString( ➥ book.hashCode())); generateGetContent(resp, book); }

catch (Exception ex) {

throw new ServletException( ➥

"LibrarianServlet generated error", ex); }

}

protected void doPut(HttpServletRequest req, ➥

HttpServletResponse resp) throws javax.servlet.ServletException, ➥ java.io.IOException { try { Librarian librarian = ➥ LibrarianBuilder.create("empty"); Book book = getDetailsFromRequest(req); librarian.checkInBook(book);

generatePutContent(resp, book); }

catch (Exception ex) {

throw new ServletException( ➥

"LibrarianServlet generated error", ex); }

} }

In the example code, a number of incomplete methods are beyond the scope of this pattern because they are implementation details specific to a code base. Starting with the method

goGet, which is called when the HTTP GET method is called, the ISBN is retrieved. At the begin- ning of this chapter, the URL /ajax/books/[ISBN].xml was used to uniquely identify a book. The method getISBNFromURL will parse the URL and retrieve the desired ISBN. Having multiple

URLs associated with a single servlet is not difficult. Specifically for Java, the administrator would change the web.xml file to associate the base URL /ajax/books with the

ValidationLibrarianServlet.

After having extracted the ISBN number, the ETag identifier is retrieved from the request by using the method req.getHeader( "If-Match"). The retrieved instance is passed as a parameter to the method LibrarianBuilder.create. Depending on the value of the ETag, a decorated

LibrarianSaveToStorage class is created.

The method checkOutBook is called, and an instance will be retrieved that indicates either that an HTTP 304 should be returned, or that a new instance has been instantiated and output should be generated. If output is generated, an ETag identifier is generated and added to the HTTP output.

The method doPut is called whenever an HTTP PUT is called. The implementation is relatively simple in that the decorated Librarian classes are instantiated, and the Book class parameters are retrieved and added to the underlying storage mechanism by using the method checkInBook. Because the Librarian classes are decorated, the hash code value will be automatically identified with the ISBN of the book.

The examples illustrated a relatively simple HTTP GET and PUT. Let’s say that you want to search for a book based on the title. Then the URL /ajax/books/search?author=[name] could be used, and ValidationLibrarianServlet would need to be extended to include the functionality.

Pattern Highlights

Let’s wrap all of this up and consider what the Cache Controller pattern accomplishes. The purpose of the Cache Controller pattern is to provide a temporary cache by complementing the Internet infrastructure. The idea is not to re-create yet another caching infrastructure, because the Internet already does that very well. In the scope of writing web applications, the cache infrastructure to use is HTTP validation. Even though HTTP validation is not typically used for scripts, it can and should be.

The following points are important highlights of the Cache Controller pattern:

• When using a cache, it is preferable to use the HTTP Validation model. The HTTP Expiration model is less useful because expiration says content is good for a certain time frame regardless of what happens to the server.

• When using HTTP validation for writing a cache, only the client actually caches the information. The server is responsible for generating the entity tags and for comparing old with new entity tags. This means that the server has to keep a sense of history with respect to the changing state of the objects.

• There are two ways to implement HTTP validation: letting the HTTP server do the heavy lifting, or creating a server-side processor that does everything.

• When letting the HTTP server do the heavy lifting, the server framework (for example, JSP, Servlet, ASP.NET) is responsible for updating the static content pieces managed by the HTTP server.

• The server framework manages the state completely, and the entity tag is calculated by using the hash code of the state of the objects. The hash code should never be taken based on the HTML content that is sent because that would conflict with the Permuta- tions pattern.

• A predictive cache that preloads data is based on the ability of associating a URL or its response with one or more URLs. If the predictive cache cannot logically associate URLs, a predictive cache cannot be created. Very often the logic used in the predictive cache is directly related to the operations that can be carried out on the data presented to the user. In the case of mapping, this means zooming and panning.

111

■ ■ ■

C H A P T E R 5

In document Ajax Patterns And Best Practices pdf (Page 127-133)