# Storage Service Example

This example demonstrates a simple in-memory web storage service.

The web storage service enables clients to create and delete containers. Containers are used to create, read, update, and delete items of arbitrary content, and to search for items containing certain content. A container can be thought of as a hash map of items. The key of an item is a URI path.

The web storage service ensures that content can be cached (by browsers and proxies) by supporting the HTTP features `Last-Modified` and `ETag`.

## Contents

The example consists of three web resources implemented by the following:

`com.sun.jersey.samples.storageservice.resources.ContainersResource`
  This Java class provides meta-data information on the containers. The resource references the ContainerResource resource using the Path annotation declared on the ContainersResource.getContainerResource method.
`com.sun.jersey.samples.storageservice.resources.ContainerResource`
  This Java class provides read, create and delete of a container. Searching of items is supported using a URI query parameter. The resource dynamically references the ItemResource resource using the getItemResource method that is annotated with Path.
`com.sun.jersey.samples.storageservice.resources.ItemResource`
  This Java class provides read, create, update, and delete of an item. The last modified time and entity tag are supported such that it conditionally returns content only if the browser or proxy has an older version of the content.

The mapping of the URI path space is presented in the following table:

URI path | Resource class | HTTP methods
--- | --- | ---
/containers | ContainersResource | GET
/containers/{container} | ContainerResource | GET, PUT, DELETE
/containers/{container}/{item} | ItemResource | GET, PUT, DELETE

## Running the Example

Run the example as follows:

>     mvn clean compile exec:java

This deploys the web storage service using Grizzly

A WADL description may be accessed at the URL:

> `http://127.0.0.1:9998/storage/application.wadl`

Following steps are using cURL command line tool:

Get the containers:

>     curl http://127.0.0.1:9998/storage/containers

This returns the following XML document:

>     <containers/>

No containers are present.

Create a container:

>     curl -X PUT http://127.0.0.1:9998/storage/containers/quotes

This creates a container called 'quotes'. Getting the containers:

>     curl http://127.0.0.1:9998/storage/containers

returns information about the 'quotes' container:

>     <containers>
>         <container>
>             <name>quotes</name>
>             <uri>http://127.0.0.1:9998/storage/containers/quotes</uri>
>         </container>
>     </containers>

Create some content:

>     curl -X PUT -HContent-type:text/plain --data "Something is rotten in the state of Denmark"  http://127.0.0.1:9998/storage/containers/quotes/1
>     curl -X PUT -HContent-type:text/plain --data "I could be bounded in a nutshell" http://127.0.0.1:9998/storage/containers/quotes/2
>     curl -X PUT -HContent-type:text/plain --data "catch the conscience of the king" http://127.0.0.1:9998/storage/containers/quotes/3
>     curl -X PUT -HContent-type:text/plain --data "Get thee to a nunnery" http://127.0.0.1:9998/storage/containers/quotes/4

The 'quotes' container has four items associated with keys 1, 2, 3, and 4 when GETing the quotes container:

>     curl http://127.0.0.1:9998/storage/containers/quotes

it returns:

>     <container>
>         <item>
>             <digest>7a54c57975de11bffcda5bc6bd92a0460d17ad03</digest>
>             <lastModified>2007-01-10T15:07:48+01:00</lastModified>
>             <mimeType>text/plain</mimeType>
>             <name>1</name>
>             <uri>http://127.0.0.1:9998/storage/containers/quotes/1</uri>
>         </item>
>         <item>
>             <digest>4769363fcf4d0513619c6a30724daab396a1d196</digest>
>             <lastModified>2007-01-10T15:08:37+01:00</lastModified>
>             <mimeType>text/plain</mimeType>
>             <name>2</name>
>             <uri>http://127.0.0.1:9998/storage/containers/quotes/2</uri>
>         </item>
>         <item>
>             <digest>-71240529c42b5b92e3086e624618d19164658616</digest>
>             <lastModified>2007-01-10T15:11:51+01:00</lastModified>
>             <mimeType>text/plain</mimeType>
>             <name>3</name>
>             <uri>http://127.0.0.1:9998/storage/containers/quotes/3</uri>
>         </item>
>         <item>
>             <digest>493388267529403c84628e12141ffe9a013205a4</digest>
>             <lastModified>2007-01-10T15:12:08+01:00</lastModified>
>             <mimeType>text/plain</mimeType>
>             <name>4</name>
>             <uri>http://127.0.0.1:9998/storage/containers/quotes/4</uri>
>         </item>
>         <name>quotes</name>
>         <uri>http://127.0.0.1:9998/storage/containers/quotes</uri>
>     </container>

Search the container for all items containing the word 'king':

>     curl "http://127.0.0.1:9998/storage/containers/quotes?search=king"

which returns the following XML document containing one item, 3:

>     <container>
>         <item>
>             <digest>-71240529c42b5b92e3086e624618d19164658616</digest>
>             <lastModified>2007-01-10T15:11:51+01:00</lastModified>
>             <mimeType>text/plain</mimeType>
>             <name>3</name>
>             <uri>http://127.0.0.1:9998/storage/containers/quotes/3</uri>
>         </item>
>         <name>quotes</name>
>         <uri>http://127.0.0.1:9998/storage/containers/quotes</uri>
>     </container>

Get the contents of item 3:

>     curl http://127.0.0.1:9998/storage/containers/quotes/3

which returns the following:

>     catch the conscience of the king

Update the contents of item 3:

>     curl -X PUT -HContent-type:text/plain --data "The play's the thing Wherein I'll catch the conscience of the king" http://127.0.0.1:9998/storage/containers/quotes/3

A new search shows that the content has been updated, because the digest is different and the last modified time is more recent:

>     <container>
>         <item>
>             <digest>36d586647af7886aadbc21f238cee7740cf319e9</digest>
>             <lastModified>2007-01-10T15:46:46+01:00</lastModified>
>             <mimeType>text/plain</mimeType>
>             <name>3</name>
>             <uri>http://127.0.0.1:9998/storage/containers/quotes/3</uri>
>         </item>
>         <name>quotes</name>
>         <uri>http://127.0.0.1:9998/storage/containers/quotes</uri>
>     </container>

Get the updated contents of item 3:

>     curl http://127.0.0.1:9998/storage/containers/quotes/3

which returns the following:

>     The play's the thing Wherein I'll catch the conscience of the king

Delete item 3:

>     curl -X DELETE http://127.0.0.1:9998/storage/containers/quotes/3

A new search using 'king' returns no items.

Delete container 'quotes':

>     curl -X DELETE http://127.0.0.1:9998/storage/containers/quotes

The state of the service is now equivalent to that of a newly started storage service.

## Caching of content

The getting of item 3 in the previous example supports the HTTP features `Last-Modified` and `ETag`. The following shows a set of HTTP requests and responses from the Firefox web browser to the web storage service that highlights the caching mechanism. (The headers can be viewed using Firefox's LiveHTTPHeaders plugin, available from the Firefox Tools menu after installation.)

Request, initial query to http://127.0.0.1:9998/storage/containers/quotes/3:

>     GET /storage/containers/quotes/3 HTTP/1.1
>     Host: 127.0.0.1:9998
>     User-Agent: Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.8.1) Gecko/20061024 Firefox/2.0
>     Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
>     Accept-Language: en-us,en;q=0.5
>     Accept-Encoding: gzip,deflate
>     Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
>     Keep-Alive: 300
>     Connection: keep-alive

Response

>     HTTP/1.1 200 OK
>     Last-modified: Wed, 10 Jan 2007 15:12:05 GMT
>     Content-type: text/plain
>     Etag: "-71240529c42b5b92e3086e624618d19164658616"
>     Transfer-encoding: chunked

>     21
>     catch the conscience of the king

>     0

The response includes the `Last-Modified` and `ETag` header fields in the response.

Getting the same item again:

Request

>     GET /storage/containers/quotes/3 HTTP/1.1
>     Host: 127.0.0.1:9998
>     User-Agent: Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.8.1) Gecko/20061024 Firefox/2.0
>     Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
>     Accept-Language: en-us,en;q=0.5
>     Accept-Encoding: gzip,deflate
>     Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
>     Keep-Alive: 300
>     Connection: keep-alive
>     If-Modified-Since: Wed, 10 Jan 2007 15:12:05 GMT
>     If-None-Match: "-71240529c42b5b92e3086e624618d19164658616"

Response

>     HTTP/1.1 304 Not Modified
>     Content-length: 0
>     Etag: "-71240529c42b5b92e3086e624618d19164658616"

The request contains the `Last-Modified` and `ETag` returned in the first response in the `If-Modified-Since` and `If-None-Match` header fields. The response contains no content, and a 304 status code is returned because the item has not been modified (updated).

Getting the updated item:

Request

>     GET /storage/containers/quotes/3 HTTP/1.1
>     Host: 127.0.0.1:9998
>     User-Agent: Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.8.1) Gecko/20061024 Firefox/2.0
>     Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
>     Accept-Language: en-us,en;q=0.5
>     Accept-Encoding: gzip,deflate
>     Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
>     Keep-Alive: 300
>     Connection: keep-alive
>     If-Modified-Since: Wed, 10 Jan 2007 15:12:05 GMT
>     If-None-Match: "-71240529c42b5b92e3086e624618d19164658616"

Response

>     HTTP/1.1 200 OK
>     Last-modified: Wed, 10 Jan 2007 15:14:17 GMT
>     Content-type: text/plain
>     Etag: "36d586647af7886aadbc21f238cee7740cf319e9"
>     Transfer-encoding: chunked

>     43
>     The play's the thing Wherein I'll catch the conscience of the king

>     0

Since item 3 has been updated, the `If-Modified-Since` and `If-None-Match` of the request do not result in a 304 response being returned. The updated content is returned with the latest `Last-Modified` and `ETag` values.