blob: 6304239b7991028216b4d684014d12eabdefbdbf [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.
-->
<document id="web-queries">
<properties>
<title>Web Queries</title>
</properties>
<body>
<p>
"Web queries" are Pivot's native means of communicating with remote data services. They
are designed primarily to facilitate interaction with JSON-based REST services, but
they are sufficiently generic to support communication with any type of HTTP-based
service, using any data format.
</p>
<p>
A web query is represented by an instance of <tt>org.apache.pivot.web.Query</tt>,
which extends the <tt>Task</tt> class discussed in the previous section. <tt>Query</tt>
is an abstract class with four concrete subclasses, each of which corresponds to once
of the four primary HTTP verbs:
</p>
<ul>
<li><p><b>GetQuery</b> - executes an HTTP GET request</p></li>
<li><p><b>PostQuery</b> - executes an HTTP POST request</p></li>
<li><p><b>PutQuery</b> - executes an HTTP PUT request</p></li>
<li><p><b>DeleteQuery</b> - executes an HTTP DELETE request</p></li>
</ul>
<p>
Query string parameters are specified via the query's parameter dictionary, and request
headers can be specified via the request header dictionary. After the query has been
executed, response headers are also available via the response header dictionary.
</p>
<p>
All query types have an associated serializer that is used to serialize or deserialize
the request or response data. <tt>GetQuery</tt> returns an <tt>Object</tt> representing
the data that was returned by the server, <tt>PostQuery</tt> and <tt>PutQuery</tt>
define a <tt>value</tt> property that is sent to the server when the query is executed,
and, by definition, <tt>DeleteQuery</tt> neither accepts nor returns a value.
</p>
<p>
Because they are instances of <tt>Task</tt>, web queries can be (and usually are)
executed asynchronously, such that the UI doesn't get bogged down waiting for the
server to respond. The following application demonstrates the use of a
<tt>GetQuery</tt> to read data from a Yahoo! Pipe. The pipe in this example searches
for "pizza" within 5 miles of Cambridge, Massachusetts (note that the applet is signed
to allow it to communicate with the Yahoo web service):
</p>
<application class="org.apache.pivot.tutorials.webqueries.WebQueries"
width="240" height="320">
<libraries signed="true">
<library>core</library>
<library>web</library>
<library>wtk</library>
<library>wtk-terra</library>
<library>tutorials</library>
</libraries>
</application>
<p>The BXML for the application's user interface is as follows:</p>
<source type="xml" location="org/apache/pivot/tutorials/webqueries/web_queries.bxml">
<![CDATA[
<Window title="Web Queries" maximized="true"
xmlns:bxml="http://pivot.apache.org/bxml"
xmlns:webqueries="org.apache.pivot.tutorials.webqueries"
xmlns="org.apache.pivot.wtk">
<Border styles="{color:10}">
<StackPane>
<ScrollPane horizontalScrollBarPolicy="fill">
<ListView bxml:id="listView">
<itemRenderer>
<webqueries:ResultItemRenderer/>
</itemRenderer>
</ListView>
</ScrollPane>
<Label bxml:id="loadingLabel" text="Loading..."
styles="{horizontalAlignment:'center', verticalAlignment:'center'}"/>
</StackPane>
</Border>
</Window>
]]>
</source>
<p>
Note that the <tt>ListView</tt> defines a custom item renderer; this renderer is used
to present the name, address, and phone number of the matching items returned by the
query.
</p>
<p>The Java source for the application is as follows:</p>
<source type="java" location="org/apache/pivot/tutorials/webqueries/WebQueries.java">
<![CDATA[
package org.apache.pivot.tutorials.webqueries;
import org.apache.pivot.beans.BXMLSerializer;
import org.apache.pivot.collections.List;
import org.apache.pivot.collections.Map;
import org.apache.pivot.json.JSON;
import org.apache.pivot.util.concurrent.Task;
import org.apache.pivot.util.concurrent.TaskListener;
import org.apache.pivot.web.GetQuery;
import org.apache.pivot.wtk.Application;
import org.apache.pivot.wtk.DesktopApplicationContext;
import org.apache.pivot.wtk.Display;
import org.apache.pivot.wtk.Label;
import org.apache.pivot.wtk.ListView;
import org.apache.pivot.wtk.TaskAdapter;
import org.apache.pivot.wtk.Window;
public class WebQueries implements Application {
private Window window = null;
private ListView listView = null;
private Label loadingLabel = null;
@Override
public void startup(Display display, Map<String, String> properties) throws Exception {
BXMLSerializer bxmlSerializer = new BXMLSerializer();
window = (Window)bxmlSerializer.readObject(WebQueries.class, "web_queries.bxml");
listView = (ListView)bxmlSerializer.getNamespace().get("listView");
loadingLabel = (Label)bxmlSerializer.getNamespace().get("loadingLabel");
// Execute the query:
// http://pipes.yahoo.com/pipes/pipe.run?_id=43115761f2da5af5341ae2e56a93d646&_render=json
GetQuery getQuery = new GetQuery("pipes.yahoo.com", "/pipes/pipe.run");
getQuery.getParameters().put("_id", "43115761f2da5af5341ae2e56a93d646");
getQuery.getParameters().put("_render", "json");
getQuery.execute(new TaskAdapter<Object>(new TaskListener<Object>() {
@Override
public void taskExecuted(Task<Object> task) {
List<?> items = (List<?>)JSON.get(task.getResult(), "value.items");
if (items.getLength() > 0) {
listView.setListData(items);
loadingLabel.setVisible(false);
} else {
loadingLabel.setText("No results.");
}
}
@Override
public void executeFailed(Task<Object> task) {
loadingLabel.setText(task.getFault().getMessage());
}
}));
window.open(display);
}
@Override
public boolean shutdown(boolean optional) {
if (window != null) {
window.close();
}
return false;
}
@Override
public void suspend() {
}
@Override
public void resume() {
}
public static void main(String[] args) {
DesktopApplicationContext.main(WebQueries.class, args);
}
}
]]>
</source>
<p>
In <tt>startup()</tt>, the application creates the query object and sets the
appropriate query string parameters to identify the pipe and ensure that the pipe's
output is returned as JSON data. It then executes the query, wrapping the task listener
in a task adapter to ensure that the callback is executed on the UI thread. When the
data is obtained, the "items" list is extracted from it and set as the data of the
list view component.
</p>
<p>
The application uses a custom list item renderer to present the result data. The
renderer is defined as follows (it extends <tt>BoxPane</tt> and uses labels to present
the name, address, and phone numbers of the result items):
</p>
<source type="java" location="org/apache/pivot/tutorials/webqueries/ResultItemRenderer.java">
<![CDATA[
package org.apache.pivot.tutorials.webqueries;
import java.awt.Color;
import java.awt.Font;
import org.apache.pivot.collections.Map;
import org.apache.pivot.json.JSON;
import org.apache.pivot.wtk.BoxPane;
import org.apache.pivot.wtk.Insets;
import org.apache.pivot.wtk.Label;
import org.apache.pivot.wtk.ListView;
import org.apache.pivot.wtk.Orientation;
public class ResultItemRenderer extends BoxPane implements ListView.ItemRenderer {
private Label titleLabel = new Label();
private Label addressLabel = new Label();
private Label phoneLabel = new Label();
public ResultItemRenderer() {
super(Orientation.VERTICAL);
add(titleLabel);
add(addressLabel);
add(phoneLabel);
getStyles().put("padding", new Insets(3, 2, 3, 2));
getStyles().put("spacing", 2);
}
@Override
public void setSize(int width, int height) {
super.setSize(width, height);
validate();
}
@Override
public String toString(Object item) {
return JSON.get(item, "title");
}
@Override
public void render(Object item, int index, ListView listView, boolean selected,
boolean checked, boolean highlighted, boolean disabled) {
if (item != null) {
titleLabel.setText((String)JSON.get(item, "title"));
phoneLabel.setText((String)JSON.get(item, "Phone"));
Map<String, ?> location = JSON.get(item, "['y:location']");
if (location == null) {
addressLabel.setText("");
} else {
String street = JSON.get(location, "street");
String city = JSON.get(location, "city");
String state = JSON.get(location, "state");
addressLabel.setText(street + ", " + city + " " + state);
}
}
Font font = (Font)listView.getStyles().get("font");
titleLabel.getStyles().put("font", font.deriveFont(font.getStyle() | Font.BOLD));
phoneLabel.getStyles().put("font", font);
addressLabel.getStyles().put("font", font);
Color color;
if (listView.isEnabled() && !disabled) {
if (selected) {
if (listView.isFocused()) {
color = (Color)listView.getStyles().get("selectionColor");
} else {
color = (Color)listView.getStyles().get("inactiveSelectionColor");
}
} else {
color = (Color)listView.getStyles().get("color");
}
} else {
color = (Color)listView.getStyles().get("disabledColor");
}
titleLabel.getStyles().put("color", color);
phoneLabel.getStyles().put("color", color);
addressLabel.getStyles().put("color", color);
}
}
]]>
</source>
</body>
</document>