Inital commit

This commit is contained in:
Tilman
2011-10-26 09:44:02 +02:00
commit 5971f4b417
1813 changed files with 737837 additions and 0 deletions
@@ -0,0 +1,35 @@
Google Spreadsheets data API Java Sample - README.txt
-----------------------------------------------------
This is a very simple Java example of how the API can be used on a
Google spreadsheet to create a table object. This table object
can be updated, and deleted and you can query it based on
it's title. It can be placed anywhere on the grid. The
records in the table (see RecordDemo) can be sorted and queried
without modifying the position of the table headers and records.
Before starting this demo, make sure you create a spreadsheet.
The spreadsheet can be empty as you will be adding a table to it
that will contain column headers.
An example table might look like:
Name Day Phone
We suggest you leave your browser open while trying this out.
This can be built and run with Ant:
// TODO down here.
1. Edit gdata/java/build-samples/build.properties with your Google Account
username and password.
2. Run the Ant rule:
ant -f gdata/java/build-samples.xml sample.spreadsheet.list.run
Alternately, you can compile and run it from the command line:
java sample.list.TableDemo
--username [user]
--password [pass]
@@ -0,0 +1,614 @@
/* Copyright (c) 2008 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.spreadsheet.table;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.TableQuery;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.spreadsheet.Column;
import com.google.gdata.data.spreadsheet.Data;
import com.google.gdata.data.spreadsheet.Header;
import com.google.gdata.data.spreadsheet.Worksheet;
import com.google.gdata.data.spreadsheet.TableEntry;
import com.google.gdata.data.spreadsheet.TableFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* An application to show the basic operations of the Table feed.
*
*
*/
public class TableDemo {
/** The message for displaying the usage parameters. */
private static final String[] USAGE_MESSAGE = {
"Usage: java TableDemo --username [user] --password [pass] ", ""};
/** Help on setting up this demo. */
private static final String[] WELCOME_MESSAGE = {
"Using this demo, you can see how tables can be conveniently created,",
"updated, queried, and deleted.", "",
"Before starting this demo, make sure you create a spreadsheet."};
/** Help on all available commands. */
private static final String[] COMMAND_HELP_MESSAGE = {
"Commands:",
" load [[select a spreadsheet]]",
" list [[shows all entries]]",
" add title=Table1, summary=Test Table, worksheet=Sheet1, header=1, "
+ "startrow=2, numrows=5, columns=a:Name;b:Phone;c:Address "
+ "[[adds a table]]",
" update <tableid> title=AwesomeTable [[updates a table]]",
" delete <tableid> [[deletes; use 'list' first]]",
" search AwesomeTable [[title search]]", // add title exact.
" exit"};
/** Our view of Google Spreadsheets as an authenticated Google user. */
private SpreadsheetService service;
/** The URL of the table feed for the selected spreadsheet. */
private URL tablesFeedUrl;
/** A factory that generates the appropriate feed URLs. */
private FeedURLFactory factory;
/** The output stream to use. */
private PrintStream out;
/**
* Caches entries.
*
* In this example, every entry we display to the user is cached. We do this
* because Google Data has a feature where if an entry is updated between the
* time you download it and update or delete it, you will be alerted of the
* edit. For example:
*
* 1. In this sample app, I look at the table with title Table1. 2. Someone
* editing the spreadsheet changes the title to UpdatedTable1.
* In this sample app, I try to change the title to Table2.
*
* By caching the entry and updating the last entry, I am telling the server
* that I am updating the age from Table1 to Table2. The server now has enough
* information to tell me that the age has already been changed, because the
* version ID that I am sending was the version ID for Table 1.
*
* If you do not wish to cache entries, an alternative is to fetch the proper
* entry ID from Google Data, update that fresh entry, and post. In that case,
* no caching is necessary, and a version conflict is less likely. On the
* other hand, you won't get alerted if someone else has changed the entry in
* the meantime.
*
* This would be achieved by getting an entry: TableEntry freshEntry=
* service.getEntry( new URL(tablesFeedUrl.toString() + "/" + id),
* TableEntry.class) (update freshEntry's fields) freshEntry.update();
*/
private Map<String, TableEntry> entriesCached;
/**
* Starts up the demo with the specified service.
*
* @param service the connection to the Google Spradsheets service.
* @param outputStream a handle for stdout.
*/
public TableDemo(SpreadsheetService service, PrintStream outputStream) {
this.out = outputStream;
this.service = service;
this.factory = FeedURLFactory.getDefault();
this.entriesCached = new HashMap<String, TableEntry>();
}
/**
* Set the user credentials for theg given user name and password.
*
* @param username the username of the user toauthenticate
* (e.g. yourname@gmail.com)
@ @param password the password of the user to authenticate.
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void login(String username, String password)
throws AuthenticationException {
// Authenticate
service.setUserCredentials(username, password);
}
/**
* Parses the command line arguments given in the format
* "title=Table1,summary=This is a test", and sets the corresponding values
* on the given TableEntry.
*
* Values that are not specified are left alone. That is, if the entry already
* contains "title=Table1", then setting summary will retain
* the title as Table1.
*
* @param entryToUpdate the entry to change based on the parameters
* @param nameValuePairs the list of name/value pairs, containing the name of
* the title.
*/
public TableEntry setEntryContentsFromString(TableEntry entryToUpdate,
String nameValuePairs) {
Map<String, String> dataParams = Maps.newHashMap();
Map<String, String> dataCols = Maps.newHashMap();
// Split first by the commas between the different fields.
for (String nameValuePair : nameValuePairs.split(",")) {
// Then, split by the equal sign. Attributes are specified as key=value.
String[] parts = nameValuePair.split("=", 2);
if (parts.length < 2) {
System.out.println("Attributes are specified as key=value, "
+ "for example, title=Table1");
}
String tag = parts[0].trim(); // such as "name"
String value = parts[1].trim(); // such as "Fred"
if (tag.equals("title")) {
entryToUpdate.setTitle(new PlainTextConstruct(value));
} else if (tag.equals("summary")) {
entryToUpdate.setSummary(new PlainTextConstruct(value));
} else if (tag.equals("worksheet")) {
entryToUpdate.setWorksheet(new Worksheet(value));
} else if (tag.equals("header")) {
entryToUpdate.setHeader(new Header(Integer.parseInt(value)));
} else if (tag.equals("startrow") || tag.equals("insertionmode")
|| tag.equals("numrows")) {
dataParams.put(tag, value);
} else if (tag.equals("columns")) {
String[] columns = value.split(";");
for (int i = 0; i < columns.length; i++) {
String[] colInfo = columns[i].split(":");
if (colInfo.length < 2) {
System.out.println("Columns are specified as column:value, for "
+ " example, B:UpdatedPhone");
}
String index = colInfo[0];
String name = colInfo[1];
dataCols.put(index, name);
}
}
}
// Update table data.
Data data = getDataFromParams(
entryToUpdate.getData(), dataParams, dataCols);
entryToUpdate.setData(data);
return entryToUpdate;
}
/**
* Create a new data object from any data params that were specified.
* Data params are numrows, startrow, insertionmode and columns.
* Any attributes that are not specified are left alone. So, if data already
* has insertionmode=insert, specifying numrows=4 and startrow=12 will leave
* insertionmode as insert.
*
* @param data original data object.
* @param dataParams new data params to use to update the original
* data object.
* @param columnMap map of column index to value used to update the column
* headers of the table.
*/
public Data getDataFromParams(Data data,
Map<String, String> dataParams, Map<String, String> columnMap) {
Data newData = new Data();
if (data == null) {
data = new Data();
}
if (dataParams.get("numrows") != null) {
newData.setNumberOfRows(Integer.parseInt(dataParams.get("numrows")));
} else {
newData.setNumberOfRows(data.getNumberOfRows());
}
if (dataParams.get("startrow") != null) {
newData.setStartIndex(Integer.parseInt(dataParams.get("startrow")));
} else {
newData.setStartIndex(data.getStartIndex());
}
String insertionMode = dataParams.get("insertionmode");
if (insertionMode != null && insertionMode.equals("insert")) {
newData.setInsertionMode(Data.InsertionMode.INSERT);
}
List<Column> existing = data.getColumns();
// Add existing column data to column map.
for (Column existingCol : existing) {
String index = existingCol.getIndex();
String name = existingCol.getName();
// If column is being updated, set value, else add a new one.
if (columnMap.get(index) == null) {
columnMap.put(index, name);
}
}
// Set columns on new data object.
for (String key : columnMap.keySet()) {
newData.addColumn(new Column(key, columnMap.get(key)));
}
return newData;
}
/**
* Adds a new table entry, based on the user-specified name value pairs.
* Note that the following parameters must be specified:
* title, startrow, numrows, columns.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void addNewEntry(String nameValuePairs) throws IOException,
ServiceException {
TableEntry newEntry = setEntryContentsFromString(new TableEntry(),
nameValuePairs);
service.insert(tablesFeedUrl, newEntry);
out.println("Added table!");
}
/**
* Prints the entire table entry, in a way that mildly resembles what the
* actual XML looks like.
*
* In addition, all printed entries are cached here. This way, they can be
* updated or deleted, without having to retrieve the version identifier again
* from the server.
*
* @param entry the list entry to print
*/
public void printAndCacheEntry(TableEntry entry) {
// We only care about the entry id, chop off the leftmost part.
// I.E., this turns http://spreadsheets.google.com/..../cpzh6 into cpzh6.
String id = entry.getId().substring(entry.getId().lastIndexOf('/') + 1);
// Cache all displayed entries so that they can be updated later.
entriesCached.put(id, entry);
out.println("-- id: " + id + " title: " + entry.getTitle().getPlainText());
out.println("<title>" + entry.getTitle().getPlainText() + "</title>");
out.println("<summary>" + entry.getSummary().getPlainText() + "</summary>");
out.println("<worksheet>" + entry.getWorksheet().getName()
+ "</worksheet>");
out.println("<header>" + entry.getHeader().getRow() + "</header>");
Data data = entry.getData();
out.println("<data> insertionMode=" + data.getInsertionMode().name()
+ " startRow=" + data.getStartIndex()
+ " numRows=" + data.getNumberOfRows());
for (Column col: data.getColumns()) {
out.println(" <column>" + col.getIndex() + " " + col.getName()
+ "</column>");
}
out.println("</data>");
}
/**
* Displays the given list of entries and prompts the user to select the index
* of one of the entries. NOTE: The displayed index is 1-based and is
* converted to 0-based before being returned.
*
* @param reader to read input from the keyboard
* @param entries the list of entries to display
* @param type describes the tyoe of things the list contains
* @return the 0-based index of the user's selection
* @throws IOException if an I/O error occurs while getting input from user
*/
private int getIndexFromUser(BufferedReader reader, List entries, String type)
throws IOException {
for (int i = 0; i < entries.size(); i++) {
BaseEntry entry = (BaseEntry) entries.get(i);
System.out.println("\t(" + (i + 1) + ") "
+ entry.getTitle().getPlainText());
}
int index = -1;
while (true) {
out.print("Enter the number of the spreadsheet to load: ");
String userInput = reader.readLine();
try {
index = Integer.parseInt(userInput);
if (index < 1 || index > entries.size()) {
throw new NumberFormatException();
}
break;
} catch (NumberFormatException e) {
System.out.println("Please enter a valid number for your selection.");
}
}
return index - 1;
}
/**
* Uses the user's credentials to get a list of spreadsheets. Then asks the
* user which spreadsheet to load. If the selected spreadsheet has multiple
* worksheets then the user will also be prompted to select what sheet to use.
*
* @param reader to read input from the keyboard
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*
*/
public void loadSheet(BufferedReader reader) throws IOException,
ServiceException {
// Get the spreadsheet to load
SpreadsheetFeed feed = service.getFeed(factory.getSpreadsheetsFeedUrl(),
SpreadsheetFeed.class);
List spreadsheets = feed.getEntries();
int spreadsheetIndex = getIndexFromUser(reader, spreadsheets,
"spreadsheet");
SpreadsheetEntry spreadsheet = (SpreadsheetEntry) spreadsheets
.get(spreadsheetIndex);
URL spreadsheetUrl = new java.net.URL(
spreadsheet.getSpreadsheetLink().getHref());
String baseUrl = new java.net.URL(spreadsheetUrl.getProtocol() + "://"
+ spreadsheetUrl.getHost()).toString();
tablesFeedUrl = new java.net.URL(baseUrl + "/feeds/" + spreadsheet.getKey()
+ "/tables");
System.out.println("Sheet loaded.");
}
/**
* Lists all tables in the spreadsheet.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void listAllEntries() throws IOException, ServiceException {
TableFeed feed = service.getFeed(tablesFeedUrl, TableFeed.class);
for (TableEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
if (feed.getEntries().size() == 0) {
System.out.println("No entries yet!");
}
}
/**
* Searches titles of tables with a text search string, finds tables that
* match the given title and prints those entries out.
*
* @param titleSearchString a string like "Table 2" will look for the
* string "Table 2" in the title of all tables available on the sheet.
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void search(String titleSearchString) throws IOException,
ServiceException {
TableQuery query = new TableQuery(tablesFeedUrl);
query.setTitleQuery(titleSearchString);
TableFeed feed = service.query(query, TableFeed.class);
out.println("Results for [" + titleSearchString + "]");
for (TableEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
}
/**
* Deletes an entry by the ID.
*
* This looks up the old cached row so that the version ID is known. A version
* ID is used by GData to avoid edit collisions, so that you know if someone
* has changed the row before you delete it.
*
* For this reason, the cached version of the row, as you last saw it, is
* kept, instead of querying the entry anew.
*
* @param idToDelete the ID of the table to delete such as "0"
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void delete(String idToDelete) throws IOException, ServiceException {
TableEntry entry = entriesCached.get(idToDelete); // Find the entry to
// delete
if (entry != null) {
entry.delete(); // This deletes the existing entry.
out.println("Deleted!");
} else {
out.println("I don't know that ID.");
out.println("In GData, you must get an entry before deleting it,");
out.println("so that you have the version ID.");
out.println("You might have to 'list' first.");
}
}
/**
* Updates an existing entry.
*
* See the comment in {@code delete} for why the entry is cached in a hash
* map.
*
* @param id the ID of the row to update
* @param nameValuePairs the name value pairs, such as "title=UpdatedTitle"
* to change
* the table's title to UpdatedTitle
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void update(String id, String nameValuePairs) throws IOException,
ServiceException {
// The next line of code finds the entry to update.
// See the javadoc on entriesCached.
TableEntry entry = entriesCached.get(id);
setEntryContentsFromString(entry, nameValuePairs);
if (entry != null) {
entry.update(); // This updates the existing entry.
out.println("Updated!");
} else {
out.println("I don't know that ID.");
out.println("In GData, you must get an entry before deleting it.");
out.println("You might have to 'list' first.");
}
}
/**
* Parses and executes a command.
*
* @param reader to read input from the keyboard
* @return false if the user quits, true on exception
*/
public boolean executeCommand(BufferedReader reader) {
for (String s : COMMAND_HELP_MESSAGE) {
out.println(s);
}
System.err.print("Command: ");
try {
String command = reader.readLine();
String[] parts = command.trim().split(" ", 2);
String name = parts[0];
String parameters = parts.length > 1 ? parts[1] : "";
if (name.equals("add")) {
addNewEntry(parameters);
} else if (name.equals("load")) {
loadSheet(reader);
} else if (name.equals("list")) {
listAllEntries();
} else if (name.equals("search")) {
search(parameters);
} else if (name.equals("delete")) {
delete(parameters);
} else if (name.equals("update")) {
String[] split = parameters.split(" ", 2);
if (split.length < 2) {
out.println("insufficient number of params for update.");
}
update(split[0], split[1]);
} else if (name.startsWith("q") || name.startsWith("exit")) {
return false;
} else {
out.println("Unknown command.");
}
} catch (ServiceException se) {
// Show *exactly* what went wrong.
se.printStackTrace();
} catch (IOException ioe) {
// Show *exactly* what went wrong.
ioe.printStackTrace();
}
return true;
}
/**
* Starts up the demo and prompts for commands.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void run(String username, String password)
throws AuthenticationException {
for (String s : WELCOME_MESSAGE) {
out.println(s);
}
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
// Login and prompt the user to pick a sheet to use.
login(username, password);
try {
loadSheet(reader);
} catch (Exception e) {
e.printStackTrace();
}
while (executeCommand(reader)) {
}
}
/**
* Runs the demo.
*
* @param args the command-line arguments
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public static void main(String[] args) throws AuthenticationException {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String username = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "p");
boolean help = parser.containsKey("help", "h");
if (help || username == null || password == null) {
usage();
System.exit(1);
}
TableDemo demo = new TableDemo(new SpreadsheetService("Table Demo"),
System.out);
demo.run(username, password);
}
/**
* Prints out the usage.
*/
private static void usage() {
for (String s : USAGE_MESSAGE) {
System.out.println(s);
}
for (String s : WELCOME_MESSAGE) {
System.out.println(s);
}
}
}