Inital commit
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Add a new item to Google Base using the Google Base data API server.
|
||||
*/
|
||||
public class InsertExample {
|
||||
/**
|
||||
* URL of the authenticated customer feed.
|
||||
*/
|
||||
private static final String ITEMS_FEED = "http://base.google.com/base/feeds/items";
|
||||
|
||||
/**
|
||||
* The data item we are going to insert, in XML/Atom format.
|
||||
*/
|
||||
private static final String DATA_ITEM =
|
||||
"<?xml version='1.0'?>\n" +
|
||||
"<entry xmlns='http://www.w3.org/2005/Atom'\n" +
|
||||
" xmlns:g='http://base.google.com/ns/1.0'>\n" +
|
||||
" <g:item_type type='text'>testrecipes</g:item_type>\n" +
|
||||
" <title type='text'>Fabulous cheese cake</title>\n" +
|
||||
" <content type='xhtml'>All that you need is lots of patience.</content>\n" +
|
||||
"</entry>";
|
||||
|
||||
/**
|
||||
* URL used for authenticating and obtaining an authentication token.
|
||||
* More details about how it works:
|
||||
* <code>http://code.google.com/apis/accounts/AuthForInstalledApps.html<code>
|
||||
*/
|
||||
private static final String AUTHENTICATION_URL = "https://www.google.com/accounts/ClientLogin";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account email here.
|
||||
*/
|
||||
private static final String EMAIL = "";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account password here.
|
||||
*/
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
/**
|
||||
* The main method constructs a <code>InsertExample</code> instance, obtains an
|
||||
* authorization token and posts a new item to Google Base.
|
||||
*/
|
||||
public static void main(String[] args) throws MalformedURLException, IOException {
|
||||
InsertExample insertExample = new InsertExample();
|
||||
String token = insertExample.authenticate();
|
||||
System.out.println("Obtained authorization token: " + token);
|
||||
insertExample.postItem(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts <code>DATA_ITEM</code> by making a POST request to
|
||||
* <code>ITEMS_URL<code>.
|
||||
* @param token authentication token obtained using <code>authenticate</code>
|
||||
* @throws IOException if an I/O exception occurs while creating/writing/
|
||||
* reading the request
|
||||
*/
|
||||
public void postItem(String token) throws IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection)(new URL(ITEMS_FEED)).openConnection();
|
||||
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
// Set the properties of the connection: the Http method, the content type
|
||||
// of the POST request and the authorization header
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/atom+xml");
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
|
||||
// Post the data item
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(DATA_ITEM.getBytes());
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = connection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_CREATED) {
|
||||
inputStream = connection.getInputStream();
|
||||
} else {
|
||||
inputStream = connection.getErrorStream();
|
||||
}
|
||||
|
||||
// write the output to the console
|
||||
System.out.println(toString(inputStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authentication token for the provided set of credentials.
|
||||
* @return the authorization token that can be used to access authenticated
|
||||
* Google Base data API feeds
|
||||
*/
|
||||
public String authenticate() {
|
||||
// create the login request
|
||||
String postOutput = null;
|
||||
try {
|
||||
URL url = new URL(AUTHENTICATION_URL);
|
||||
postOutput = makeLoginRequest(url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Could not connect to authentication server: "
|
||||
+ e.toString());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Parse the result of the login request. If everything went fine, the
|
||||
// response will look like
|
||||
// HTTP/1.0 200 OK
|
||||
// Server: GFE/1.3
|
||||
// Content-Type: text/plain
|
||||
// SID=DQAAAGgA...7Zg8CTN
|
||||
// LSID=DQAAAGsA...lk8BBbG
|
||||
// Auth=DQAAAGgA...dk3fA5N
|
||||
// so all we need to do is look for "Auth" and get the token that comes after it
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(postOutput, "=\n ");
|
||||
String token = null;
|
||||
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
if (tokenizer.nextToken().equals("Auth")) {
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
token = tokenizer.nextToken();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (token == null) {
|
||||
System.out.println("Authentication error. Response from server:\n" + postOutput);
|
||||
System.exit(1);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a HTTP POST request to the provided {@code url} given the provided
|
||||
* {@code parameters}. It returns the output from the POST handler as a
|
||||
* String object.
|
||||
*
|
||||
* @param url the URL to post the request
|
||||
* @return the output from the handler
|
||||
* @throws IOException if an I/O exception occurs while
|
||||
* creating/writing/reading the request
|
||||
*/
|
||||
private String makeLoginRequest(URL url)
|
||||
throws IOException {
|
||||
// Create a login request. A login request is a POST request that looks like
|
||||
// POST /accounts/ClientLogin HTTP/1.0
|
||||
// Content-type: application/x-www-form-urlencoded
|
||||
// Email=johndoe@gmail.com&Passwd=north23AZ&service=gbase&source=Insert Example
|
||||
|
||||
// Open connection
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
|
||||
// Set properties of the connection
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoInput(true);
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("Content-Type",
|
||||
"application/x-www-form-urlencoded");
|
||||
|
||||
// Form the POST parameters
|
||||
StringBuilder content = new StringBuilder();
|
||||
content.append("Email=").append(URLEncoder.encode(EMAIL, "UTF-8"));
|
||||
content.append("&Passwd=").append(URLEncoder.encode(PASSWORD, "UTF-8"));
|
||||
content.append("&source=").append(URLEncoder.encode("Google Base data API example", "UTF-8"));
|
||||
content.append("&service=").append(URLEncoder.encode("gbase", "UTF-8"));
|
||||
|
||||
OutputStream outputStream = urlConnection.getOutputStream();
|
||||
outputStream.write(content.toString().getBytes("UTF-8"));
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = urlConnection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
inputStream = urlConnection.getInputStream();
|
||||
} else {
|
||||
inputStream = urlConnection.getErrorStream();
|
||||
}
|
||||
|
||||
return toString(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of the input stream to a <code>String<code>.
|
||||
*/
|
||||
private String toString(InputStream inputStream) throws IOException {
|
||||
String string;
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
if (inputStream != null) {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
||||
while (null != (string = reader.readLine())) {
|
||||
outputBuilder.append(string).append('\n');
|
||||
}
|
||||
}
|
||||
return outputBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* Dumps to the console the response of a Google Base data API query.
|
||||
*/
|
||||
public class QueryExample1 {
|
||||
/**
|
||||
* Url of the Google Base data API snippet feed.
|
||||
*/
|
||||
private static final String SNIPPETS_FEED = "http://base.google.com/base/feeds/snippets";
|
||||
|
||||
/**
|
||||
* The query that is sent over to the Google Base data API server.
|
||||
*/
|
||||
private static final String QUERY = "cars [item type : products]";
|
||||
|
||||
/**
|
||||
* Connect to <code>SNIPPETS_FEED</code> and display the response.
|
||||
* @throws IOException if an error occured while connecting or reading from
|
||||
* the feed
|
||||
*/
|
||||
public void displayItems() throws IOException {
|
||||
URL url = new URL(SNIPPETS_FEED + "?bq=" +
|
||||
URLEncoder.encode(QUERY, "UTF-8"));
|
||||
|
||||
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
|
||||
InputStream inputStream = httpConnection.getInputStream();
|
||||
|
||||
int ch;
|
||||
while ((ch=inputStream.read()) > 0) {
|
||||
System.out.print((char)ch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method simply creates a <code>QueryExample2</code> instance and
|
||||
* calls <code>displayItems</code>.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
new QueryExample1().displayItems();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Stack;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
/**
|
||||
* Display the titles of the Google Base items that match a specific query.
|
||||
*/
|
||||
public class QueryExample2 {
|
||||
/**
|
||||
* Url of the Google Base data API snippet feed.
|
||||
*/
|
||||
private static final String SNIPPETS_FEED = "http://base.google.com/base/feeds/snippets";
|
||||
|
||||
/**
|
||||
* The query that is sent over to the Google Base data API server.
|
||||
*/
|
||||
private static final String QUERY = "cars [item type : products]";
|
||||
|
||||
/**
|
||||
* Create a <code>QueryExample2</code> instance and
|
||||
* call <code>displayItems</code>.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException, SAXException,
|
||||
ParserConfigurationException {
|
||||
new QueryExample2().displayItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the Google Base data API server, retrieve the items that match
|
||||
* <code>QUERY</code> and call <code>DisplayTitlesHandler</code> to extract
|
||||
* and display the titles from the XML response.
|
||||
*/
|
||||
public void displayItems() throws IOException, SAXException,
|
||||
ParserConfigurationException {
|
||||
/*
|
||||
* Create a URL object, open an Http connection on it and get the input
|
||||
* stream that reads the Http response.
|
||||
*/
|
||||
URL url = new URL(SNIPPETS_FEED + "?bq=" +
|
||||
URLEncoder.encode(QUERY, "UTF-8"));
|
||||
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
|
||||
InputStream inputStream = httpConnection.getInputStream();
|
||||
|
||||
/*
|
||||
* Create a SAX XML parser and pass in the input stream to the parser.
|
||||
* The parser will use DisplayTitleHandler to extract the titles from the
|
||||
* XML stream.
|
||||
*/
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
parser.parse(inputStream, new DisplayTitlesHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple SAX event handler, which prints out the titles of all entries in the
|
||||
* Atom response feed.
|
||||
*/
|
||||
private static class DisplayTitlesHandler extends DefaultHandler {
|
||||
/**
|
||||
* Stack containing the opening XML tags of the response.
|
||||
*/
|
||||
private Stack<String> xmlTags = new Stack<String>();
|
||||
|
||||
/**
|
||||
* Counter that keeps track of the currently parsed item.
|
||||
*/
|
||||
private int itemNo = 0;
|
||||
|
||||
/**
|
||||
* True if we are inside of a data entry's title, false otherwise.
|
||||
*/
|
||||
private boolean insideEntryTitle = false;
|
||||
|
||||
/**
|
||||
* Receive notification of an opening XML tag: push the tag to
|
||||
* <code>xmlTags</code>. If the tag is a title tag inside an entry tag,
|
||||
* turn <code>insideEntryTitle</code> to <code>true</code>.
|
||||
*/
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName,
|
||||
Attributes attributes) throws SAXException {
|
||||
if (qName.equals("title") && xmlTags.peek().equals("entry")) {
|
||||
insideEntryTitle = true;
|
||||
System.out.print("Item " + ++itemNo + ": ");
|
||||
}
|
||||
xmlTags.push(qName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive notification of a closing XML tag: remove the tag from teh stack.
|
||||
* If we were inside of an entry's title, turn <code>insideEntryTitle</code>
|
||||
* to <code>false</code>.
|
||||
*/
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName)
|
||||
throws SAXException {
|
||||
// If a "title" element is closed, we start a new line, to prepare
|
||||
// printing the new title.
|
||||
xmlTags.pop();
|
||||
if (insideEntryTitle) {
|
||||
insideEntryTitle = false;
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for receiving notification of character data inside an
|
||||
* XML element.
|
||||
*/
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
// display the character data if the opening tag is "title" and its parent is
|
||||
// "entry"
|
||||
if (insideEntryTitle) {
|
||||
System.out.print(new String(ch, start, length));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Display all items of a specific customer.
|
||||
*/
|
||||
public class QueryExample3 {
|
||||
/**
|
||||
* URL of the authenticated customer feed.
|
||||
*/
|
||||
private static final String ITEMS_FEED = "http://base.google.com/base/feeds/items";
|
||||
|
||||
/**
|
||||
* URL used for authenticating and obtaining an authentication token.
|
||||
* More details about how it works:
|
||||
* <code>http://code.google.com/apis/accounts/AuthForInstalledApps.html<code>
|
||||
*/
|
||||
private static final String AUTHENTICATION_URL = "https://www.google.com/accounts/ClientLogin";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account email here.
|
||||
*/
|
||||
private static final String EMAIL = "";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account password here.
|
||||
*/
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
/**
|
||||
* Create a <code>QueryExample3</code> instance and call
|
||||
* <code>displayMyItems</code>, which displays all items that belong to the
|
||||
* currently authenticated user.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
QueryExample3 queryExample = new QueryExample3();
|
||||
String token = queryExample.authenticate();
|
||||
queryExample.displayMyItems(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authentication token for the provided set of credentials.
|
||||
* @return the authorization token that can be used to access authenticated
|
||||
* Google Base data API feeds
|
||||
*/
|
||||
public String authenticate() {
|
||||
// create the login request
|
||||
String postOutput = null;
|
||||
try {
|
||||
URL url = new URL(AUTHENTICATION_URL);
|
||||
postOutput = makeLoginRequest(url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Could not connect to authentication server: "
|
||||
+ e.toString());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Parse the result of the login request. If everything went fine, the
|
||||
// response will look like
|
||||
// HTTP/1.0 200 OK
|
||||
// Server: GFE/1.3
|
||||
// Content-Type: text/plain
|
||||
// SID=DQAAAGgA...7Zg8CTN
|
||||
// LSID=DQAAAGsA...lk8BBbG
|
||||
// Auth=DQAAAGgA...dk3fA5N
|
||||
// so all we need to do is look for "Auth" and get the token that comes after it
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(postOutput, "=\n ");
|
||||
String token = null;
|
||||
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
if (tokenizer.nextToken().equals("Auth")) {
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
token = tokenizer.nextToken();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (token == null) {
|
||||
System.out.println("Authentication error. Response from server:\n" + postOutput);
|
||||
System.exit(1);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the "items" feed, that is the feed that contains the items that
|
||||
* belong to the currently authenticated user.
|
||||
*
|
||||
* @param token the authorization token, as returned by
|
||||
* <code>authenticate<code>
|
||||
* @throws IOException if an IOException occurs while creating/reading the
|
||||
* request
|
||||
*/
|
||||
public void displayMyItems(String token) throws MalformedURLException, IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection)(new URL(ITEMS_FEED)).openConnection() ;
|
||||
// Set properties of the connection
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
inputStream = connection.getInputStream();
|
||||
} else {
|
||||
inputStream = connection.getErrorStream();
|
||||
}
|
||||
|
||||
System.out.println(toString(inputStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a HTTP POST request to the provided {@code url} given the provided
|
||||
* {@code parameters}. It returns the output from the POST handler as a
|
||||
* String object.
|
||||
*
|
||||
* @param url the URL to post the request
|
||||
* @return the output from the Google Accounts server, as string
|
||||
* @throws IOException if an I/O exception occurs while
|
||||
* creating/writing/reading the request
|
||||
*/
|
||||
private String makeLoginRequest(URL url)
|
||||
throws IOException {
|
||||
// Create a login request. A login request is a POST request that looks like
|
||||
// POST /accounts/ClientLogin HTTP/1.0
|
||||
// Content-type: application/x-www-form-urlencoded
|
||||
// Email=johndoe@gmail.com&Passwd=north23AZ&service=gbase&source=Insert Example
|
||||
|
||||
// Open connection
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
|
||||
// Set properties of the connection
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoInput(true);
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("Content-Type",
|
||||
"application/x-www-form-urlencoded");
|
||||
|
||||
// Form the POST parameters
|
||||
StringBuilder content = new StringBuilder();
|
||||
content.append("Email=").append(URLEncoder.encode(EMAIL, "UTF-8"));
|
||||
content.append("&Passwd=").append(URLEncoder.encode(PASSWORD, "UTF-8"));
|
||||
content.append("&service=").append(URLEncoder.encode("gbase", "UTF-8"));
|
||||
content.append("&source=").append(URLEncoder.encode("Google Base data API example", "UTF-8"));
|
||||
|
||||
OutputStream outputStream = urlConnection.getOutputStream();
|
||||
outputStream.write(content.toString().getBytes("UTF-8"));
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = urlConnection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
inputStream = urlConnection.getInputStream();
|
||||
} else {
|
||||
inputStream = urlConnection.getErrorStream();
|
||||
}
|
||||
|
||||
return toString(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of the input stream to a <code>String<code>.
|
||||
*/
|
||||
private String toString(InputStream inputStream) throws IOException {
|
||||
String string;
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
if (inputStream != null) {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(inputStream));
|
||||
while (null != (string = reader.readLine())) {
|
||||
outputBuilder.append(string).append('\n');
|
||||
}
|
||||
}
|
||||
return outputBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Update a Google Base data item using the Google Base data API server.
|
||||
*/
|
||||
public class UpdateExample {
|
||||
/**
|
||||
* URL of the authenticated customer feed.
|
||||
*/
|
||||
private static final String ITEMS_FEED = "http://base.google.com/base/feeds/items";
|
||||
|
||||
/**
|
||||
* The data item we are going to insert, in XML/Atom format.
|
||||
*/
|
||||
private static final String DATA_ITEM =
|
||||
"<?xml version='1.0'?>\n" +
|
||||
"<entry xmlns='http://www.w3.org/2005/Atom'\n" +
|
||||
" xmlns:g='http://base.google.com/ns/1.0'>\n" +
|
||||
" <g:item_type type='text'>testrecipes</g:item_type>\n" +
|
||||
" <title type='text'>Fabulous cheese cake</title>\n" +
|
||||
" <content type='xhtml'>All that you need is lots of patience.</content>\n" +
|
||||
"</entry>";
|
||||
|
||||
/**
|
||||
* The updated data item, in XML/Atom format. It adds an additional label to
|
||||
* <code>DATA_ITEM</code>.
|
||||
*/
|
||||
private static final String NEW_DATA_ITEM =
|
||||
"<?xml version='1.0'?>\n" +
|
||||
"<entry xmlns='http://www.w3.org/2005/Atom'\n" +
|
||||
" xmlns:g='http://base.google.com/ns/1.0'>\n" +
|
||||
" <g:item_type type='text'>testrecipes</g:item_type>\n" +
|
||||
" <title type='text'>Yummy cheese cake</title>\n" +
|
||||
" <content type='xhtml'>All that you need is lots of patience.</content>\n" +
|
||||
" <g:main_ingredient type='text'>cheese</g:main_ingredient>\n" +
|
||||
"</entry>";
|
||||
|
||||
/**
|
||||
* URL used for authenticating and obtaining an authentication token.
|
||||
* More details about how it works:
|
||||
* <code>http://code.google.com/apis/accounts/AuthForInstalledApps.html<code>
|
||||
*/
|
||||
private static final String AUTHENTICATION_URL =
|
||||
"https://www.google.com/accounts/ClientLogin";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account email here.
|
||||
*/
|
||||
private static final String EMAIL = "";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account password here.
|
||||
*/
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
/**
|
||||
* The main method constructs an <code>UpdateExample</code> instance,
|
||||
* obtains an authorization token, posts a new item to Google Base, extracts
|
||||
* the new item's id from the reponse and uses it to update the item.
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
throws MalformedURLException, IOException {
|
||||
UpdateExample updateExample = new UpdateExample();
|
||||
String token = updateExample.authenticate();
|
||||
System.out.println("Obtained authorization token: " + token);
|
||||
|
||||
System.out.println("Posting item:\n" + DATA_ITEM);
|
||||
String itemUrl = updateExample.extractItemUrlFromResponse(
|
||||
updateExample.postItem(token));
|
||||
|
||||
System.out.println("Updating item: " + itemUrl);
|
||||
String updateResponse = updateExample.updateItem(token, itemUrl);
|
||||
System.out.println(updateResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authentication token for the provided set of credentials.
|
||||
* @return the authorization token that can be used to access authenticated
|
||||
* Google Base data API feeds
|
||||
*/
|
||||
public String authenticate() {
|
||||
// create the login request
|
||||
String postOutput = null;
|
||||
try {
|
||||
URL url = new URL(AUTHENTICATION_URL);
|
||||
postOutput = makeLoginRequest(url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Could not connect to authentication server: "
|
||||
+ e.toString());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Parse the result of the login request. If everything went fine, the
|
||||
// response will look like
|
||||
// HTTP/1.0 200 OK
|
||||
// Server: GFE/1.3
|
||||
// Content-Type: text/plain
|
||||
// SID=DQAAAGgA...7Zg8CTN
|
||||
// LSID=DQAAAGsA...lk8BBbG
|
||||
// Auth=DQAAAGgA...dk3fA5N
|
||||
// so all we need to do is look for "Auth" and get the token that comes after it
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(postOutput, "=\n ");
|
||||
String token = null;
|
||||
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
if (tokenizer.nextToken().equals("Auth")) {
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
token = tokenizer.nextToken();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (token == null) {
|
||||
System.out.println("Authentication error. Response from server:\n" + postOutput);
|
||||
System.exit(1);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the POST XML response returned by <code>insertResponse</code> and
|
||||
* extract the Google Base item id of the newly created item. To keep parsing
|
||||
* simple, we assume that the first "id" tag contains the Atom item id; this
|
||||
* is true for the Google Base data API servers, but it's not enforced by Atom -
|
||||
* see how the title is parsed in {@link QueryExample2}
|
||||
* @param insertResponse the response sent by the Google Base data API server
|
||||
* after the insert operation
|
||||
* @return the Url that identifies the item, for example: <code>
|
||||
* http://base.google.com/base/feeds/items/18020038538902937385</code>
|
||||
*/
|
||||
public String extractItemUrlFromResponse(String insertResponse) {
|
||||
int startIndex = insertResponse.indexOf("<id>") + 4;
|
||||
int endIndex = insertResponse.indexOf("</id>");
|
||||
String itemUrl = insertResponse.substring(startIndex, endIndex);
|
||||
return itemUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts <code>DATA_ITEM</code> by making a POST request to
|
||||
* <code>ITEMS_FEED<code>.
|
||||
* @param token authentication token obtained using <code>authenticate</code>
|
||||
* @return the Google Base data API server's insert response
|
||||
* @throws IOException if an I/O exception occurs while creating/writing/
|
||||
* reading the request
|
||||
*/
|
||||
public String postItem(String token) throws IOException {
|
||||
return makeHttpRequest(token, ITEMS_FEED, DATA_ITEM, "POST",
|
||||
HttpURLConnection.HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates <code>NEW_DATA_ITEM</code> by making a PUT request to
|
||||
* <code>itemUrl</code>.
|
||||
*
|
||||
* @param token authentication token obtained using <code>authenticate</code>
|
||||
* @param itemUrl the identifier of the item to update, which has the form
|
||||
* <code>ITEMS_URL + "/itemId"</code>
|
||||
* @return the Google Base data API server's update response
|
||||
* @throws IOException if an I/O exception occurs while creating/writing/
|
||||
* reading the request
|
||||
*/
|
||||
public String updateItem(String token, String itemUrl)
|
||||
throws MalformedURLException, IOException {
|
||||
return makeHttpRequest(token, itemUrl, NEW_DATA_ITEM, "PUT",
|
||||
HttpURLConnection.HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an Http request to <code>url</code>, using <code>httpMethod</code>,
|
||||
* post <code>item</code> and return the response.
|
||||
*
|
||||
* @param token authentication token obtained using <code>authenticate</code>
|
||||
* @param url the identifier of the item to update, which has the form
|
||||
* <code>ITEMS_URL + "/itemId"</code>
|
||||
* @param item the item to be posted via the request
|
||||
* @param httpMethod the httpMethod to use for posting (should be PUT or POST)
|
||||
* @param expectedResponseCode the response code returned in case of a
|
||||
* successful operation
|
||||
* @return the Google Base data API update response
|
||||
* @throws IOException if an I/O exception occurs while
|
||||
* creating/writing/reading the request
|
||||
*/
|
||||
private String makeHttpRequest(String token, String url, String item,
|
||||
String httpMethod, int expectedResponseCode) throws IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection)(new URL(url)).openConnection() ;
|
||||
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
// Set the properties of the connection: the http request method, the
|
||||
// content type and the authorization header
|
||||
connection.setRequestMethod(httpMethod);
|
||||
connection.setRequestProperty("Content-Type", "application/atom+xml");
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
|
||||
// Post the data item
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(item.getBytes());
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode == expectedResponseCode) {
|
||||
return toString(connection.getInputStream());
|
||||
} else {
|
||||
throw new RuntimeException(toString(connection.getErrorStream()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes a HTTP POST request to the provided {@code url} given the provided
|
||||
* {@code parameters}. It returns the output from the POST handler as a
|
||||
* String object.
|
||||
*
|
||||
* @param url the URL to post the request
|
||||
* @return the output from the server
|
||||
* @throws IOException if an I/O exception occurs while
|
||||
* creating/writing/reading the request
|
||||
*/
|
||||
private String makeLoginRequest(URL url)
|
||||
throws IOException {
|
||||
// Create a login request. A login request is a POST request that looks like
|
||||
// POST /accounts/ClientLogin HTTP/1.0
|
||||
// Content-type: application/x-www-form-urlencoded
|
||||
// Email=johndoe@gmail.com&Passwd=north23AZ&service=gbase&source=Insert Example
|
||||
|
||||
// Open connection
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
|
||||
// Set properties of the connection
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoInput(true);
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("Content-Type",
|
||||
"application/x-www-form-urlencoded");
|
||||
|
||||
// Form the POST parameters
|
||||
StringBuilder content = new StringBuilder();
|
||||
content.append("Email=").append(URLEncoder.encode(EMAIL, "UTF-8"));
|
||||
content.append("&Passwd=").append(URLEncoder.encode(PASSWORD, "UTF-8"));
|
||||
content.append("&source=").append(URLEncoder.encode("Google Base data API example", "UTF-8"));
|
||||
content.append("&service=").append(URLEncoder.encode("gbase", "UTF-8"));
|
||||
|
||||
OutputStream outputStream = urlConnection.getOutputStream();
|
||||
outputStream.write(content.toString().getBytes("UTF-8"));
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = urlConnection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
inputStream = urlConnection.getInputStream();
|
||||
} else {
|
||||
inputStream = urlConnection.getErrorStream();
|
||||
}
|
||||
|
||||
return toString(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of the input stream to a <code>String<code>.
|
||||
*/
|
||||
private String toString(InputStream inputStream) throws IOException {
|
||||
String lineToRead;
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
if (inputStream != null) {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
||||
while (null != (lineToRead = reader.readLine())) {
|
||||
outputBuilder.append(lineToRead).append('\n');
|
||||
}
|
||||
}
|
||||
return outputBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,641 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta name="generator" content=
|
||||
"HTML Tidy for Linux/x86 (vers 1st November 2003), see www.w3.org" />
|
||||
|
||||
<title>Google Base data API: Sample Applications</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<P>Sample standalone applications accessing Google Base data API feeds</P>
|
||||
|
||||
<h2><a name="intro" id="intro"></a>Introduction</h2>The Google Base data Java
|
||||
<a href='http://code.google.com/apis/base/sample-apps.html'>Client
|
||||
Library</a> offers a nice object oriented abstraction for accessing the
|
||||
Google Base data API. However, if you prefer to interact with the Google Base
|
||||
data API servers directly, here are a few examples that will start you up.
|
||||
|
||||
<p>This document assumes you know Java programming (including some basic
|
||||
knowledge of Http connections and SAX parsers) and that you are familiar with
|
||||
<a href="http://code.google.com/apis/base/concepts.html">Google Base
|
||||
concepts</a>. You need to understand the following concepts before you can
|
||||
take full advantage of the sample applications:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href=
|
||||
"http://code.google.com/apis/base/attrs-queries.html#queries">queries</a></li>
|
||||
|
||||
<li><a href=
|
||||
"http://code.google.com/apis/base/attrs-queries.html#gbItemTypes">item
|
||||
types</a></li>
|
||||
|
||||
<li><a href=
|
||||
"http://code.google.com/apis/base/attrs-queries.html#gbAttrs">attributes</a></li>
|
||||
</ul>
|
||||
|
||||
<p>This tutorial consists of stepping through 5 examples. The first example
|
||||
shows how to connect to a Google Base data API feed and query data. The
|
||||
second example extends this by showing how to parse the result and extract
|
||||
data of interest from the feed. The third example introduces authentication
|
||||
and demonstrates how to display your own items, rather than querying
|
||||
snippets. The fourth example demonstrates how to insert your own item into
|
||||
Google Base, while the last example shows how to update a previously inserted
|
||||
item.</p>
|
||||
|
||||
<h2><a name="queryExample1" id="queryExample1"></a>Query Example 1 - query
|
||||
the Google Base data API and display the result</h2>
|
||||
|
||||
<p><code>QueryExample1</code> is a simple Java application that runs from the
|
||||
command line. It performs an unauthenticated query on the public <a href=
|
||||
'http://code.google.com/apis/base/snippets-feed.html'>snippets feed</a>
|
||||
(<code>/feeds/snippets</code>) and it dumps the query response to the console
|
||||
(it won't look pretty!).</p>
|
||||
|
||||
<h3><a name="QE1run" id="QE1run"></a>Running
|
||||
<code>QueryExample1</code></h3>Edit QueryExample1.java and fill in the
|
||||
|
||||
Compile and run the example using your favorite editor, or using the
|
||||
command line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/QueryExample1.java
|
||||
java sample.gbase/basic/QueryExample1
|
||||
|
||||
</pre>The output (conveniently formatted) will look like:
|
||||
<pre>
|
||||
<feed>
|
||||
<id>http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets</id>
|
||||
<updated>2006-08-22T14:14:11.984Z</updated>
|
||||
<title type="text">Items matching query: cars [item type : products]</title>
|
||||
<link rel="alternate" type="text/html" href="http://base.google.com"/>
|
||||
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets"/>
|
||||
<link rel="self" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets?key=ABQ...9P2Y4A&bq=cars+%5Bitem+type+%3A+products%5D"/>
|
||||
<link rel="next" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets?start-index=26&max-results=25&key=ABQ...9P2Y4A&bq=cars+%5Bitem+type+%3A+products%5D"/>
|
||||
<generator version="1.0" uri="http://base.google.com">GoogleBase</generator>
|
||||
<openSearch:totalResults>278120</openSearch:totalResults>
|
||||
<openSearch:itemsPerPage>25</openSearch:itemsPerPage>
|
||||
<entry>
|
||||
<id>http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets/10062394959501653657</id>
|
||||
<published>2006-06-30T21:45:12.000Z</published>
|
||||
<updated>2006-07-28T00:58:14.000Z</updated>
|
||||
...
|
||||
|
||||
</pre>
|
||||
|
||||
<h3><a name="QE1stepThru" id="QE1stepThru"></a>Stepping through the
|
||||
<code>QueryExample1</code> code</h3>
|
||||
|
||||
<p>At the very beginning we define the url of the feed we are connecting to
|
||||
and the query that we are going to run:</p>
|
||||
<pre>
|
||||
private static final String SNIPPETS_FEED = "http://base.google.com/base/feeds/snippets";
|
||||
|
||||
private static final String QUERY = "cars [item type : products]";
|
||||
|
||||
</pre>Feel free to change the query to a more relevant or interesting one. Take
|
||||
a look at the <a href=
|
||||
'http://code.google.com/apis/base/query-lang-spec.htm'>Google Base Query
|
||||
Language</a> description if you need some inspiration.
|
||||
|
||||
<p>After opening a connection on the snippets feed, we grab the connection's
|
||||
input stream, and dump its content to the output, character by character:</p>
|
||||
<pre>
|
||||
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
|
||||
InputStream inputStream = httpConnection.getInputStream();
|
||||
|
||||
int ch;
|
||||
while ((ch=inputStream.read()) > 0) {
|
||||
System.out.print((char)ch);
|
||||
}
|
||||
|
||||
</pre>In the <code>main</code> method, all we do is create a
|
||||
<code>QueryExample1</code> instance, and invoke its <code>displayItems</code>
|
||||
method:
|
||||
<pre>
|
||||
public static void main(String[] args) throws IOException, SAXException,
|
||||
ParserConfigurationException {
|
||||
new QueryExample1().displayItems();
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2><a name="queryExample2" id="queryExample2"></a>Query Example 2 - query
|
||||
the Google Base data API, parse the result and display the titles of returned
|
||||
data items</h2>
|
||||
|
||||
<p>One major problem with <code>QueryExample1</code> is that it simply dumps
|
||||
the items returned for the query to the console, and the result is barely
|
||||
readable. In any real life application the query result would need to be
|
||||
parsed, interpreted and relevant information should be extracted and
|
||||
displayed to the user. In <code>QueryExample2</code> we demonstrate a
|
||||
possible way of doing this by using a SAX parser to extract each data item's
|
||||
title from the result, and display it to the console. Some very basic
|
||||
understanding of how SAX parsers work is necessary in order to fully
|
||||
understand this example.</p>
|
||||
|
||||
<p>One might argue that for this task we don't even need a SAX parser. We
|
||||
could just search for all <code><title></code> tags in the result and
|
||||
display the characters that they enclose. Unfortunately, that wouldn't work,
|
||||
as the Atom response also has a <code><title></code> tag, which is the
|
||||
title of the feed:</p>
|
||||
<pre>
|
||||
<feed>
|
||||
...
|
||||
<title type="text">Items matching query: cars [item type : products]</title>
|
||||
...
|
||||
<entry>
|
||||
...
|
||||
<title type='text'>Great care for sale</title>
|
||||
...
|
||||
|
||||
</pre>Atom does not mandate that the feed's <code><title></code> tag
|
||||
should appear at a specific position inside the feed, so we need to make sure
|
||||
we only display the <code><title></code> tags which are sub-elements of
|
||||
an <code><entry></code> tag.<br />
|
||||
<br />
|
||||
|
||||
<h3><a name="QE2run" id=
|
||||
"QE2run"></a>Running<code>QueryExample2</code></h3>
|
||||
Compile and run the example using your favorite editor, or using the
|
||||
command line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/QueryExample2.java
|
||||
java sample.gbase/basic/QueryExample2
|
||||
|
||||
</pre>The output will look like:
|
||||
<pre>
|
||||
Item 1: Johnny Lightning MUSCLE CARS R8 1967 Chevelle SS
|
||||
Item 2: Johnny Lightning MUSCLE CARS USA 2005 Ford GT
|
||||
...
|
||||
Item 25: The Cars movie Hinged tool Box Toy Organize lunch RARE
|
||||
|
||||
</pre>
|
||||
|
||||
<ul class="noindent"></ul>
|
||||
|
||||
<h3><a name="QE2stepThru" id="QE2stepThru"></a>Stepping through the
|
||||
<code>QueryExample2</code> code</h3>
|
||||
|
||||
<p>Just as in the previous example, we first send the query to the Google
|
||||
Base data API server, and obtain an <code>inputStream</code> containing the
|
||||
response:</p>
|
||||
<pre>
|
||||
URL url = new URL(SNIPPETS_FEED + "?bq=" +
|
||||
URLEncoder.encode(QUERY, "UTF-8"));
|
||||
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
|
||||
InputStream inputStream = httpConnection.getInputStream();
|
||||
</pre>
|
||||
|
||||
<p>We then use a standard SAX parser to parse the result. We obtain a
|
||||
SAXParser instance using a SAXParserFactory:</p>
|
||||
<pre>
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
</pre>We then parse the result <code>inputStream</code> using
|
||||
<code>DisplayTitlesHandler</code>, our custom SAX event handler:
|
||||
<pre>
|
||||
parser.parse(inputStream, new DisplayTitlesHandler());
|
||||
</pre>
|
||||
|
||||
<p><code>DisplayTitlesHandler</code> is derived from the no-op SAX parser,
|
||||
<code>org.xml.sax.helpers.DefaultHandler</code>. The logic inside
|
||||
<code>DisplayTitlesHandler</code> is pretty simple: we keep a stack of the
|
||||
currently open XML tags and print all character data when we are inside a
|
||||
<code><title></code> tag with a <code><entry></code> parent. The
|
||||
<code>insideEntryTitle</code> flag is turned on each time we are inside a
|
||||
<code><entry><title></code> pair:</p>
|
||||
<pre>
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if (qName.equals("title") && xmlTags.peek().equals("entry")) {
|
||||
insideEntryTitle = true;
|
||||
System.out.print("Item " + ++itemNo + ": ");
|
||||
}
|
||||
xmlTags.push(qName);
|
||||
}
|
||||
</pre>Since <code>startElement</code> is invoked each time the SAX parser
|
||||
encounters an opening XML tag, we switch on <code>insideEntryTitle</code> only
|
||||
if the currently parsed opening tag is <code><title></code> and the tag
|
||||
on the top of the stack is <code><entry></code> . We are also printing
|
||||
here the "Item no: " messages, rather than in the <code>characters</code>
|
||||
method, as <code>characters</code> can be called multiple times for different
|
||||
chunks of the title's character data.<br />
|
||||
<br />
|
||||
The <code>endElement</code> method is invoked each time an XML tag closes.
|
||||
All we need to do here is to remove the closing XML tag from the stack and,
|
||||
in case the removed XML tag was an entry's title, flip
|
||||
<code>insideEntryTitle</code> to false and go to a new line in the console,
|
||||
in preparation for printing out the next title:
|
||||
<pre>
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
xmlTags.pop();
|
||||
if (insideEntryTitle) {
|
||||
insideEntryTitle = false;
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
</pre>The <code>characters</code> method is invoked when the parser encounters
|
||||
character data inside an XML element. If we are inside the
|
||||
<code><title></code> tag, that is, if the <code>insideEntryTitle</code>
|
||||
flag is on, we display the current characters: <code>length</code> characters
|
||||
from the <code>ch</code> array, starting with <code>start</code>. As noted
|
||||
earlier, we can't use <code>println</code> here to get to a new line, as <code>
|
||||
characters</code> can be invoked multiple times for different chunks of the
|
||||
same title:
|
||||
<pre>
|
||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||
if (insideEntryTitle) {
|
||||
System.out.print(new String(ch, start, length));
|
||||
}
|
||||
}
|
||||
</pre>In the <code>main</code> method, all we do is create a
|
||||
<code>QueryExample2</code> instance, and invoke its <code>displayItems</code>
|
||||
method:
|
||||
<pre>
|
||||
public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException {
|
||||
new QueryExample2().displayItems();
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2><a name="queryExample3" id="queryExample3"></a>Query Example 3 -
|
||||
Introducing authentication. Querying your own items using the items
|
||||
feed.</h2>
|
||||
|
||||
<p>The previous two examples demonstrated how to query the Google Base data
|
||||
API public feeds, also known as snippets. Snippets are accessible to anyone
|
||||
without authentication. The downside is that snippets are the "indexable"
|
||||
version of the items and can slightly differ from the original items. It can
|
||||
also take a while for a newly inserted or updated item to show up in the
|
||||
snippets feed. Therefore, if you need to change your own items, the Google
|
||||
Base data API server exposes the customer-specific "items" feed. This feed is
|
||||
very similar to the "snippets" feed, except that:</p>
|
||||
|
||||
<ul>
|
||||
<li>it only allows you to query your own items, and thus you need to
|
||||
authenticate in order to access it</li>
|
||||
|
||||
<li>there is no delay between updating an item and being able to display it
|
||||
in the "items" feed</li>
|
||||
</ul>Read <a href='http://code.google.com/apis/base/items-feed.html'>here</a>
|
||||
more about the characteristics of the "items" feed. You will need a Google
|
||||
Account email and password in order to run this example. If you don't have a
|
||||
Google Account, sign up for one <a href=
|
||||
'https://www.google.com/accounts/NewAccount'>here</a>.
|
||||
|
||||
<p>QueryExample3 connects to your "items" feed, and dumps your items to the
|
||||
console, just as in <code>QueryExample1</code>. If you don't have any items
|
||||
in Google Base yet, use <a href='#insertRun'>InsertExample</a> to insert one,
|
||||
or go to the <a href='http://base.google.com/base/step1offer?hl=en_US'>Google
|
||||
Base Provider Frontenac</a> and insert one.</p>
|
||||
|
||||
<h3><a name="QE3run" id="QE3run"></a>Running <code>QueryExample3</code></h3>
|
||||
|
||||
<ol>
|
||||
<li>Edit QueryExample3.java and make the following changes:
|
||||
|
||||
<ul>
|
||||
<li>Enter your Google Accounts email address and your password in the
|
||||
<code>EMAIL</code> and <code>PASSWORD</code> static strings:
|
||||
<pre>
|
||||
private static final String EMAIL = "";
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Compile and run the example using your favorite editor, or the command
|
||||
line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/QueryExample3.java
|
||||
java sample.gbase/basic/QueryExample3
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>The output will look like:
|
||||
<pre>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<feed>
|
||||
<id>http://base.google.com/base/feeds/items</id>
|
||||
<updated>2006-08-22T12:00:00.000Z</updated>
|
||||
<title type="text">Items matching query: [customer id(int):1870031]</title>
|
||||
...
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h3><a name="QE3stepThru" id="QE3stepThru"></a>Stepping through the
|
||||
<code>QueryExample3</code> code</h3>
|
||||
|
||||
<p>As opposed to the previous examples, here we need to obtain an
|
||||
authorization token by authenticating with the Google Accounts server. We
|
||||
then use this authorization token to invoke <code>displayMyItems</code>:</p>
|
||||
<pre>
|
||||
public static void main(String[] args) throws IOException {
|
||||
QueryExample3 queryExample = new QueryExample3();
|
||||
String token = queryExample.authenticate();
|
||||
new QueryExample3().displayMyItems(token);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>We authenticate using <a href=
|
||||
'http://code.google.com/apis/accounts/AuthForInstalledApps.html'>authentication
|
||||
for installed applications</a>. The authentication procedure is simple. We
|
||||
make a POST request to <code>AUTHENTICATION_URL</code>:</p>
|
||||
<pre>
|
||||
private static final String AUTHENTICATION_URL = "https://www.google.com/accounts/ClientLogin";
|
||||
</pre>The POST request is constructed in <code>makeLoginRequest</code>, and it
|
||||
looks like this:
|
||||
<pre>
|
||||
// POST /accounts/ClientLogin HTTP/1.0
|
||||
// Content-type: application/x-www-form-urlencoded
|
||||
// Email=johndoe@gmail.com&Passwd=north23AZ&service=gbase&source=Insert Example
|
||||
</pre><code>makeLoginRequest</code> sends the request to the Google Accounts
|
||||
server and returns the response as a <code>String</code>. A successful response
|
||||
will have the following structure:
|
||||
<pre>
|
||||
// HTTP/1.0 200 OK
|
||||
// Server: GFE/1.3
|
||||
// Content-Type: text/plain
|
||||
// SID=DQAAAGgA...7Zg8CTN
|
||||
// LSID=DQAAAGsA...lk8BBbG
|
||||
// Auth=DQAAAGgA...dk3fA5N
|
||||
</pre><code>authenticate</code> first obtains the authentication response from
|
||||
<code>makeLoginRequest</code> and stores it in <code>postOutput</code>:
|
||||
<pre>
|
||||
String postOutput = null;
|
||||
try {
|
||||
URL url = new URL(AUTHENTICATION_URL);
|
||||
postOutput = makeLoginRequest(url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Authentication error: " + e.toString());
|
||||
}
|
||||
</pre>It then tokenizes <code>postOutput</code>, and returns the next token
|
||||
after "Auth", or <code>null</code> if the token is not found:
|
||||
<pre>
|
||||
StringTokenizer tokenizer = new StringTokenizer(postOutput, "=\n ");
|
||||
String token = null;
|
||||
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
if (tokenizer.nextToken().equals("Auth")) {
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
token = tokenizer.nextToken();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
</pre><br />
|
||||
<br />
|
||||
|
||||
<p>The items are displayed in <code>displayMyItems</code>, which is very
|
||||
similar to <code>displayItems</code> in QueryExample1, except that it injects
|
||||
the authorization token in the Http header (as in this example):</p>
|
||||
<pre>
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
</pre>
|
||||
|
||||
<h2><a name="insertExample" id="insertExample"></a>Insert Example - Adding
|
||||
your own item to Google Base.</h2>
|
||||
|
||||
<p>The previous examples demonstrated how to query the Google Base data API
|
||||
server, both for snippets (unauthenticated feeds) and for items
|
||||
(authenticated feeds, containing a specific customer's items). Let's
|
||||
demonstrate now how to add to Google Base all the cool stuff you have, so
|
||||
that the world can see it. Again, you will need a Google Account email and
|
||||
password in order to run this example. If you don't have a Google Account,
|
||||
sign up for one <a href=
|
||||
'https://www.google.com/accounts/NewAccount'>here</a>.</p>
|
||||
|
||||
<p>In this example we will connect to your "items" feed, and do an Http POST
|
||||
operation (as opposed to GET, used for querying) to add a new item. The item
|
||||
to be added is encoded in Atom format, and is defined a <code>String</code>
|
||||
constant:</p>
|
||||
<pre>
|
||||
private static final String DATA_ITEM =
|
||||
"<?xml version=\'1.0\'?>\n" +
|
||||
"<entry xmlns=\'http://www.w3.org/2005/Atom\' xmlns:g=\'http://base.google.com/ns/1.0\'>\n" +
|
||||
" <category scheme=\'http://base.google.com/categories/itemtypes\' term=\'Products\'/>\n" +
|
||||
" <g:item_type type=\'text\'>Products</g:item_type>\n" +
|
||||
" <title type=\'text\'>My cool car is for sale</title>" +
|
||||
" <content type=\'xhtml\'>Light pink, yellow seats.</content>" +
|
||||
"</entry>";
|
||||
</pre>It's a very simple item, consisting only of an item type ("products", in
|
||||
our case), a title and a content (description). Feel free to change these
|
||||
fields to contain your personalized items or to add new attributes and labels
|
||||
(use the responses dumped by <code>QueryExample1</code> and
|
||||
<code>QueryExample3</code> as an inspiration for adding new attributes).
|
||||
|
||||
<h3><a name="insertRun" id="insertRun"></a>Running
|
||||
<code>InsertExample</code></h3>
|
||||
|
||||
<ol>
|
||||
<li>Edit InsertExample.java and make the following changes:
|
||||
|
||||
<ul>
|
||||
<li>Enter your Google Accounts email address and your password in the
|
||||
<code>EMAIL</code> and <code>PASSWORD</code> static strings:
|
||||
<pre>
|
||||
private static final String EMAIL = "";
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Compile and run the example using your favorite editor, or the command
|
||||
line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/InsertExample.java
|
||||
java sample.gbase/basic/InsertExample
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>The output will look like:
|
||||
<pre>
|
||||
Obtained authorization token: DQAAAGgA...dk3fA5N
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry>
|
||||
<id>http://base.google.com/base/feeds/items/16024998325761524417</id>
|
||||
<published>2006-08-23T15:18:55.184Z</published>
|
||||
<updated>2006-08-23T15:18:55.184Z</updated>
|
||||
<category scheme="http://base.google.com/categories/itemtypes" term="Products"/>
|
||||
<title type="text">My cool car is for sale</title>
|
||||
<content type="xhtml">Light pink, yellow seats.</content>
|
||||
<link rel="self" type="application/atom+xml" href="http://base.google.com/base/feeds/items/16024998325761524417"/>
|
||||
<link rel="edit" type="application/atom+xml" href="http://base.google.com/base/feeds/items/16024998325761524417"/>
|
||||
<g:item_type type="text">Products</g:item_type>
|
||||
</entry>
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h3><a name="InsertStepThru" id="InsertStepThru"></a>Stepping through the
|
||||
<code>InsertExample</code> code</h3>
|
||||
|
||||
<p>We use the same feed as in QueryExample3.java to insert the item:</p>
|
||||
<pre>
|
||||
private static final String ITEMS_FEED = "http://base.google.com/base/feeds/items";
|
||||
</pre>Authentication is also performed as in <a href=
|
||||
'#QE3stepThru'>QueryExample3</a>, using <code>makeLoginRequest</code> to
|
||||
request an authorization token and <code>authenticate</code> to parse the
|
||||
authentication response. The insertion of the new data item is done in
|
||||
<code>postItem</code>, which connects to the items feed:
|
||||
<pre>
|
||||
HttpURLConnection connection = (HttpURLConnection)(new URL(ITEMS_FEED)).openConnection();
|
||||
</pre>Once the connection is created, we need to set its properties: the Http
|
||||
request method, the content type of the information that is being posted, the
|
||||
authorization header:
|
||||
<pre>
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/atom+xml");
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
</pre>We then obtain the output stream of the connection and dump
|
||||
<code>DATA_ITEM</code> into it:
|
||||
<pre>
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(DATA_ITEM.getBytes());
|
||||
outputStream.close();
|
||||
</pre>The rest of the method is already familiar: we obtain the response code
|
||||
and print out to the console the contents of the input stream corresponding to
|
||||
the response code.<br />
|
||||
<br />
|
||||
|
||||
<h2><a name="updateExample" id="updateExample"></a>Update Example - Modifying
|
||||
your Google Base items.</h2>
|
||||
|
||||
<p>The previous examples demonstrated how to query the Google Base data API
|
||||
server both for authenticated and unauthenticated feeds and how to insert a
|
||||
new item. We will combine this knowledge in order to demonstrate how to
|
||||
update an already existing item. Again, you will need a Google Account email
|
||||
and password in order to run this example. If you don't have a Google
|
||||
Account, sign up for one <a href=
|
||||
'https://www.google.com/accounts/NewAccount'>here</a>. This example does not
|
||||
introduce important new concepts, but rather uses all the essentials that
|
||||
have been presented in the previous examples: we will authenticate, insert an
|
||||
item, and then update the inserted item by adding a new label to it.</p>
|
||||
|
||||
<h3><a name="updateRun" id="updateRun"></a>Running
|
||||
<code>UpdateExample</code></h3>
|
||||
|
||||
<ol>
|
||||
<li>Edit UpdateExample.java and make the following changes:
|
||||
|
||||
<ul>
|
||||
<li>Enter your Google Accounts email address and your password in the
|
||||
<code>EMAIL</code> and <code>PASSWORD</code> static strings:
|
||||
<pre>
|
||||
private static final String EMAIL = "";
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Compile and run the example using your favorite editor, or the command
|
||||
line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/UpdateExample.java
|
||||
java sample.gbase/basic/UpdateExample
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>The output will look like:
|
||||
<pre>
|
||||
Obtained authorization token: DQAAAGgA...dk3fA5N
|
||||
Posting item:
|
||||
<?xml version='1.0'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:g='http://base.google.com/ns/1.0'>
|
||||
<category scheme='http://base.google.com/categories/itemtypes' term='Products'/>
|
||||
<g:item_type type='text'>Products</g:item_type>
|
||||
<title type='text'>My cool car is for sale</title>
|
||||
<content type='xhtml'>Light pink, yellow seats.</content>
|
||||
</entry>
|
||||
|
||||
Updating item: http://base.google.com/base/feeds/items/18020038538902937385
|
||||
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry>
|
||||
<id>http://base.google.com/base/feeds/items/18020038538902937385</id>
|
||||
<updated>2006-08-23T16:20:21.601Z</updated>
|
||||
<category scheme="http://base.google.com/categories/itemtypes" term="Products"/>
|
||||
<title type="text">My cool car is for sale</title>
|
||||
<content type="xhtml">Light pink, yellow seats.</content>
|
||||
<link rel="self" type="application/atom+xml" href="http://base.google.com/base/feeds/items/18020038538902937385"/>
|
||||
<link rel="edit" type="application/atom+xml" href="http://base.google.com/base/feeds/items/18020038538902937385"/>
|
||||
<g:item_type type="text">Products</g:item_type>
|
||||
</entry>
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h3><a name="UpdateStepThru" id="UpdateStepThru"></a>Stepping through the
|
||||
<code>UpdateExample</code> code</h3>
|
||||
|
||||
<p>The <code>main</code> method of <code>UpdateExample</code> provides a good
|
||||
outline of the example's structure:</p>
|
||||
<pre>
|
||||
public static void main(String[] args) throws MalformedURLException, IOException {
|
||||
UpdateExample updateExample = new UpdateExample();
|
||||
String token = updateExample.authenticate();
|
||||
System.out.println("Obtained authorization token: " + token);
|
||||
|
||||
System.out.println("Posting item:\n" + DATA_ITEM);
|
||||
String itemUrl = updateExample.extractItemUrlFromResponse(
|
||||
updateExample.postItem(token));
|
||||
|
||||
System.out.println("Updating item: " + itemUrl);
|
||||
String updateResponse = updateExample.updateItem(token, itemUrl);
|
||||
System.out.println(updateResponse);
|
||||
}
|
||||
</pre>Just like in the previous examples, we start by authenticating and
|
||||
obtaining an authorization token using the <code>authenticate</code> method:
|
||||
<pre>
|
||||
String token = updateExample.authenticate();
|
||||
</pre>We then insert <code>DATA_ITEM</code> using <code>postItem</code>:
|
||||
<pre>
|
||||
String itemUrl = updateExample.extractItemUrlFromResponse(
|
||||
updateExample.postItem(token));
|
||||
</pre>In the line above, we pass the output of the post operation
|
||||
to<code>extractItemUrlFromResponse</code> (rather than dumping it out to the
|
||||
console), which extracts the inserted item's id:
|
||||
<pre>
|
||||
<id>http://base.google.com/base/feeds/items/18020038538902937385</id>
|
||||
</pre>We assume that the item's id is surrounded by the first
|
||||
<id></id> tags; this is true for the Google Base data API servers,
|
||||
but it's not enforced by the Atom protocol. See how the title gets parsed in
|
||||
<a href='#QE2stepThru'>Query Example 2</a>, for a superior approach on parsing
|
||||
the item's title.
|
||||
|
||||
<p>Once <code>DATA_ITEM</code> is successfully inserted, we replace it with
|
||||
<code>NEW_DATA_ITEM</code> using <code>updateItem</code>. Updating an item is
|
||||
very similar to inserting a new one - in fact so similar that both operations
|
||||
can be performed by the same method: <code>makeHttpRequest</code>.
|
||||
<code>makeHttpRequest</code> receives as parameters the authorization token,
|
||||
the url to connect to, the item to be inserted or posted, the http method to
|
||||
use (this will be POST for inserting, and PUT for deleting) and the response
|
||||
code to expect in case of a successful operation (HTTP_CREATED in case of
|
||||
insert, HTTP_OK in case of update). Thus, <code>postItem</code> will contain
|
||||
a simple invocation to <code>makeHttpRequest</code>:</p>
|
||||
<pre>
|
||||
public String postItem(String token) throws IOException {
|
||||
return makeHttpRequest(token, ITEMS_FEED, NEW_DATA_ITEM, "POST", HttpURLConnection.HTTP_CREATED);
|
||||
}
|
||||
|
||||
</pre>Similarly, <code>updateItem</code> invokes <code>makeHttpRequest</code>
|
||||
with slightly different parameters:
|
||||
<pre>
|
||||
public String updateItem(String token, String itemUrl) throws MalformedURLException, IOException {
|
||||
return makeHttpRequest(token, itemUrl, NEW_DATA_ITEM, "PUT", HttpURLConnection.HTTP_OK);
|
||||
}
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
/**
|
||||
* Execute batch operations.
|
||||
* This command is called from {@link sample.gbase.cmdline.CustomerTool}.
|
||||
*/
|
||||
class BatchCommand extends Command {
|
||||
|
||||
public void execute() throws Exception {
|
||||
|
||||
Service service = createService();
|
||||
Service.GDataRequest request =
|
||||
service.createBatchRequest(
|
||||
fixEditUrl(urlFactory.getItemsBatchFeedURL()));
|
||||
|
||||
inputRawRequest(request);
|
||||
// Send the request (HTTP POST)
|
||||
request.execute();
|
||||
|
||||
// Save the response
|
||||
outputRawResponse(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.gdata.client.Service;
|
||||
import com.google.gdata.util.AuthenticationException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
|
||||
/**
|
||||
* One command that is part of CustomerTool.
|
||||
* This class contains code that is common to all
|
||||
* commands. It deals, in particular, with the creation
|
||||
* of the GData service object.
|
||||
*/
|
||||
abstract class Command {
|
||||
|
||||
/**
|
||||
* URL of the google authentication server to use for log in.
|
||||
*/
|
||||
private static final String DEFAULT_AUTH_HOSTNAME = "www.google.com";
|
||||
|
||||
/**
|
||||
* Username for google base (e-mail address).
|
||||
*/
|
||||
protected String username;
|
||||
|
||||
/**
|
||||
* The user's password.
|
||||
*/
|
||||
protected String password;
|
||||
|
||||
/**
|
||||
* Base url of the google base server.
|
||||
*/
|
||||
protected FeedURLFactory urlFactory = FeedURLFactory.getDefault();
|
||||
|
||||
/**
|
||||
* Base url of the google authentication server.
|
||||
*/
|
||||
private String authenticationServer = DEFAULT_AUTH_HOSTNAME;
|
||||
|
||||
/**
|
||||
* Protocol (http or https) to use to connect to the authentication server.
|
||||
*/
|
||||
private String authenticationProtocol = "https";
|
||||
|
||||
/**
|
||||
* Developer key used for identification against the Google Base data API
|
||||
* servers.
|
||||
*/
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* Enables dry-run mode for edit operations.
|
||||
*/
|
||||
private boolean dryRun;
|
||||
|
||||
/**
|
||||
* Executes the command.
|
||||
*
|
||||
* Call this method only after setting the username and password.
|
||||
*/
|
||||
public abstract void execute() throws Exception;
|
||||
|
||||
/**
|
||||
* Sets the username, which is required for {@link #execute()} to work.
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password, which is required for {@link #execute()} to work.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Url of the google base server to connect to.
|
||||
*/
|
||||
public void setGoogleBaseServerUrl(String url) throws MalformedURLException {
|
||||
this.urlFactory = new FeedURLFactory(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the google authentication server to connect to.
|
||||
*/
|
||||
public void setAuthenticationServerUrl(String urlString)
|
||||
throws MalformedURLException {
|
||||
URL url = new URL(urlString);
|
||||
this.authenticationProtocol = url.getProtocol();
|
||||
this.authenticationServer = url.getHost();
|
||||
if (url.getPort() != -1) {
|
||||
this.authenticationServer += ":" + url.getPort();
|
||||
}
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure username and password have been set.
|
||||
*/
|
||||
public boolean hasAllIdentificationInformation() {
|
||||
return username != null && password != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the service and sets the username and password for
|
||||
* authentication.
|
||||
*
|
||||
* @return the GData service object to use
|
||||
* @throws com.google.gdata.util.AuthenticationException
|
||||
* if authentication failed
|
||||
*/
|
||||
protected GoogleBaseService createService()
|
||||
throws AuthenticationException {
|
||||
GoogleBaseService service =
|
||||
new GoogleBaseService("Google.-CustomerTool-1.0",
|
||||
key,
|
||||
authenticationProtocol,
|
||||
authenticationServer);
|
||||
service.setUserCredentials(username, password);
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL of the customer feed.
|
||||
*
|
||||
* The feed contains only the items uploaded by this
|
||||
* specific customer. This is also the feed that is
|
||||
* used to upload customer data.
|
||||
*
|
||||
* @return the url to the customer feed
|
||||
*/
|
||||
protected URL getCustomerFeedURL() throws MalformedURLException {
|
||||
return urlFactory.getItemsFeedURL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the response (XML feed) to standard output.
|
||||
*/
|
||||
protected void outputRawResponse(Service.GDataRequest request)
|
||||
throws IOException {
|
||||
InputStream responseStream = request.getResponseStream();
|
||||
try {
|
||||
copyStreamContent(responseStream, System.out);
|
||||
} finally {
|
||||
responseStream.close();
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from in input stream and write it into an
|
||||
* output stream.
|
||||
*/
|
||||
protected void copyStreamContent(InputStream in, OutputStream out)
|
||||
throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
int l;
|
||||
while ( (l=in.read(buffer)) > 0 ) {
|
||||
out.write(buffer, 0, l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from standard input and use it in the request.
|
||||
*
|
||||
* The data must be the XML feed appropriate for the command.
|
||||
* For update, get or insert it should be one Atom XML entry.
|
||||
*/
|
||||
protected void inputRawRequest(Service.GDataRequest request)
|
||||
throws IOException {
|
||||
OutputStream outputStream = request.getRequestStream();
|
||||
try {
|
||||
copyStreamContent(System.in, outputStream);
|
||||
} finally {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the command in dry-run mode, in which nothing will
|
||||
* really happen on the server.
|
||||
*
|
||||
* @param dryRun
|
||||
*/
|
||||
public void setDryRun(boolean dryRun) {
|
||||
this.dryRun = dryRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an edit URL from a string, adding the dry-run parameter
|
||||
* if necessary.
|
||||
*
|
||||
* This method is not applicable to query URLs, for which the dry-run
|
||||
* parameter is not supported.
|
||||
*
|
||||
* @param url the original url
|
||||
* @return the same URL with maybe some parameters
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
protected URL fixEditUrl(URL url) throws MalformedURLException {
|
||||
return fixEditUrl(url.toExternalForm());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an edit URL from a string, adding the dry-run parameter
|
||||
* if necessary.
|
||||
*
|
||||
* This method is not applicable to query URLs, for which the dry-run
|
||||
* parameter is not supported.
|
||||
*
|
||||
* @param url the original url, as a string
|
||||
* @return the same URL with maybe some parameters
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
protected URL fixEditUrl(String url) throws MalformedURLException {
|
||||
if (dryRun) {
|
||||
char separator = url.contains("?") ? '&' : '?';
|
||||
url = url + separator + "dry-run=true";
|
||||
}
|
||||
return new URL(url);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Creates and initializes commands given command-line
|
||||
* arguments.
|
||||
*
|
||||
* This class is totally useless if you want to understand
|
||||
* how the API works. All it does is parse command-line
|
||||
* arguments and call some setters on the different <code>*Command</code>
|
||||
* objects. Have a look at the <code>*Command</code> classes instead.
|
||||
*/
|
||||
class CommandFactory {
|
||||
|
||||
/**
|
||||
* All commands available in this system, for producing error messages.
|
||||
*/
|
||||
private static final String ALL_COMMANDS =
|
||||
"query, get, update, insert, delete, batch";
|
||||
|
||||
/**
|
||||
* Creates a {@link Command} object and initializes it using
|
||||
* command-line arguments.
|
||||
*
|
||||
* @param args command-line arguments
|
||||
* @return a new Command object, properly initialized and ready to use
|
||||
*/
|
||||
public static Command createCommand(String[] args) {
|
||||
if (args.length == 0) {
|
||||
throw error("Please give first the command you want to run (" +
|
||||
ALL_COMMANDS + ") then the parameters for that " +
|
||||
"command.");
|
||||
}
|
||||
|
||||
String commandName = args[0];
|
||||
if ("query".equals(commandName)) {
|
||||
return createQueryCommand(args);
|
||||
} else if("insert".equals(commandName)) {
|
||||
return createInsertCommand(args);
|
||||
} else if("update".equals(commandName)) {
|
||||
return createUpdateCommand(args);
|
||||
} else if("delete".equals(commandName)) {
|
||||
return createDeleteCommand(args);
|
||||
} else if("get".equals(commandName)) {
|
||||
return createGetCommand(args);
|
||||
} else if("batch".equals(commandName)) {
|
||||
return createBatchCommand(args);
|
||||
} else if("query-media".equals(commandName)) {
|
||||
return createQueryMediaCommand(args);
|
||||
} else if("insert-media".equals(commandName)) {
|
||||
return createInsertMediaCommand(args);
|
||||
} else if("update-media".equals(commandName)) {
|
||||
return createUpdateMediaCommand(args);
|
||||
} else if("delete-media".equals(commandName)) {
|
||||
return createDeleteMediaCommand(args);
|
||||
} else if("get-media".equals(commandName)) {
|
||||
return createGetMediaCommand(args);
|
||||
} else {
|
||||
throw error("Unknown command: " + commandName +
|
||||
". Available commands: " + ALL_COMMANDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link QueryCommand}.
|
||||
*/
|
||||
private static Command createQueryCommand(String[] args) {
|
||||
QueryCommand command = new QueryCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
|
||||
if (args.length == 1) {
|
||||
command.setQuery(args[0]);
|
||||
} else if (args.length > 1) {
|
||||
throw error("Expected at most one query argument, got " + args.length);
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link InsertCommand}.
|
||||
*/
|
||||
private static Command createInsertCommand(String[] args) {
|
||||
InsertCommand command = new InsertCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
expectNoMoreArguments(args);
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link BatchCommand}.
|
||||
*/
|
||||
private static Command createBatchCommand(String[] args) {
|
||||
BatchCommand command = new BatchCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
expectNoMoreArguments(args);
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link UpdateCommand}.
|
||||
*/
|
||||
private static Command createUpdateCommand(String[] args) {
|
||||
UpdateCommand command = new UpdateCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
|
||||
command.setItemId(getItemId(args));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link DeleteCommand}.
|
||||
*/
|
||||
private static Command createDeleteCommand(String[] args) {
|
||||
DeleteCommand command = new DeleteCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
|
||||
command.setItemId(getItemId(args));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link GetCommand).
|
||||
*/
|
||||
private static Command createGetCommand(String[] args) {
|
||||
GetCommand command = new GetCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
|
||||
command.setItemId(getItemId(args));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link QueryMediaCommand}.
|
||||
*/
|
||||
private static Command createQueryMediaCommand(String[] args) {
|
||||
QueryMediaCommand command = new QueryMediaCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
|
||||
if (args.length == 1) {
|
||||
command.setItemMediaUrl(args[0]);
|
||||
} else {
|
||||
throw error("Expected [item_media_feed_url], got " + Arrays.toString(args));
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link InsertMediaCommand}.
|
||||
*/
|
||||
private static Command createInsertMediaCommand(String[] args) {
|
||||
InsertMediaCommand command = new InsertMediaCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
|
||||
if (args.length < 3 || args.length > 4) {
|
||||
throw error("Expected four arguments: [item_media_feed_url attachment_path_to_file " +
|
||||
"attachment_mime_type caption?], got " + Arrays.toString(args));
|
||||
}
|
||||
|
||||
command.setItemMediaUrl(args[0]);
|
||||
command.setAttachmentFile(args[1]);
|
||||
command.setAttachmentMimeType(args[2]);
|
||||
if (args.length == 4) {
|
||||
command.setCaption(args[3]);
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link UpdateMediaCommand}.
|
||||
*/
|
||||
private static Command createUpdateMediaCommand(String[] args) {
|
||||
UpdateMediaCommand command = new UpdateMediaCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
|
||||
command.setAttachmentId(getItemId(args));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link DeleteMediaCommand}.
|
||||
*/
|
||||
private static Command createDeleteMediaCommand(String[] args) {
|
||||
DeleteMediaCommand command = new DeleteMediaCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
|
||||
command.setAttachmentId(getItemId(args));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a {@link GetMediaCommand).
|
||||
*/
|
||||
private static Command createGetMediaCommand(String[] args) {
|
||||
GetMediaCommand command = new GetMediaCommand();
|
||||
args = parseAndSetCommonArguments(command, args);
|
||||
|
||||
command.setAttachmentId(getItemId(args));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item id from the command line and make sure it's the
|
||||
* only argument left.
|
||||
*
|
||||
* @param args command line arguments left over from
|
||||
* {@link #parseAndSetCommonArguments(Command, String[])}
|
||||
* @return the item ID (an url)
|
||||
*/
|
||||
private static String getItemId(String[] args) {
|
||||
if (args.length != 1) {
|
||||
throw error("Expected one argument after the command name: " +
|
||||
"the ID (url) of the item to delete.");
|
||||
}
|
||||
return args[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the command line and initialize things that are common
|
||||
* to all {@link Command}s.
|
||||
*
|
||||
* @param command the command object
|
||||
* @param args command-line arguments (0 is the command name)
|
||||
* @return the arguments that are left that haven't been parsed
|
||||
* by this method, or an empty array if there's nothing left
|
||||
*/
|
||||
private static String[] parseAndSetCommonArguments(Command command,
|
||||
String[] args) {
|
||||
// Start at the first argument after the command name
|
||||
int current = 1;
|
||||
|
||||
while (current < args.length && args[current].startsWith("-")) {
|
||||
String option = args[current];
|
||||
current++;
|
||||
if ( current >= args.length) {
|
||||
throw error("expected an argument after option " + option);
|
||||
}
|
||||
if ("--dry_run".equals(option)) {
|
||||
command.setDryRun(true);
|
||||
continue;
|
||||
}
|
||||
String value = args[current];
|
||||
current++;
|
||||
|
||||
if ("--user".equals(option)) {
|
||||
command.setUsername(value);
|
||||
} else if("--password".equals(option)) {
|
||||
command.setPassword(value);
|
||||
} else if("--url".equals(option)) {
|
||||
try {
|
||||
command.setGoogleBaseServerUrl(value);
|
||||
} catch(MalformedURLException e) {
|
||||
throw error("Value for --url should be a valid URL: " +
|
||||
e.getMessage());
|
||||
}
|
||||
} else if("--auth".equals(option)) {
|
||||
try {
|
||||
command.setAuthenticationServerUrl(value);
|
||||
} catch(MalformedURLException e) {
|
||||
throw error("Value for --auth should be a valid http or https " +
|
||||
"URL: " + e.getMessage());
|
||||
}
|
||||
} else if("--key".equals(option)) {
|
||||
command.setKey(value);
|
||||
} else {
|
||||
throw error("unexpected option: " + option);
|
||||
}
|
||||
}
|
||||
|
||||
if (!command.hasAllIdentificationInformation()) {
|
||||
throw error("You must input all two required parameters: " +
|
||||
"--user email --password password ");
|
||||
}
|
||||
|
||||
// leave the rest for the command
|
||||
String[] retval = new String[args.length-current];
|
||||
System.arraycopy(args, current, retval, 0, retval.length);
|
||||
return retval;
|
||||
}
|
||||
|
||||
private static void expectNoMoreArguments(String[] args) {
|
||||
if (args.length > 0) {
|
||||
throw error("Expected no more arguments, got instead " + args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private static IllegalArgumentException error(String message) {
|
||||
return new IllegalArgumentException("Error: wrong arguments. " + message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.util.ServiceException;
|
||||
import com.google.api.gbase.client.ServiceErrors;
|
||||
import com.google.api.gbase.client.ServiceError;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An example tool that helps manage customer items on
|
||||
* Google Base using Google data API.
|
||||
*
|
||||
* This tool deals directly with XML feeds. If you would
|
||||
* like to use a higher-level API, have a look at QueryExample.
|
||||
*
|
||||
* Have a look at the different <code>*Command</code> classes for some more
|
||||
* interesting code.
|
||||
*/
|
||||
public class CustomerTool {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Command command = CommandFactory.createCommand(args);
|
||||
try {
|
||||
command.execute();
|
||||
} catch (ServiceException e) {
|
||||
/* Display the error message sent by the server, if it
|
||||
* is available. A real application would need to parse
|
||||
* the body (as HTML or XML, depending on e.getContentType())
|
||||
* and display it nicely.
|
||||
*/
|
||||
StringBuffer message = new StringBuffer("Response code:");
|
||||
ServiceErrors errors = new ServiceErrors(e);
|
||||
|
||||
if (e.getHttpErrorCodeOverride() > 0) {
|
||||
message.append(" ");
|
||||
message.append(e.getHttpErrorCodeOverride());
|
||||
}
|
||||
message.append(" ");
|
||||
message.append(e.getMessage());
|
||||
System.err.println(message);
|
||||
|
||||
List<? extends ServiceError> allErrors = errors.getAllErrors();
|
||||
for (ServiceError error: allErrors) {
|
||||
String field = error.getField();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(" ");
|
||||
if (field != null) {
|
||||
buffer.append("in field '");
|
||||
buffer.append(field);
|
||||
buffer.append("'");
|
||||
buffer.append(": ");
|
||||
}
|
||||
buffer.append(error.getReason());
|
||||
System.err.println(buffer);
|
||||
}
|
||||
System.exit(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
/**
|
||||
* Deletes an item.
|
||||
*/
|
||||
public class DeleteCommand extends Command {
|
||||
|
||||
private String itemId;
|
||||
|
||||
public void execute() throws Exception {
|
||||
|
||||
Service service = createService();
|
||||
Service.GDataRequest request =
|
||||
service.createDeleteRequest(fixEditUrl(itemId));
|
||||
|
||||
// Send the request (HTTP DELETE)
|
||||
request.execute();
|
||||
|
||||
System.out.println("Item deleted successfully.");
|
||||
}
|
||||
|
||||
/** Sets the Id of the item, which is also its URL. */
|
||||
public void setItemId(String itemId) {
|
||||
this.itemId = itemId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Copyright (c) 2007 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
/**
|
||||
* Deletes a media attachment from an item.
|
||||
* This command is called from {@link CustomerTool}.
|
||||
*/
|
||||
public class DeleteMediaCommand extends Command {
|
||||
|
||||
private String attachmentId;
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Service service = createService();
|
||||
Service.GDataRequest request =
|
||||
service.createDeleteRequest(fixEditUrl(attachmentId));
|
||||
|
||||
// Send the request (HTTP DELETE)
|
||||
request.execute();
|
||||
|
||||
System.out.println("Item deleted successfully.");
|
||||
}
|
||||
|
||||
/** Sets the Id of the media attachment, which is also its URL. */
|
||||
public void setAttachmentId(String attachmentId) {
|
||||
this.attachmentId = attachmentId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.api.gbase.client.ServiceError;
|
||||
import com.google.api.gbase.client.ServiceErrors;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Utility class that allows creating simple Example Tools.
|
||||
*
|
||||
* Contains methods for parsing the arguments and for printing errors.
|
||||
*/
|
||||
public abstract class Example {
|
||||
|
||||
protected static FeedURLFactory urlFactory = FeedURLFactory.getDefault();
|
||||
|
||||
protected static GoogleBaseService service;
|
||||
|
||||
|
||||
/**
|
||||
* Parses the arguments, creates a FeedURLFactory and a GoogleBaseService.
|
||||
* @return the remaining arguments
|
||||
*/
|
||||
public static String[] init(String[] args, String applicationName)
|
||||
throws IOException {
|
||||
String baseUrl = null;
|
||||
|
||||
int argsIndex = 0;
|
||||
while (argsIndex < args.length && args[argsIndex].startsWith("-")) {
|
||||
String arg = args[argsIndex];
|
||||
argsIndex++;
|
||||
if ( argsIndex >= args.length) {
|
||||
throw new IllegalArgumentException("Expected a parameter value " +
|
||||
"after " + arg);
|
||||
}
|
||||
String value = args[argsIndex];
|
||||
argsIndex++;
|
||||
if ("--url".equals(arg)) {
|
||||
baseUrl = value;
|
||||
} else if("--key".equals(arg)) {
|
||||
// This parameter used to contain the developer key.
|
||||
// It is still accepted so as not to break scripts that used it, but
|
||||
// it is now ignored.
|
||||
} else {
|
||||
throw new IllegalArgumentException("unknown parameter: " + arg);
|
||||
}
|
||||
}
|
||||
|
||||
if(baseUrl != null) {
|
||||
urlFactory = new FeedURLFactory(baseUrl);
|
||||
}
|
||||
|
||||
// service.query does a GET on the url above and parses the result,
|
||||
// which is an ATOM feed with some extensions (called the Google Base
|
||||
// data API items feed).
|
||||
service = new GoogleBaseService(applicationName);
|
||||
if (argsIndex > 0) {
|
||||
String[] newargs = new String[args.length - argsIndex];
|
||||
System.arraycopy(args, argsIndex, newargs, 0, newargs.length);
|
||||
args = newargs;
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints an error message returned by the server, if any.
|
||||
*
|
||||
* @param e an exception that may contain an error message from the server
|
||||
*/
|
||||
protected static void printServiceException(ServiceException e) {
|
||||
|
||||
System.err.print("Error");
|
||||
if (e.getHttpErrorCodeOverride() > 0) {
|
||||
System.err.print(e.getHttpErrorCodeOverride());
|
||||
}
|
||||
System.err.print(": ");
|
||||
System.err.println(e.getMessage());
|
||||
|
||||
ServiceErrors errors = new ServiceErrors(e);
|
||||
for (ServiceError error: errors.getAllErrors()) {
|
||||
String field = error.getField();
|
||||
System.err.print(" ");
|
||||
if (field != null) {
|
||||
System.err.print("in field '");
|
||||
System.err.print(field);
|
||||
System.err.print("' ");
|
||||
}
|
||||
System.err.println(error.getReason());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Displays one item.
|
||||
*/
|
||||
public class GetCommand extends Command {
|
||||
|
||||
private String itemId;
|
||||
|
||||
public void execute() throws Exception {
|
||||
Service service = createService();
|
||||
Service.GDataRequest request =
|
||||
service.createEntryRequest(new URL(itemId));
|
||||
|
||||
// Send the request (HTTP GET)
|
||||
request.execute();
|
||||
|
||||
// Save the response
|
||||
outputRawResponse(request);
|
||||
}
|
||||
|
||||
/** Sets the id/URL of the item to display. */
|
||||
public void setItemId(String itemId) {
|
||||
this.itemId = itemId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/* Copyright (c) 2007 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Displays the media entry (meta-data) of one attachment.
|
||||
* This command is called from {@link CustomerTool}.
|
||||
*/
|
||||
public class GetMediaCommand extends Command {
|
||||
|
||||
private String attachmentId;
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Service service = createService();
|
||||
Service.GDataRequest request =
|
||||
service.createEntryRequest(new URL(attachmentId));
|
||||
|
||||
// Send the request (HTTP GET)
|
||||
request.execute();
|
||||
|
||||
// Save the response
|
||||
outputRawResponse(request);
|
||||
}
|
||||
|
||||
/** Sets the id/URL of the media attachment to display. */
|
||||
public void setAttachmentId(String attachmentId) {
|
||||
this.attachmentId = attachmentId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
/**
|
||||
* Inserts a new Item into Google Base items.
|
||||
* This command is called from {@link CustomerTool}.
|
||||
*/
|
||||
class InsertCommand extends Command {
|
||||
|
||||
public void execute() throws Exception {
|
||||
|
||||
Service service = createService();
|
||||
Service.GDataRequest request =
|
||||
service.createInsertRequest(fixEditUrl(getCustomerFeedURL()));
|
||||
|
||||
inputRawRequest(request);
|
||||
// Send the request (HTTP POST)
|
||||
request.execute();
|
||||
|
||||
// Save the response
|
||||
outputRawResponse(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Copyright (c) 2007 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
import com.google.gdata.client.Service.GDataRequest;
|
||||
import com.google.gdata.data.media.MediaFileSource;
|
||||
import com.google.gdata.data.media.MediaSource;
|
||||
import com.google.gdata.util.ContentType;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Inserts a new media attachment to a Google Base item, by using
|
||||
* a media binary POST. See
|
||||
* {@link com.google.api.gbase.client.GoogleBaseService#insert(URL, Class, MediaSource)}
|
||||
* for an easier way to do a media binary POST, or look at
|
||||
* {@link com.google.api.gbase.client.GoogleBaseService#insert(URL, com.google.gdata.data.BaseEntry)}
|
||||
* for an easier way to insert an attachment together with the media entry (meta-data) describing it.
|
||||
* This command is called from {@link CustomerTool}.
|
||||
*/
|
||||
class InsertMediaCommand extends Command {
|
||||
|
||||
private String itemMediaUrl;
|
||||
private String attachmentFile;
|
||||
private String attachmentMimeType;
|
||||
private String caption;
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
MediaFileSource media = new MediaFileSource(new File(attachmentFile), attachmentMimeType);
|
||||
|
||||
Service service = createService();
|
||||
Service.GDataRequest request = service.createRequest(GDataRequest.RequestType.INSERT,
|
||||
new URL(itemMediaUrl), new ContentType(attachmentMimeType));
|
||||
|
||||
if (caption != null) {
|
||||
request.setHeader("Slug", caption);
|
||||
}
|
||||
|
||||
MediaSource.Output.writeTo(media, request.getRequestStream());
|
||||
|
||||
// Send the request (HTTP POST)
|
||||
request.execute();
|
||||
|
||||
// Save the response
|
||||
outputRawResponse(request);
|
||||
}
|
||||
|
||||
/** Set the url of the media feed for the item to insert the attachment into. */
|
||||
public void setItemMediaUrl(String itemMediaUrl) {
|
||||
this.itemMediaUrl = itemMediaUrl;
|
||||
}
|
||||
|
||||
/** Sets the path to the file on the disk containing the attachment to upload. */
|
||||
public void setAttachmentFile(String attachmentFile) {
|
||||
this.attachmentFile = attachmentFile;
|
||||
}
|
||||
|
||||
/** Sets the mime-type of the attachment. */
|
||||
public void setAttachmentMimeType(String attachmentMimeType) {
|
||||
this.attachmentMimeType = attachmentMimeType;
|
||||
}
|
||||
|
||||
/** Sets the caption (title) of the attachment. */
|
||||
public void setCaption(String caption) {
|
||||
this.caption = caption;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.api.gbase.client.GoogleBaseAttributeId;
|
||||
import com.google.api.gbase.client.GoogleBaseEntry;
|
||||
import com.google.api.gbase.client.GoogleBaseFeed;
|
||||
import com.google.api.gbase.client.GoogleBaseQuery;
|
||||
import com.google.api.gbase.client.ItemTypeDescription;
|
||||
import com.google.api.gbase.client.MetadataEntryExtension;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* This class demonstrates how to retrieve Google Base item types
|
||||
* using the client library of the Google Base data API.
|
||||
*
|
||||
* The tool implemented by this class will connect to Google Base,
|
||||
* run the request and display some results.
|
||||
*/
|
||||
public class ItemTypesExample extends Example {
|
||||
|
||||
/**
|
||||
* Runs the example.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException, ServiceException {
|
||||
String locale = null;
|
||||
String itemType = null;
|
||||
|
||||
args = init(args, "Google-ItemTypesExample-1.0");
|
||||
|
||||
if (args.length == 0) {
|
||||
// nothing to do
|
||||
} else if (args.length == 1) {
|
||||
locale = args[0];
|
||||
} else if (args.length == 2) {
|
||||
locale = args[0];
|
||||
itemType = args[1];
|
||||
} else {
|
||||
System.err.println("Invalid argument count.");
|
||||
System.err.println("Expected either two arguments, to get an itemtype:");
|
||||
System.err.println(" locale itemtype");
|
||||
System.err.println("or one argument, to get the itemtypes of a locale:");
|
||||
System.err.println(" locale");
|
||||
System.err.println("or no argument, to get the locales.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (locale == null) {
|
||||
queryLocales();
|
||||
} else {
|
||||
if (itemType == null) {
|
||||
queryItemTypes(locale);
|
||||
} else {
|
||||
queryItemType(locale, itemType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and prints the locales.
|
||||
*
|
||||
*/
|
||||
private static void queryLocales()
|
||||
throws IOException, ServiceException {
|
||||
// Create a query URL
|
||||
URL url = urlFactory.getLocalesFeedURL();
|
||||
GoogleBaseQuery query = new GoogleBaseQuery(url);
|
||||
|
||||
// Display the URL generated by the API
|
||||
System.out.println("Sending request to: " + query.getUrl());
|
||||
|
||||
try {
|
||||
GoogleBaseFeed feed = service.query(query);
|
||||
// Print the locales
|
||||
for (GoogleBaseEntry entry : feed.getEntries()) {
|
||||
System.out.println(entry.getTitle().getPlainText());
|
||||
}
|
||||
} catch (ServiceException e) {
|
||||
printServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and prints the item types Google suggests for a locale.
|
||||
*
|
||||
* @param locale the locale to be analysed
|
||||
*/
|
||||
private static void queryItemTypes(String locale)
|
||||
throws IOException, ServiceException {
|
||||
// Create a query URL from the given arguments
|
||||
URL url = urlFactory.getItemTypesFeedURL(locale);
|
||||
GoogleBaseQuery query = new GoogleBaseQuery(url);
|
||||
|
||||
// Display the URL generated by the API
|
||||
System.out.println("Sending request to: " + query.getUrl());
|
||||
|
||||
try {
|
||||
GoogleBaseFeed feed = service.query(query);
|
||||
// Print the item types
|
||||
printItemTypeFeed(feed);
|
||||
} catch (ServiceException e) {
|
||||
printServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and prints the attribute ids Google suggests for an item type of
|
||||
* a locale.
|
||||
*
|
||||
* @param locale the locale of the item type
|
||||
* @param itemType the item type to be analysed
|
||||
*/
|
||||
private static void queryItemType(String locale, String itemType)
|
||||
throws IOException, ServiceException {
|
||||
// Create a query URL from the given arguments
|
||||
URL url = urlFactory.getItemTypesEntryURL(locale, itemType);
|
||||
|
||||
// Display the URL generated by the API
|
||||
System.out.println("Sending request to: " + url);
|
||||
|
||||
try {
|
||||
GoogleBaseEntry entry = service.getEntry(url);
|
||||
// Print the item type
|
||||
printItemTypeEntry(entry);
|
||||
} catch (ServiceException e) {
|
||||
printServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints each itemtype item in the feed to the output.
|
||||
* Uses {@link #printItemTypeEntry(GoogleBaseEntry)}.
|
||||
*
|
||||
* @param feed a Google Base data API itemtypes feed
|
||||
*/
|
||||
private static void printItemTypeFeed(GoogleBaseFeed feed) {
|
||||
if (feed.getTotalResults() == 0) {
|
||||
System.out.println("No matches.");
|
||||
return;
|
||||
}
|
||||
for (GoogleBaseEntry entry : feed.getEntries()) {
|
||||
printItemTypeEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the name and the recommended attribute names of
|
||||
* an itemtype GoogleBaseEntry item.
|
||||
*
|
||||
* @param entry a Google Base data API itemtype entry
|
||||
*/
|
||||
private static void printItemTypeEntry(GoogleBaseEntry entry) {
|
||||
MetadataEntryExtension metadata = entry.getGoogleBaseMetadata();
|
||||
ItemTypeDescription itemTypeDescription = metadata.getItemTypeDescription();
|
||||
System.out.println(itemTypeDescription.getName() + " - " + entry.getId());
|
||||
for (GoogleBaseAttributeId attrId : itemTypeDescription.getAttributeIds()) {
|
||||
System.out.println(attrId.getName() +
|
||||
" (" + attrId.getType().getName() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.api.gbase.client.AttributeHistogram;
|
||||
import com.google.api.gbase.client.GoogleBaseEntry;
|
||||
import com.google.api.gbase.client.GoogleBaseFeed;
|
||||
import com.google.api.gbase.client.GoogleBaseQuery;
|
||||
import com.google.api.gbase.client.MetadataEntryExtension;
|
||||
import com.google.api.gbase.client.AttributeHistogram.UniqueValue;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* This class demonstrates how to retrieve Google Base metadata
|
||||
* using the client library of the Google Base data API.
|
||||
*
|
||||
* The tool implemented by this class will connect to Google Base,
|
||||
* run the request and display some results.
|
||||
*/
|
||||
public class MetadataExample extends Example {
|
||||
|
||||
/**
|
||||
* Runs the example.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException, ServiceException {
|
||||
String queryString = null;
|
||||
|
||||
args = init(args, "Google-MetadataExample-1.0");
|
||||
|
||||
// Process command-line arguments
|
||||
if (args.length == 1) {
|
||||
queryString = args[0];
|
||||
} else {
|
||||
System.err.println("Invalid argument count.");
|
||||
System.err.println("Expected one argument:");
|
||||
System.err.println(" query");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
queryMetadata(queryString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and prints the list of the most used attributes used by
|
||||
* the items that match a query.
|
||||
*
|
||||
* @param queryString a Google Base Query Language query
|
||||
*/
|
||||
private static void queryMetadata(String queryString)
|
||||
throws IOException, ServiceException {
|
||||
// Create a query URL from the given arguments
|
||||
URL url = urlFactory.getAttributesFeedURL();
|
||||
GoogleBaseQuery query = new GoogleBaseQuery(url);
|
||||
query.setGoogleBaseQuery(queryString);
|
||||
|
||||
// Display the URL generated by the API
|
||||
System.out.println("Sending request to: " + query.getUrl());
|
||||
|
||||
try {
|
||||
GoogleBaseFeed feed = service.query(query);
|
||||
// Print the items
|
||||
printMetadataFeed(feed);
|
||||
} catch (ServiceException e) {
|
||||
printServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints each metadata item in the feed to the output.
|
||||
* Uses {@link #printMetadataEntry(GoogleBaseEntry)}.
|
||||
*
|
||||
* @param feed a Google Base data API metadata feed
|
||||
*/
|
||||
private static void printMetadataFeed(GoogleBaseFeed feed) {
|
||||
if (feed.getTotalResults() == 0) {
|
||||
System.out.println("No matches.");
|
||||
return;
|
||||
}
|
||||
for (GoogleBaseEntry entry : feed.getEntries()) {
|
||||
printMetadataEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a few relevant attributes and the values of the attribute histogram
|
||||
* of a metadata GoogleBaseEntry item.
|
||||
*
|
||||
* @param entry a Google Base data API metadata entry
|
||||
*/
|
||||
private static void printMetadataEntry(GoogleBaseEntry entry) {
|
||||
MetadataEntryExtension metadata = entry.getGoogleBaseMetadata();
|
||||
AttributeHistogram attributeHistogram = metadata.getAttributeHistogram();
|
||||
System.out.println(attributeHistogram.getAttributeName() +
|
||||
" (" + attributeHistogram.getAttributeType().getName() + "): " +
|
||||
"valueCount=" + attributeHistogram.getTotalValueCount() + " - " +
|
||||
entry.getId());
|
||||
for (UniqueValue value : attributeHistogram.getValues()) {
|
||||
System.out.println(value.getValueAsString() +
|
||||
" count=" + value.getCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.api.gbase.client.GoogleBaseQuery;
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
/**
|
||||
* Runs a query on Google Base items.
|
||||
* This command is called from {@link CustomerTool}.
|
||||
*/
|
||||
class QueryCommand extends Command {
|
||||
|
||||
private String query;
|
||||
|
||||
public void execute() throws Exception {
|
||||
|
||||
// Build the query URL
|
||||
GoogleBaseQuery queryObject = new GoogleBaseQuery(getCustomerFeedURL());
|
||||
queryObject.setGoogleBaseQuery(query);
|
||||
|
||||
Service service = createService();
|
||||
Service.GDataRequest request =
|
||||
service.createFeedRequest(queryObject.getUrl());
|
||||
|
||||
// Send the request (HTTP GET)
|
||||
request.execute();
|
||||
|
||||
outputRawResponse(request);
|
||||
}
|
||||
|
||||
/** Sets the Google Base query to run. */
|
||||
public void setQuery(String query) {
|
||||
this.query = query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.api.gbase.client.GoogleBaseEntry;
|
||||
import com.google.api.gbase.client.GoogleBaseFeed;
|
||||
import com.google.api.gbase.client.GoogleBaseQuery;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* This class demonstrates how to send simple Google Base search queries
|
||||
* using the client library of the Google Base data API.
|
||||
*
|
||||
* The tool implemented by this class will connect to Google Base, run the
|
||||
* query and display some results.
|
||||
*/
|
||||
public class QueryExample extends Example {
|
||||
|
||||
/**
|
||||
* Maximum number of results to return.
|
||||
*/
|
||||
private static final int MAX_RESULTS = 10;
|
||||
|
||||
/**
|
||||
* Runs the example.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException, ServiceException {
|
||||
String queryString = null;
|
||||
|
||||
args = init(args, "Google-QueryExample-1.0");
|
||||
|
||||
// Process command-line arguments
|
||||
if (args.length == 1) {
|
||||
queryString = args[0];
|
||||
} else {
|
||||
System.err.println("Invalid argument count.");
|
||||
System.err.println("Expected one argument:");
|
||||
System.err.println(" query");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Create a query URL from the given arguments
|
||||
GoogleBaseQuery query =
|
||||
new GoogleBaseQuery(urlFactory.getSnippetsFeedURL());
|
||||
query.setGoogleBaseQuery(queryString);
|
||||
query.setResultFormat(GoogleBaseQuery.ResultFormat.ATOM);
|
||||
query.setMaxResults(MAX_RESULTS);
|
||||
|
||||
// Display the URL generated by the API
|
||||
System.out.println("Sending request to: " + query.getUrl());
|
||||
|
||||
try {
|
||||
GoogleBaseFeed feed = service.query(query, GoogleBaseFeed.class);
|
||||
// Print the items
|
||||
printResult(feed);
|
||||
} catch (ServiceException e) {
|
||||
printServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a few relevant attributes from each item in the feed to the output.
|
||||
*
|
||||
* @param feed a Google Base data API items feed
|
||||
*/
|
||||
private static void printResult(GoogleBaseFeed feed) {
|
||||
if (feed.getTotalResults() == 0) {
|
||||
System.out.println("No matches.");
|
||||
} else {
|
||||
for (GoogleBaseEntry entry : feed.getEntries()) {
|
||||
System.out.println(entry.getGoogleBaseAttributes().getItemType() +
|
||||
": " + entry.getTitle().getPlainText() +
|
||||
" - " +entry.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Copyright (c) 2007 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Queries the specified media feed for all the media attachments
|
||||
* of one item.
|
||||
* This command is called from {@link CustomerTool}.
|
||||
*/
|
||||
class QueryMediaCommand extends Command {
|
||||
|
||||
private String itemMediaUrl;
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Service service = createService();
|
||||
Service.GDataRequest request = service.createFeedRequest(new URL(itemMediaUrl));
|
||||
|
||||
// Send the request (HTTP GET)
|
||||
request.execute();
|
||||
|
||||
outputRawResponse(request);
|
||||
}
|
||||
|
||||
/** Set the url of the media feed. */
|
||||
public void setItemMediaUrl(String itemMediaUrl) {
|
||||
this.itemMediaUrl = itemMediaUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
/**
|
||||
* Modifies an existing item in Google Base.
|
||||
*
|
||||
* This command is called from
|
||||
* {@link com.google.commerce.api.client.cmdline.CustomerTool}.
|
||||
*/
|
||||
class UpdateCommand extends Command {
|
||||
|
||||
private String itemId;
|
||||
|
||||
public void execute() throws Exception {
|
||||
Service service = createService();
|
||||
Service.GDataRequest request =
|
||||
service.createUpdateRequest(fixEditUrl(itemId));
|
||||
inputRawRequest(request);
|
||||
// Send the request (HTTP POST)
|
||||
request.execute();
|
||||
System.out.println("Item updated successfully.");
|
||||
}
|
||||
|
||||
/** Sets the Id of the item, which is also its URL. */
|
||||
public void setItemId(String itemId) {
|
||||
this.itemId = itemId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Copyright (c) 2007 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
/**
|
||||
* Modifies the media entry (meta-data) describing a media attachment
|
||||
* of a Google Base item.
|
||||
* This command is called from {@link CustomerTool}.
|
||||
*/
|
||||
class UpdateMediaCommand extends Command {
|
||||
|
||||
private String attachmentId;
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Service service = createService();
|
||||
Service.GDataRequest request = service.createUpdateRequest(fixEditUrl(attachmentId));
|
||||
inputRawRequest(request);
|
||||
|
||||
// Send the request (HTTP POST)
|
||||
request.execute();
|
||||
|
||||
System.out.println("Item attachment updated successfully.");
|
||||
}
|
||||
|
||||
/** Sets the Id of the media attachment to be updated. */
|
||||
public void setAttachmentId(String attachmentId) {
|
||||
this.attachmentId = attachmentId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
This directory contains some XML files for uploading
|
||||
sample data to Google Base via the API. For instance,
|
||||
the customer tool which is part of the Java client
|
||||
library examples can be used for submitting the data.
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version='1.0'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom'
|
||||
xmlns:g='http://base.google.com/ns/1.0'>
|
||||
<author>
|
||||
<name>Jane Doe</name>
|
||||
<email>JaneDoe@gmail.com</email>
|
||||
</author>
|
||||
<category scheme='http://base.google.com/categories/itemtypes'
|
||||
term='recipes'/>
|
||||
<title type="text">Marie-Louise's chocolate butter</title>
|
||||
<content type="xhtml">
|
||||
<b>Ingredients:</b>
|
||||
<ul>
|
||||
<li>250 g margerine,</li>
|
||||
<li>200 g sugar,</li>
|
||||
<li>2 eggs, and</li>
|
||||
<li>approx. 8 tsp cacao.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Mix everything. Heat while stirring, but do not allow the mix to boil.
|
||||
Put in a container and cool in fridge.
|
||||
</p>
|
||||
</content>
|
||||
<g:item_type type="text">recipes</g:item_type>
|
||||
<g:cuisine type="text">danish</g:cuisine>
|
||||
<g:label type="text">butter</g:label>
|
||||
<g:label type="text">chocolate</g:label>
|
||||
<g:cooking_time type="intUnit">10 minutes</g:cooking_time>
|
||||
<g:main_ingredient type="text">cacao</g:main_ingredient>
|
||||
</entry>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version='1.0'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom'
|
||||
xmlns:g='http://base.google.com/ns/1.0'>
|
||||
<author>
|
||||
<name>Jane Doe</name>
|
||||
<email>JaneDoe@gmail.com</email>
|
||||
</author>
|
||||
<category scheme='http://base.google.com/categories/itemtypes'
|
||||
term='recipes'/>
|
||||
<title>Ulla's famous chocolate mousse</title>
|
||||
<content type="xhtml">
|
||||
<b>Ingredients:</b>
|
||||
<ul>
|
||||
<li>125 g dark chocolate,</li>
|
||||
<li>50 g butter,</li>
|
||||
<li>50 g sugar, and</li>
|
||||
<li>4 eggs</li>
|
||||
</ul>
|
||||
<p>
|
||||
Melt the chocolate togther with butter and two tablespoons
|
||||
of water. Add the sugar. Beat in the egg yolks one at the time.
|
||||
Add strong coffee, rum, cognac or something similar until the
|
||||
consistency is like mayonnaise. Beat the egg whites until they are stiff
|
||||
and gently fold them into the chocolate mix. Poor the mix into a bowl
|
||||
or individual serving pots and leave in the fridge to cool down.
|
||||
Serve decorated with whipped cream.
|
||||
</p>
|
||||
</content>
|
||||
<g:item_type type="text">recipes</g:item_type>
|
||||
<g:cuisine type="text">danish</g:cuisine>
|
||||
<g:cooking_time type="intUnit">20 minutes</g:cooking_time>
|
||||
<g:servings type="int">4</g:servings>
|
||||
<g:course type="text">dessert</g:course>
|
||||
<g:main_ingredient type="text">dark chocolate</g:main_ingredient>
|
||||
<g:main_ingredient type="text">butter</g:main_ingredient>
|
||||
</entry>
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,348 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.gdata.client.http.AuthSubUtil;
|
||||
import com.google.gdata.util.AuthenticationException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Provides an authenticated GoogleBaseService
|
||||
* to the servlet that will process the request.
|
||||
*/
|
||||
public class AuthenticationFilter implements Filter {
|
||||
|
||||
/**
|
||||
* The request attribute that contains the authenticated service.
|
||||
*/
|
||||
static final String SERVICE_ATTRIBUTE = "googleBaseService";
|
||||
|
||||
/**
|
||||
* The parameter used by AuthSub to specify the authentication token.
|
||||
* Also used as the name of the http session attribute that contains
|
||||
* the session token.
|
||||
*/
|
||||
static final String TOKEN_PARAMETER = "token";
|
||||
|
||||
static final String TOKEN_COOKIE_NAME = "AuthSubSessionToken";
|
||||
|
||||
static final String DEFAULT_AUTHSUB_PROTOCOL = "https";
|
||||
static final String DEFAULT_AUTHSUB_HOSTNAME = "www.google.com";
|
||||
|
||||
protected String authsubProtocol;
|
||||
protected String authsubHostname;
|
||||
|
||||
protected FeedURLFactory urlFactory;
|
||||
|
||||
protected String applicationName;
|
||||
|
||||
/**
|
||||
* Developer key, used for identification against the Google Base data
|
||||
* API servers.
|
||||
*/
|
||||
protected String key;
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
servletContext = filterConfig.getServletContext();
|
||||
key = servletContext.getInitParameter(RecipeUtil.DEVELOPER_KEY_PARAMETER);
|
||||
if (key == null || "".equals(key.trim())) {
|
||||
String errorMessage = "No developer key specified.\n Please edit " +
|
||||
"web.xml and add your developer key in the \"key\" context " +
|
||||
"parameter. \n You can obtain a developer key at: \n\t" +
|
||||
"http://code.google.com/api/base/signup.html";
|
||||
System.err.println(errorMessage);
|
||||
throw new ServletException(errorMessage);
|
||||
}
|
||||
|
||||
urlFactory = (FeedURLFactory)
|
||||
servletContext.getAttribute(RecipeListener.FEED_URL_FACTORY_ATTRIBUTE);
|
||||
authsubProtocol = filterConfig.getInitParameter("authsubProtocol");
|
||||
if (authsubProtocol == null) {
|
||||
authsubProtocol = DEFAULT_AUTHSUB_PROTOCOL;
|
||||
}
|
||||
authsubHostname = filterConfig.getInitParameter("authsubHostname");
|
||||
if (authsubHostname == null) {
|
||||
authsubHostname = DEFAULT_AUTHSUB_HOSTNAME;
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
servletContext = null;
|
||||
urlFactory = null;
|
||||
applicationName = null;
|
||||
authsubProtocol = null;
|
||||
authsubHostname = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts or stops an authenticated session, depending on the value
|
||||
* of the {@value #TOKEN_PARAMETER} parameter, or provides the servlets
|
||||
* with an authenticated
|
||||
* {@link com.google.api.gbase.client.GoogleBaseService GoogleBaseService},
|
||||
* during an authenticated session.
|
||||
*/
|
||||
public void doFilter(ServletRequest request,
|
||||
ServletResponse response,
|
||||
FilterChain filterChain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
String oneTimeToken = httpRequest.getParameter(TOKEN_PARAMETER);
|
||||
String sessionToken = getSessionTokenCookie(httpRequest);
|
||||
|
||||
if (oneTimeToken != null) {
|
||||
if ("".equals(oneTimeToken)) {
|
||||
// Revoke the session token
|
||||
if (sessionToken != null) {
|
||||
stopAuthenticatedSession(httpRequest, httpResponse, sessionToken);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Convert the token to a session token and keep it
|
||||
try {
|
||||
startAuthenticatedSession(httpRequest, httpResponse, oneTimeToken);
|
||||
return;
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new ServletException(e);
|
||||
} catch (AuthenticationException e) {
|
||||
// Log and then continue as if this token was not there.
|
||||
// (It was probably bookmarked.)
|
||||
servletContext.log("Invalid one-time token", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Request a new token if we don't have one at this point
|
||||
if (sessionToken == null) {
|
||||
redirectToAuthSub(httpRequest, httpResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a service that authenticates using the session token
|
||||
GoogleBaseService service = new GoogleBaseService(
|
||||
applicationName, key, authsubProtocol, authsubHostname);
|
||||
service.setAuthSubToken(sessionToken);
|
||||
|
||||
// Make the service available to the servlet
|
||||
httpRequest.setAttribute(SERVICE_ATTRIBUTE, service);
|
||||
|
||||
// Execute the servlet
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
} catch(ServletException e) {
|
||||
Throwable cause = e.getRootCause();
|
||||
if (cause instanceof AuthenticationException &&
|
||||
!response.isCommitted()) {
|
||||
// Token has been revoked. Re-run AuthSub.
|
||||
redirectToAuthSub(httpRequest, httpResponse);
|
||||
} else {
|
||||
// Let the exception be handled as usual.
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the AuthSub session token from a cookie.
|
||||
*
|
||||
* @param httpRequest
|
||||
* @return session token or null
|
||||
*/
|
||||
String getSessionTokenCookie(HttpServletRequest httpRequest) {
|
||||
Cookie[] cookies = httpRequest.getCookies();
|
||||
if (cookies == null) {
|
||||
return null;
|
||||
}
|
||||
for (Cookie cookie : cookies) {
|
||||
if (cookie.getName().equals(TOKEN_COOKIE_NAME)) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes the specified session token and redirects the browser to
|
||||
* the context of the request.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param sessionToken a session token
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
private void stopAuthenticatedSession(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
String sessionToken)
|
||||
throws IOException, ServletException {
|
||||
if (sessionToken != null) {
|
||||
revokeSessionToken(sessionToken);
|
||||
clearSessionTokenCookie(request, response);
|
||||
}
|
||||
String url = request.getContextPath();
|
||||
response.sendRedirect(response.encodeRedirectURL(url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Force cookie expiration by sending an expired cookie to
|
||||
* the browser.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
private void clearSessionTokenCookie(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws ServletException {
|
||||
response.addCookie(newExpiredSessionTokenCookie(request));
|
||||
}
|
||||
|
||||
private Cookie newExpiredSessionTokenCookie(HttpServletRequest request)
|
||||
throws ServletException {
|
||||
Cookie cookie = newSessionTokenCookie(request, "");
|
||||
cookie.setMaxAge(0);
|
||||
return cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitely revoke the session token.
|
||||
*
|
||||
* @param token
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected void revokeSessionToken(String token) throws IOException, ServletException
|
||||
{
|
||||
try {
|
||||
AuthSubUtil.revokeToken(authsubProtocol, authsubHostname, token, null);
|
||||
} catch (AuthenticationException e) {
|
||||
throw new ServletException(e);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exchanges the single use token for a session token and
|
||||
* redirects the browser to the same address with the
|
||||
* token specification part removed.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param oneTimeToken a single use AuthSub token
|
||||
* @throws IOException
|
||||
* @throws GeneralSecurityException
|
||||
* @throws AuthenticationException if the one-time token is invalid
|
||||
*/
|
||||
private void startAuthenticatedSession(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
String oneTimeToken)
|
||||
throws IOException, GeneralSecurityException, AuthenticationException,
|
||||
ServletException {
|
||||
String sessionToken = exchangeForSessionToken(oneTimeToken);
|
||||
|
||||
// Store the authentication token in a cookie
|
||||
response.addCookie(newSessionTokenCookie(request, sessionToken));
|
||||
|
||||
// Redirect the browser to the same address
|
||||
// with the "token=value" part removed from the query string
|
||||
StringBuffer url = request.getRequestURL();
|
||||
String queryString = request.getQueryString();
|
||||
if (queryString != null) {
|
||||
queryString = queryString.replaceFirst("token=[^&]*&?", "");
|
||||
if (queryString.length() > 0) {
|
||||
url.append("?").append(queryString);
|
||||
}
|
||||
}
|
||||
response.sendRedirect(response.encodeRedirectURL(url.toString()));
|
||||
}
|
||||
|
||||
protected Cookie newSessionTokenCookie(HttpServletRequest request,
|
||||
String sessionToken)
|
||||
throws ServletException {
|
||||
Cookie cookie = new Cookie(TOKEN_COOKIE_NAME, sessionToken);
|
||||
// AuthSub session tokens effectively don't expire. Hang on to it.
|
||||
// If the AuthSub token is revoked, the filter will request
|
||||
// a new token.
|
||||
cookie.setMaxAge(365*24*60*60);
|
||||
cookie.setPath(request.getContextPath() + "/");
|
||||
try {
|
||||
cookie.setDomain(new URL(request.getRequestURL().toString()).getHost());
|
||||
} catch(MalformedURLException e) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
|
||||
// Cookie domain set automatically by the server.
|
||||
return cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a one-time token into a reusable session token.
|
||||
* @param oneTimeToken
|
||||
* @throws IOException
|
||||
*/
|
||||
protected String exchangeForSessionToken(String oneTimeToken)
|
||||
throws IOException, GeneralSecurityException, AuthenticationException {
|
||||
return AuthSubUtil.exchangeForSessionToken(authsubProtocol,
|
||||
authsubHostname,
|
||||
oneTimeToken,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects to the AuthSub authentication page.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws IOException
|
||||
*/
|
||||
private void redirectToAuthSub(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException {
|
||||
StringBuffer next = request.getRequestURL();
|
||||
String queryString = request.getQueryString();
|
||||
if (queryString != null && !"".equals(queryString) ) {
|
||||
next.append("?").append(queryString);
|
||||
}
|
||||
String scope = new URL(urlFactory.getBaseURL(), "feeds").toExternalForm();
|
||||
String url = AuthSubUtil.getRequestUrl(authsubProtocol,
|
||||
authsubHostname,
|
||||
next.toString(),
|
||||
scope,
|
||||
false,
|
||||
true);
|
||||
response.sendRedirect(response.encodeRedirectURL(url));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
|
||||
/**
|
||||
* Methods called from the JSP for generating HTML code.
|
||||
*
|
||||
* This is the work normally done by a web framework.
|
||||
*/
|
||||
public class DisplayUtils {
|
||||
|
||||
/**
|
||||
* Prints checkboxes on two colums, with a text input field at the end.
|
||||
* The checked values will be displayed along with the values to be showed.
|
||||
*
|
||||
* The text input field can be used to input a custom value. It has the
|
||||
* same name as the checkbox input fields, so when the submitted values
|
||||
* are processed, you have to remove the empty value, in case this field
|
||||
* remains empty.
|
||||
*
|
||||
* @param out output writer
|
||||
* @param name name of the input field
|
||||
* @param values values to be shown
|
||||
* @param checked checked values
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void printCheckboxes(Writer out,
|
||||
String name,
|
||||
String[] values,
|
||||
Set<String> checked) throws IOException {
|
||||
Set<String> allValues = new TreeSet<String>();
|
||||
// The displayed values are the static values plus the checked values
|
||||
allValues.addAll(Arrays.asList(values));
|
||||
if (checked == null) {
|
||||
checked = new HashSet<String>();
|
||||
}
|
||||
allValues.addAll(checked);
|
||||
int middle = (allValues.size() + 2) / 2;
|
||||
int row = 0;
|
||||
out.write("<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">");
|
||||
out.write("<tr><td><ul class=\"inputlist\">");
|
||||
for (String value : allValues) {
|
||||
if (row == middle) {
|
||||
out.write("</ul></td><td><ul class=\"inputlist\">");
|
||||
}
|
||||
out.write("<li>");
|
||||
printCheckbox(out, name, value, checked.contains(value));
|
||||
out.write("</li>");
|
||||
row++;
|
||||
}
|
||||
out.write("<li><label>Other:<br/><input id=\"other");
|
||||
out.write(name);
|
||||
out.write("\" type=\"text\" name=\"");
|
||||
out.write(name);
|
||||
out.write("\" value=\"\" size=\"15\" class=\"txt\"></label></li>");
|
||||
out.write("</ul></td></tr></table>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a checkbox input field with a label.
|
||||
*
|
||||
* @param out output writer
|
||||
* @param name name of the field
|
||||
* @param value value of the field
|
||||
* @param checked true if the field is checked
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void printCheckbox(Writer out, String name, String value,
|
||||
boolean checked) throws IOException {
|
||||
value = escape(value);
|
||||
out.write("<label><input type=\"checkbox\" name=\"");
|
||||
out.write(name);
|
||||
out.write("\" value=\"");
|
||||
out.write(value);
|
||||
out.write("\"");
|
||||
if (checked) {
|
||||
out.write(" checked");
|
||||
}
|
||||
out.write("/> ");
|
||||
if (checked) {
|
||||
out.write("<b>");
|
||||
}
|
||||
out.write(value);
|
||||
if (checked) {
|
||||
out.write("</b>");
|
||||
}
|
||||
out.write("</label>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes the items of the Collection and returns them in a StringBuffer,
|
||||
* separated by commas.
|
||||
*
|
||||
* @param list
|
||||
* @return list of the elements of the collection, sepparated by commas
|
||||
*/
|
||||
public static StringBuffer printList(Collection<String> list) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (list != null && list.size() > 0) {
|
||||
Iterator<String> iter = list.iterator();
|
||||
while (true) {
|
||||
sb.append(escape(iter.next()));
|
||||
if (iter.hasNext()) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints <option> tags and set the selected option.
|
||||
*
|
||||
* @param out output writer
|
||||
* @param names option names, which are used both for
|
||||
* values and for labels
|
||||
* @param current name of the current option
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void printOptions(Writer out,
|
||||
String[] names,
|
||||
String current) throws IOException {
|
||||
for (int i=0; i<names.length; i++) {
|
||||
String name = names[i];
|
||||
printOption(out, name, name, name.equals(current));
|
||||
}
|
||||
printOption(out, "all", "", current==null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints one <option> tag and select it if necessary.
|
||||
*
|
||||
* @param out output writer
|
||||
* @param label option label
|
||||
* @param value option value
|
||||
* @param selected true if it's selected
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void printOption(Writer out,
|
||||
String label,
|
||||
String value,
|
||||
boolean selected) throws IOException {
|
||||
out.write("<option");
|
||||
if (selected) {
|
||||
out.write(" selected");
|
||||
}
|
||||
out.write(" value=\"");
|
||||
out.write(value);
|
||||
out.write("\">");
|
||||
out.write(escape(label));
|
||||
out.write("</option>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple HTML escaping of the String version of the specified Object.
|
||||
*
|
||||
* @param obj Object that has a meaningful toString() value
|
||||
* @return string with some escaped characters
|
||||
*/
|
||||
public static String escape(Object obj) {
|
||||
if (obj == null) {
|
||||
return "";
|
||||
}
|
||||
return escapeAndShorten(obj.toString(), -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple HTML escaping.
|
||||
*
|
||||
* Escapes < & and > and leaves the rest as it is.
|
||||
*
|
||||
* @param raw
|
||||
* @return string with some escaped characters
|
||||
*/
|
||||
public static String escape(String raw) {
|
||||
return escapeAndShorten(raw, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape HTML data and shorted the result if necessary.
|
||||
*
|
||||
* If the text is escaped, <b>...</b> will be
|
||||
* appended.
|
||||
*
|
||||
* @param raw raw text to escape
|
||||
* @param maxLength maximum output length
|
||||
* @return HTML code
|
||||
*/
|
||||
public static String escapeAndShorten(String raw, int maxLength) {
|
||||
if (raw == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder retval = new StringBuilder();
|
||||
int length = raw.length();
|
||||
boolean shortened = false;
|
||||
if (maxLength != -1 && length > maxLength) {
|
||||
length = maxLength;
|
||||
shortened = true;
|
||||
}
|
||||
for (int i=0; i<length; i++) {
|
||||
char c = raw.charAt(i);
|
||||
switch (c) {
|
||||
case '<':
|
||||
retval.append("<");
|
||||
break;
|
||||
case '>':
|
||||
retval.append(">");
|
||||
break;
|
||||
case '&':
|
||||
retval.append("&");
|
||||
break;
|
||||
case '\'':
|
||||
retval.append("'");
|
||||
break;
|
||||
case '"':
|
||||
retval.append(""");
|
||||
break;
|
||||
default:
|
||||
retval.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shortened) {
|
||||
retval.append("<b>...</b>");
|
||||
}
|
||||
return retval.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import com.google.api.gbase.client.AttributeHistogram;
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseEntry;
|
||||
import com.google.api.gbase.client.GoogleBaseFeed;
|
||||
import com.google.api.gbase.client.GoogleBaseQuery;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.api.gbase.client.MetadataEntryExtension;
|
||||
import com.google.api.gbase.client.AttributeHistogram.UniqueValue;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
/**
|
||||
* Holds the most used values of attributes in Google Base and
|
||||
* periodically refreshes them.
|
||||
*
|
||||
* A MostUsedValues object is focused on a GoogleBaseService and
|
||||
* a FeedURLFactory. One object can be used to analyse only the items that
|
||||
* match a specific query.
|
||||
*
|
||||
* The class currently works for TEXT attributes only.
|
||||
*
|
||||
* The cache() and clear() calls are synchronized,
|
||||
* so that the different Maps and Collections remain in sync.
|
||||
*
|
||||
* Typically, right after you create a MostUsedValues object, you call the
|
||||
* {@link #cache(long, int, ServletContext, String[])} method to set it up
|
||||
* to cache the most used values of your attributes. This creates
|
||||
* {@link java.util.TimerTask} objects that periodically refresh the cached
|
||||
* values. After this, you use {@link #getMostUsedValuesForAttribute(String)}
|
||||
* to get the most used values for the attributes you previously specified.
|
||||
* In the end, when you no longer need the cache, you can call
|
||||
* {@link #clear()} to stop the TimerTask objects and clear the cache.
|
||||
*/
|
||||
public class MostUsedValues {
|
||||
|
||||
protected static final String TEXT_TYPE = "(text)";
|
||||
|
||||
/**
|
||||
* The initial value of the max values limit when making a query;
|
||||
* the step used to increase that limit if some of the attributes
|
||||
* are not found.
|
||||
*/
|
||||
protected static final int STEP_MAXRESULTS = 25;
|
||||
|
||||
/**
|
||||
* The max of the max values limit when making a query.
|
||||
*/
|
||||
protected static final int MAX_MAXRESULTS = 200;
|
||||
|
||||
/**
|
||||
* The cached most used values.
|
||||
* This is a synchronized map.
|
||||
*/
|
||||
private java.util.Map<String, String[]> mostUsedValues;
|
||||
|
||||
/**
|
||||
* The timers that periodically refresh the cache.
|
||||
* The access to this object has to be synchronized.
|
||||
*/
|
||||
private Collection<Timer> timers;
|
||||
|
||||
private GoogleBaseService service;
|
||||
private FeedURLFactory urlFactory;
|
||||
private String queryString;
|
||||
|
||||
/**
|
||||
* Creates an empty MostUsedValues.
|
||||
*
|
||||
* @param service any GoogleBaseService used to retrieve attribute histograms
|
||||
* @param urlFactory a FeedURLFactory used to create the URLs of
|
||||
* the attribute histograms
|
||||
* @param queryString the query string used to filter the analyzed items,
|
||||
* for example one that focuses only on the items that
|
||||
* have a specific item type.
|
||||
*/
|
||||
public MostUsedValues(GoogleBaseService service,
|
||||
FeedURLFactory urlFactory,
|
||||
String queryString) {
|
||||
this.service = service;
|
||||
this.urlFactory = urlFactory;
|
||||
this.queryString = queryString;
|
||||
|
||||
mostUsedValues = new Hashtable<String, String[]>();
|
||||
timers = new ArrayList<Timer>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cached most used values of an attribute.
|
||||
*
|
||||
* @param attrName the name of the attribute
|
||||
* @return a cached list of the most used values
|
||||
*/
|
||||
public String[] getMostUsedValuesForAttribute(String attrName) {
|
||||
return mostUsedValues.get(attrName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the object to cache a limited number of the most used values of
|
||||
* each of the specified attributes; the cache is refreshed periodically.
|
||||
*
|
||||
* This method does not check if the specified attributes are already cached.
|
||||
* You have to make sure an attribute is specified only once in your calls.
|
||||
*
|
||||
* @param interval the cache refresh period, in millis
|
||||
* @param maxValues the maximum number of values to cache
|
||||
* @param servletContext a ServletContext to be used for logging
|
||||
* @param attrNames the names of the attributes to be cached
|
||||
*/
|
||||
synchronized public void cache(long interval,
|
||||
final int maxValues,
|
||||
ServletContext servletContext,
|
||||
final String... attrNames) {
|
||||
if (attrNames.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Timer timer = new Timer(true);
|
||||
TimerTask task = createRefresher(maxValues, servletContext, attrNames);
|
||||
task.run();
|
||||
timer.schedule(task, interval, interval);
|
||||
timers.add(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TimerTask that refreshes the cached most used values of
|
||||
* the specified attributes.
|
||||
*
|
||||
* @param maxValues how many values to cache for each attribute
|
||||
* @param servletContext servlet context for logging error messages
|
||||
* @param attrNames the names of the attributes
|
||||
* @return a TimerTask that refreshes the cache
|
||||
*/
|
||||
private TimerTask createRefresher(final int maxValues,
|
||||
final ServletContext servletContext,
|
||||
final String... attrNames) {
|
||||
TimerTask task = new TimerTask() {
|
||||
/**
|
||||
* Tells the MostUsedValues object that created this TimerTask to
|
||||
* refresh the cached most used values of some of the attributes.
|
||||
*/
|
||||
@Override public void run() {
|
||||
try {
|
||||
MostUsedValues.this.retrieveMostUsedValues(maxValues, attrNames);
|
||||
} catch (IOException e) {
|
||||
servletContext.log(e.getMessage(), e);
|
||||
} catch (ServiceException e) {
|
||||
servletContext.log(e.getMessage() + " " +
|
||||
e.getHttpErrorCodeOverride() + " " +
|
||||
e.getResponseContentType() + ": " +
|
||||
e.getResponseBody(), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the most used values for some attributes
|
||||
* for the items that match the query string
|
||||
* and stores a limited number of those values for each attribute.
|
||||
*
|
||||
* @param numValue maximum number of values to store
|
||||
* @param attrNames the names of the attributes
|
||||
*/
|
||||
protected void retrieveMostUsedValues(int numValue, final String... attrNames)
|
||||
throws ServiceException, IOException {
|
||||
URL url = urlFactory.getAttributesFeedURL();
|
||||
GoogleBaseQuery query = new GoogleBaseQuery(url);
|
||||
|
||||
StringBuffer queryString = createQueryString(attrNames);
|
||||
query.setGoogleBaseQuery(queryString.toString());
|
||||
query.setMaxValues(numValue);
|
||||
|
||||
int numResults = 0;
|
||||
int lastNumResults = 0;
|
||||
Collection<String> attrToRetrieve =
|
||||
new ArrayList<String>(Arrays.asList(attrNames));
|
||||
do {
|
||||
// Get the feed
|
||||
numResults += STEP_MAXRESULTS;
|
||||
query.setMaxResults(numResults);
|
||||
GoogleBaseFeed feed = service.query(query);
|
||||
if (lastNumResults == feed.getTotalResults()) {
|
||||
// No new entries to process
|
||||
break;
|
||||
}
|
||||
lastNumResults = feed.getTotalResults();
|
||||
// Extract the values from the entries
|
||||
Iterator<String> attrIter = attrToRetrieve.iterator();
|
||||
while (attrIter.hasNext()) {
|
||||
String attrName = attrIter.next();
|
||||
// Searching for the entry with the following name
|
||||
String entryTitle = attrName + TEXT_TYPE;
|
||||
for (GoogleBaseEntry entry : feed.getEntries()) {
|
||||
if (entryTitle.equals(entry.getTitle().getPlainText())) {
|
||||
extractValuesFromEntry(numValue, attrName, entry);
|
||||
attrIter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!attrToRetrieve.isEmpty() && numResults <= MAX_MAXRESULTS);
|
||||
|
||||
if (!attrToRetrieve.isEmpty()) {
|
||||
throw new ServiceException("The retrieved histograms do not contain" +
|
||||
"some of the attributes. The most used values of these attributes " +
|
||||
"have not been refreshed.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the query string extended so that it filters out the items
|
||||
* that do not have at least one of the specified attributes of type TEXT.
|
||||
*
|
||||
* @param attrNames the attributes we are interested in
|
||||
* @return an extended query string
|
||||
*/
|
||||
protected StringBuffer createQueryString(final String... attrNames) {
|
||||
StringBuffer queryString = new StringBuffer(this.queryString);
|
||||
queryString.append("(");
|
||||
queryString.append("[").append(attrNames[0]).append(TEXT_TYPE).append("]");
|
||||
for (int i = 1; i < attrNames.length; i++) {
|
||||
String attrName = attrNames[i];
|
||||
queryString.append("|[").append(attrName).append(TEXT_TYPE).append("]");
|
||||
}
|
||||
queryString.append(")");
|
||||
return queryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches a limited number of the values of a GoogleBaseEntry.
|
||||
*
|
||||
* @param numValue maximum number of values to cache
|
||||
* @param attrName the name of the attribute that has the values
|
||||
* @param entry an entry with a MetadataEntryExtension
|
||||
*/
|
||||
private void extractValuesFromEntry(int numValue,
|
||||
String attrName,
|
||||
GoogleBaseEntry entry) {
|
||||
MetadataEntryExtension metadata = entry.getGoogleBaseMetadata();
|
||||
AttributeHistogram attributeHistogram = metadata.getAttributeHistogram();
|
||||
List<? extends UniqueValue> values = attributeHistogram.getValues();
|
||||
|
||||
int valuesCount = Math.min(numValue, values.size());
|
||||
String[] usedValues = new String[valuesCount];
|
||||
for (int i = 0; i < valuesCount; i++) {
|
||||
usedValues[i] = values.get(i).getValueAsString();
|
||||
}
|
||||
|
||||
updateMostUsedValue(attrName, usedValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels all refresh timers and clears the cache.
|
||||
*/
|
||||
synchronized public void clear() {
|
||||
for (Timer timer : timers) {
|
||||
timer.cancel();
|
||||
}
|
||||
timers.clear();
|
||||
mostUsedValues.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of cached attributes.
|
||||
*/
|
||||
public int size() {
|
||||
return mostUsedValues.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if no attribute is cached.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return mostUsedValues.isEmpty();
|
||||
}
|
||||
|
||||
public String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the most used values of an attribute.
|
||||
* @param attrName
|
||||
* @param stringValues
|
||||
*/
|
||||
protected void updateMostUsedValue(String attrName, String[] stringValues) {
|
||||
mostUsedValues.put(attrName, stringValues);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import com.google.api.gbase.client.GoogleBaseEntry;
|
||||
import com.google.api.gbase.client.NumberUnit;
|
||||
import com.google.gdata.data.Content;
|
||||
import com.google.gdata.data.DateTime;
|
||||
import com.google.gdata.data.OtherContent;
|
||||
import com.google.gdata.data.Person;
|
||||
import com.google.gdata.data.TextConstruct;
|
||||
import com.google.gdata.data.TextContent;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* One recipe, ready to be displayed.
|
||||
* Just a data holding object.
|
||||
*/
|
||||
public class Recipe {
|
||||
public final static String RECIPE_ITEMTYPE = "recipes";
|
||||
|
||||
public final static String MAIN_INGREDIENT_ATTRIBUTE = "main ingredient";
|
||||
public final static String CUISINE_ATTRIBUTE = "cuisine";
|
||||
public final static String COOKING_TIME_ATTRIBUTE = "cooking time";
|
||||
|
||||
public final static String AUTHOR_UNKNOWN = "";
|
||||
|
||||
private final String id;
|
||||
private final DateTime postedOn;
|
||||
private final String postedBy;
|
||||
private final NumberUnit<Integer> cookingTime;
|
||||
private final String url;
|
||||
private final String title;
|
||||
private final String description;
|
||||
/** A never-null list that contains the main ingredients. */
|
||||
private final Set<String> mainIngredient;
|
||||
/** A never-null list that contains the cuisines. */
|
||||
private final Set<String> cuisine;
|
||||
|
||||
/**
|
||||
* Creates a recipe. The parameters can be null.
|
||||
*
|
||||
* @param id id generated by the GoogleBase server
|
||||
* @param title
|
||||
* @param url alternate url of the recipe;
|
||||
* if null, when the recipe is used to insert or to update
|
||||
* it is generated by the GoogleBase server
|
||||
* @param description
|
||||
* @param mainIngredient
|
||||
* @param cuisine
|
||||
* @param cookingTime
|
||||
*/
|
||||
public Recipe(String id, String title, String url,
|
||||
String description, Set<String> mainIngredient, Set<String> cuisine,
|
||||
NumberUnit<Integer> cookingTime) {
|
||||
if (mainIngredient == null) {
|
||||
mainIngredient = new HashSet<String>();
|
||||
}
|
||||
if (cuisine == null) {
|
||||
cuisine = new HashSet<String>();
|
||||
}
|
||||
this.id = id;
|
||||
|
||||
this.title = title;
|
||||
this.url = url;
|
||||
this.description = description;
|
||||
this.mainIngredient = mainIngredient;
|
||||
this.cuisine = cuisine;
|
||||
this.cookingTime = cookingTime;
|
||||
|
||||
this.postedOn = null;
|
||||
this.postedBy = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a recipe out of a GoogleBaseEntry.
|
||||
*
|
||||
* @param entry an entry that represents a recipe
|
||||
*/
|
||||
public Recipe(GoogleBaseEntry entry) {
|
||||
id = extractIdFromUrl(entry.getId());
|
||||
title = entry.getTitle().getPlainText();
|
||||
url = entry.getHtmlLink().getHref();
|
||||
String description = null;
|
||||
if (entry.getContent() != null) {
|
||||
Content content = entry.getContent();
|
||||
if (content instanceof TextContent) {
|
||||
description = ((TextContent)content).getContent().getPlainText();
|
||||
} else if (content instanceof OtherContent) {
|
||||
description = ((OtherContent)content).getText();
|
||||
}
|
||||
}
|
||||
this.description = description;
|
||||
mainIngredient = new HashSet<String>(entry.getGoogleBaseAttributes().
|
||||
getTextAttributeValues(MAIN_INGREDIENT_ATTRIBUTE));
|
||||
cuisine = new HashSet<String>(entry.getGoogleBaseAttributes().
|
||||
getTextAttributeValues(CUISINE_ATTRIBUTE));
|
||||
cookingTime = entry.getGoogleBaseAttributes().
|
||||
getIntUnitAttribute(COOKING_TIME_ATTRIBUTE);
|
||||
postedOn = entry.getPublished();
|
||||
|
||||
// if an entry has no author specified, will set it to empty string
|
||||
List<Person> authors = entry.getAuthors();
|
||||
postedBy = (authors.isEmpty() ? AUTHOR_UNKNOWN : authors.get(0).getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty recipe, the values are null or empty Sets.
|
||||
*/
|
||||
public Recipe() {
|
||||
this(null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public GoogleBaseEntry toGoogleBaseEntry(String idUrl)
|
||||
{
|
||||
GoogleBaseEntry entry = new GoogleBaseEntry();
|
||||
entry.getGoogleBaseAttributes().setItemType(RECIPE_ITEMTYPE);
|
||||
if (idUrl != null) {
|
||||
entry.setId(idUrl);
|
||||
}
|
||||
entry.setTitle(TextConstruct.create(TextConstruct.Type.TEXT, title, null));
|
||||
if (url != null) {
|
||||
entry.addHtmlLink(url, null, null);
|
||||
}
|
||||
if (description != null) {
|
||||
// If the original content was not TEXT, the formatting is lost
|
||||
entry.setContent(
|
||||
TextConstruct.create(TextConstruct.Type.TEXT, description, null));
|
||||
}
|
||||
for (String ingredient : mainIngredient) {
|
||||
entry.getGoogleBaseAttributes().addTextAttribute(
|
||||
MAIN_INGREDIENT_ATTRIBUTE, ingredient);
|
||||
}
|
||||
for (String cuisineItem : cuisine) {
|
||||
entry.getGoogleBaseAttributes().addTextAttribute(
|
||||
CUISINE_ATTRIBUTE, cuisineItem);
|
||||
}
|
||||
if (cookingTime != null) {
|
||||
entry.getGoogleBaseAttributes().addIntUnitAttribute(
|
||||
COOKING_TIME_ATTRIBUTE, cookingTime);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the id of the item from the given url.
|
||||
*
|
||||
* The id found in GoogleBaseEntry is a URL that contains the real, numerical
|
||||
* id of the item in Google Base. Parsing the URL is unfortunately the
|
||||
* only way of getting a numerical id given a GoogleBaseEntry.
|
||||
*
|
||||
* @param url a URL that ends with "/" [N] number
|
||||
*/
|
||||
private static String extractIdFromUrl(String url) {
|
||||
int lastSlash = url.lastIndexOf('/');
|
||||
if (lastSlash == -1 || lastSlash == (url.length()-1)) {
|
||||
throw new IllegalArgumentException("Id is in a strange format. " + url);
|
||||
}
|
||||
String oid = url.substring(lastSlash + 1);
|
||||
return oid;
|
||||
}
|
||||
|
||||
/** Checks whether there is a description for the recipe. */
|
||||
public boolean hasDescription() {
|
||||
return description != null;
|
||||
}
|
||||
|
||||
/** Checks whether there is a cooking time for the recipe. */
|
||||
public boolean hasCookingTime() {
|
||||
return cookingTime != null;
|
||||
}
|
||||
|
||||
/** Checks whether there are some cuisines for the recipe. */
|
||||
public boolean hasCuisine() {
|
||||
return cuisine.size() > 0;
|
||||
}
|
||||
|
||||
/** Checks whether there are some main ingredients for the recipe. */
|
||||
public boolean hasMainIngredient() {
|
||||
return mainIngredient.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date at which the recipe was posted, as a string.
|
||||
*
|
||||
* @param detailed set to true to get a full date and time
|
||||
*/
|
||||
public String getPostedOnAsString(boolean detailed) {
|
||||
Date date = new Date(postedOn.getValue());
|
||||
String template = detailed ? "MMMMM d, yyyy HH:mm z" : "MMM d";
|
||||
DateFormat format = new SimpleDateFormat(template);
|
||||
return format.format(date);
|
||||
}
|
||||
|
||||
/** Gets the host and protocol from the recipe URL. */
|
||||
public String getHostAndProtocol() throws MalformedURLException {
|
||||
URL urlObject = new URL(getUrl());
|
||||
return urlObject.getProtocol() + "://" + urlObject.getHost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the title, description, mainIngredient and cuisine
|
||||
* attributes are not null nor empty.
|
||||
*/
|
||||
public boolean isComplete() {
|
||||
return title != null &&
|
||||
description != null &&
|
||||
mainIngredient.size() > 0 &&
|
||||
cuisine.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("Recipe[");
|
||||
appendNamedParameter(sb, "title", title);
|
||||
appendNamedParameter(sb, "id", id);
|
||||
appendNamedParameter(sb, "url", url);
|
||||
appendNamedParameter(sb, "description", description);
|
||||
appendNamedParameter(sb, "cookingTime", cookingTime);
|
||||
appendNamedParameter(sb, "postedOn", postedOn);
|
||||
appendNamedParameter(sb, "postedBy", postedBy);
|
||||
appendNamedCollection(sb, "mainIngredient", mainIngredient);
|
||||
appendNamedCollection(sb, "cuisine", cuisine);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the name and the value of an Object to a StringBuffer.
|
||||
*
|
||||
* @param sb
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
private static void appendNamedParameter(StringBuffer sb,
|
||||
String name,
|
||||
Object value) {
|
||||
if (value != null) {
|
||||
sb.append(name).append("=\"").append(value).append("\" ");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the name and the elements of a Collection to a StringBuffer.
|
||||
*
|
||||
* @param sb
|
||||
* @param name
|
||||
* @param collection
|
||||
*/
|
||||
private static void appendNamedCollection(
|
||||
StringBuffer sb,
|
||||
String name,
|
||||
Collection<String> collection) {
|
||||
if (collection.size() > 0) {
|
||||
sb.append(name).append("=(");
|
||||
for (String value : collection) {
|
||||
sb.append("\"").append(value).append("\", ");
|
||||
}
|
||||
sb.append(") ");
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the id generated by the server. */
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/** Gets the user assigned title. */
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the url of the recipe, as set by the customer.
|
||||
* If the customer sets no url, the server will generate one.
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/** Gets the user assigned description. */
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/** Returns a never-null Set with the main ingredients of the recipe. */
|
||||
public Set<String> getMainIngredient() {
|
||||
return mainIngredient;
|
||||
}
|
||||
|
||||
/** Returns a never-null Set with the cuisines the recipe belongs to. */
|
||||
public Set<String> getCuisine() {
|
||||
return cuisine;
|
||||
}
|
||||
|
||||
/** Gets the user assigned cooking time. */
|
||||
public NumberUnit<Integer> getCookingTime() {
|
||||
return cookingTime;
|
||||
}
|
||||
|
||||
/** Gets the server generated owner attribute of the recipe. */
|
||||
public String getPostedBy() {
|
||||
return postedBy;
|
||||
}
|
||||
|
||||
/** Gets the server generated date at which the recipe was posted. */
|
||||
public DateTime getPostedOn() {
|
||||
return postedOn;
|
||||
}
|
||||
|
||||
/** Returns true when the Recipe doesn't have an id. */
|
||||
public boolean isNew() {
|
||||
return id == null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseEntry;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.api.gbase.client.NumberUnit;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Inserts, updates or deletes a recipe,
|
||||
* depending on the "action" servlet initialization parameter.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class RecipeActionServlet extends HttpServlet {
|
||||
|
||||
public static final String DISPLAY_JSP = "/WEB-INF/recipeEdit.jsp";
|
||||
|
||||
private static final int ACTION_ADD = 0;
|
||||
private static final int ACTION_UPDATE = 1;
|
||||
private static final int ACTION_DELETE = 2;
|
||||
|
||||
protected FeedURLFactory urlFactory;
|
||||
|
||||
/** The operation this servlet has to perform. */
|
||||
protected int action = -1;
|
||||
|
||||
@Override
|
||||
public void init(ServletConfig servletConfig) throws ServletException {
|
||||
super.init(servletConfig);
|
||||
ServletContext context = servletConfig.getServletContext();
|
||||
urlFactory = (FeedURLFactory)
|
||||
context.getAttribute(RecipeListener.FEED_URL_FACTORY_ATTRIBUTE);
|
||||
String action = servletConfig.getInitParameter("action");
|
||||
if ("add".equals(action)) {
|
||||
this.action = ACTION_ADD;
|
||||
} else if ("update".equals(action)) {
|
||||
this.action = ACTION_UPDATE;
|
||||
} else if ("delete".equals(action)) {
|
||||
this.action = ACTION_DELETE;
|
||||
} else {
|
||||
throw new ServletException("Unknown action: " + action);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAdd() { return ACTION_ADD == action; }
|
||||
private boolean isUpdate() { return ACTION_UPDATE == action; }
|
||||
private boolean isDelete() { return ACTION_DELETE == action; }
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/** Inserts or updates the submitted recipe and redirects to recipeList. */
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
GoogleBaseService service = (GoogleBaseService) request.getAttribute(
|
||||
AuthenticationFilter.SERVICE_ATTRIBUTE);
|
||||
Recipe recipe = getPostedRecipe(request);
|
||||
if (!recipe.isComplete()) {
|
||||
String message = "<div class='errormessage'>Please fill out " +
|
||||
"all the mandatory fields.</div>";
|
||||
editRecipe(request, response, recipe, message);
|
||||
} else {
|
||||
try {
|
||||
if (isAdd()) {
|
||||
recipeAdd(service, recipe);
|
||||
} else if (isUpdate()) {
|
||||
recipeUpdate(service, recipe);
|
||||
} else {
|
||||
throw new ServletException("Unknown POST action: " + action);
|
||||
}
|
||||
} catch (ServiceException e) {
|
||||
RecipeUtil.logServiceException(this, e);
|
||||
RecipeUtil.forwardToErrorPage(request, response, e);
|
||||
return;
|
||||
}
|
||||
listOwnRecipes(response);
|
||||
}
|
||||
}
|
||||
|
||||
/** Redirect to the page that lists customer's recipes. */
|
||||
protected void listOwnRecipes(HttpServletResponse response)
|
||||
throws IOException {
|
||||
String redirectUrl = "recipeList";
|
||||
response.sendRedirect(response.encodeRedirectURL(redirectUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a recipe using the specified authenticated service.
|
||||
*
|
||||
* @param service an authenticated GoogleBaseService
|
||||
* @param recipe recipe to be inserted
|
||||
* @throws IOException
|
||||
* @throws ServiceException
|
||||
*/
|
||||
protected void recipeAdd(GoogleBaseService service,
|
||||
Recipe recipe)
|
||||
throws IOException, ServiceException {
|
||||
URL feedUrl = urlFactory.getItemsFeedURL();
|
||||
GoogleBaseEntry entry = recipe.toGoogleBaseEntry(null);
|
||||
service.insert(feedUrl, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a recipe using the specified authenticated service.
|
||||
*
|
||||
* The recipe must have a valid GoogleBase id.
|
||||
*
|
||||
* @param service an authenticted GoogleBaseService
|
||||
* @param recipe recipe to be updated
|
||||
* @throws ServiceException
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void recipeUpdate(GoogleBaseService service,
|
||||
Recipe recipe)
|
||||
throws ServiceException, IOException {
|
||||
URL feedUrl = urlFactory.getItemsEntryURL(recipe.getId());
|
||||
GoogleBaseEntry entry = recipe.toGoogleBaseEntry(feedUrl.toString());
|
||||
service.update(feedUrl, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the specified authenticated service to delete a recipe.
|
||||
*
|
||||
* @param service an authenticated service
|
||||
* @param id the id of the recipe
|
||||
* @throws ServiceException
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void recipeDelete(GoogleBaseService service,
|
||||
String id)
|
||||
throws ServiceException, IOException {
|
||||
URL feedUrl = urlFactory.getItemsEntryURL(id);
|
||||
service.delete(feedUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Recipe from the parameters submitted with the specified request.
|
||||
*
|
||||
* @param request http request to be processed
|
||||
* @return a submitted recipe
|
||||
*/
|
||||
static Recipe getPostedRecipe(HttpServletRequest request) {
|
||||
String id = getNullIfEmpty(request.getParameter(RecipeUtil.ID_PARAMETER));
|
||||
String title = getNullIfEmpty(request.getParameter(
|
||||
RecipeUtil.TITLE_PARAMETER));
|
||||
String url = getNullIfEmpty(request.getParameter(RecipeUtil.URL_PARAMETER));
|
||||
String description = getNullIfEmpty(request.getParameter(
|
||||
RecipeUtil.DESCRIPTION_PARAMETER));
|
||||
Set<String> mainIngredient = RecipeUtil.validateValues(
|
||||
request.getParameterValues(RecipeUtil.MAIN_INGREDIENT_PARAMETER));
|
||||
Set<String> cuisine = RecipeUtil.validateValues(
|
||||
request.getParameterValues(RecipeUtil.CUISINE_PARAMETER));
|
||||
NumberUnit<Integer> cookingTime;
|
||||
try {
|
||||
cookingTime = new NumberUnit<Integer>(
|
||||
new Integer(request.getParameter(RecipeUtil.COOKING_TIME_PARAMETER)),
|
||||
RecipeUtil.COOKING_TIME_UNIT);
|
||||
} catch (Exception e) {
|
||||
// If anything goes bad, we set cookingTime to null
|
||||
cookingTime = null;
|
||||
}
|
||||
Recipe recipe = new Recipe(id,
|
||||
title,
|
||||
url,
|
||||
description,
|
||||
mainIngredient,
|
||||
cuisine,
|
||||
cookingTime);
|
||||
return recipe;
|
||||
}
|
||||
|
||||
static private String getNullIfEmpty(String s) {
|
||||
return s != null && "".equals(s) ? null : s;
|
||||
}
|
||||
|
||||
|
||||
/** Shows the page for inserting or updating a recipe or deletes a recipe. */
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
GoogleBaseService service = (GoogleBaseService) request.getAttribute(
|
||||
AuthenticationFilter.SERVICE_ATTRIBUTE);
|
||||
String id = request.getParameter(RecipeUtil.ID_PARAMETER);
|
||||
try {
|
||||
if (isDelete()) {
|
||||
recipeDelete(service, id);
|
||||
listOwnRecipes(response);
|
||||
} else {
|
||||
// The recipe that will be used on the edit page
|
||||
// for inserting or updating.
|
||||
Recipe recipe = null;
|
||||
if (isAdd()) {
|
||||
recipe = new Recipe();
|
||||
} else if (isUpdate()) {
|
||||
URL entryUrl = urlFactory.getItemsEntryURL(id);
|
||||
GoogleBaseEntry entry = service.getEntry(entryUrl);
|
||||
recipe = new Recipe(entry);
|
||||
}
|
||||
if (recipe != null) {
|
||||
// Ready to add or update
|
||||
editRecipe(request, response, recipe, null);
|
||||
}
|
||||
}
|
||||
} catch (ServiceException e) {
|
||||
RecipeUtil.logServiceException(this, e);
|
||||
RecipeUtil.forwardToErrorPage(request, response, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@value RecipeUtil#RECIPE_ATTRIBUTE} attribute of the request to
|
||||
* contain the specified recipe and forwards the request to the
|
||||
* {@value #DISPLAY_JSP} page.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param recipe the recipe to be passed to the edit jsp page
|
||||
* @param message HTML code to be displayed at the top of the page, usually an
|
||||
* error message
|
||||
*/
|
||||
private void editRecipe(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Recipe recipe,
|
||||
String message)
|
||||
throws ServletException, IOException {
|
||||
request.setAttribute(RecipeUtil.RECIPE_ATTRIBUTE, recipe);
|
||||
request.setAttribute(RecipeUtil.MESSAGE_ATTRIBUTE,
|
||||
message == null ? "" : message);
|
||||
// Forward to the JSP
|
||||
request.getRequestDispatcher(DISPLAY_JSP).forward(request, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseEntry;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Displays a recipe.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class RecipeDisplayServlet extends HttpServlet {
|
||||
|
||||
public static final String DISPLAY_JSP = "/WEB-INF/recipeDisplay.jsp";
|
||||
|
||||
protected FeedURLFactory urlFactory;
|
||||
|
||||
@Override
|
||||
public void init(ServletConfig servletConfig) throws ServletException {
|
||||
super.init(servletConfig);
|
||||
ServletContext context = servletConfig.getServletContext();
|
||||
urlFactory = (FeedURLFactory)
|
||||
context.getAttribute(RecipeListener.FEED_URL_FACTORY_ATTRIBUTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the page for displaying a Recipe.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
// This is a public page, so we use a simple, nonauthenticated service
|
||||
GoogleBaseService service = RecipeUtil.getGoogleBaseService(request,
|
||||
this.getServletContext());
|
||||
String id = request.getParameter(RecipeUtil.ID_PARAMETER);
|
||||
recipeDisplay(request, response, service, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a recipe and forwards the request
|
||||
* to the {@link #DISPLAY_JSP} jsp page that displays the recipe.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param service the service used to retrieve the recipe
|
||||
* @param id the id of the recipe
|
||||
*/
|
||||
private void recipeDisplay(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
GoogleBaseService service,
|
||||
String id)
|
||||
throws ServletException, IOException {
|
||||
GoogleBaseEntry entry;
|
||||
try {
|
||||
URL feedUrl = urlFactory.getSnippetsEntryURL(id);
|
||||
entry = service.getEntry(feedUrl, GoogleBaseEntry.class);
|
||||
} catch (ServiceException e) {
|
||||
RecipeUtil.logServiceException(this, e);
|
||||
RecipeUtil.forwardToErrorPage(request, response, e);
|
||||
return;
|
||||
}
|
||||
Recipe recipe = new Recipe(entry);
|
||||
request.setAttribute(RecipeUtil.RECIPE_ATTRIBUTE, recipe);
|
||||
RecipeSearch results = new RecipeSearch(service, urlFactory, false);
|
||||
RecipeUtil.setRecipeSearch(request, results);
|
||||
// Forward to the JSP
|
||||
request.getRequestDispatcher(DISPLAY_JSP).forward(request, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
/**
|
||||
* Creates objects needed by the servlets and makes them available by
|
||||
* setting them as attributes of the global servlet context.
|
||||
*
|
||||
* Makes sure the required initialization parameters are present.
|
||||
*
|
||||
*/
|
||||
public class RecipeListener implements ServletContextListener {
|
||||
|
||||
public static final String MOST_USED_VALUES_ATTRIBUTE = "mostUsedValues";
|
||||
|
||||
public static final String FEED_URL_FACTORY_ATTRIBUTE = "feedUrlFactory";
|
||||
|
||||
FeedURLFactory urlFactory;
|
||||
|
||||
protected MostUsedValues mostUsedValues;
|
||||
|
||||
/**
|
||||
* Creates an initialised MostUsedValues object and a FeedURLFactory
|
||||
* to be used by the servlets.
|
||||
* Makes sure the applicationName init parameter is set.
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public void contextInitialized(ServletContextEvent event) {
|
||||
ServletContext servletContext = event.getServletContext();
|
||||
|
||||
String applicationName =
|
||||
servletContext.getInitParameter(RecipeUtil.APPLICATION_NAME_PARAMETER);
|
||||
if (applicationName == null) {
|
||||
RuntimeException re =
|
||||
new RuntimeException("applicationName context parameter is missing");
|
||||
servletContext.log(re.getMessage(), re.getCause());
|
||||
throw re;
|
||||
}
|
||||
|
||||
String baseUrl = servletContext.getInitParameter("baseUrl");
|
||||
if (baseUrl == null) {
|
||||
urlFactory = FeedURLFactory.getDefault();
|
||||
} else {
|
||||
try {
|
||||
urlFactory = new FeedURLFactory(baseUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
RuntimeException re =
|
||||
new RuntimeException("Cannot use the baseUrl context parameter", e);
|
||||
servletContext.log(re.getMessage(), re.getCause());
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
servletContext.setAttribute(FEED_URL_FACTORY_ATTRIBUTE, urlFactory);
|
||||
|
||||
String key = servletContext.getInitParameter(RecipeUtil.DEVELOPER_KEY_PARAMETER);
|
||||
|
||||
GoogleBaseService service = new GoogleBaseService(applicationName, key);
|
||||
mostUsedValues = new MostUsedValues(service,
|
||||
urlFactory,
|
||||
RecipeUtil.RECIPE_ITEMTYPE_QUERY);
|
||||
initMostUsedValues(mostUsedValues, servletContext);
|
||||
RecipeUtil.setMostUsedValues(servletContext, mostUsedValues);
|
||||
}
|
||||
|
||||
public void contextDestroyed(ServletContextEvent event) {
|
||||
mostUsedValues.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a MostUsedValues object to cache the most used values
|
||||
* of some attributes, suitable to be used in the web pages.
|
||||
*
|
||||
* @param mostUsedValues object to initialize
|
||||
* @param servletContext the servlet context used by mostUsedValues
|
||||
* to log exceptions
|
||||
*/
|
||||
public static void initMostUsedValues(MostUsedValues mostUsedValues,
|
||||
ServletContext servletContext) {
|
||||
long interval = 1000L * 60L * 60L; // 1 hour
|
||||
mostUsedValues.cache(interval, 14, servletContext,
|
||||
Recipe.CUISINE_ATTRIBUTE);
|
||||
mostUsedValues.cache(interval, 16, servletContext,
|
||||
Recipe.MAIN_INGREDIENT_ATTRIBUTE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseEntry;
|
||||
import com.google.api.gbase.client.GoogleBaseFeed;
|
||||
import com.google.api.gbase.client.GoogleBaseQuery;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A recipe search.
|
||||
*
|
||||
* There will be such an object in all cases, even
|
||||
* if no query has been run. This object is created
|
||||
* by RecipeSearchServlet and displayed by the JSP.
|
||||
*/
|
||||
public class RecipeSearch {
|
||||
private final GoogleBaseService service;
|
||||
private Set<String> mainIngredient;
|
||||
private Set<String> cuisine;
|
||||
private Integer cookingTime;
|
||||
private String query;
|
||||
|
||||
/** The query string, with the unsupported characters replaced with spaces.*/
|
||||
private String queryClean;
|
||||
|
||||
/** The index of the first retrieved recipe. */
|
||||
private int startIndex = 0;
|
||||
|
||||
/** Set to true to perform the search on the user's items. */
|
||||
private boolean ownItems;
|
||||
|
||||
/** Total number of results, -1 means the query hasn't been run yet. */
|
||||
protected int total = -1;
|
||||
|
||||
protected List<Recipe> recipes;
|
||||
|
||||
private static final int DEFAULT_MAX_RESULTS = 10;
|
||||
private int maxResults = DEFAULT_MAX_RESULTS;
|
||||
|
||||
private final FeedURLFactory urlFactory;
|
||||
|
||||
/**
|
||||
* Create a new search.
|
||||
*
|
||||
* @param service Google data API service
|
||||
* @param urlFactory feed URL factory to be used when creating a Query
|
||||
* @param ownItems true to show only the items of the authenticated user
|
||||
*/
|
||||
public RecipeSearch(GoogleBaseService service,
|
||||
FeedURLFactory urlFactory,
|
||||
boolean ownItems) {
|
||||
this.service = service;
|
||||
this.urlFactory = urlFactory;
|
||||
this.ownItems = ownItems;
|
||||
|
||||
mainIngredient = null;
|
||||
cuisine = null;
|
||||
cookingTime = null;
|
||||
query = null;
|
||||
queryClean = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the search has been run and there is at least one result.
|
||||
*
|
||||
* @return true if the search has been run and there is at least one result
|
||||
*/
|
||||
public boolean hasResults() {
|
||||
return recipes != null && ! recipes.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result of the search, if it has been run.
|
||||
*
|
||||
* @return a list of Recipe which might be empty if the
|
||||
* search has been run, or null if the search has not
|
||||
* been run yet
|
||||
*/
|
||||
public List<Recipe> getRecipes() {
|
||||
return recipes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the search will be done for the authenticated user's items only.
|
||||
*
|
||||
* @return true if the search returns only the items that belong to the
|
||||
* authenticated user
|
||||
*/
|
||||
public boolean isOwnItems() {
|
||||
return ownItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if we are searching the authenticated user's items.
|
||||
*
|
||||
* @param ownItems true to search only the authenticated user's items
|
||||
*/
|
||||
public void setOwnItems(boolean ownItems) {
|
||||
this.ownItems = ownItems;
|
||||
}
|
||||
|
||||
/** Gets the current main ingredients, or null. */
|
||||
public Set<String> getMainIngredientValues() {
|
||||
return mainIngredient;
|
||||
}
|
||||
|
||||
/** Sets the main ingredient. */
|
||||
public void setMainIngredientValues(String[] mainIngredient) {
|
||||
this.mainIngredient = RecipeUtil.validateValues(mainIngredient);
|
||||
}
|
||||
|
||||
/** Gets the current cuisines, or null. */
|
||||
public Set<String> getCuisineValues() {
|
||||
return cuisine;
|
||||
}
|
||||
|
||||
/** Sets the cuisine. */
|
||||
public void setCuisineValues(String[] cuisine) {
|
||||
this.cuisine = RecipeUtil.validateValues(cuisine);
|
||||
}
|
||||
|
||||
/** Gets the current (maximum) cooking time, or null. */
|
||||
public Integer getCookingTime() {
|
||||
return cookingTime;
|
||||
}
|
||||
|
||||
/** Sets the current maximum cooking time. */
|
||||
public void setCookingTime(Integer cookingTime) {
|
||||
this.cookingTime = cookingTime;
|
||||
}
|
||||
|
||||
/** Gets the current page length. */
|
||||
public int getMaxResults() {
|
||||
return maxResults;
|
||||
}
|
||||
|
||||
/** Sets the page length. */
|
||||
public void setMaxResults(int maxResults) {
|
||||
this.maxResults = maxResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of recipes that matched the query, which
|
||||
* might be larger than the page length.
|
||||
*
|
||||
* @return the total, or -1 if the total is unknown, either because
|
||||
* the query has not been run or because the total was not in
|
||||
* the result
|
||||
*/
|
||||
public int getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the first result to return.
|
||||
*
|
||||
* @return a positive value
|
||||
*/
|
||||
public int getStartIndex() {
|
||||
return startIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index of the first result to return.
|
||||
* @param startIndex a positive value
|
||||
*/
|
||||
public void setStartIndex(int startIndex) {
|
||||
this.startIndex = startIndex;
|
||||
}
|
||||
|
||||
/** Gets the current page. */
|
||||
public int getCurrentPage() {
|
||||
return startIndex / maxResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a description of the retrieved (current) interval, showing
|
||||
* the index of the first item and the index of the last item.
|
||||
*
|
||||
* @return short description of the current page interval
|
||||
*/
|
||||
public String getCurrentPageInterval() {
|
||||
return "" + (startIndex + 1) + " - " +
|
||||
Math.min(startIndex + maxResults, total);
|
||||
}
|
||||
|
||||
/** Gets the number of pages needed to contain all the results. */
|
||||
public int getTotalPages() {
|
||||
if (total == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* Using total-1, because if we have 10 results and 10 items per page,
|
||||
* we still want one page.
|
||||
*/
|
||||
return (total - 1) / maxResults;
|
||||
}
|
||||
|
||||
/** Runs the query and fills the result. */
|
||||
public void runQuery() throws IOException, ServiceException {
|
||||
GoogleBaseQuery query = createQuery();
|
||||
System.out.println("Searching: " + query.getUrl());
|
||||
GoogleBaseFeed feed = service.query(query);
|
||||
List<Recipe> result = new ArrayList<Recipe>(maxResults);
|
||||
for (GoogleBaseEntry entry : feed.getEntries()) {
|
||||
result.add(new Recipe(entry));
|
||||
}
|
||||
this.recipes = result;
|
||||
total = feed.getTotalResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a GoogleBaseQuery that searches for recipes, according to
|
||||
* the various properties of the RecipeSearch.
|
||||
*
|
||||
* @return a query to be used for querying with a
|
||||
* {@link com.google.api.gbase.client.GoogleBaseService
|
||||
* GoogleBaseService}
|
||||
* @see com.google.api.gbase.client.GoogleBaseService#query(com.google.gdata.client.Query)
|
||||
*/
|
||||
private GoogleBaseQuery createQuery() {
|
||||
URL queryUrl;
|
||||
if (ownItems) {
|
||||
queryUrl = urlFactory.getItemsFeedURL();
|
||||
} else {
|
||||
queryUrl = urlFactory.getSnippetsFeedURL();
|
||||
}
|
||||
GoogleBaseQuery query = new GoogleBaseQuery(queryUrl);
|
||||
query.setMaxResults(maxResults);
|
||||
if (startIndex > 0) {
|
||||
// the first index is 1
|
||||
query.setStartIndex(startIndex + 1);
|
||||
}
|
||||
query.setGoogleBaseQuery(createQueryString());
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a full text query out of the values of the query, mainIngredient,
|
||||
* cuisine and cookingTime.
|
||||
*
|
||||
* @return a query to be used for setting the full text query of a
|
||||
* {@link com.google.api.gbase.client.GoogleBaseQuery}
|
||||
* @see com.google.api.gbase.client.GoogleBaseQuery#setFullTextQuery(String)
|
||||
*/
|
||||
private String createQueryString() {
|
||||
StringBuffer retval = new StringBuffer(RecipeUtil.RECIPE_ITEMTYPE_QUERY);
|
||||
if (queryClean != null) {
|
||||
retval.append(queryClean);
|
||||
}
|
||||
appendAttributeCondition(retval, "main ingredient", mainIngredient, true);
|
||||
appendAttributeCondition(retval, "cuisine", cuisine, false);
|
||||
if (cookingTime != null) {
|
||||
Collection<String> cookingTimes = new ArrayList<String>();
|
||||
cookingTimes.add("0.." + cookingTime + " min");
|
||||
cookingTimes.add("0.." + cookingTime + " minutes");
|
||||
appendAttributeCondition(retval, "cooking time", cookingTimes, false);
|
||||
}
|
||||
return retval.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a filtering condition to a full text query.
|
||||
* It is composed by simple [name: value] conditions
|
||||
* joined by and AND or an OR operation.
|
||||
*
|
||||
* @param sb a StringBuffer for creating a full text query
|
||||
* @param name name of the attributes
|
||||
* @param values values the attributes have to match
|
||||
* @param isAnd true if the attributes have to match all the values,
|
||||
* false if the attributes have to match at least one value
|
||||
*/
|
||||
private static void appendAttributeCondition(StringBuffer sb,
|
||||
String name,
|
||||
Collection<String> values,
|
||||
boolean isAnd) {
|
||||
if (values != null && !values.isEmpty()) {
|
||||
sb.append(" (");
|
||||
Iterator iter = values.iterator();
|
||||
while (iter.hasNext()) {
|
||||
sb.append("[").append(name).append(": ").append(iter.next()).append("]");
|
||||
if (iter.hasNext()) {
|
||||
sb.append(isAnd ? " " : "|");
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true when the current page is not the first page. */
|
||||
public boolean hasPreviousPage() {
|
||||
return getCurrentPage() > 0;
|
||||
}
|
||||
|
||||
/** Returns true when the current page is not the last one. */
|
||||
public boolean hasNextPage() {
|
||||
return getTotalPages() > getCurrentPage();
|
||||
}
|
||||
|
||||
/** Gets the expected number of recipes for the next page. */
|
||||
public int getNextPageSize() {
|
||||
return Math.min(maxResults, total - (getCurrentPage() + 1) * maxResults);
|
||||
}
|
||||
|
||||
/** Gets a description of the query used in the search. */
|
||||
public StringBuffer getFilterDescription() {
|
||||
StringBuffer retval = new StringBuffer();
|
||||
if (queryClean != null && ! "".equals(queryClean)) {
|
||||
retval.append("<b>keywords</b> are <b>").
|
||||
append(queryClean).
|
||||
append("</b> ");
|
||||
}
|
||||
addCollectionDescription(retval, cuisine, "cuisine", false);
|
||||
addCollectionDescription(retval, mainIngredient, "main ingredient", true);
|
||||
if (cookingTime != null) {
|
||||
if (retval.length() > 0) {
|
||||
retval.append("and ");
|
||||
}
|
||||
retval.append("<b>cooking time</b> is under <b>").
|
||||
append(cookingTime).
|
||||
append(" ").
|
||||
append(RecipeUtil.COOKING_TIME_UNIT).
|
||||
append("</b> ");
|
||||
}
|
||||
if (retval.length() > 0) {
|
||||
retval.insert(0, "where ");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
private static void addCollectionDescription(StringBuffer buffer,
|
||||
Collection<String> collection,
|
||||
String name,
|
||||
boolean isAnd) {
|
||||
if (collection != null && ! collection.isEmpty()) {
|
||||
if (buffer.length() > 0) {
|
||||
buffer.append("and ");
|
||||
}
|
||||
buffer.append("<b>").append(name).append("</b> is");
|
||||
Iterator<String> iter = collection.iterator();
|
||||
while (iter.hasNext()) {
|
||||
buffer.append(" <b>").append(iter.next()).append("</b> ");
|
||||
if (iter.hasNext()) {
|
||||
buffer.append(isAnd ? "and " : "or ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query string.
|
||||
*
|
||||
* @param query the query string, as provided by user
|
||||
* @throws NullPointerException if the {@code query} is null.
|
||||
*/
|
||||
public void setQuery(String query) {
|
||||
if (query != null) {
|
||||
this.query = query;
|
||||
this.queryClean = RecipeUtil.cleanQueryString(query);
|
||||
} else {
|
||||
throw new NullPointerException("Query must not be null.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original query string, as specified in the
|
||||
* {@link #setQuery(String)} method.
|
||||
*/
|
||||
public String getQuery() {
|
||||
return query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Setup a {@link RecipeSearch} object and optionally fill it.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class RecipeSearchServlet extends HttpServlet {
|
||||
|
||||
private static final String START_INDEX_PARAMETER = "startIndex";
|
||||
|
||||
private static final String MAX_RESULTS_PARAMETER = "maxResults";
|
||||
|
||||
private static final String QUERY_PARAMETER = "query";
|
||||
|
||||
public static final String DISPLAY_JSP = "/WEB-INF/recipeSearch.jsp";
|
||||
|
||||
protected boolean ownItems;
|
||||
|
||||
protected FeedURLFactory urlFactory;
|
||||
|
||||
@Override
|
||||
public void init(ServletConfig servletConfig) throws ServletException {
|
||||
super.init(servletConfig);
|
||||
ServletContext context = servletConfig.getServletContext();
|
||||
urlFactory = (FeedURLFactory)
|
||||
context.getAttribute(RecipeListener.FEED_URL_FACTORY_ATTRIBUTE);
|
||||
String scope = servletConfig.getInitParameter("scope");
|
||||
ownItems = "own".equals(scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Runs a recipe search.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
GoogleBaseService service = RecipeUtil.getGoogleBaseService(request,
|
||||
this.getServletContext());
|
||||
RecipeSearch recipeSearch;
|
||||
try {
|
||||
if (request.getParameter("query") == null) {
|
||||
recipeSearch = new RecipeSearch(service, urlFactory, ownItems);
|
||||
} else {
|
||||
recipeSearch = createRecipeSearch(service, request);
|
||||
}
|
||||
recipeSearch.runQuery();
|
||||
} catch (RecipeValidationException rve) {
|
||||
// internal exception in the argument handling (possibly incorrect args)
|
||||
RecipeUtil.forwardToErrorPage(request, response, rve.getMessage());
|
||||
return;
|
||||
} catch (ServiceException se) {
|
||||
// exception comming from Google Base
|
||||
RecipeUtil.logServiceException(this, se);
|
||||
RecipeUtil.forwardToErrorPage(request, response, se);
|
||||
return;
|
||||
}
|
||||
|
||||
RecipeUtil.setRecipeSearch(request, recipeSearch);
|
||||
// Forward to the JSP
|
||||
request.getRequestDispatcher(DISPLAY_JSP).forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and fills in a {@link RecipeSearch} object based on the content
|
||||
* of the {@code request}.
|
||||
*
|
||||
* @param service the object used to connect to the Google Base service
|
||||
* @param request the representation of the Http request
|
||||
* @throws RecipeValidationException if a parameter from the request has an
|
||||
* invalid value (cooking time, start index, max results are not valid
|
||||
* numbers).
|
||||
*/
|
||||
private RecipeSearch createRecipeSearch(GoogleBaseService service,
|
||||
HttpServletRequest request)
|
||||
throws RecipeValidationException {
|
||||
RecipeSearch search = new RecipeSearch(service, urlFactory, ownItems);
|
||||
|
||||
String query = request.getParameter(QUERY_PARAMETER);
|
||||
if (isSet(query)) {
|
||||
search.setQuery(query);
|
||||
}
|
||||
|
||||
String[] mainIngredient = request.getParameterValues(
|
||||
RecipeUtil.MAIN_INGREDIENT_PARAMETER);
|
||||
if (isSet(mainIngredient)) {
|
||||
search.setMainIngredientValues(mainIngredient);
|
||||
}
|
||||
|
||||
String[] cuisine = request.getParameterValues(
|
||||
RecipeUtil.CUISINE_PARAMETER);
|
||||
if (isSet(cuisine)) {
|
||||
search.setCuisineValues(cuisine);
|
||||
}
|
||||
|
||||
String cookingTime = request.getParameter(
|
||||
RecipeUtil.COOKING_TIME_PARAMETER);
|
||||
if (isSet(cookingTime)) {
|
||||
try {
|
||||
search.setCookingTime(new Integer(cookingTime));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RecipeValidationException(String.format(
|
||||
"Cooking time is not a number (%s).", cookingTime));
|
||||
}
|
||||
}
|
||||
|
||||
String startIndex = request.getParameter(START_INDEX_PARAMETER);
|
||||
if (isSet(startIndex)) {
|
||||
try {
|
||||
search.setStartIndex(Integer.parseInt(startIndex));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RecipeValidationException(String.format(
|
||||
"Start index is not a number (%s).", startIndex));
|
||||
}
|
||||
}
|
||||
|
||||
String maxResults = request.getParameter(MAX_RESULTS_PARAMETER);
|
||||
if (isSet(maxResults)) {
|
||||
try {
|
||||
search.setMaxResults(Integer.parseInt(maxResults));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RecipeValidationException(String.format(
|
||||
"Max results is not a number (%s).", maxResults));
|
||||
}
|
||||
}
|
||||
|
||||
search.setOwnItems(ownItems);
|
||||
|
||||
return search;
|
||||
}
|
||||
|
||||
private boolean isSet(String parameter) {
|
||||
return parameter != null && !"".equals(parameter);
|
||||
}
|
||||
|
||||
private boolean isSet(String[] parameter) {
|
||||
return parameter != null && parameter.length > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.api.gbase.client.ServiceErrors;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Contains the names of the HTML input fields used to edit a recipe.
|
||||
* Has methods that are generally useful, for example for logging
|
||||
* or validating values.
|
||||
* Has methods to extract values from servlet context init parameters.
|
||||
* Has methods used for passing objects from a servlet to a JSP.
|
||||
*/
|
||||
public class RecipeUtil {
|
||||
|
||||
public static final String ID_PARAMETER = "oid";
|
||||
public static final String APPLICATION_NAME_PARAMETER = "applicationName";
|
||||
public static final String TITLE_PARAMETER = "title";
|
||||
public static final String URL_PARAMETER = "url";
|
||||
public static final String DESCRIPTION_PARAMETER = "description";
|
||||
public static final String MAIN_INGREDIENT_PARAMETER = "mainIngredient";
|
||||
public static final String CUISINE_PARAMETER = "cuisine";
|
||||
public static final String COOKING_TIME_PARAMETER = "cookingTime";
|
||||
public static final String DEVELOPER_KEY_PARAMETER = "key";
|
||||
|
||||
public static final String COOKING_TIME_UNIT = "minutes";
|
||||
|
||||
public static final String RECIPE_ATTRIBUTE = "recipe";
|
||||
public static final String RECIPESEARCH_ATTRIBUTE = "recipeSearch";
|
||||
public static final String RECIPESEARCH_ERROR = "recipeSearchError";
|
||||
public static final String RECIPESEARCH_ERROR_DESCRIPTION =
|
||||
"recipeSearchErrorDescription";
|
||||
public static final String RECIPESEARCH_ERROR_OBJECT =
|
||||
"recipeSearchErrorService";
|
||||
public static final String MESSAGE_ATTRIBUTE = "message";
|
||||
|
||||
public static final String RECIPE_ITEMTYPE_QUERY =
|
||||
"[item type : recipe | recipes]";
|
||||
|
||||
/** Pattern used for finding the unsupported characters in the query string.*/
|
||||
private static final Pattern QUERY_REPLACE_PATTERN =
|
||||
Pattern.compile("\\p{Punct}");
|
||||
|
||||
public static final String ERROR_JSP = "/WEB-INF/recipeError.jsp";
|
||||
|
||||
/**
|
||||
* Builds a HashSet containing the specified values,
|
||||
* filtering the null and empty ones.
|
||||
*
|
||||
* @param values usually an array returned by request.getParameterValues()
|
||||
* @return a HashSet containing the nonempty values
|
||||
*/
|
||||
public static Set<String> validateValues(String[] values) {
|
||||
Set<String> valuesList = new HashSet<String>();
|
||||
if (values != null) {
|
||||
for (String value : values) {
|
||||
value = cleanQueryString(value);
|
||||
if (value != null && ! "".equals(value)) {
|
||||
valuesList.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return valuesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the {@code searchString} set by the user, by removing the special
|
||||
* punctuation characters not allowed directly in a query.
|
||||
*
|
||||
* @param searchString the string set by the user
|
||||
* @return the String to be used for executing the query to Google Base.
|
||||
*/
|
||||
public static String cleanQueryString(String searchString) {
|
||||
Matcher matcher = QUERY_REPLACE_PATTERN.matcher(searchString);
|
||||
return matcher.replaceAll(" ").trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an exception in a convenient format,
|
||||
* using the log method of a servlet context.
|
||||
*
|
||||
* @param servlet the servlet used to log the exception
|
||||
* @param e exception to be logged
|
||||
*/
|
||||
public static void logServiceException(HttpServlet servlet,
|
||||
ServiceException e) {
|
||||
if (e.getResponseBody() != null) {
|
||||
// Log the full error message and response code.
|
||||
servlet.log(e.getMessage() + " " +
|
||||
e.getHttpErrorCodeOverride() + " " +
|
||||
e.getResponseContentType() + ": " +
|
||||
e.getResponseBody(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a RecipeSearch as an attribute of a HttpServletRequest.
|
||||
*
|
||||
* @param request a request that will be passed to a JSP
|
||||
* @param results the RecipeSearch, executed or not
|
||||
*/
|
||||
public static void setRecipeSearch(HttpServletRequest request,
|
||||
RecipeSearch results) {
|
||||
request.setAttribute(RECIPESEARCH_ATTRIBUTE, results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets from a HttpServletRequest a RecipeSearch that was previously set
|
||||
* using {@link #setRecipeSearch}.
|
||||
* If it is missing, a NullPointerException is thrown.
|
||||
*
|
||||
* @param request a request passed from a Servlet
|
||||
* @return a non-null RecipeSearch
|
||||
*/
|
||||
public static RecipeSearch getRecipeSearch(HttpServletRequest request) {
|
||||
RecipeSearch results = (RecipeSearch)request.getAttribute(
|
||||
RECIPESEARCH_ATTRIBUTE);
|
||||
if (null == results) {
|
||||
throw new NullPointerException("recipe search results are missing");
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error message, or {@code null} if no error message was set in the
|
||||
* request.
|
||||
*
|
||||
* @param request the request in which the method will locate the error
|
||||
* @return the error message, or {@code null} if no message was set
|
||||
*/
|
||||
public static String getRecipeError(HttpServletRequest request) {
|
||||
return (String)request.getAttribute(RECIPESEARCH_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error message, or {@code null} if no error message was set in the
|
||||
* request.
|
||||
*
|
||||
* @param request the request in which the method will locate the error
|
||||
* @return the error message, or {@code null} if no message was set
|
||||
*/
|
||||
public static String getRecipeErrorDescription(HttpServletRequest request) {
|
||||
return (String)request.getAttribute(RECIPESEARCH_ERROR_DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the errors obtained from Google Base, or {@code null} if no service
|
||||
* error was set in the request.
|
||||
*
|
||||
* @param request the request in which the method will locate the error
|
||||
* @return the service errors, or {@code null} if no service errors were set
|
||||
*/
|
||||
public static ServiceErrors getRecipeErrorObject(HttpServletRequest request) {
|
||||
return (ServiceErrors)request.getAttribute(RECIPESEARCH_ERROR_OBJECT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the request to the error page, for displaying the specified
|
||||
* {@code errorMessage} and the {@code description}. No service errors will
|
||||
* be displayed.
|
||||
*
|
||||
* @param request the request object
|
||||
* @param response the response object
|
||||
* @param errorMessage the error message to be displayed
|
||||
* @param description the description of the error message, {@code null} if
|
||||
* no description should be displayed.
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void forwardToErrorPage(HttpServletRequest request,
|
||||
HttpServletResponse response, String errorMessage)
|
||||
throws ServletException, IOException {
|
||||
request.setAttribute(RECIPESEARCH_ERROR, errorMessage);
|
||||
request.getRequestDispatcher(ERROR_JSP).forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the request to the error page, for displaying the information
|
||||
* contained by the {@code se} parameter. This method registers the service
|
||||
* errors too, using a {@link ServiceErrors} object.
|
||||
*
|
||||
* @param request the request object
|
||||
* @param response the response object
|
||||
* @param se the service error containing the information for the error page
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void forwardToErrorPage(HttpServletRequest request,
|
||||
HttpServletResponse response, ServiceException se)
|
||||
throws ServletException, IOException {
|
||||
request.setAttribute(RECIPESEARCH_ERROR, se.getMessage());
|
||||
request.setAttribute(RECIPESEARCH_ERROR_DESCRIPTION, se.getResponseBody());
|
||||
request.setAttribute(RECIPESEARCH_ERROR_OBJECT, new ServiceErrors(se));
|
||||
request.getRequestDispatcher(ERROR_JSP).forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the GoogleBaseService object created by {@link AuthenticationFilter}
|
||||
* or creates a new one if <code>AuthenticationFilter</code> has not been
|
||||
* applied yet.
|
||||
*
|
||||
* @param req
|
||||
* @param servletContext
|
||||
* @return a GoogleBaseService object
|
||||
*/
|
||||
public static GoogleBaseService getGoogleBaseService(HttpServletRequest req,
|
||||
ServletContext servletContext) {
|
||||
GoogleBaseService service;
|
||||
service = (GoogleBaseService) req.getAttribute(
|
||||
AuthenticationFilter.SERVICE_ATTRIBUTE);
|
||||
if (service == null) {
|
||||
service = new GoogleBaseService(
|
||||
servletContext.getInitParameter(APPLICATION_NAME_PARAMETER),
|
||||
servletContext.getInitParameter(DEVELOPER_KEY_PARAMETER));
|
||||
req.setAttribute(AuthenticationFilter.SERVICE_ATTRIBUTE, service);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a MostUsedValues that was previously set using
|
||||
* {@link #setMostUsedValues}.
|
||||
*
|
||||
* @param servletContext
|
||||
* @return a non-null initialized MostUsedValues
|
||||
*/
|
||||
public static MostUsedValues getMostUsedValues(ServletContext servletContext)
|
||||
throws ServletException {
|
||||
MostUsedValues mostUsedValues = (MostUsedValues)
|
||||
servletContext.getAttribute(RecipeListener.MOST_USED_VALUES_ATTRIBUTE);
|
||||
if (null == mostUsedValues) {
|
||||
throw new ServletException("Most used values cache is missing");
|
||||
}
|
||||
return mostUsedValues;
|
||||
}
|
||||
|
||||
public static void setMostUsedValues(ServletContext servletContext,
|
||||
MostUsedValues mostUsedValues) {
|
||||
servletContext.setAttribute(RecipeListener.MOST_USED_VALUES_ATTRIBUTE,
|
||||
mostUsedValues);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/* Copyright (c) 2007 Google Inc.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package sample.gbase.recipe;
|
||||
|
||||
/**
|
||||
* Exception thrown when an invalid parameter is received by the Recipe Demo
|
||||
* Application.
|
||||
*/
|
||||
public class RecipeValidationException extends Exception {
|
||||
|
||||
public RecipeValidationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="demolabel">
|
||||
This recipe book is a demo of the Google Base Data API. <br/><a href="http://code.google.com/apis/base">Learn more and download API tools</a>.
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
<div id="footer">
|
||||
<a href="http://code.google.com/apis/base">Google Base Data API</a> -
|
||||
<a href="http://code.google.com/apis/base/terms.html">Terms and Conditions</a> -
|
||||
<a href="http://base.google.com">Google Base</a> -
|
||||
<a href="http://www.google.com">Google home</a>
|
||||
<p id="copyright">© Google 2006</p>
|
||||
</div>
|
||||
@@ -0,0 +1,68 @@
|
||||
<%--
|
||||
Copyright (c) 2006 Google Inc.
|
||||
|
||||
Licensed 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.
|
||||
--%>
|
||||
<%@ page import="sample.gbase.recipe.DisplayUtils"%>
|
||||
<%@ page import="sample.gbase.recipe.Recipe"%>
|
||||
<%@ page import="sample.gbase.recipe.RecipeSearch"%>
|
||||
<%@ page import="sample.gbase.recipe.RecipeUtil"%>
|
||||
<%RecipeSearch searchResults = RecipeUtil.getRecipeSearch(request);%>
|
||||
<div id="leftnav">
|
||||
<div id="search">
|
||||
<form name="searchForm" action="recipe<%= searchResults.isOwnItems() ? "List" : "Search" %>" method="GET"><h2>Find a recipe</h2>
|
||||
<table border="0" cellpadding="0" cellspacing="0" id="advancedsearch">
|
||||
<tr><th colspan="2">With the word or phrase</th></tr>
|
||||
<tr>
|
||||
<td><input type="text" name="query" size="25" class="txt"
|
||||
value='<%=DisplayUtils.escape(searchResults.getQuery()) %>'>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Cuisine type</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%DisplayUtils.printCheckboxes(out,
|
||||
RecipeUtil.CUISINE_PARAMETER,
|
||||
RecipeUtil.getMostUsedValues(pageContext.getServletContext()).getMostUsedValuesForAttribute(Recipe.CUISINE_ATTRIBUTE),
|
||||
searchResults.getCuisineValues()); %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Main ingredient</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%DisplayUtils.printCheckboxes(out,
|
||||
RecipeUtil.MAIN_INGREDIENT_PARAMETER,
|
||||
RecipeUtil.getMostUsedValues(pageContext.getServletContext()).getMostUsedValuesForAttribute(Recipe.MAIN_INGREDIENT_ATTRIBUTE),
|
||||
searchResults.getMainIngredientValues()); %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Cooking time</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input name="cookingTime" type="text" size="4"
|
||||
value='<%=DisplayUtils.escape(searchResults.getCookingTime()) %>'
|
||||
> <%=RecipeUtil.COOKING_TIME_UNIT %></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<button onclick="document.searchForm.startIndex.value='0'; document.searchForm.submit();"
|
||||
style="font-weight:bold; -moz-border-radius:3px;border: 2px outset #bbbbbb;font-size:124%; padding:2px 1em;">Search</button>
|
||||
<input type="hidden" name="startIndex" value="0"></form>
|
||||
</div>
|
||||
|
||||
<p id="poweredby">
|
||||
Powered by<br>
|
||||
<a href="http://base.google.com/"><img src="googleBase.gif" border="0" alt="Google Base" vspace="2"></a>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,71 @@
|
||||
<%--
|
||||
Copyright (c) 2006 Google Inc.
|
||||
|
||||
Licensed 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.
|
||||
--%>
|
||||
<%@ page contentType="text/html; charset=UTF-8"%>
|
||||
<%@ page import="sample.gbase.recipe.DisplayUtils"%>
|
||||
<%@ page import="sample.gbase.recipe.Recipe"%>
|
||||
<%@ page import="sample.gbase.recipe.RecipeUtil"%>
|
||||
<html>
|
||||
<head>
|
||||
<title>Google Base API Demo: Recipe Book</title>
|
||||
<link rel="stylesheet" href="style.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="content">
|
||||
<%@ include file="demoLabel.inc" %>
|
||||
|
||||
<%Recipe recipe = (Recipe) request.getAttribute(RecipeUtil.RECIPE_ATTRIBUTE); %>
|
||||
<h1><a href="recipeSearch" class="on">All Recipes</a> > <%=DisplayUtils.escape(recipe.getTitle()) %></h1>
|
||||
|
||||
<%@ include file="leftNav.jsp" %>
|
||||
<div id="body" class="main">
|
||||
<div id="singleitem">
|
||||
<h3 class="itemtitle"><%=DisplayUtils.escape(recipe.getTitle()) %></h3>
|
||||
<h4 class="postdate"><%=recipe.getPostedOnAsString(true) %></h4>
|
||||
<%if (recipe.hasCuisine()) { %>
|
||||
<h5>Cuisine: <%=DisplayUtils.printList(recipe.getCuisine()) %></h5><br/>
|
||||
<%} %>
|
||||
<%if (recipe.hasCookingTime()) { %>
|
||||
<h5>Cooking time: <%=recipe.getCookingTime().getValue() %> <%=DisplayUtils.escape(recipe.getCookingTime().getUnit()) %></h5>
|
||||
<%} %>
|
||||
|
||||
<%if (recipe.hasMainIngredient()) { %>
|
||||
<div class="ingredients">
|
||||
<ul>
|
||||
<%for (String ingredient : recipe.getMainIngredient()) { %>
|
||||
<li><%=DisplayUtils.escape(ingredient) %></li>
|
||||
<%} %>
|
||||
</ul>
|
||||
</div>
|
||||
<%} %>
|
||||
<br/>
|
||||
<div class="preparation">
|
||||
<%=DisplayUtils.escape(recipe.getDescription()) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br clear="all">
|
||||
|
||||
<%@ include file="demoLabel.inc" %>
|
||||
</div>
|
||||
|
||||
<%@ include file="footer.inc" %>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
<%--
|
||||
Copyright (c) 2006 Google Inc.
|
||||
|
||||
Licensed 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.
|
||||
--%>
|
||||
<%@ page contentType="text/html; charset=UTF-8"%>
|
||||
<%@ page import="sample.gbase.recipe.DisplayUtils"%>
|
||||
<%@ page import="sample.gbase.recipe.Recipe"%>
|
||||
<%@ page import="sample.gbase.recipe.RecipeUtil"%>
|
||||
<html>
|
||||
<head>
|
||||
<title>Google Base API Demo: Recipe Book</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<style type="text/css">
|
||||
.main {
|
||||
margin-left: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="content">
|
||||
<%@ include file="demoLabel.inc" %>
|
||||
|
||||
<%Recipe recipe = (Recipe) request.getAttribute(RecipeUtil.RECIPE_ATTRIBUTE); %>
|
||||
<%String message = (String) request.getAttribute(RecipeUtil.MESSAGE_ATTRIBUTE); %>
|
||||
<h1><a href="recipeList" class="on">My Recipes</a> > <%=recipe.isNew() ? "Add" : "Update" %> a recipe</h1>
|
||||
|
||||
<div id="body" class="main">
|
||||
|
||||
<div id="newitem">
|
||||
<%=message %>
|
||||
<form name="newitem" method="POST" action="recipe<%=recipe.isNew() ? "Add" : "Update?" + RecipeUtil.ID_PARAMETER + "=" + DisplayUtils.escape(recipe.getId()) %>"/>
|
||||
|
||||
<table cellpadding="0" cellspacing="0" border="0" id="createrecipe">
|
||||
<tr>
|
||||
<th>Recipe title *</th>
|
||||
<td><input type="text" name="<%=RecipeUtil.TITLE_PARAMETER %>"
|
||||
value="<%=DisplayUtils.escape(recipe.getTitle()) %>"
|
||||
class="txt" size="35"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Cuisine type *</th>
|
||||
<td>
|
||||
<%DisplayUtils.printCheckboxes(out,
|
||||
RecipeUtil.CUISINE_PARAMETER,
|
||||
RecipeUtil.getMostUsedValues(pageContext.getServletContext()).getMostUsedValuesForAttribute(Recipe.CUISINE_ATTRIBUTE),
|
||||
recipe.getCuisine()); %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
<th>Instructions *</th>
|
||||
<td><textarea name="<%=RecipeUtil.DESCRIPTION_PARAMETER %>"
|
||||
cols="40" rows="8"
|
||||
><%=DisplayUtils.escape(recipe.getDescription()) %></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Main ingredients *</th>
|
||||
<td>
|
||||
<%DisplayUtils.printCheckboxes(out,
|
||||
RecipeUtil.MAIN_INGREDIENT_PARAMETER,
|
||||
RecipeUtil.getMostUsedValues(pageContext.getServletContext()).getMostUsedValuesForAttribute(Recipe.MAIN_INGREDIENT_ATTRIBUTE),
|
||||
recipe.getMainIngredient()); %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>URL</th>
|
||||
<td><input type="text" name="<%=RecipeUtil.URL_PARAMETER %>"
|
||||
value="<%=DisplayUtils.escape(recipe.getUrl()) %>"
|
||||
class="txt" size="40"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Cooking time</th>
|
||||
<td><input type="text" name="<%=RecipeUtil.COOKING_TIME_PARAMETER %>"
|
||||
value="<%=recipe.hasCookingTime() ? recipe.getCookingTime().getValue() : "" %>"
|
||||
class="txt" size="4"> <%=RecipeUtil.COOKING_TIME_UNIT %></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
This recipe will be publicly viewable on the internet once you click "Publish". <br> <br>
|
||||
<input type="submit" value="Publish this recipe" style="font-weight:bold;">
|
||||
<button onclick="history.go(-1); return false;">Cancel</button>
|
||||
</p>
|
||||
<p>* Mandatory attributes</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br clear="all">
|
||||
|
||||
<%@ include file="demoLabel.inc" %>
|
||||
</div>
|
||||
|
||||
<%@ include file="footer.inc" %>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<%--
|
||||
Copyright (c) 2007 Google Inc.
|
||||
|
||||
Licensed 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.
|
||||
--%>
|
||||
<%@ page contentType="text/html; charset=UTF-8"%>
|
||||
<%@ page import="com.google.api.gbase.client.ServiceErrors"%>
|
||||
<%@ page import="sample.gbase.recipe.RecipeUtil"%>
|
||||
<%@page import="sample.gbase.recipe.DisplayUtils"%>
|
||||
<%@page import="com.google.api.gbase.client.ServiceError"%>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>Google Base API demo: Recipe Book</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="content">
|
||||
<%@ include file="demoLabel.inc" %>
|
||||
<%
|
||||
String error = RecipeUtil.getRecipeError(request);
|
||||
String description = RecipeUtil.getRecipeErrorDescription(request);
|
||||
ServiceErrors serviceErrors = RecipeUtil.getRecipeErrorObject(request);
|
||||
%>
|
||||
|
||||
<div style="height:70%; padding-top: 20px;">
|
||||
An error has occured. Hit the browser's Back button for continuing to use
|
||||
the Recipe Demo Application. <br/>
|
||||
|
||||
<%if (error != null) { %>
|
||||
<div class="errordiv">
|
||||
<span class="errormessage"><%= DisplayUtils.escape(error) %></span>
|
||||
<br/>
|
||||
</div>
|
||||
<%} // has error %>
|
||||
|
||||
<%if (description != null) { %>
|
||||
<div class="errordiv">
|
||||
Detailed information about the error: <br/>
|
||||
<pre><%= DisplayUtils.escape(description) %></pre>
|
||||
</div>
|
||||
<%} // has description %>
|
||||
|
||||
<%if (serviceErrors != null) { %>
|
||||
<div class="errordiv">
|
||||
Detailed information about the Google Base service error: <br/>
|
||||
<ul>
|
||||
<%for (ServiceError serviceError : serviceErrors.getAllErrors()) { %>
|
||||
<li> <%= DisplayUtils.escape(serviceError.getType()) %> : <%= DisplayUtils.escape(serviceError.getReason()) %>
|
||||
<%} // for each service error %>
|
||||
</ul>
|
||||
|
||||
<%if (serviceErrors.getAllErrors().size() == 0) { %>
|
||||
<i>No service errors could be parsed</i>
|
||||
<%} // if no service errors registered %>
|
||||
</div>
|
||||
<%} // has errors object %>
|
||||
|
||||
</div>
|
||||
|
||||
<br clear="all">
|
||||
<%@ include file="demoLabel.inc" %>
|
||||
</div>
|
||||
|
||||
<%@ include file="footer.inc" %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,138 @@
|
||||
<%--
|
||||
Copyright (c) 2006 Google Inc.
|
||||
|
||||
Licensed 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.
|
||||
--%>
|
||||
<%@ page contentType="text/html; charset=UTF-8"%>
|
||||
<%@ page import="sample.gbase.recipe.DisplayUtils"%>
|
||||
<%@ page import="sample.gbase.recipe.Recipe"%>
|
||||
<%@ page import="sample.gbase.recipe.RecipeSearch"%>
|
||||
<%@ page import="sample.gbase.recipe.RecipeUtil"%>
|
||||
<%@ page import="java.util.Iterator"%>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>Google Base API demo: Recipe Book</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="content">
|
||||
<%@ include file="demoLabel.inc" %>
|
||||
|
||||
<%RecipeSearch recipeSearch = RecipeUtil.getRecipeSearch(request); %>
|
||||
<%if (recipeSearch.isOwnItems()) { %>
|
||||
<a href="recipeSearch" class="toplink">All recipes</a>
|
||||
<%} else { %>
|
||||
<a href="recipeList" class="toplink">My recipes</a>
|
||||
<%} %>
|
||||
|
||||
|
||||
<%if (recipeSearch.isOwnItems()) { %>
|
||||
<a href="recipeAdd" class="toplink">Add a recipe</a>
|
||||
<%} %>
|
||||
|
||||
<h1>
|
||||
<%if (recipeSearch.isOwnItems()) { %>
|
||||
<a href="recipeList" class="on">My Recipes</a>
|
||||
<%} else { %>
|
||||
<a href="recipeSearch" class="on">All Recipes</a>
|
||||
<%} %>
|
||||
> Search
|
||||
<%if (recipeSearch.getTotal() > 0) { %>
|
||||
results
|
||||
<%} %>
|
||||
</h1>
|
||||
|
||||
<%@ include file="leftNav.jsp" %>
|
||||
|
||||
<div id="body" class="main">
|
||||
<div id="searchresults">
|
||||
|
||||
<script language="JavaScript">
|
||||
function gotoPage(index) {
|
||||
document.searchForm.reset();
|
||||
document.searchForm.startIndex.value =
|
||||
index*<%=recipeSearch.getMaxResults()%>;
|
||||
document.searchForm.submit();
|
||||
}
|
||||
function narrowSearchByIngredient(ingredient) {
|
||||
document.searchForm.reset();
|
||||
document.searchForm.othermainIngredient.value = ingredient;
|
||||
document.searchForm.submit();
|
||||
}
|
||||
function confirmDelete(oid) {
|
||||
if (confirm("Do you really want to delete this recipe?")) {
|
||||
window.location = "recipeDelete?oid=" + oid;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<%if (recipeSearch.getTotal() >= 0) {%>
|
||||
<%if (recipeSearch.getTotal() == 0) {%>
|
||||
<h4>Your search for recipes
|
||||
<%=recipeSearch.getFilterDescription() %>
|
||||
did not match any recipes.</h4>
|
||||
<%} %>
|
||||
<%if (recipeSearch.hasResults()) {%>
|
||||
<h4><%=recipeSearch.getTotal()%> recipes
|
||||
<%=recipeSearch.getFilterDescription() %>
|
||||
- showing <%=recipeSearch.getCurrentPageInterval()%></h4>
|
||||
<%for (Iterator iter = recipeSearch.getRecipes().iterator(); iter.hasNext(); ) {%>
|
||||
<%Recipe recipe = (Recipe)iter.next();%>
|
||||
<p>
|
||||
<a href="recipeDisplay?oid=<%=recipe.getId()%>" class="m"><%=DisplayUtils.escape(recipe.getTitle()).toUpperCase() %></a>
|
||||
Main ingredient:
|
||||
<%for (Iterator<String> ingredientIter = recipe.getMainIngredient().iterator(); ingredientIter.hasNext(); ) { %>
|
||||
<%String ingredient = ingredientIter.next(); %>
|
||||
<a href="javascript:narrowSearchByIngredient('<%=ingredient%>')" class="r"><%=ingredient%></a><%=ingredientIter.hasNext() ? ", " : "" %>
|
||||
<%} %>
|
||||
<br>
|
||||
posted on <%=recipe.getPostedOnAsString(false)%>
|
||||
by <%=DisplayUtils.escape(recipe.getPostedBy())%><br>
|
||||
|
||||
<%if (recipeSearch.isOwnItems()) { %>
|
||||
<a href="recipeUpdate?oid=<%=recipe.getId() %>">Update</a> |
|
||||
<a href="javascript:confirmDelete('<%=recipe.getId() %>')">Delete</a>
|
||||
<%} %>
|
||||
</p>
|
||||
<%} // for recipe in recipeSearch.getRecipes()%>
|
||||
<%} // if recipeSearch.hasResults%>
|
||||
|
||||
<%if (recipeSearch.getTotal() > recipeSearch.getMaxResults()) { //results don't fit on one page?%>
|
||||
<p class="pagination">
|
||||
Results <%=recipeSearch.getCurrentPageInterval() %> of <%=recipeSearch.getTotal() %><br/>
|
||||
<%if (recipeSearch.hasPreviousPage()) {%>
|
||||
<a href="javascript:gotoPage(<%=recipeSearch.getCurrentPage() - 1 %>)"
|
||||
style="margin-right:1em;"
|
||||
class="next">« Previous <%=recipeSearch.getMaxResults() %></a>
|
||||
<%} %>
|
||||
<%if (recipeSearch.hasNextPage()) {%>
|
||||
<a href="javascript:gotoPage(<%=recipeSearch.getCurrentPage() + 1 %>)"
|
||||
class="next">Next <%=recipeSearch.getNextPageSize() %> »</a>
|
||||
<%} %>
|
||||
</p>
|
||||
<%} // pages? %>
|
||||
<%} //total >= 0 %>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<br clear="all">
|
||||
<%@ include file="demoLabel.inc" %>
|
||||
</div>
|
||||
|
||||
<%@ include file="footer.inc" %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
|
||||
<web-app>
|
||||
<display-name>Google Base Recipe Search</display-name>
|
||||
<description>Search Recipes on Google Base</description>
|
||||
<context-param>
|
||||
<param-name>baseUrl</param-name>
|
||||
<param-value>http://www.google.com/base/</param-value>
|
||||
<description>URL of the google base server to connect to.</description>
|
||||
</context-param>
|
||||
<context-param>
|
||||
<param-name>applicationName</param-name>
|
||||
<param-value>Google-RecipeDemo-1.0</param-value>
|
||||
<description>Application name used when authenticating.</description>
|
||||
</context-param>
|
||||
<context-param>
|
||||
<param-name>key</param-name>
|
||||
<param-value></param-value>
|
||||
<description>Developer key used to authenticate against the Google Base data API servers.</description>
|
||||
</context-param>
|
||||
<filter>
|
||||
<filter-name>AuthenticationFilter</filter-name>
|
||||
<filter-class>sample.gbase.recipe.AuthenticationFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>authsubProtocol</param-name>
|
||||
<param-value>https</param-value>
|
||||
<description>Protocol to be used when connecting to AuthSub.</description>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>authsubHostname</param-name>
|
||||
<param-value>www.google.com</param-value>
|
||||
<description>Hostname of the authentication server.</description>
|
||||
</init-param>
|
||||
</filter>
|
||||
<listener>
|
||||
<listener-class>sample.gbase.recipe.RecipeListener</listener-class>
|
||||
</listener>
|
||||
<filter-mapping>
|
||||
<filter-name>AuthenticationFilter</filter-name>
|
||||
<servlet-name>OwnRecipeSearchServlet</servlet-name>
|
||||
</filter-mapping>
|
||||
<filter-mapping>
|
||||
<filter-name>AuthenticationFilter</filter-name>
|
||||
<servlet-name>RecipeAddServlet</servlet-name>
|
||||
</filter-mapping>
|
||||
<filter-mapping>
|
||||
<filter-name>AuthenticationFilter</filter-name>
|
||||
<servlet-name>RecipeUpdateServlet</servlet-name>
|
||||
</filter-mapping>
|
||||
<filter-mapping>
|
||||
<filter-name>AuthenticationFilter</filter-name>
|
||||
<servlet-name>RecipeDeleteServlet</servlet-name>
|
||||
</filter-mapping>
|
||||
<servlet>
|
||||
<servlet-name>AllRecipeSearchServlet</servlet-name>
|
||||
<servlet-class>sample.gbase.recipe.RecipeSearchServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>scope</param-name>
|
||||
<param-value>all</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>OwnRecipeSearchServlet</servlet-name>
|
||||
<servlet-class>sample.gbase.recipe.RecipeSearchServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>scope</param-name>
|
||||
<param-value>own</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>RecipeAddServlet</servlet-name>
|
||||
<servlet-class>sample.gbase.recipe.RecipeActionServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>action</param-name>
|
||||
<param-value>add</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>RecipeUpdateServlet</servlet-name>
|
||||
<servlet-class>sample.gbase.recipe.RecipeActionServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>action</param-name>
|
||||
<param-value>update</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>RecipeDeleteServlet</servlet-name>
|
||||
<servlet-class>sample.gbase.recipe.RecipeActionServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>action</param-name>
|
||||
<param-value>delete</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>RecipeDisplayServlet</servlet-name>
|
||||
<servlet-class>sample.gbase.recipe.RecipeDisplayServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>AllRecipeSearchServlet</servlet-name>
|
||||
<url-pattern>/recipeSearch</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>OwnRecipeSearchServlet</servlet-name>
|
||||
<url-pattern>/recipeList</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>RecipeAddServlet</servlet-name>
|
||||
<url-pattern>/recipeAdd</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>RecipeUpdateServlet</servlet-name>
|
||||
<url-pattern>/recipeUpdate</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>RecipeDeleteServlet</servlet-name>
|
||||
<url-pattern>/recipeDelete</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>RecipeDisplayServlet</servlet-name>
|
||||
<url-pattern>/recipeDisplay</url-pattern>
|
||||
</servlet-mapping>
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
</web-app>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@@ -0,0 +1 @@
|
||||
<%response.sendRedirect(request.getContextPath() + "/recipeSearch");%>
|
||||
@@ -0,0 +1,89 @@
|
||||
body {
|
||||
font-family: geneva,tahoma,arial,sans-serif; font-size: 83%;
|
||||
background: #FFFFCC;
|
||||
text-align:center;
|
||||
vertical-align:top;
|
||||
}
|
||||
td {
|
||||
font-size: 78%;
|
||||
vertical-align:top;
|
||||
}
|
||||
th {
|
||||
font-size: 78%;
|
||||
text-align: left;
|
||||
vertical-align:top;
|
||||
}
|
||||
|
||||
a:link { color: #0000CC; }
|
||||
a:visited { color:#0000CC; }
|
||||
a.on:visited { color: #0000CC; }
|
||||
.toplink:visited { color: #0000CC; }
|
||||
.demolabel a:link { color: #0000E0!important; font-weight:bold; }
|
||||
|
||||
a.m { display:block; }
|
||||
a.r { color: #6666cc; text-decoration:none;}
|
||||
|
||||
#search th { padding: 1em 0 2px 0; }
|
||||
#newitem th { padding: .8ex 1em 2px 0px; }
|
||||
#newitem td { padding: 2px 1em 2px 0px; }
|
||||
|
||||
.demolabel { background: #ffffff; font-size: 124%; text-align:center; padding: .5em; -moz-border-radius:4px; border: 1px solid #EEEE66;}
|
||||
|
||||
|
||||
input.txt, textarea { border: 1px inset #999999; -moz-border-radius: 3px; padding:2px;}
|
||||
textarea { font-family: geneva, tahoma, arial, sans-serif; font-size: 105%; }
|
||||
label { cursor: pointer; }
|
||||
ul.inputlist {
|
||||
padding-left:0;
|
||||
list-style-type:none;
|
||||
}
|
||||
.inputlist li { padding-right: 1em; }
|
||||
|
||||
#content { text-align:left; margin: 0 15% 0 15%;}
|
||||
#leftnav {
|
||||
width: 30%;
|
||||
float:left;
|
||||
}
|
||||
#search {
|
||||
border:1px solid #EEEE66;
|
||||
-moz-border-radius:12px;
|
||||
background: #FFFFe0;
|
||||
padding:.5em;
|
||||
}
|
||||
#rpp { float:right; }
|
||||
.next { font-weight: bold; font-size: 124%; }
|
||||
.main {
|
||||
margin-left: 33%;
|
||||
border: 1px solid #EEEE66;
|
||||
-moz-border-radius:8px;
|
||||
background: #FFFFe0;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#footer { margin-top: 2em; }
|
||||
#footer p { margin:0; }
|
||||
|
||||
h2 { margin:0; }
|
||||
h3 { margin:0; }
|
||||
h4 { margin:0; font-size: 100%; font-weight: normal;}
|
||||
h5 { margin:0; font-weight: normal; display:inline; font-size: 100%;}
|
||||
|
||||
.toplink {
|
||||
float:right;
|
||||
font-weight:bold;
|
||||
margin-left:1.6em;
|
||||
padding-top:1.6em;
|
||||
font-size: 124%;
|
||||
}
|
||||
|
||||
#poweredby {
|
||||
font-size: 82%;
|
||||
margin-left:3%;
|
||||
}
|
||||
#poweredby img { height: 27px; width: 75px; }
|
||||
|
||||
.instructions { font-size: 78%; color: #000000;}
|
||||
.instructions i { font-style: normal; color:#008000; }
|
||||
|
||||
.errormessage { font-weight: bold; color: #CC1100; margin-bottom: 0.5em; }
|
||||
.errordiv { padding-top: 35px; }
|
||||
Reference in New Issue
Block a user