You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by sm...@apache.org on 2012/01/19 01:51:42 UTC

svn commit: r1233143 [30/47] - in /pivot/site/trunk/deploy: ./ 2.0.1/ 2.0.1/docs/ 2.0.1/docs/api/ demos/ tutorials/

Modified: pivot/site/trunk/deploy/tutorials/query-servlet.html
URL: http://svn.apache.org/viewvc/pivot/site/trunk/deploy/tutorials/query-servlet.html?rev=1233143&r1=1233142&r2=1233143&view=diff
==============================================================================
--- pivot/site/trunk/deploy/tutorials/query-servlet.html (original)
+++ pivot/site/trunk/deploy/tutorials/query-servlet.html Thu Jan 19 00:51:39 2012
@@ -1,4 +1,4 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <!--
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -14,669 +14,671 @@ distributed under the License is distrib
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
---><html xmlns="http://www.w3.org/1999/xhtml"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /><title>QueryServlet | Apache Pivot</title><link xmlns="" type="text/css" rel="stylesheet" href="/styles/pivot.css"><script xmlns="http://www.w3.org/1999/xhtml" type="text/javascript">
-                var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
-                document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
-                </script><script type="text/javascript">
-                try {
-                var pageTracker = _gat._getTracker("UA-7977275-3");
-                pageTracker._trackPageview();
-                } catch(err) {}</script></head><body><div xmlns="" id="wrapper"><div id="main"><div id="header"><div class="logo"><a href="/index.html"><img title="Apache Pivot Homepage" alt="Apache Pivot" src="/images/logo.png"></a></div><div class="tagline"><img style="visibility:hidden" alt="Rich Internet Applications in Java" src="/images/tagline.png"></div><ul class="navi"><li><a href="/demos/">Demos</a></li><li><a href="/download.cgi#2.0">Download</a></li><li><a href="/tutorials/">Tutorial</a></li><li><a href="/get-involved.html">Get Involved</a></li><li><a href="/about.html">About</a></li></ul></div><div class="group" id="contentBase"><h1>QueryServlet</h1><ul class="naviLeft"><li><a href="/tutorials/sample-application.html">Sample Application</a></li><li><a href="/tutorials/platform-overview.html">Platform Overview</a></li><li><a href="/tutorials/hello-world.html">Hello, World!</a></li><li><a href="/tutorials/hello-bxml.html">Hello, BXML!</a></li><li><a href="/tutoria
 ls/component-and-container.html">Component &amp; Container</a></li><li><a href="/tutorials/labels-and-image-views.html">Labels &amp; Image Views</a></li><li><a href="/tutorials/svg-images.html">SVG Images</a></li><li><a href="/tutorials/buttons.html">Buttons</a></li><li><a href="/tutorials/push-buttons.html">Push Buttons</a></li><li><a href="/tutorials/toggle-buttons.html">Toggle Buttons</a></li><li><a href="/tutorials/radio-buttons.html">Radio Buttons</a></li><li><a href="/tutorials/checkboxes.html">Checkboxes</a></li><li><a href="/tutorials/link-buttons.html">Link Buttons</a></li><li><a href="/tutorials/lists.html">Lists</a></li><li><a href="/tutorials/list-buttons.html">List Buttons</a></li><li><a href="/tutorials/repeatable-list-buttons.html">Repeatable List Buttons</a></li><li><a href="/tutorials/text.html">Text</a></li><li><a href="/tutorials/suggestion-popups.html">Suggestion Popups</a></li><li><a href="/tutorials/text-areas.html">Text Areas</a></li><li><a href="/tuto
 rials/separators.html">Separators</a></li><li><a href="/tutorials/layout-containers.html">Layout Containers</a></li><li><a href="/tutorials/flow-panes.html">Flow Panes</a></li><li><a href="/tutorials/box-panes.html">Box Panes</a></li><li><a href="/tutorials/grid-panes.html">Grid Panes</a></li><li><a href="/tutorials/table-panes.html">Table Panes</a></li><li><a href="/tutorials/borders.html">Borders</a></li><li><a href="/tutorials/stack-panes.html">Stack Panes</a></li><li><a href="/tutorials/split-panes.html">Split Panes</a></li><li><a href="/tutorials/forms.html">Forms</a></li><li><a href="/tutorials/panels.html">Panels</a></li><li><a href="/tutorials/navigation-containers.html">Navigation Containers</a></li><li><a href="/tutorials/card-panes.html">Card Panes</a></li><li><a href="/tutorials/tab-panes.html">Tab Panes</a></li><li><a href="/tutorials/accordions.html">Accordions</a></li><li><a href="/tutorials/expanders.html">Expanders</a></li><li><a href="/tutorials/rollups.htm
 l">Rollups</a></li><li><a href="/tutorials/viewports.html">Viewports</a></li><li><a href="/tutorials/scroll-panes.html">Scroll Panes</a></li><li><a href="/tutorials/panoramas.html">Panoramas</a></li><li><a href="/tutorials/progress-indicators.html">Progress Indicators</a></li><li><a href="/tutorials/meters.html">Meters</a></li><li><a href="/tutorials/activity-indicators.html">Activity Indicators</a></li><li><a href="/tutorials/bounded-range-components.html">Bounded Range Components</a></li><li><a href="/tutorials/sliders.html">Sliders</a></li><li><a href="/tutorials/scroll-bars.html">Scroll Bars</a></li><li><a href="/tutorials/spinners.html">Spinners</a></li><li><a href="/tutorials/calendars.html">Calendars</a></li><li><a href="/tutorials/menus.html">Menus</a></li><li><a href="/tutorials/context-menus.html">Context Menus</a></li><li><a href="/tutorials/menu-bars.html">Menu Bars</a></li><li><a href="/tutorials/menu-buttons.html">Menu Buttons</a></li><li><a href="/tutorials/co
 lor-choosers.html">Color Choosers</a></li><li><a href="/tutorials/table-views.html">Table Views</a></li><li><a href="/tutorials/table-views.json.html">JSON-based TableView</a></li><li><a href="/tutorials/table-views.custom.html">Custom TableView</a></li><li><a href="/tutorials/tree-views.html">Tree Views</a></li><li><a href="/tutorials/file-browsing.html">File Browsing</a></li><li><a href="/tutorials/windows.html">Windows</a></li><li><a href="/tutorials/clipboard.html">Clipboard</a></li><li><a href="/tutorials/drag-and-drop.html">Drag and Drop</a></li><li><a href="/tutorials/effects.html">Effects</a></li><li><a href="/tutorials/effects.transitions.html">Transitions</a></li><li><a href="/tutorials/data-binding.html">Data Binding</a></li><li><a href="/tutorials/property-binding.html">Property Binding</a></li><li><a href="/tutorials/localization.html">Localization</a></li><li><a href="/tutorials/background-tasks.html">Background Tasks</a></li><li><a href="/tutorials/web-queries
 .html">Web Queries</a></li><li><a href="/tutorials/query-servlet.html">QueryServlet</a></li><li><a href="/tutorials/scripting.html">Scripting</a></li><li><a href="/tutorials/summary.html">Summary</a></li><li><a href="/tutorials/stock-tracker.html">The "Stock Tracker" Application</a></li><li><a href="/tutorials/stock-tracker.ui.html">UI Markup Using BXML</a></li><li><a href="/tutorials/stock-tracker.events.html">Event Handling</a></li><li><a href="/tutorials/stock-tracker.web-queries.html">Web Queries</a></li><li><a href="/tutorials/stock-tracker.data-binding.html">Data Binding</a></li><li><a href="/tutorials/stock-tracker.localization.html">Localization</a></li><li><a href="/tutorials/bxml-primer.html">BXML Primer</a></li></ul><div class="content"><style type="text/css">
-            applet {
-                border: 1px solid #999999;
-            }
-        </style><!--NOTE: Syntax highlighting script is LGPL--><script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"></script><script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js" type="text/javascript"></script><script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js" type="text/javascript"></script><script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js" type="text/javascript"></script><link href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css" rel="stylesheet" type="text/css"><link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" rel="stylesheet" type="text/css"><script type="text/javascript">
-            SyntaxHighlighter.all();
-        </script><div class="section">
-        <p>
-            As discussed in the previous section, Pivot provides a set of classes for interacting
-            with HTTP-based REST services, which Pivot calls "web queries". Pivot also provides an
-            abstract base class named <tt>org.apache.pivot.web.server.QueryServlet</tt> that helps
-            to facilitate implementation of such services.
-        </p>
-
-        <p>
-            The following example shows a Pivot client application that interacts with a REST
-            service for managing expense data. The web service is implemented using
-            <tt>QueryServlet</tt> and is discussed below:
-        </p>
-
-        <p>
-            <em>NOTE</em> This application must be run via a locally-deployed WAR file. It will not
-            work in the online tutorial.
-        </p>
-
-        <script src="http://java.com/js/deployJava.js" type="text/javascript"></script><script type="text/javascript">
-
-            var attributes = {
-                code:"org.apache.pivot.wtk.BrowserApplicationContext$HostApplet",
-                width:"480",
-                height:"280"
-            };
-
-
-
-
-
-            var libraries = [];
-            libraries.push("/lib/pivot-core-2.0.jar");
-                libraries.push("/lib/pivot-web-2.0.jar");
-                libraries.push("/lib/pivot-wtk-2.0.jar");
-                libraries.push("/lib/pivot-wtk-terra-2.0.jar");
-                libraries.push("/lib/pivot-tutorials-2.0.jar");
-
-                    libraries.push("/lib/svgSalamander-tiny.jar");
-
-
-            attributes.archive = libraries.join(",");
-
-
-            var parameters = {
-                codebase_lookup:false,
-                application_class_name:'org.apache.pivot.tutorials.webqueries.Expenses'
-            };
-
-
-            var javaArguments = ["-Dsun.awt.noerasebackground=true",
-                "-Dsun.awt.erasebackgroundonresize=true"];
-
-
-
-            parameters.java_arguments = javaArguments.join(" ");
-
-
-
-
-            deployJava.runApplet(attributes, parameters, "1.6");
-        </script>
-
-        <h2>QueryServlet</h2>
-
-        <p>
-            The <tt>QueryServlet</tt> class extends <tt>javax.servlet.http.HttpServlet</tt> and
-            provides overloaded versions of the base HTTP handler methods that make them easier to
-            work with in a REST-oriented manner:
-        </p>
-
-        <ul>
-            <li><tt>Object doGet(Path path)</tt></li>
-            <li><tt>URL doPost(Path path, Object value)</tt></li>
-            <li><tt>boolean doPut(Path path, Object value)</tt></li>
-            <li><tt>void doDelete(Path path)</tt></li>
-        </ul>
-
-        <p>
-            Each method takes an instance of <tt>QueryServlet.Path</tt> that represents the path to
-            the resource being accessed, relative to the location of the servlet itself.
-            <tt>Path</tt> is a sequence type that allows a caller to access the components of the
-            path via numeric index. For example, if the query servlet is mapped to the
-            "/my_service/*" URL pattern, given the following URL:
-        </p>
-
-        <pre>http://pivot.apache.org/my_service/foo/bar</pre>
-
-        <p>
-            the <tt>path</tt> argument would contain the values "foo" and "bar", accessible via
-            indices 0 and 1, respectively.
-        </p>
-
-        <h4>Serializers</h4>
-
-        <p>
-            Unlike the base <tt>HttpServlet</tt> class, <tt>QueryServlet</tt> operates on arbitrary
-            Java types rather than HTTP request and response objects. This allows developers to
-            focus on the resources managed by the service rather than the lower-level details of
-            the HTTP protocol.
-        </p>
-
-        <p>
-            <tt>QueryServlet</tt> uses a serializer (an implementation of the
-            <tt>org.apache.pivot.serialization.Serializer</tt> interface) to determine how to
-            serialize the data sent to and returned from the servlet. The serializer used for a
-            given HTTP request is determined by the return value of the abstract
-            <tt>createSerializer()</tt> method. This method is called by <tt>QueryServlet</tt>
-            prior to invoking the actual HTTP handler method. The example servlet uses an instance
-            of <tt>org.apache.pivot.json.JSONSerializer</tt>, which supports reading and writing of
-            JSON data. Pivot provides a number of additional serializers supporting XML, CSV, and
-            Java serialization, among others, and service implementations are free to define their
-            own custom serializers as well.
-        </p>
-
-        <h4>Exceptions</h4>
-
-        <p>
-            Each handler method declares that it may throw an instance of
-            <tt>org.apache.pivot.web.QueryException</tt>. This exception encapsulates an HTTP error
-            response. It takes an integer value representing the response code as a constructor
-            argument (the <tt>org.apache.pivot.web.Query.Status</tt> class defines a number of
-            constants for status codes commonly used in REST responses). The web query client API,
-            discussed in the previous section, effectively re-throws these exceptions, allowing the
-            client to handle an error response returned by the server as if the exception was
-            generated locally.
-        </p>
-
-        <h4>Query String Parameters and HTTP Headers</h4>
-
-        <p>
-            Though it is not shown in this example, query servlet implementations can also access
-            the query string arguments and HTTP headers included in the HTTP request, as well as
-            control the headers sent back with the response. Query string parameters are accessible
-            via the <tt>getParameters()</tt> method of <tt>QueryServlet</tt>, and the
-            request/response headers can be accessed via <tt>getRequestHeaders()</tt> and
-            <tt>getResponseHeaders()</tt>, respectively. All three methods return an instance of
-            <tt>org.apache.pivot.web.QueryDictionary</tt>, which allows the caller to manipulate
-            these collections via <tt>get()</tt>, <tt>put()</tt>, and <tt>remove()</tt> methods.
-        </p>
-
-        <h2>ExpenseServlet</h2>
-
-        <p>
-            The following listing contains the full source code for <tt>ExpenseServlet</tt>, which
-            provides the implementation for the REST service used in this example. The
-            implementation of each method is discussed in more detail below:
-        </p>
-
-        <pre class="brush:java">
-
-            package org.apache.pivot.tutorials.webqueries.server;
-
-            import java.io.IOException;
-            import java.io.InputStream;
-            import java.net.MalformedURLException;
-            import java.net.URL;
-
-            import javax.servlet.ServletException;
-
-            import org.apache.pivot.collections.HashMap;
-            import org.apache.pivot.collections.List;
-            import org.apache.pivot.json.JSONSerializer;
-            import org.apache.pivot.serialization.CSVSerializer;
-            import org.apache.pivot.serialization.SerializationException;
-            import org.apache.pivot.serialization.Serializer;
-            import org.apache.pivot.web.Query;
-            import org.apache.pivot.web.QueryException;
-            import org.apache.pivot.web.server.QueryServlet;
-
-            /**
-             * Servlet that implements expense management web service.
-             */
-            public class ExpenseServlet extends QueryServlet {
-                private static final long serialVersionUID = 0;
-
-                private List&amp;lt;Expense&amp;gt; expenses = null;
-                private HashMap&amp;lt;Integer, Expense&amp;gt; expenseMap = new HashMap&amp;lt;Integer, Expense&amp;gt;();
-
-                private static int nextID = 0;
-
-                @Override
-                @SuppressWarnings("unchecked")
-                public void init() throws ServletException {
-                    CSVSerializer csvSerializer = new CSVSerializer();
-                    csvSerializer.getKeys().add("date");
-                    csvSerializer.getKeys().add("type");
-                    csvSerializer.getKeys().add("amount");
-                    csvSerializer.getKeys().add("description");
-                    csvSerializer.setItemClass(Expense.class);
-
-                    // Load the initial expense data
-                    InputStream inputStream = ExpenseServlet.class.getResourceAsStream("expenses.csv");
-
-                    try {
-                        expenses = (List&amp;lt;Expense&amp;gt;)csvSerializer.readObject(inputStream);
-                    } catch (IOException exception) {
-                        throw new ServletException(exception);
-                    } catch (SerializationException exception) {
-                        throw new ServletException(exception);
-                    }
-
-                    // Index the initial expenses
-                    for (Expense expense : expenses) {
-                        int id = nextID++;
-                        expense.setID(id);
-                        expenseMap.put(id, expense);
-                    }
-                }
-
-                @Override
-                protected Object doGet(Path path) throws QueryException {
-                    Object value;
-
-                    if (path.getLength() == 0) {
-                        value = expenses;
-                    } else {
-                        // Get the ID of the expense to retrieve from the path
-                        int id = Integer.parseInt(path.get(0));
-
-                        // Get the expense data from the map
-                        synchronized (this) {
-                            value = expenseMap.get(id);
-                        }
-
-                        if (value == null) {
-                            throw new QueryException(Query.Status.NOT_FOUND);
-                        }
-                    }
-
-                    return value;
-                }
-
-                @Override
-                protected URL doPost(Path path, Object value) throws QueryException {
-                    if (value == null) {
-                        throw new QueryException(Query.Status.BAD_REQUEST);
-                    }
-
-                    Expense expense = (Expense)value;
-
-                    // Add the expense to the list/map
-                    int id;
-                    synchronized (this) {
-                        id = nextID++;
-                        expense.setID(id);
-                        expenses.add(expense);
-                        expenseMap.put(id, expense);
-                    }
-
-                    // Return the location of the newly-created resource
-                    URL location = getLocation();
-                    try {
-                        location = new URL(location, Integer.toString(id));
-                    } catch (MalformedURLException exception) {
-                        throw new QueryException(Query.Status.INTERNAL_SERVER_ERROR);
-                    }
-
-                    return location;
-                }
-
-                @Override
-                protected boolean doPut(Path path, Object value) throws QueryException {
-                    if (path.getLength() == 0
-                        || value == null) {
-                        throw new QueryException(Query.Status.BAD_REQUEST);
-                    }
-
-                    // Get the ID of the expense to retrieve from the path
-                    int id = Integer.parseInt(path.get(0));
-
-                    // Create the new expense and bind the data to it
-                    Expense expense = (Expense)value;
-                    expense.setID(id);
-
-                    // Update the list/map
-                    Expense previousExpense;
-                    synchronized (this) {
-                        previousExpense = expenseMap.put(id, expense);
-                        expenses.remove(previousExpense);
-                        expenses.add(expense);
-                    }
-
-                    return (previousExpense == null);
-                }
-
-                @Override
-                protected void doDelete(Path path) throws QueryException {
-                    if (path.getLength() == 0) {
-                        throw new QueryException(Query.Status.BAD_REQUEST);
-                    }
-
-                    // Get the ID of the expense to retrieve from the path
-                    int id = Integer.parseInt(path.get(0));
-
-                    // Update the list/map
-                    Expense expense;
-                    synchronized (this) {
-                        expense = expenseMap.remove(id);
-                        expenses.remove(expense);
-                    }
-
-                    if (expense == null) {
-                        throw new QueryException(Query.Status.NOT_FOUND);
-                    }
-                }
-
-                @Override
-                protected Serializer&amp;lt;?&amp;gt; createSerializer(Path path) throws QueryException {
-                    return new JSONSerializer(Expense.class);
-                }
-            }
-
-        </pre>
-
-        <h3>init()</h3>
-
-        <p>
-            The <tt>init()</tt> method, which is defined by <tt>QueryServlet</tt>'s base class
-            <tt>HttpServlet</tt>, is called when a servlet is first created by a servlet container.
-            <tt>ExpenseServlet</tt>'s implementation of <tt>init()</tt> is as follows:
-        </p>
-
-        <pre class="brush:java">
-
-            public void init() throws ServletException {
-                CSVSerializer csvSerializer = new CSVSerializer();
-                csvSerializer.getKeys().add("date");
-                csvSerializer.getKeys().add("type");
-                csvSerializer.getKeys().add("amount");
-                csvSerializer.getKeys().add("description");
-                csvSerializer.setItemClass(Expense.class);
-
-                // Load the initial expense data
-                InputStream inputStream = ExpenseServlet.class.getResourceAsStream("expenses.csv");
-
-                try {
-                    expenses = (List&amp;lt;Expense&amp;gt;)csvSerializer.readObject(inputStream);
-                } catch (IOException exception) {
-                    throw new ServletException(exception);
-                } catch (SerializationException exception) {
-                    throw new ServletException(exception);
-                }
-
-                // Index the initial expenses
-                for (Expense expense : expenses) {
-                    int id = nextID++;
-                    expense.setID(id);
-                    expenseMap.put(id, expense);
-                }
-            }
-
-        </pre>
-
-        <p>
-            It loads an initial list of expenses using an instance of <tt>CSVSerializer</tt>. The
-            contents of the CSV file are as follows:
-        </p>
-
-        <pre>
-        2010-03-28, Travel,     1286.90,    Ticket #145-XX-71903-09
-        2010-03-28, Meals,      34.12,      Took client out
-        2010-03-31, Meals,      27.00,
-        2010-04-01, Meals,      12.55,
-        2010-04-02, Meals,      18.86,
-        2010-04-02, Parking,    30.00,      Cambridge Center parking
-        2010-04-03, Meals,      20.72,
-        2010-04-06, Travel,     529.00,     Marriott reservation #DF-9982-BRN
-        </pre>
-
-        <p>
-            Due to the call to <tt>setItemClass()</tt>, the rows in the CSV file are deserialized
-            as instances of <tt>org.apache.pivot.tutorials.webqueries.server.Expense</tt>, a Java
-            Bean class that is defined as follows:
-        </p>
-
-        <pre class="brush:java">
-
-            package org.apache.pivot.tutorials.webqueries.server;
-
-            public class Expense {
-                private Integer id = -1;
-                private String date = null;
-                private String type = null;
-                private Double amount = 0d;
-                private String description = null;
-
-                public Integer getID() {
-                    return id;
-                }
-
-                public Integer getId() {
-                    return getID();
-                }
-
-                public void setID(Integer id) {
-                    this.id = id;
-                }
-
-                public void setId(Integer id) {
-                    setID(id);
-                }
-
-                public String getDate() {
-                    return date;
-                }
-
-                public void setDate(String date) {
-                    this.date = date;
-                }
-
-                public String getType() {
-                    return type;
-                }
-
-                public void setType(String type) {
-                    this.type = type;
-                }
-
-                public Double getAmount() {
-                    return amount;
-                }
-
-                public void setAmount(Double amount) {
-                    this.amount = amount;
-                }
-
-                public final void setAmount(String amount) {
-                    setAmount(Double.parseDouble(amount));
-                }
-
-                public String getDescription() {
-                    return description;
-                }
-
-                public void setDescription(String description) {
-                    this.description = description;
-                }
-            }
-
-        </pre>
-
-        <p>
-            After the list of expenses has been loaded, <tt>init()</tt> iterates over the list,
-            assigns each expense an ID, and adds it to a map. This collection-based approach is
-            sufficient for a tutorial example; a real application would most likely use a
-            relational database to manage the expense data.
-        </p>
-
-        <h3>doGet()</h3>
-
-        <p>
-            <tt>doGet()</tt> is used to handle an HTTP GET request. It returns an object
-            representing the resource at a given path. The <tt>doGet()</tt> method in the example
-            servlet is defined as follows:
-        </p>
-
-        <pre class="brush:java">
-
-            protected Object doGet(Path path) throws QueryException {
-                Object value;
-
-                if (path.getLength() == 0) {
-                    value = expenses;
-                } else {
-                    // Get the ID of the expense to retrieve from the path
-                    int id = Integer.parseInt(path.get(0));
-
-                    // Get the expense data from the map
-                    synchronized (this) {
-                        value = expenseMap.get(id);
-                    }
-
-                    if (value == null) {
-                        throw new QueryException(Query.Status.NOT_FOUND);
-                    }
-                }
-
-                return value;
-            }
-
-        </pre>
-
-        <p>
-            If the request does not contain a path, the method returns the list of all expenses.
-            Otherwise, it attemps to look up and return the requested expense by its ID. If the
-            expense is not found, an HTTP 404 ("Not Found") error is returned to the caller via the
-            thrown <tt>QueryException</tt>; otherwise, the expense is returned along with the
-            default HTTP 200 ("OK") status code. The bean value is converted to JSON format by the
-            <tt>JSONSerializer</tt> instance returned by <tt>createSerializer()</tt>.
-        </p>
-
-        <h3>doPost()</h3>
-
-        <p>
-            <tt>doPost()</tt> is used to handle an HTTP POST request. It is primarily used to
-            create a new resource on the server, but can also be used to execute arbitrary
-            server-side actions.
-        </p>
-
-        <p>
-            When a resource is created, <tt>doPost()</tt> returns a URL representing the location
-            of the new resource. Consistent with the HTTP specification, this value is returned in
-            the "Location" response header along with an HTTP status code of 201 ("Created"). If a
-            POST request does not result in the creation of a resource, <tt>doPost()</tt> can
-            return <tt>null</tt>, which is translated by <tt>QueryServlet</tt> to an HTTP response
-            of 204 ("No Content") and no corresponding "Location" header.
-        </p>
-
-        <p>
-            The <tt>doPost()</tt> method in the example looks like this:
-        </p>
-
-        <pre class="brush:java">
-
-            protected URL doPost(Path path, Object value) throws QueryException {
-                if (value == null) {
-                    throw new QueryException(Query.Status.BAD_REQUEST);
-                }
-
-                Expense expense = (Expense)value;
-
-                // Add the expense to the list/map
-                int id;
-                synchronized (this) {
-                    id = nextID++;
-                    expense.setID(id);
-                    expenses.add(expense);
-                    expenseMap.put(id, expense);
-                }
-
-                // Return the location of the newly-created resource
-                URL location = getLocation();
-                try {
-                    location = new URL(location, Integer.toString(id));
-                } catch (MalformedURLException exception) {
-                    throw new QueryException(Query.Status.INTERNAL_SERVER_ERROR);
-                }
-
-                return location;
-            }
-
-        </pre>
-
-        <p>
-            The first thing the method does is ensure that the request is valid. If the caller has
-            not provided a value in the body of the request, HTTP 400 ("Bad Request") is returned.
-            Otherwise, it assigns the expense an ID and adds it to the list and map.
-        </p>
-
-        <p>
-            Finally, it returns the location of the new expense resource. The location value is
-            generated simply by appending the name of the temp file to the location of the servlet,
-            obtained by a call to <tt>QueryServlet#getLocation()</tt>.
-        </p>
-
-        <h3>doPut()</h3>
-
-        <p>
-            <tt>doPut()</tt> handles an HTTP PUT request. It is often used to update an existing
-            resource, but can also be used to create a new resource. The return value of
-            <tt>doPut()</tt> is a boolean flag indicating whether or not a resource was created.
-            If <tt>true</tt>, HTTP 201 is returned to the caller; otherwise, HTTP 204 is
-            returned.
-        </p>
-
-        <p>
-            <tt>ExpenseServlet</tt>'s implementation of <tt>doPut()</tt> is as follows:
-        </p>
-
-        <pre class="brush:java">
-
-            protected boolean doPut(Path path, Object value) throws QueryException {
-                if (path.getLength() == 0
-                    || value == null) {
-                    throw new QueryException(Query.Status.BAD_REQUEST);
-                }
-
-                // Get the ID of the expense to retrieve from the path
-                int id = Integer.parseInt(path.get(0));
-
-                // Create the new expense and bind the data to it
-                Expense expense = (Expense)value;
-                expense.setID(id);
-
-                // Update the list/map
-                Expense previousExpense;
-                synchronized (this) {
-                    previousExpense = expenseMap.put(id, expense);
-                    expenses.remove(previousExpense);
-                    expenses.add(expense);
-                }
-
-                return (previousExpense == null);
-            }
-
-        </pre>
-
-        <p>
-            Like <tt>doPost()</tt>, it first validates the format of the request. In addition to a
-            body, <tt>doPut()</tt> also requires a path component to identify the resource to be
-            updated. A real expense service might want to verify that the requested resource exists
-            before proceeding; however, the example service simply interprets an unused ID as a
-            request to create a new resource. Consistent with the API, it returns <tt>true</tt> if
-            a resource was created and <tt>false</tt> otherwise.
-        </p>
-
-        <h3>doDelete()</h3>
-
-        <p>
-            <tt>doDelete()</tt> handles an HTTP DELETE request. When successful, it simply
-            deletes the resource specified by the path and returns HTTP 204. The source code for
-            this method is shown below:
-        </p>
-
-        <pre class="brush:java">
-
-            protected void doDelete(Path path) throws QueryException {
-                if (path.getLength() == 0) {
-                    throw new QueryException(Query.Status.BAD_REQUEST);
-                }
-
-                // Get the ID of the expense to retrieve from the path
-                int id = Integer.parseInt(path.get(0));
-
-                // Update the list/map
-                Expense expense;
-                synchronized (this) {
-                    expense = expenseMap.remove(id);
-                    expenses.remove(expense);
-                }
-
-                if (expense == null) {
-                    throw new QueryException(Query.Status.NOT_FOUND);
-                }
-            }
-
-        </pre>
-
-        <p>
-            Like the other methods, the request is first validated; then, if the expense exists,
-            it is deleted. Otherwise, HTTP 404 is returned.
-        </p>
-
-        <h2>The Expenses Application</h2>
-
-        <p>
-            The Expenses client application allows a user to interact with the web service. It is
-            not described in this section, but builds on concepts discussed in earlier sections.
-            The source code is available in the Pivot source distribution under the "tutorials"
-            project.
-        </p>
-    </div><p>Next: <a href="scripting.html">Scripting</a></p></div></div></div><div class="group" id="footer"><div class="footerLogo">Copyright (c) 1999-2011<br>The Apache Software Foundation.</div><div class="footerLinks"><ul class="footerMenuGr"><li><strong>Demos</strong><ul><li><a href="/demos/kitchen-sink.html" target="_new">"Kitchen Sink"</a></li><li><a href="/demos/component-explorer.html" target="_new">Component Explorer</a></li><li><a href="http://ixnay.biz/pivot-jfree-demos/charts_demo.html" target="_new">Charting</a></li><li><a href="/demos/">More Demos</a></li></ul></li><li><strong>Documentation</strong><ul><li><a href="/getting-started.html">Getting Started</a></li><li><a href="/tutorials/">Tutorial</a></li><li><a href="/faq.html">FAQ</a></li><li><a href="/2.0/docs/api/">Javadoc (2.0)</a></li></ul></li><li><strong>Get Involved</strong><ul><li><a href="/svn.html">SVN Repositories</a></li><li><a href="/lists.html">Mailing Lists</a></li><li><a href="http://issues.ap
 ache.org/jira/browse/PIVOT">Bug Database</a></li><li><a href="http://cwiki.apache.org/PIVOT/">Wiki</a></li></ul></li><li><strong>Related</strong><ul><li><a href="http://code.google.com/p/pivot-jfree/">JFreeChart Provider</a></li></ul></li><li><strong>About</strong><ul><li><a href="/who-we-are.html">Who We Are</a></li><li><a href="/contact.html">Contact</a></li><li><a href="/news.html">News</a></li><li><a href="/legal.html">Legal/License</a></li></ul></li></ul></div></div></div></body></html>
\ No newline at end of file
+--><html xmlns="http://www.w3.org/1999/xhtml"><head><META http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>QueryServlet | Apache Pivot</title><link href="/styles/pivot.css" rel="stylesheet" type="text/css"><script type="text/javascript">
+                var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+                document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+                </script><script type="text/javascript">
+                try {
+                var pageTracker = _gat._getTracker("UA-7977275-3");
+                pageTracker._trackPageview();
+                } catch(err) {}</script></head><body><div id="wrapper"><div id="main"><div id="header"><div xmlns="" class="logo"><a href="/index.html"><img src="/images/logo.png" alt="Apache Pivot" title="Apache Pivot Homepage"></a></div><div class="tagline"><img src="/images/tagline.png" alt="Rich Internet Applications in Java" style="visibility:hidden"></div><ul class="navi"><li><a href="/demos/">Demos</a></li><li><a href="/download.cgi#2.0.1">Download</a></li><li><a href="/tutorials/">Tutorial</a></li><li><a href="/get-involved.html">Get Involved</a></li><li><a href="/about.html">About</a></li></ul></div><div id="contentBase" class="group"><h1>QueryServlet</h1><ul class="naviLeft"><li><a href="/tutorials/sample-application.html">Sample Application</a></li><li><a href="/tutorials/platform-overview.html">Platform Overview</a></li><li><a href="/tutorials/hello-world.html">Hello, World!</a></li><li><a href="/tutorials/hello-bxml.html">Hello, BXML!</a></li><li><a href="/tutor
 ials/component-and-container.html">Component &amp; Container</a></li><li><a href="/tutorials/labels-and-image-views.html">Labels &amp; Image Views</a></li><li><a href="/tutorials/svg-images.html">SVG Images</a></li><li><a href="/tutorials/buttons.html">Buttons</a></li><li><a href="/tutorials/push-buttons.html">Push Buttons</a></li><li><a href="/tutorials/toggle-buttons.html">Toggle Buttons</a></li><li><a href="/tutorials/radio-buttons.html">Radio Buttons</a></li><li><a href="/tutorials/checkboxes.html">Checkboxes</a></li><li><a href="/tutorials/link-buttons.html">Link Buttons</a></li><li><a href="/tutorials/lists.html">Lists</a></li><li><a href="/tutorials/list-buttons.html">List Buttons</a></li><li><a href="/tutorials/repeatable-list-buttons.html">Repeatable List Buttons</a></li><li><a href="/tutorials/text.html">Text</a></li><li><a href="/tutorials/suggestion-popups.html">Suggestion Popups</a></li><li><a href="/tutorials/text-areas.html">Text Areas</a></li><li><a href="/tu
 torials/separators.html">Separators</a></li><li><a href="/tutorials/layout-containers.html">Layout Containers</a></li><li><a href="/tutorials/flow-panes.html">Flow Panes</a></li><li><a href="/tutorials/box-panes.html">Box Panes</a></li><li><a href="/tutorials/fill-panes.html">Fill Panes</a></li><li><a href="/tutorials/grid-panes.html">Grid Panes</a></li><li><a href="/tutorials/table-panes.html">Table Panes</a></li><li><a href="/tutorials/borders.html">Borders</a></li><li><a href="/tutorials/stack-panes.html">Stack Panes</a></li><li><a href="/tutorials/split-panes.html">Split Panes</a></li><li><a href="/tutorials/forms.html">Forms</a></li><li><a href="/tutorials/panels.html">Panels</a></li><li><a href="/tutorials/navigation-containers.html">Navigation Containers</a></li><li><a href="/tutorials/card-panes.html">Card Panes</a></li><li><a href="/tutorials/tab-panes.html">Tab Panes</a></li><li><a href="/tutorials/accordions.html">Accordions</a></li><li><a href="/tutorials/expande
 rs.html">Expanders</a></li><li><a href="/tutorials/rollups.html">Rollups</a></li><li><a href="/tutorials/viewports.html">Viewports</a></li><li><a href="/tutorials/scroll-panes.html">Scroll Panes</a></li><li><a href="/tutorials/panoramas.html">Panoramas</a></li><li><a href="/tutorials/progress-indicators.html">Progress Indicators</a></li><li><a href="/tutorials/meters.html">Meters</a></li><li><a href="/tutorials/activity-indicators.html">Activity Indicators</a></li><li><a href="/tutorials/bounded-range-components.html">Bounded Range Components</a></li><li><a href="/tutorials/sliders.html">Sliders</a></li><li><a href="/tutorials/scroll-bars.html">Scroll Bars</a></li><li><a href="/tutorials/spinners.html">Spinners</a></li><li><a href="/tutorials/calendars.html">Calendars</a></li><li><a href="/tutorials/menus.html">Menus</a></li><li><a href="/tutorials/context-menus.html">Context Menus</a></li><li><a href="/tutorials/menu-bars.html">Menu Bars</a></li><li><a href="/tutorials/menu
 -buttons.html">Menu Buttons</a></li><li><a href="/tutorials/color-choosers.html">Color Choosers</a></li><li><a href="/tutorials/table-views.html">Table Views</a></li><li><a href="/tutorials/table-views.json.html">JSON-based TableView</a></li><li><a href="/tutorials/table-views.custom.html">Custom TableView</a></li><li><a href="/tutorials/tree-views.html">Tree Views</a></li><li><a href="/tutorials/file-browsing.html">File Browsing</a></li><li><a href="/tutorials/windows.html">Windows</a></li><li><a href="/tutorials/clipboard.html">Clipboard</a></li><li><a href="/tutorials/drag-and-drop.html">Drag and Drop</a></li><li><a href="/tutorials/effects.html">Effects</a></li><li><a href="/tutorials/effects.transitions.html">Transitions</a></li><li><a href="/tutorials/data-binding.html">Data Binding</a></li><li><a href="/tutorials/property-binding.html">Property Binding</a></li><li><a href="/tutorials/localization.html">Localization</a></li><li><a href="/tutorials/background-tasks.html
 ">Background Tasks</a></li><li><a href="/tutorials/web-queries.html">Web Queries</a></li><li><a href="/tutorials/query-servlet.html">QueryServlet</a></li><li><a href="/tutorials/scripting.html">Scripting</a></li><li><a href="/tutorials/summary.html">Summary</a></li><li><a href="/tutorials/stock-tracker.html">The "Stock Tracker" Application</a></li><li><a href="/tutorials/stock-tracker.ui.html">UI Markup Using BXML</a></li><li><a href="/tutorials/stock-tracker.events.html">Event Handling</a></li><li><a href="/tutorials/stock-tracker.web-queries.html">Web Queries</a></li><li><a href="/tutorials/stock-tracker.data-binding.html">Data Binding</a></li><li><a href="/tutorials/stock-tracker.localization.html">Localization</a></li><li><a href="/tutorials/bxml-primer.html">BXML Primer</a></li></ul><div class="content"><style type="text/css">
+            applet {
+                border: 1px solid #999999;
+            }
+        </style><!--NOTE: Syntax highlighting script is LGPL--><script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js"></script><script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js"></script><script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js"></script><script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js"></script><link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css"><link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css"><script type="text/javascript">
+            SyntaxHighlighter.all();
+        </script><div class="section">
+        <p>
+            As discussed in the previous section, Pivot provides a set of classes for interacting
+            with HTTP-based REST services, which Pivot calls "web queries". Pivot also provides an
+            abstract base class named <tt>org.apache.pivot.web.server.QueryServlet</tt> that helps
+            to facilitate implementation of such services.
+        </p>
+
+        <p>
+            The following example shows a Pivot client application that interacts with a REST
+            service for managing expense data. The web service is implemented using
+            <tt>QueryServlet</tt> and is discussed below:
+        </p>
+
+        <p>
+            <em>NOTE</em> This application must be run via a locally-deployed WAR file. It will not
+            work in the online tutorial.
+        </p>
+
+        <script type="text/javascript" src="http://java.com/js/deployJava.js"></script><script type="text/javascript">
+            
+            var attributes = {
+                code:"org.apache.pivot.wtk.BrowserApplicationContext$HostApplet",
+                width:"480",
+                height:"280"
+            };
+
+            
+            
+
+            
+            var libraries = [];
+            libraries.push("/lib/pivot-core-2.0.1.jar");
+                libraries.push("/lib/pivot-web-2.0.1.jar");
+                libraries.push("/lib/pivot-wtk-2.0.1.jar");
+                libraries.push("/lib/pivot-wtk-terra-2.0.1.jar");
+                libraries.push("/lib/pivot-tutorials-2.0.1.jar");
+                
+                    libraries.push("/lib/svgSalamander-tiny.jar");
+                
+
+            attributes.archive = libraries.join(",");
+
+            
+            var parameters = {
+                codebase_lookup:false,
+                application_class_name:'org.apache.pivot.tutorials.webqueries.Expenses'
+            };
+
+            
+            var javaArguments = ["-Dsun.awt.noerasebackground=true",
+                "-Dsun.awt.erasebackgroundonresize=true"];
+
+            
+
+            parameters.java_arguments = javaArguments.join(" ");
+
+            
+            
+
+            deployJava.runApplet(attributes, parameters, "1.6");
+        </script>
+
+        <h3>QueryServlet</h3>
+
+        <p>
+            The <tt>QueryServlet</tt> class extends <tt>javax.servlet.http.HttpServlet</tt> and
+            provides overloaded versions of the base HTTP handler methods that make them easier to
+            work with in a REST-oriented manner:
+        </p>
+
+        <ul>
+            <li><tt>Object doGet(Path path)</tt></li>
+            <li><tt>URL doPost(Path path, Object value)</tt></li>
+            <li><tt>boolean doPut(Path path, Object value)</tt></li>
+            <li><tt>void doDelete(Path path)</tt></li>
+        </ul>
+
+        <p>
+            Each method takes an instance of <tt>QueryServlet.Path</tt> that represents the path to
+            the resource being accessed, relative to the location of the servlet itself.
+            <tt>Path</tt> is a sequence type that allows a caller to access the components of the
+            path via numeric index. For example, if the query servlet is mapped to the
+            "/my_service/*" URL pattern, given the following URL:
+        </p>
+
+        <pre>http://pivot.apache.org/my_service/foo/bar</pre>
+
+        <p>
+            the <tt>path</tt> argument would contain the values "foo" and "bar", accessible via
+            indices 0 and 1, respectively.
+        </p>
+
+        <h4>Serializers</h4>
+
+        <p>
+            Unlike the base <tt>HttpServlet</tt> class, <tt>QueryServlet</tt> operates on arbitrary
+            Java types rather than HTTP request and response objects. This allows developers to
+            focus on the resources managed by the service rather than the lower-level details of
+            the HTTP protocol.
+        </p>
+
+        <p>
+            <tt>QueryServlet</tt> uses a serializer (an implementation of the
+            <tt>org.apache.pivot.serialization.Serializer</tt> interface) to determine how to
+            serialize the data sent to and returned from the servlet. The serializer used for a
+            given HTTP request is determined by the return value of the abstract
+            <tt>createSerializer()</tt> method. This method is called by <tt>QueryServlet</tt>
+            prior to invoking the actual HTTP handler method. The example servlet uses an instance
+            of <tt>org.apache.pivot.json.JSONSerializer</tt>, which supports reading and writing of
+            JSON data. Pivot provides a number of additional serializers supporting XML, CSV, and
+            Java serialization, among others, and service implementations are free to define their
+            own custom serializers as well.
+        </p>
+
+        <h4>Exceptions</h4>
+
+        <p>
+            Each handler method declares that it may throw an instance of
+            <tt>org.apache.pivot.web.QueryException</tt>. This exception encapsulates an HTTP error
+            response. It takes an integer value representing the response code as a constructor
+            argument (the <tt>org.apache.pivot.web.Query.Status</tt> class defines a number of
+            constants for status codes commonly used in REST responses). The web query client API,
+            discussed in the previous section, effectively re-throws these exceptions, allowing the
+            client to handle an error response returned by the server as if the exception was
+            generated locally.
+        </p>
+
+        <h4>Query String Parameters and HTTP Headers</h4>
+
+        <p>
+            Though it is not shown in this example, query servlet implementations can also access
+            the query string arguments and HTTP headers included in the HTTP request, as well as
+            control the headers sent back with the response. Query string parameters are accessible
+            via the <tt>getParameters()</tt> method of <tt>QueryServlet</tt>, and the
+            request/response headers can be accessed via <tt>getRequestHeaders()</tt> and
+            <tt>getResponseHeaders()</tt>, respectively. All three methods return an instance of
+            <tt>org.apache.pivot.web.QueryDictionary</tt>, which allows the caller to manipulate
+            these collections via <tt>get()</tt>, <tt>put()</tt>, and <tt>remove()</tt> methods.
+        </p>
+
+        <h3>ExpenseServlet</h3>
+
+        <p>
+            The following listing contains the full source code for <tt>ExpenseServlet</tt>, which
+            provides the implementation for the REST service used in this example. The
+            implementation of each method is discussed in more detail below:
+        </p>
+
+        <pre class="brush:java">
+            
+            package org.apache.pivot.tutorials.webqueries.server;
+
+            import java.io.IOException;
+            import java.io.InputStream;
+            import java.net.MalformedURLException;
+            import java.net.URL;
+
+            import javax.servlet.ServletException;
+
+            import org.apache.pivot.collections.HashMap;
+            import org.apache.pivot.collections.List;
+            import org.apache.pivot.json.JSONSerializer;
+            import org.apache.pivot.serialization.CSVSerializer;
+            import org.apache.pivot.serialization.SerializationException;
+            import org.apache.pivot.serialization.Serializer;
+            import org.apache.pivot.web.Query;
+            import org.apache.pivot.web.QueryException;
+            import org.apache.pivot.web.server.QueryServlet;
+
+            /**
+             * Servlet that implements expense management web service.
+             */
+            public class ExpenseServlet extends QueryServlet {
+                private static final long serialVersionUID = 0;
+
+                private List&amp;lt;Expense&amp;gt; expenses = null;
+                private HashMap&amp;lt;Integer, Expense&amp;gt; expenseMap = new HashMap&amp;lt;Integer, Expense&amp;gt;();
+
+                private static int nextID = 0;
+
+                @Override
+                @SuppressWarnings("unchecked")
+                public void init() throws ServletException {
+                    CSVSerializer csvSerializer = new CSVSerializer();
+                    csvSerializer.getKeys().add("date");
+                    csvSerializer.getKeys().add("type");
+                    csvSerializer.getKeys().add("amount");
+                    csvSerializer.getKeys().add("description");
+                    csvSerializer.setItemClass(Expense.class);
+
+                    // Load the initial expense data
+                    InputStream inputStream = ExpenseServlet.class.getResourceAsStream("expenses.csv");
+
+                    try {
+                        expenses = (List&amp;lt;Expense&amp;gt;)csvSerializer.readObject(inputStream);
+                    } catch (IOException exception) {
+                        throw new ServletException(exception);
+                    } catch (SerializationException exception) {
+                        throw new ServletException(exception);
+                    }
+
+                    // Index the initial expenses
+                    for (Expense expense : expenses) {
+                        int id = nextID++;
+                        expense.setID(id);
+                        expenseMap.put(id, expense);
+                    }
+                }
+
+                @Override
+                protected Object doGet(Path path) throws QueryException {
+                    Object value;
+
+                    if (path.getLength() == 0) {
+                        value = expenses;
+                    } else {
+                        // Get the ID of the expense to retrieve from the path
+                        int id = Integer.parseInt(path.get(0));
+
+                        // Get the expense data from the map
+                        synchronized (this) {
+                            value = expenseMap.get(id);
+                        }
+
+                        if (value == null) {
+                            throw new QueryException(Query.Status.NOT_FOUND);
+                        }
+                    }
+
+                    return value;
+                }
+
+                @Override
+                protected URL doPost(Path path, Object value) throws QueryException {
+                    if (value == null) {
+                        throw new QueryException(Query.Status.BAD_REQUEST);
+                    }
+
+                    Expense expense = (Expense)value;
+
+                    // Add the expense to the list/map
+                    int id;
+                    synchronized (this) {
+                        id = nextID++;
+                        expense.setID(id);
+                        expenses.add(expense);
+                        expenseMap.put(id, expense);
+                    }
+
+                    // Return the location of the newly-created resource
+                    URL location = getLocation();
+                    try {
+                        location = new URL(location, Integer.toString(id));
+                    } catch (MalformedURLException exception) {
+                        throw new QueryException(Query.Status.INTERNAL_SERVER_ERROR);
+                    }
+
+                    return location;
+                }
+
+                @Override
+                protected boolean doPut(Path path, Object value) throws QueryException {
+                    if (path.getLength() == 0
+                        || value == null) {
+                        throw new QueryException(Query.Status.BAD_REQUEST);
+                    }
+
+                    // Get the ID of the expense to retrieve from the path
+                    int id = Integer.parseInt(path.get(0));
+
+                    // Create the new expense and bind the data to it
+                    Expense expense = (Expense)value;
+                    expense.setID(id);
+
+                    // Update the list/map
+                    Expense previousExpense;
+                    synchronized (this) {
+                        previousExpense = expenseMap.put(id, expense);
+                        expenses.remove(previousExpense);
+                        expenses.add(expense);
+                    }
+
+                    return (previousExpense == null);
+                }
+
+                @Override
+                protected void doDelete(Path path) throws QueryException {
+                    if (path.getLength() == 0) {
+                        throw new QueryException(Query.Status.BAD_REQUEST);
+                    }
+
+                    // Get the ID of the expense to retrieve from the path
+                    int id = Integer.parseInt(path.get(0));
+
+                    // Update the list/map
+                    Expense expense;
+                    synchronized (this) {
+                        expense = expenseMap.remove(id);
+                        expenses.remove(expense);
+                    }
+
+                    if (expense == null) {
+                        throw new QueryException(Query.Status.NOT_FOUND);
+                    }
+                }
+
+                @Override
+                protected Serializer&amp;lt;?&amp;gt; createSerializer(Path path) throws QueryException {
+                    return new JSONSerializer(Expense.class);
+                }
+            }
+            
+        </pre>
+
+        <h3>init()</h3>
+
+        <p>
+            The <tt>init()</tt> method, which is defined by <tt>QueryServlet</tt>'s base class
+            <tt>HttpServlet</tt>, is called when a servlet is first created by a servlet container.
+            <tt>ExpenseServlet</tt>'s implementation of <tt>init()</tt> is as follows:
+        </p>
+
+        <pre class="brush:java">
+            
+            public void init() throws ServletException {
+                CSVSerializer csvSerializer = new CSVSerializer();
+                csvSerializer.getKeys().add("date");
+                csvSerializer.getKeys().add("type");
+                csvSerializer.getKeys().add("amount");
+                csvSerializer.getKeys().add("description");
+                csvSerializer.setItemClass(Expense.class);
+
+                // Load the initial expense data
+                InputStream inputStream = ExpenseServlet.class.getResourceAsStream("expenses.csv");
+
+                try {
+                    expenses = (List&amp;lt;Expense&amp;gt;)csvSerializer.readObject(inputStream);
+                } catch (IOException exception) {
+                    throw new ServletException(exception);
+                } catch (SerializationException exception) {
+                    throw new ServletException(exception);
+                }
+
+                // Index the initial expenses
+                for (Expense expense : expenses) {
+                    int id = nextID++;
+                    expense.setID(id);
+                    expenseMap.put(id, expense);
+                }
+            }
+            
+        </pre>
+
+        <p>
+            It loads an initial list of expenses using an instance of <tt>CSVSerializer</tt>. The
+            contents of the CSV file are as follows:
+        </p>
+
+        <pre>
+        2010-03-28, Travel,     1286.90,    Ticket #145-XX-71903-09
+        2010-03-28, Meals,      34.12,      Took client out
+        2010-03-31, Meals,      27.00,
+        2010-04-01, Meals,      12.55,
+        2010-04-02, Meals,      18.86,
+        2010-04-02, Parking,    30.00,      Cambridge Center parking
+        2010-04-03, Meals,      20.72,
+        2010-04-06, Travel,     529.00,     Marriott reservation #DF-9982-BRN
+        </pre>
+
+        <p>
+            Due to the call to <tt>setItemClass()</tt>, the rows in the CSV file are deserialized
+            as instances of <tt>org.apache.pivot.tutorials.webqueries.server.Expense</tt>, a Java
+            Bean class that is defined as follows:
+        </p>
+
+        <pre class="brush:java">
+            
+            package org.apache.pivot.tutorials.webqueries.server;
+
+            public class Expense {
+                private Integer id = -1;
+                private String date = null;
+                private String type = null;
+                private Double amount = 0d;
+                private String description = null;
+
+                public Integer getID() {
+                    return id;
+                }
+
+                public Integer getId() {
+                    return getID();
+                }
+
+                public void setID(Integer id) {
+                    this.id = id;
+                }
+
+                public void setId(Integer id) {
+                    setID(id);
+                }
+
+                public String getDate() {
+                    return date;
+                }
+
+                public void setDate(String date) {
+                    this.date = date;
+                }
+
+                public String getType() {
+                    return type;
+                }
+
+                public void setType(String type) {
+                    this.type = type;
+                }
+
+                public Double getAmount() {
+                    return amount;
+                }
+
+                public void setAmount(Double amount) {
+                    this.amount = amount;
+                }
+
+                public final void setAmount(String amount) {
+                    setAmount(Double.parseDouble(amount));
+                }
+
+                public String getDescription() {
+                    return description;
+                }
+
+                public void setDescription(String description) {
+                    this.description = description;
+                }
+            }
+            
+        </pre>
+
+        <p>
+            After the list of expenses has been loaded, <tt>init()</tt> iterates over the list,
+            assigns each expense an ID, and adds it to a map. This collection-based approach is
+            sufficient for a tutorial example; a real application would most likely use a
+            relational database to manage the expense data.
+        </p>
+
+        <h3>doGet()</h3>
+
+        <p>
+            <tt>doGet()</tt> is used to handle an HTTP GET request. It returns an object
+            representing the resource at a given path. The <tt>doGet()</tt> method in the example
+            servlet is defined as follows:
+        </p>
+
+        <pre class="brush:java">
+            
+            protected Object doGet(Path path) throws QueryException {
+                Object value;
+
+                if (path.getLength() == 0) {
+                    value = expenses;
+                } else {
+                    // Get the ID of the expense to retrieve from the path
+                    int id = Integer.parseInt(path.get(0));
+
+                    // Get the expense data from the map
+                    synchronized (this) {
+                        value = expenseMap.get(id);
+                    }
+
+                    if (value == null) {
+                        throw new QueryException(Query.Status.NOT_FOUND);
+                    }
+                }
+
+                return value;
+            }
+            
+        </pre>
+
+        <p>
+            If the request does not contain a path, the method returns the list of all expenses.
+            Otherwise, it attemps to look up and return the requested expense by its ID. If the
+            expense is not found, an HTTP 404 ("Not Found") error is returned to the caller via the
+            thrown <tt>QueryException</tt>; otherwise, the expense is returned along with the
+            default HTTP 200 ("OK") status code. The bean value is converted to JSON format by the
+            <tt>JSONSerializer</tt> instance returned by <tt>createSerializer()</tt>.
+        </p>
+
+        <h3>doPost()</h3>
+
+        <p>
+            <tt>doPost()</tt> is used to handle an HTTP POST request. It is primarily used to
+            create a new resource on the server, but can also be used to execute arbitrary
+            server-side actions.
+        </p>
+
+        <p>
+            When a resource is created, <tt>doPost()</tt> returns a URL representing the location
+            of the new resource. Consistent with the HTTP specification, this value is returned in
+            the "Location" response header along with an HTTP status code of 201 ("Created"). If a
+            POST request does not result in the creation of a resource, <tt>doPost()</tt> can
+            return <tt>null</tt>, which is translated by <tt>QueryServlet</tt> to an HTTP response
+            of 204 ("No Content") and no corresponding "Location" header.
+        </p>
+
+        <p>
+            The <tt>doPost()</tt> method in the example looks like this:
+        </p>
+
+        <pre class="brush:java">
+            
+            protected URL doPost(Path path, Object value) throws QueryException {
+                if (value == null) {
+                    throw new QueryException(Query.Status.BAD_REQUEST);
+                }
+
+                Expense expense = (Expense)value;
+
+                // Add the expense to the list/map
+                int id;
+                synchronized (this) {
+                    id = nextID++;
+                    expense.setID(id);
+                    expenses.add(expense);
+                    expenseMap.put(id, expense);
+                }
+
+                // Return the location of the newly-created resource
+                URL location = getLocation();
+                try {
+                    location = new URL(location, Integer.toString(id));
+                } catch (MalformedURLException exception) {
+                    throw new QueryException(Query.Status.INTERNAL_SERVER_ERROR);
+                }
+
+                return location;
+            }
+            
+        </pre>
+
+        <p>
+            The first thing the method does is ensure that the request is valid. If the caller has
+            not provided a value in the body of the request, HTTP 400 ("Bad Request") is returned.
+            Otherwise, it assigns the expense an ID and adds it to the list and map.
+        </p>
+
+        <p>
+            Finally, it returns the location of the new expense resource. The location value is
+            generated simply by appending the name of the temp file to the location of the servlet,
+            obtained by a call to <tt>QueryServlet#getLocation()</tt>.
+        </p>
+
+        <h3>doPut()</h3>
+
+        <p>
+            <tt>doPut()</tt> handles an HTTP PUT request. It is often used to update an existing
+            resource, but can also be used to create a new resource. The return value of
+            <tt>doPut()</tt> is a boolean flag indicating whether or not a resource was created.
+            If <tt>true</tt>, HTTP 201 is returned to the caller; otherwise, HTTP 204 is
+            returned.
+        </p>
+
+        <p>
+            <tt>ExpenseServlet</tt>'s implementation of <tt>doPut()</tt> is as follows:
+        </p>
+
+        <pre class="brush:java">
+            
+            protected boolean doPut(Path path, Object value) throws QueryException {
+                if (path.getLength() == 0
+                    || value == null) {
+                    throw new QueryException(Query.Status.BAD_REQUEST);
+                }
+
+                // Get the ID of the expense to retrieve from the path
+                int id = Integer.parseInt(path.get(0));
+
+                // Create the new expense and bind the data to it
+                Expense expense = (Expense)value;
+                expense.setID(id);
+
+                // Update the list/map
+                Expense previousExpense;
+                synchronized (this) {
+                    previousExpense = expenseMap.put(id, expense);
+                    expenses.remove(previousExpense);
+                    expenses.add(expense);
+                }
+
+                return (previousExpense == null);
+            }
+            
+        </pre>
+
+        <p>
+            Like <tt>doPost()</tt>, it first validates the format of the request. In addition to a
+            body, <tt>doPut()</tt> also requires a path component to identify the resource to be
+            updated. A real expense service might want to verify that the requested resource exists
+            before proceeding; however, the example service simply interprets an unused ID as a
+            request to create a new resource. Consistent with the API, it returns <tt>true</tt> if
+            a resource was created and <tt>false</tt> otherwise.
+        </p>
+
+        <h3>doDelete()</h3>
+
+        <p>
+            <tt>doDelete()</tt> handles an HTTP DELETE request. When successful, it simply
+            deletes the resource specified by the path and returns HTTP 204. The source code for
+            this method is shown below:
+        </p>
+
+        <pre class="brush:java">
+            
+            protected void doDelete(Path path) throws QueryException {
+                if (path.getLength() == 0) {
+                    throw new QueryException(Query.Status.BAD_REQUEST);
+                }
+
+                // Get the ID of the expense to retrieve from the path
+                int id = Integer.parseInt(path.get(0));
+
+                // Update the list/map
+                Expense expense;
+                synchronized (this) {
+                    expense = expenseMap.remove(id);
+                    expenses.remove(expense);
+                }
+
+                if (expense == null) {
+                    throw new QueryException(Query.Status.NOT_FOUND);
+                }
+            }
+            
+        </pre>
+
+        <p>
+            Like the other methods, the request is first validated; then, if the expense exists,
+            it is deleted. Otherwise, HTTP 404 is returned.
+        </p>
+
+        <h3>The Expenses Application</h3>
+
+        <p>
+            The Expenses client application allows a user to interact with the web service. It is
+            not described in this section, but builds on concepts discussed in earlier sections.
+            The source code is available in the Pivot source distribution under the "tutorials"
+            project.
+        </p>
+    </div><p>Next: <a href="scripting.html">Scripting</a></p></div></div></div><div id="footer" class="group"><div class="footerLogo">Copyright (c) 1999-2012<br>The Apache Software Foundation.</div><div class="footerLinks"><ul class="footerMenuGr"><li><strong>Demos</strong><ul><li><a href="/demos/kitchen-sink.html" target="_new">"Kitchen Sink"</a></li><li><a href="/demos/component-explorer.html" target="_new">Component Explorer</a></li><li><a href="http://cwiki.apache.org/confluence/display/PIVOT/Other+Demos" target="_new">Charting</a></li><li><a href="/demos/">More Demos</a></li></ul></li><li><strong>Documentation</strong><ul><li><a href="/getting-started.html">Getting Started</a></li><li><a href="/tutorials/">Tutorial</a></li><li><a href="/faq.html">FAQ</a></li><li><a href="/2.0.1/docs/api/">Javadoc (2.0.1)</a></li></ul></li><li><strong>Get Involved</strong><ul><li><a href="/svn.html">SVN Repositories</a></li><li><a href="/lists.html">Mailing Lists</a></li><li><a href="htt
 p://issues.apache.org/jira/browse/PIVOT">Bug Database</a></li><li><a href="http://cwiki.apache.org/PIVOT/">Wiki</a></li></ul></li><li><strong>Related</strong><ul><li><a href="http://code.google.com/a/apache-extras.org/p/pivot-jfree/">JFreeChart Provider</a></li><li><a href="http://code.google.com/a/apache-extras.org/p/pivot-common/">Pivot-Common</a></li><li><a href="http://code.google.com/a/apache-extras.org/p/pivot-contrib/">Pivot-Contrib</a></li><li><a href="http://code.google.com/a/apache-extras.org/p/pivot-multilang/">Pivot-Multilang</a></li></ul></li><li><strong>About</strong><ul><li><a href="/who-we-are.html">Who We Are</a></li><li><a href="/contact.html">Contact</a></li><li><a href="http://cwiki.apache.org/confluence/display/PIVOT/News">News</a></li><li><a href="/legal.html">Legal/License</a></li></ul></li></ul></div><div class="footerLinks">
+                	Apache Pivot is a trademark of the Apache Software Foundation
+                </div></div></div></body></html>
\ No newline at end of file