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,202 @@
/* 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.analytics;
import com.google.gdata.client.analytics.AnalyticsService;
import com.google.gdata.client.analytics.DataQuery;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.data.analytics.AccountEntry;
import com.google.gdata.data.analytics.AccountFeed;
import com.google.gdata.data.analytics.DataEntry;
import com.google.gdata.data.analytics.DataFeed;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
/**
* Demonstrates how to use the Google Data API's Java client library to access
* Google Analytics data.
*
*
*/
public class AnalyticsClient {
private AnalyticsClient() {}
public static final String ACCOUNTS_URL
= "https://www.google.com/analytics/feeds/accounts/default";
public static final String DATA_URL = "https://www.google.com/analytics/feeds/data";
/**
* Returns a data feed containing the accounts that the user logged in to the
* given AnalyticsService has access to.
*
* @param myService The AnalyticsService to request accounts from
* @return An AccountFeed containing an entry for each profile the logged-in
* user has access to
* @throws IOException If an error occurs while trying to communicate with
* the Analytics server
* @throws ServiceException If the API cannot fulfill the user request for
* any reason
*/
public static AccountFeed getAvailableAccounts(AnalyticsService myService)
throws IOException, ServiceException {
URL feedUrl = new URL(ACCOUNTS_URL);
return myService.getFeed(feedUrl, AccountFeed.class);
}
/**
* Displays the accounts in the given account feed.
*/
public static void printAccounts(AccountFeed accountFeed) {
System.out.println(accountFeed.getTitle().getPlainText());
for (AccountEntry entry : accountFeed.getEntries()) {
System.out.println(
"\t" + entry.getTitle().getPlainText() + ": "
+ entry.getTableId().getValue());
}
System.out.println();
}
/**
* Gets a very basic data query request for the given table.
*
* @param tableId The ID of the table to request data from
* @return A basic query for browser, visits, and bounce information from
* the given table
* @throws MalformedURLException If the URL used to request data is malformed
*/
public static DataQuery getBasicQuery(String tableId) throws MalformedURLException {
// Set up the request (we could alternately construct a URL manually with all query parameters
// set)
DataQuery query = new DataQuery(new URL(DATA_URL));
query.setIds(tableId);
query.setStartDate("2009-01-01");
query.setEndDate("2009-01-31");
query.setDimensions("ga:browser");
query.setMetrics("ga:visits,ga:bounces");
return query;
}
/**
* Prints the contents of a data feed.
*
* @param title A header to print before the results
* @param dataFeed The data feed containing data to print. Assumed to contain
* ga:browser, ga:visits, and ga:bounces information.
*/
public static void printData(String title, DataFeed dataFeed) {
System.out.println(title);
for (DataEntry entry : dataFeed.getEntries()) {
System.out.println("\tBrowser: " + entry.stringValueOf("ga:browser"));
System.out.println("\t\tVisits: " + entry.stringValueOf("ga:visits"));
System.out.println("\t\tBounces: " + entry.stringValueOf("ga:bounces"));
System.out.println("\t\tBounce rate: "
+ entry.longValueOf("ga:bounces") / (double) entry.longValueOf("ga:visits"));
}
System.out.println();
}
/**
* Runs through all the examples using the given GoogleService instance.
*
* @param myService An unauthenticated AnalyticsService object
* @throws ServiceException If the service is unable to handle the request
* @throws IOException If there is an error communicating with the server
*/
public static void run(AnalyticsService myService, String username, String password)
throws ServiceException, IOException {
// Authenticate using ClientLogin
myService.setUserCredentials(username, password);
// Print a list of all accessible accounts
AccountFeed accountFeed = getAvailableAccounts(myService);
printAccounts(accountFeed);
if (accountFeed.getEntries().isEmpty()) {
return;
}
// Each entry in the account feed represents an individual profile
AccountEntry profile = accountFeed.getEntries().get(0);
String tableId = profile.getTableId().getValue();
// Print the results of a basic request
DataQuery basicQuery = getBasicQuery(tableId);
DataFeed basicData = myService.getFeed(basicQuery, DataFeed.class);
printData("BASIC RESULTS", basicData);
// Ask Analytics to return the data sorted in descending order of visits
DataQuery sortedQuery = getBasicQuery(tableId);
sortedQuery.setSort("-ga:visits");
DataFeed sortedData = myService.getFeed(sortedQuery, DataFeed.class);
printData("SORTED RESULTS", sortedData);
// Ask Analytics to filter out browsers that contain the word "Explorer"
DataQuery filteredQuery = getBasicQuery(tableId);
filteredQuery.setFilters("ga:browser!@Explorer");
DataFeed filteredData = myService.getFeed(filteredQuery, DataFeed.class);
printData("FILTERED RESULTS", filteredData);
}
/**
* Uses the command line arguments to authenticate the GoogleService and build
* the basic feed URI, then invokes all the other methods to demonstrate how
* to interface with the Analytics service.
*
* @param args See the usage method.
*/
public static void main(String[] args) {
// Set username, password and feed URI from command-line arguments.
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String userName = parser.getValue("username", "user", "u");
String userPassword = parser.getValue("password", "pwd", "p");
boolean help = parser.containsKey("help", "h");
if (help || (userName == null)) {
usage();
System.exit(1);
}
AnalyticsService myService = new AnalyticsService("exampleCo-exampleApp-1");
try {
run(myService, userName, userPassword);
} catch (ServiceException se) {
se.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Prints the command line usage of this sample application.
*/
private static void usage() {
System.err.println("Usage: AnalyticsClient --username <username> --password <password>");
System.err.println();
System.err.println("Fetches and displays various pieces of "
+ "information from the Google Analytics "
+ "Data Export API.");
}
}
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,318 @@
/* 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.appsforyourdomain.adminsettings;
import com.google.gdata.util.common.util.Base64;
import com.google.gdata.client.appsforyourdomain.adminsettings.AdminSettingsConstants;
import com.google.gdata.client.appsforyourdomain.adminsettings.DomainSettingsService;
import com.google.gdata.client.appsforyourdomain.adminsettings.DomainVerificationService;
import com.google.gdata.client.appsforyourdomain.adminsettings.EmailManagementService;
import com.google.gdata.client.appsforyourdomain.adminsettings.EncodeUtil;
import com.google.gdata.client.appsforyourdomain.adminsettings.SingleSignOnService;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.data.appsforyourdomain.generic.GenericEntry;
import com.google.gdata.data.appsforyourdomain.generic.GenericFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A sample client for Admin Settings API. Consists of drivers to run these
* services: {@link DomainSettingsService} {@link SingleSignOnService}
* {@link DomainVerificationService} {@link EmailManagementService}
*
*
*
*/
public class AdminSettingsClient {
private static final Logger LOGGER = Logger.getLogger(AdminSettingsClient.class.getName());
/**
* run() does a demo run and performs all operations possible with the client
*
* @param adminEmail the email id of the administrator.
* @param password the administrator password.
* @param domainName the domain name to be configured.
*/
public static void runAccountSettings(String adminEmail, String password, String domainName) {
System.out.println("Intiating demo run");
try {
DomainSettingsService client =
new DomainSettingsService(adminEmail, password, domainName, "test");
System.out.println("Enter full path to logo file");
Scanner in = new Scanner(System.in);
String file = in.nextLine();
client.setDomainLogo(EncodeUtil.encodeBinaryFile(file));
String countryCode = client.getCountryCodeForDomain();
LOGGER.log(Level.INFO, "Retrieved CountryCode: " + countryCode);
String customerPIN = client.getCustomerPIN();
LOGGER.log(Level.INFO, "Retrieved customerPIN: " + customerPIN);
String defaultLanguage = client.getDefaultLanguage();
LOGGER.log(Level.INFO, "Retrieved defaultLanguage: " + defaultLanguage);
String domainCreationTime = client.getDomainCreationTime();
LOGGER.log(Level.INFO, "Retrieved domainCreationTime: " + domainCreationTime);
String domainEdition = client.getDomainEdition();
LOGGER.log(Level.INFO, "Retrieved domainEdition: " + domainEdition);
String domainSecondaryEmailAddress = client.getDomainSecondaryEmailAddress();
LOGGER.log(Level.INFO, "Retrieved domainSecondaryEmailAddress: "
+ domainSecondaryEmailAddress);
String domainVerificationStatus = client.getDomainVerificationStatus();
LOGGER.log(Level.INFO, "Retrieved domainVerificationStatus: " + domainVerificationStatus);
int maxUserCount = client.getMaxUserCount();
LOGGER.log(Level.INFO, "Retrieved maxUserCount: " + maxUserCount);
String organizationName = client.getOrganizationName();
LOGGER.log(Level.INFO, "Retrieved organizationName: " + organizationName);
String supportPin = client.getSupportPIN();
LOGGER.log(Level.INFO, "Retrieved supportPin: " + supportPin);
System.out.println("Enter a secondary email ID for your domain:");
String secondaryEmail = in.nextLine();
LOGGER.log(Level.INFO, "Changing secondary email address to admin email: " + secondaryEmail);
client.setDomainSecondaryEmailAddress(secondaryEmail);
LOGGER.log(Level.INFO, "Changed secondary email address to : "
+ client.getDomainSecondaryEmailAddress());
LOGGER.log(Level.INFO, "Changing organization name to newOrg:");
client.setOrganizationName("newOrg");
LOGGER.log(Level.INFO, "Changed organization name: " + client.getOrganizationName());
LOGGER.log(Level.INFO, "Changing default language to fr:");
client.setDefaultLanguage("fr");
LOGGER.log(Level.INFO, "Changed default language: " + client.getDefaultLanguage());
// Restore original values
client.setDefaultLanguage(defaultLanguage);
client.setDomainSecondaryEmailAddress(domainSecondaryEmailAddress);
client.setOrganizationName(organizationName);
} catch (AuthenticationException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (ServiceException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (MalformedURLException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
}
/**
* A sample run for SSO settings API
*
* @param adminEmail the email id of the administrator.
* @param password the administrator password.
* @param domainName the domain name to be configured.
*/
public static void runSsoSettings(String adminEmail, String password, String domainName) {
try {
SingleSignOnService client =
new SingleSignOnService(adminEmail, password, domainName, "test");
final String key = Base64.encode(("-----BEGIN CERTIFICATE-----\n"
+ "MIIEbDCCA9WgAwIBAgIBCTANBgkqhkiG9w0BAQUFADCBjDELMAkGA1UEBhMCVVMx\n"
+ "ETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcgWW9yazEPMA0GA1UEChMG\n"
+ "R29vZ2xlMSQwIgYDVQQDFBtUaW0gRGllcmtzIENBIFtubyBzZWN1cml0eV0xIDAe\n"
+ "BgkqhkiG9w0BCQEWEWRpZXJrc0Bnb29nbGUuY29tMB4XDTA0MDQxNDIwMzM1NFoX\n"
+ "DTA1MDQxNDIwMzM1NFowQTEPMA0GA1UEChMGR29vZ2xlMRcwFQYDVQQLEw5TaW5n\n"
+ "bGUgU2lnbi1vbjEVMBMGA1UEAxMMTG9naW4gU2VydmVyMIIBtzCCASwGByqGSM44\n"
+ "BAEwggEfAoGBAKGpKYcoXxcgewIuAdDxT8QzSNI9I7Lja/LoueR1z7A/l0UWqZHO\n"
+ "6J8SyudgXFVxfkQEeYGbidsew2RMxvMl6pWMfqr/22eCqr9GPVkT7GVGqjAVdHVu\n"
+ "qJOPKSW7fQV3c82aj5g2qgkpwc1fUep8Cn1+Nz4ApCttVCSJD5kPtDTPAhUAo9jk\n"
+ "HrC8TH0kMFARmNbG5pizRS8CgYEAiB/TJmxCStDDMhDwo0ccnWgNo4oOQlMSeN46\n"
+ "Gb5YyVejeFBZSGni958ZcaaPW0Dg4VpbGxsQTSuF8P1BVY03fqimMd+dbRWSGgNy\n"
+ "YpkpdWBe21FnsSrnIrWnv/3K/7HMB7Xn4rEbhSvJF14I5TDuRN3lIOnIOKK6I5O9\n"
+ "QYfIfYoDgYQAAoGABPbEsbJS59Gj9556j9eAnGeLur56b98AGO7OFvYSoo9XcjoS\n"
+ "uYiFNhxu8MLzhkEqA6bqUif0mpl/d/VAXc74mdxaeg3vGb5MUGzdcr/mk9+32KYx\n"
+ "aX1hxn3UEN6WuypWe1eKuRVUzI/OepC88ib60XZHnkW9ByqqYXWdyGxW/G2jggEN\n"
+ "MIIBCTAJBgNVHRMEAjAAMCEGCWCGSAGG+EIBDQQUFhJHb29nbGUgLSBEaWVya3Mg\n"
+ "Q0EwHQYDVR0OBBYEFISoKKfKZlD6QIGqX60VCQA07sGLMIG5BgNVHSMEgbEwga6A\n"
+ "FK517Zhw+C2LH0rAjGRdEx61PYsIoYGSpIGPMIGMMQswCQYDVQQGEwJVUzERMA8G\n"
+ "A1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMQ8wDQYDVQQKEwZHb29n\n"
+ "bGUxJDAiBgNVBAMUG1RpbSBEaWVya3MgQ0EgW25vIHNlY3VyaXR5XTEgMB4GCSqG\n"
+ "SIb3DQEJARYRZGllcmtzQGdvb2dsZS5jb22CAQAwDQYJKoZIhvcNAQEFBQADgYEA\n"
+ "qwjvp27Xq1lp2ZyVWrGj8A3vuwUhsA2xGHvw4FTk4bCPwuuErugP/pwNl2582KNR\n"
+ "bjl1Vnz6zXkW1T4855EFWOZZkhIrvLGTRIoyQODCoW/Zd+3e7CfTvPdmJJNaVpD7\n"
+ "1RMPC45yjolVq4JLTT9/y6/+/5Nnn7oELnXRgDiMAR0=\n"
+ "-----END CERTIFICATE-----").getBytes());
LOGGER.log(Level.INFO, "Retrieving SSO Settings: \n"
+ client.getSsoSettings().getAllProperties());
LOGGER.log(Level.INFO, "Retrieving SSO Key: \n"
+ client.getSsoSigningKey().getAllProperties());
LOGGER.log(Level.INFO, "Updating SSO Key: \n"
+ client.updateSsoSigningKey(key).getAllProperties());
} catch (AuthenticationException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (ServiceException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (MalformedURLException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
}
/**
*
* @param adminEmail the email id of the administrator.
* @param adminPassword the administrator password.
* @param domainName the domain name to be configured.
*/
public static void runDomainVerificationService(String adminEmail, String password,
String domainName) {
try {
DomainVerificationService client =
new DomainVerificationService(adminEmail, password, domainName, "test");
GenericEntry entry = client.retrieveCnameVerificationStatus();
LOGGER.log(Level.INFO, "Retrieving CNAME verification status: " + entry.getAllProperties());
entry = client.updateVerifiedStatus(entry, true);
LOGGER.log(Level.INFO, "Updated CNAME verfication status: " + entry.getAllProperties());
entry = client.retrieveMxVerificationStatus();
LOGGER.log(Level.INFO, "Retrieving MX verification status: " + entry.getAllProperties());
entry = client.updateVerifiedStatus(entry, true);
LOGGER.log(Level.INFO, "Updating MX verfication status: " + entry.getAllProperties());
} catch (AuthenticationException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (ServiceException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (MalformedURLException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
}
/**
*
* @param adminEmail the email id of the administrator.
* @param adminPassword the administrator password.
* @param domainName the domain name to be configured.
*/
public static void runEmailManagementService(
String adminEmail, String password, String domainName) {
try {
EmailManagementService client =
new EmailManagementService(adminEmail, password, domainName, "test");
GenericEntry entry = client.retrieveOutboundGatewaySettings();
LOGGER.log(Level.INFO, "Outbound gateway settings" + entry.getAllProperties());
client.updateOutboundGatewaySettings(AdminSettingsConstants.TEST_EMAIL_ROUTE,
AdminSettingsConstants.TEST_SMTPMODE);
GenericFeed feed = client.retrieveEmailRoutingSettings();
List<GenericEntry> entries = feed.getEntries();
for (GenericEntry genericEntry : entries) {
LOGGER.log(Level.INFO, "Email Routing Settings" + genericEntry.getAllProperties());
LOGGER.log(Level.INFO, "Email Routing Settings" + genericEntry.getId());
// update settings
LOGGER.log(Level.INFO, "Updating Routing Settings");
genericEntry.removeProperty("routeEnabled");
genericEntry.addProperty("routeEnabled", String.valueOf(false));
genericEntry.update();
}
} catch (AuthenticationException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (ServiceException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (MalformedURLException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
}
/**
* @param args
*/
public static void main(String[] args) {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String adminEmail = parser.getValue("admin_email", "email", "e");
String adminPassword = parser.getValue("admin_password", "pass", "p");
String domain = parser.getValue("domain", "domain", "d");
boolean help = parser.containsKey("help", "h");
if (help || (adminEmail == null) || (adminPassword == null) || (domain == null)) {
usage();
System.exit(1);
}
System.out.println("WARNING: This sample modifies the admin settings of a domain."
+ "Use a TEST domain only.\nDo you want to continue (y/n):");
Scanner in = new Scanner(System.in);
String continueDemo = in.next();
if (!String.valueOf(continueDemo).equalsIgnoreCase("y")) {
System.exit(1);
}
LOGGER.log(Level.INFO, "-----------------Domain Settings Demo-------------");
runAccountSettings(adminEmail, adminPassword, domain);
LOGGER.log(Level.INFO, "-------------------SSO Settings Demo--------------");
runSsoSettings(adminEmail, adminPassword, domain);
LOGGER.log(Level.INFO, "--------------Verification Settings Demo----------");
runDomainVerificationService(adminEmail, adminPassword, domain);
LOGGER.log(Level.INFO, "---------------Email Management Demo--------------");
runEmailManagementService(adminEmail, adminPassword, domain);
}
/*
* Prints the command line usage of this sample application.
*/
private static void usage() {
System.out.println("Usage: java AdminSettngsClient"
+ " --admin_email [email] --admin_password [pass] --domain [domain]");
System.out.println("\nA simple application that performs domain configuration \n"
+ "on the given domain using the provided admin username and password.\n"
+ "WARNING: Please use a test domain for the sample run.");
}
}
@@ -0,0 +1,249 @@
/* 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.appsforyourdomain.audit;
import com.google.gdata.client.appsforyourdomain.audit.AccountInfo;
import com.google.gdata.client.appsforyourdomain.audit.AuditService;
import com.google.gdata.client.appsforyourdomain.audit.MailBoxDumpRequest;
import com.google.gdata.client.appsforyourdomain.audit.MailMonitor;
import com.google.gdata.data.appsforyourdomain.AppsForYourDomainErrorCode;
import com.google.gdata.data.appsforyourdomain.AppsForYourDomainException;
import com.google.gdata.data.appsforyourdomain.generic.GenericEntry;
import com.google.gdata.data.appsforyourdomain.generic.GenericFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A sample client for Google Apps Audit API service that helps you to audit
* user's emails, email drafts, and archived chats.
*
*
*
*/
public class AuditSampleClient {
private static Logger LOGGER = Logger.getLogger(AuditSampleClient.class.toString());
/**
* Google Apps Audit API sample run.
*
* Usage: java AuditSampleClient admin@example.com adminpassword domain
* srcUserName destUserName
*
*/
public static void main(String[] args) {
AuditService service = null;
try {
if (args.length != 5) {
System.out.println("Usage: java AuditSampleClient <admin@example.com> <adminpassword> "
+ "<domain> <srcUserName> <destUserName>");
System.out.println("A simple demo for Audit API features like managing email \n"
+ "monitors, mailbox dump requests, retrieving account info and uploading \n"
+ "domain key for encrypting files. The demo creates mail monitor for 'srcUserName' \n"
+ "with 'destUserName' as the auditor and uses 'srcUserName' as the test user for \n"
+ "the other listed operations above");
System.exit(1);
}
String adminEmail = args[0];
String adminPassword = args[1];
String domain = args[2];
String user = args[3];
String destUser = args[4];
//A sample base64 encoded PGP format key.
String sampleKey =
"LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tDQpWZXJzaW9uOiBHbn"
+ "VQRyB2MS40LjEwIChHTlUvTGludXgpDQoNCm1RRU5CRXJXYUQ0QkNBQ3QybmdmczYv"
+ "K1FPR1lieE5iYzNnTG5YSHRxcDdOVFRYTlc0U0pvKy9BMW9VWm9HeEENClF4NnpGWG"
+ "hRLzhNWFc2Nis4U1RTMVlxTkpPQVJGdGpiSUtQd2pyZGN1a2RQellWS0dacmUwUmF4"
+ "Q25NeUNWKzYNCkY0WU5RRDFVZWdIVHUyd0NHUjF1aVlPZkx4VWE3L2RvNnMzMVdSVE"
+ "g4dmJ0aVBZOS82b2JFSXhEakR6S0lxWU8NCnJ2UkRXcUFMQllrbE9rSjNIYmdmeWw0"
+ "MkVzbkxpQWhTK2RNczJQQ0RpMlgwWkpDUFo4ZVRqTHNkQXRxVlpKK1INCldDMUozVU"
+ "R1RmZtY3BzRFlSdFVMOXc2WU10bGFwQys5bW1KM0FCRUJBQUcwVjBSaGMyaGxjaUJV"
+ "WlhOMElDaFUNCmRHVnlNa0JrWVhOb1pYSXRhSGxrTFhSbGMzUXVZMjl0UG9rQk9BUV"
+ "RBUUlBSWdVQ1N0Wm9QZ0liRFFZTENRZ0gNCmsxOVFja1Rwd0Jkc2tFWXVtRnZtV3Zl"
+ "NVVYMlNWVjdmek9DMG5adGdGeHRaR2xKaEdtanNBM3J4RlRsYitJcmENCldaYXlYQ1"
+ "dZaUN6ZDdtOXo1L0t5R0QyR0ZUSy85NG1kbTI1TjZHWGgvYjM1cElGWlhCSS9yWmpy"
+ "WXJoWVJCRnUNCkd0ekdGSXc5QUFuRnlVekVVVVZmUFdVdEJlNXlITVc1NEM2MG5Iaz"
+ "V4WUlhNnFGaGlMcDRQWXFaQ3JZWDFpSXMNCmZSUk9GQT09DQo9U1RIcg0KLS0tLS1F"
+ "TkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQ==";
service = new AuditService(adminEmail, adminPassword, domain, "audit-test-" + domain);
LOGGER.log(Level.INFO, "\n-------------uploadPublicKey-------------");
GenericEntry sampleEntry = null;
sampleEntry = service.uploadPublicKey(sampleKey);
LOGGER.log(Level.INFO, "UploadedKey - " + sampleEntry.getAllProperties());
// retrieve all MailboxDump requests with fromDate query.
LOGGER.log(Level.INFO, "\n------retrieveAllMailboxDumpRequests with fromDate---- ");
Calendar c = Calendar.getInstance();
List<GenericEntry> entries = service.retrieveAllMailboxDumpRequests(c.getTime());
for (GenericEntry sampleEntry2 : entries) {
MailBoxDumpRequest request = new MailBoxDumpRequest(sampleEntry2);
LOGGER.log(Level.INFO, "All requests -" + sampleEntry2.getAllProperties().toString());
}
/*
* retrieve all MailboxDump requests without fromDate query. This will
* retrieve all requests made in the last 3 weeks.
*/
LOGGER.log(Level.INFO, "\n------------retrieveAllMailboxDumpRequests-------------");
entries = service.retrieveAllMailboxDumpRequests(null);
for (GenericEntry sampleEntry2 : entries) {
MailBoxDumpRequest request = new MailBoxDumpRequest(sampleEntry2);
LOGGER.log(Level.INFO, "All requests -" + sampleEntry2.getAllProperties().toString());
}
// Create MailboxDumpRequest
MailBoxDumpRequest request = new MailBoxDumpRequest();
request.setAdminEmailAddress(adminEmail);
c.add(Calendar.MONTH, -1);
request.setEndDate(c.getTime());
c.add(Calendar.MONTH, -1);
request.setBeginDate(c.getTime());
request.setPackageContent("FULL_MESSAGE");
request.setSearchQuery("in:chats");
request.setIncludeDeleted(false);
request.setUserEmailAddress(user + "@" + domain);
LOGGER.log(Level.INFO, "\n-------------createMailboxDumpRequest-------------");
sampleEntry = service.createMailboxDumpRequest(request);
LOGGER.log(Level.INFO, "\nCreated request - " + sampleEntry.getAllProperties().toString());
String createdId = sampleEntry.getProperty("requestId");
LOGGER.log(Level.INFO, "\n-------------retrieveMailboxDumpRequest-------------");
sampleEntry = service.retrieveMailboxDumpRequest(user, createdId);
LOGGER.log(Level.INFO, "\nRetrieved dump request - "
+ sampleEntry.getAllProperties().toString());
LOGGER.log(Level.INFO, "\n-------------deleteMailboxDumpRequest-------------");
boolean isDeleted = service.deleteMailboxDumpRequest(user, createdId);
LOGGER.log(Level.INFO, "Deleted mailbox dump request - " + isDeleted);
MailMonitor monitor = new MailMonitor();
c = Calendar.getInstance();
c.add(Calendar.MONTH, 1);
monitor.setBeginDate(c.getTime());
c.add(Calendar.MONTH, 1);
monitor.setEndDate(c.getTime());
monitor.setDestUserName(destUser);
monitor.setIncomingEmailMonitorLevel("FULL_MESSAGE");
monitor.setOutgoingEmailMonitorLevel("HEADER_ONLY");
monitor.setChatMonitorLevel("FULL_MESSAGE");
monitor.setDraftMonitorLevel("FULL_MESSAGE");
LOGGER.log(Level.INFO, "\n-------------createMailMonitor-------------");
LOGGER.log(Level.INFO, "\nCreating mail monitor for the user: " + user);
service.createMailMonitor(user, monitor);
// Retrieve all monitors for the user
LOGGER.log(Level.INFO, "\n-------------retrieveMonitors-------------");
LOGGER.log(Level.INFO, "\nRetrieving monitors for the user: " + user);
GenericFeed feed = service.retrieveMonitors(user);
for (GenericEntry entry : feed.getEntries()) {
monitor = new MailMonitor(entry);
LOGGER.log(Level.INFO, "Request Id: " + monitor.getRequestId());
LOGGER.log(Level.INFO, "Destination User: " + monitor.getDestUserName());
LOGGER.log(Level.INFO, "Monitor Begin Date: " + monitor.getBeginDate());
LOGGER.log(Level.INFO, "Monitor End Date: " + monitor.getEndDate());
LOGGER.log(Level.INFO, "Outgoing Email Monitor Level: "
+ monitor.getOutgoingEmailMonitorLevel());
LOGGER.log(Level.INFO, "Incoming Email Monitor Level: "
+ monitor.getIncomingEmailMonitorLevel());
LOGGER.log(Level.INFO, "Draft Email Monitor Level: " + monitor.getDraftMonitorLevel());
LOGGER.log(Level.INFO, "Chat Monitor Level: " + monitor.getChatMonitorLevel());
}
// Delete the monitor for the user
LOGGER.log(Level.INFO, "\n-------------deleteMonitor-------------");
LOGGER.log(Level.INFO, "Deleting monitor for the user...");
service.deleteMonitor(user, destUser);
//Account Info requests
LOGGER.log(Level.INFO, "\n-------------createAccountInfoRequest-------------");
sampleEntry = service.createAccountInfoRequest(user);
LOGGER.log(Level.INFO, sampleEntry.getAllProperties().toString());
AccountInfo info = new AccountInfo(sampleEntry);
LOGGER.log(Level.INFO, "\n-------------retrieveAccountInfoRequest-------------");
sampleEntry = service.retrieveAccountInfoRequest(user, info.getRequestId());
info = new AccountInfo(sampleEntry);
LOGGER.log(Level.INFO, info.getRequestId() + " : " + info.getStatus());
if (info.getStatus().equalsIgnoreCase("COMPLETED")) {
for ( String url : info.getFileUrls())
LOGGER.log(Level.INFO, "File: " + url);
}
// retrieve all account info requests from the given date.
LOGGER.log(Level.INFO, "\n------retrieveAllAccountInfoRequests with fromDate-----");
Calendar temp = Calendar.getInstance();
temp.add(Calendar.MONTH, -1);
entries = service.retrieveAllAccountInfoRequests(temp.getTime());
for (GenericEntry entry : entries) {
LOGGER.log(Level.INFO, entry.getAllProperties().toString());
}
/*
* retrieve all account info requests without fromDate query. This will
* retrieve all requests made in the last 3 weeks.
*/
LOGGER.log(Level.INFO, "\n-------------retrieveAllAccountInfoRequests-------------");
entries = service.retrieveAllAccountInfoRequests(null);
for (GenericEntry entry : entries) {
LOGGER.log(Level.INFO, entry.getAllProperties().toString());
}
LOGGER.log(Level.INFO, "\n-------------deleteAccountInfoRequest-------------");
try {
service.deleteAccountInfoRequest(user, info.getRequestId());
} catch (AppsForYourDomainException e) {
if (e.getErrorCode() == AppsForYourDomainErrorCode.InvalidValue) {
LOGGER.log(Level.INFO, e.getMessage());
} else {
e.printStackTrace();
}
}
LOGGER.log(Level.INFO, "End Audit API demo run");
} catch (AuthenticationException e) {
LOGGER.log(Level.SEVERE, "Authentication Error: " + e.getMessage(), e);
} catch (AppsForYourDomainException e) {
LOGGER.log(Level.SEVERE, "AppsForYourDomain Error: " + e.getMessage(), e);
} catch (MalformedURLException e) {
LOGGER.log(Level.SEVERE, "Malformed URL Error: " + e.getMessage(), e);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Network I/O Error: " + e.getMessage(), e);
} catch (ServiceException e) {
LOGGER.log(Level.SEVERE, "Google Data Service Error: " + e.getMessage(), e);
}
}
}
@@ -0,0 +1,254 @@
/* 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.appsforyourdomain.gmailsettings;
import com.google.gdata.client.appsforyourdomain.gmailsettings.GmailFilterService;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.data.appsforyourdomain.generic.GenericEntry;
import com.google.gdata.data.appsforyourdomain.generic.GenericFeed;
import com.google.gdata.data.batch.BatchStatus;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This is the client library for the Google Apps Gmail Settings API. It
* shows how the GmailFilterService can be used to create filters into Gmail
* account.
*
*
*/
public class AppsForYourDomainGmailFilterClient {
private static final Logger LOGGER =
Logger.getLogger(AppsForYourDomainGmailFilterClient.class.getName());
private final String domain;
private final String destinationUser;
// Number of filters to insert.
private static final int ITEMS_TO_BATCH = 5;
private final GmailFilterService gmailFilterService;
// Change the value of these field for your own filter
private final String from = "me@google.com";
private final String to = "you@google.com";
private final String subject = "subject";
private final String hasTheWord = "has";
private final String doesNotHaveTheWord = "no";
private final String hasAttachment = "true";
private final String shouldMarkAsRead = "true";
private final String shouldArchive = "true";
private final String label = "label";
/**
* Constructs an AppsForYourDomainGmailFilterClient for the given domain
* using the given admin credentials.
*
* @param username The user name (not email) of a domain administrator.
* @param password The user's password on the domain.
* @param domain The domain in which filter is being created.
* @param destinationUser the user who owns the new filter.
*/
public AppsForYourDomainGmailFilterClient(String username, String password,
String domain, String destinationUser) throws Exception {
this.domain = domain;
if (destinationUser == null) {
this.destinationUser = username;
} else {
this.destinationUser = destinationUser;
}
// Set up the gmail filter service.
gmailFilterService = new GmailFilterService("exampleCo-exampleApp-1");
gmailFilterService.setUserCredentials(username + "@" + domain, password);
// Run the sample.
runSample();
}
/**
* Main driver for the sample.
* <ul>
* <li>Create an entry of Gmail filter and print the results </li>
* <li>Create an feed of Gmail filters and using batch to send the
* request</li>
* </ul>
*/
private void runSample() {
GenericEntry entry = new GenericEntry();
entry.addProperty("user", destinationUser);
entry.addProperty("key", domain);
entry.addProperty("from", from);
entry.addProperty("to", to);
entry.addProperty("subject", subject);
entry.addProperty("hasTheWord", hasTheWord);
entry.addProperty("doesNotHaveTheWord", doesNotHaveTheWord);
entry.addProperty("hasAttachment", hasAttachment);
entry.addProperty("shouldMarkAsRead", shouldMarkAsRead);
entry.addProperty("shouldArchive", shouldArchive);
entry.addProperty("label", label);
LOGGER.log(Level.INFO, "Inserting 1 gmail filter.");
GenericEntry[] entries = new GenericEntry[ITEMS_TO_BATCH];
for (int i = 0; i < ITEMS_TO_BATCH; i ++) {
GenericEntry newEntry = new GenericEntry();
newEntry.addProperty("user", destinationUser);
newEntry.addProperty("key", domain);
newEntry.addProperty("from", from);
newEntry.addProperty("to", to);
newEntry.addProperty("subject", subject);
newEntry.addProperty("hasTheWord", hasTheWord);
newEntry.addProperty("doesNotHaveTheWord", doesNotHaveTheWord);
newEntry.addProperty("hasAttachment", hasAttachment);
newEntry.addProperty("shouldMarkAsRead", shouldMarkAsRead);
newEntry.addProperty("shouldArchive", shouldArchive);
// Apply different label to different filter
newEntry.addProperty("label", String.valueOf(i));
entries[i] = newEntry;
}
try {
LOGGER.log(Level.INFO, "Inserting 1 Gmail filter.");
GenericEntry resultEntry = insertGmailFilter(entry);
LOGGER.log(Level.INFO, "Insert 1 filter succeeded.");
LOGGER.log(Level.INFO, "Batch inserting " + ITEMS_TO_BATCH +
" Gmail filters");
GenericFeed resultFeed = batchInsertGmailFilters(entries);
// Check for failure in the returned entries.
int failedInsertions = 0, successfulInsertions = 0;
for (GenericEntry returnedEntry : resultFeed.getEntries()) {
if (BatchUtils.isFailure(returnedEntry)) {
BatchStatus status = BatchUtils.getBatchStatus(returnedEntry);
LOGGER.log(Level.SEVERE, "Entry "
+ BatchUtils.getBatchId(returnedEntry) + " failed insertion: "
+ status.getCode() + " " + status.getReason());
failedInsertions++;
} else {
successfulInsertions++;
}
}
LOGGER.log(Level.INFO, "Batch insertion: "
+ Integer.toString(successfulInsertions) + " succeeded, "
+ Integer.toString(failedInsertions) + " failed.");
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Caught IOException: " + e.toString());
e.printStackTrace();
} catch (ServiceException e) {
LOGGER.log(Level.SEVERE, "Caught ServiceException: " + e.toString());
e.printStackTrace();
}
}
/**
* Inserts one Gmail filter entry.
*
* @param filter an {@link GenericEntry} objects that has all the Gmail filter
* properties set.
* @return an entry with the result of the operation.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the insert request failed due to system error.
*/
private GenericEntry insertGmailFilter(GenericEntry filter)
throws ServiceException, IOException {
return gmailFilterService.insert(domain, filter);
}
/**
* Insert one or more Gmail filter entries in a single batch operation. Using
* batch insertion is helpful in reducing HTTP overhead.
*
* @param filters one or more {@link GenericEntry} objects containing Gmail
* filter properties.
* @return a feed with the result of each operation in a separate
* {@link GenericEntry} object.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the insert request failed due to system error.
*/
private GenericFeed batchInsertGmailFilters(GenericEntry ... filters)
throws ServiceException, IOException {
GenericFeed feed = new GenericFeed();
for (int i = 0; i < filters.length; i++) {
BatchUtils.setBatchId(filters[i], Integer.toString(i));
feed.getEntries().add(filters[i]);
}
return gmailFilterService.batch(domain, feed);
}
/**
* Prints the command line usage of this sample application.
*/
private static void usage() {
System.out.println("Usage: java AppsForYourDomainGmailFilterClient"
+ " --username <username> --password <password> --domain <domain>\n"
+ " --destination_user <destination_user>");
System.out.println();
System.out.println("A simple application that demonstrates how to create"
+ " filters to a Google Apps email account. Authenticates using the"
+ " provided login credentials, then create sample filters to the"
+ " specified destination account.");
System.out.println();
System.out.println("Specify username and destination_user as just the name,"
+ " not email address. For example, to create filter to joe@example.com"
+ " use these options: --username joe --password your_password"
+ " --domain example.com");
}
/**
* Main entry point. Parses arguments and creates and invokes the
* AppsForYourDomainGmailFilterClient.
*
* Usage: java AppsForYourDomainGmailFilterClient --username &lt;user&gt;
* --password &lt;pass&gt; --domain &lt;domain&gt;
* --destination_user &lt;destination_user&gt;
*/
public static void main(String[] arg) throws Exception {
SimpleCommandLineParser parser = new SimpleCommandLineParser(arg);
// Parse command-line flags
String username = parser.getValue("username");
String password = parser.getValue("password");
String domain = parser.getValue("domain");
String destinationUser = parser.getValue("destination_user");
boolean help = parser.containsKey("help");
if (help || (username == null) || (password == null) || (domain == null)) {
usage();
System.exit(1);
}
new AppsForYourDomainGmailFilterClient(username, password, domain,
destinationUser);
}
}
@@ -0,0 +1,156 @@
/* 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.appsforyourdomain.gmailsettings;
/**
* Contains constants used by the GMail Settings API sample clients.
*/
public final class Constants {
/**
*/
private Constants() {}
public static final int FILTER_FROM_MAX_LENGTH = 400;
public static final int FILTER_TO_MAX_LENGTH = 400;
public static final int FILTER_SUBJECT_MAX_LENGTH = 1000;
public static final int FILTER_HAS_THE_WORD_MAX_LENGTH = 1000;
public static final int FILTER_DOES_NOT_HAVE_THE_WORD_MAX_LENGTH = 1000;
public static final String[] FORWARDING_ACTION = {"KEEP", "ARCHIVE", "DELETE"};
public static final String[] GENERAL_ALLOWED_PAGE_SIZES = {"25", "50", "100"};
public static final int LABEL_MIN_LENGTH = 1;
public static final int LABEL_MAX_LENGTH = 40;
public static final String[] LANGUAGE_VALID_KEY = {
"ar", // Arabic
"bn", // Bengali
"bg", // Bulgarian
"ca", // Catalan
"zh-CN", // Chinese (Simplified)
"zh-TW", // Chinese (Traditional)
"hr", // Croatian
"cs", // Czech
"da", // Danish
"nl", // Dutch
"en-US", // English (United States)
"en-GB", // English (United Kingdom)
"et", // Estonian
"fi", // Finnish
"fr", // French
"de", // German
"el", // Greek
"gu", // Gujarati
"iw", // Hebrew
"hi", // Hindi
"hu", // Hungarian
"is", // Icelandic
"in", // Indonesian
"it", // Italian
"ja", // Japanese
"kn", // Kannada
"ko", // Korean
"lv", // Latvian
"lt", //Lithuanian
"ms", // Malay
"ml", // Malayalam
"mr", // Marathi
"no", // Norwegian
"or", // Oriya
"fa", // Persian
"pl", // Polish
"pt-BR", // Portuguese (Brazil)
"pt-PT", // Portuguese (Portugal)
"ro", // Romanian
"ru", // Russian
"sr", // Serbian
"sk", // Slovak
"sl", // Slovenian
"es", // Spanish
"sv", // Swedish
"tl", // Tagalog
"ta", // Tamil
"te", // Telugu
"th", // Thai
"tr", // Turkish
"uk", // Ukrainian
"ur", // Urdu
"vi" // Vietnamese
};
public static final String[] POP_ENABLE_FOR = {"ALL_MAIL", "MAIL_FROM_NOW_ON"};
public static final String[] POP_ACTION = {"KEEP", "ARCHIVE", "DELETE"};
public static final int SENDAS_NAME_MIN_LENGTH = 1;
public static final int SENDAS_NAME_MAX_LENGTH = 250;
public static final int SIGNATURE_MIN_LENGTH = 0;
public static final int SIGNATURE_MAX_LENGTH = 1000;
public static final int VACATION_SUBJECT_MIN_LENGTH = 0;
public static final int VACATION_SUBJECT_MAX_LENGTH = 500;
public static final int VACATION_MESSAGE_MIN_LENGTH = 0;
public static final int VACATION_MESSAGE_MAX_LENGTH = 100 * 1024;
public static final String DEFAULT_DOMAIN = "";
public static final String DEFAULT_USERNAME = "";
public static final String DEFAULT_PASSWORD = "";
public static final String PROTOCOL = "https";
public static final String APPS_APIS_DOMAIN = "apps-apis.google.com";
public static final String APPS_APIS_URL = "/a/feeds/emailsettings/2.0";
public static final String FROM = "from";
public static final String TO = "to";
public static final String SUBJECT = "subject";
public static final String HAS_THE_WORD = "hasTheWord";
public static final String DOESNT_HAVE_THE_WORD = "doesNotHaveTheWord";
public static final String HAS_ATTACHMENT = "hasAttachment";
public static final String SHOULD_MARK_AS_READ = "shouldMarkAsRead";
public static final String SHOULD_ARCHIVE = "shouldArchive";
public static final String LABEL = "label";
public static final String ADDRESS = "address";
public static final String NAME = "name";
public static final String REPLY_TO = "replyTo";
public static final String IS_DEFAULT = "isDefault";
public static final String MAKE_DEFAULT = "makeDefault";
public static final String VERIFIED = "verified";
public static final String UNREAD_COUNT = "unreadCount";
public static final String VISIBILITY = "visibility";
public static final String ENABLE = "enable";
public static final String ENABLE_FOR = "enableFor";
public static final String ACTION = "action";
public static final String MESSAGE = "message";
public static final String CONTACTS_ONLY = "contactsOnly";
public static final String TRUE = "true";
public static final String FALSE = "false";
public static final String SIGNATURE = "signature";
public static final String LANGUAGE = "language";
public static final String PAGE_SIZE = "pageSize";
public static final String SHORTCUTS = "shortcuts";
public static final String ARROWS = "arrows";
public static final String SNIPPETS = "snippets";
public static final String UNICODE = "unicode";
public static final String IMAP = "imap";
public static final String POP = "pop";
public static final String FORWARD_TO = "forwardTo";
public static final String FORWARDING = "forwarding";
public static final String SEND_AS = "sendas";
public static final String VACATION = "vacation";
}
@@ -0,0 +1,74 @@
/* 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.appsforyourdomain.gmailsettings;
/**
* Contains default values for the GMail Settings API sample clients.
*/
public final class Defaults {
/**
* Prevents the class from being instantiated.
*/
private Defaults() {}
public static final String FILTER_FROM = "me@google.com";
public static final String FILTER_TO = "you@google.com";
public static final String FILTER_SUBJECT = "subject";
public static final String FILTER_HAS_THE_WORD = "has";
public static final String FILTER_DOES_NOT_HAVE_THE_WORD = "no";
public static final boolean FILTER_HAS_ATTACHMENT = true;
public static final boolean FILTER_SHOULD_MARK_AS_READ = true;
public static final boolean FILTER_SHOULD_ARCHIVE = true;
public static final String FILTER_LABEL = "label";
public static final String SEND_AS_NAME = "test-alias";
public static final String SEND_AS_ADDRESS = "johndoe@example.com";
public static final String SEND_AS_REPLY_TO = "reply-to@someplace.com";
public static final boolean SEND_AS_MAKE_DEFAULT = false;
public static final String LABEL = "label";
public static final boolean FORWARDING_ENABLE = true;
public static final String FORWARDING_FORWARD_TO = "test@admin-api.com";
public static final String FORWARDING_ACTION = "ARCHIVE";
public static final boolean FORWARDING_MAKE_DEFAULT = false;
public static final boolean POP_ENABLE = true;
public static final String POP_ENABLE_FOR = "MAIL_FROM_NOW_ON";
public static final String POP_ACTION = "ARCHIVE";
public static final boolean IMAP_ENABLE = true;
public static final boolean VACATION_ENABLE = true;
public static final String VACATION_SUBJECT = "I'm on vacation";
public static final String VACATION_MESSAGE = "Actually I'm just testing the vacation " +
"responder";
public static final boolean VACATION_CONTACTS_ONLY = true;
public static final String SIGNATURE = "<Insert witty signature here>";
public static final String GENERAL_PAGE_SIZE = "50";
public static final boolean GENERAL_ENABLE_SHORTCUTS = true;
public static final boolean GENERAL_ENABLE_ARROWS = true;
public static final boolean GENERAL_ENABLE_SNIPPETS = true;
public static final boolean GENERAL_ENABLE_UNICODE = true;
public static final String LANGUAGE = "en-US";
public static final boolean WEBCLIP_ENABLE = true;
}
@@ -0,0 +1,287 @@
/* 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.appsforyourdomain.gmailsettings;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* This is the command line client for the Google Apps Gmail Settings API.
*/
public class GmailSettingsClient {
/**
* Prevents the class from being instantiated.
*/
private GmailSettingsClient() {}
/**
* Prints the command line usage of this sample application.
*/
private static void printUsageAndExit() {
System.out.println("Usage: java GmailSettingsClient"
+ " --username <username> --password <password> --domain <domain>\n"
+ " --setting <setting> [--disable]"
+ " [--get true --destination_user <destination_user>] ");
System.out.println();
System.out.println("A simple application that demonstrates how to get or"
+ " change Gmail settings in a Google Apps email account."
+ " Authenticates using the provided login credentials, then retrieves"
+ " or modifies the settings of the specified account.");
System.out.println();
System.out.println("Specify username and destination_user as just the name,"
+ " not the email address. For example, to change settings for"
+ " joe@example.com use these options: --username joe --password"
+ " your_password --domain example.com");
System.out.println();
System.out.println("**For changing settings...");
System.out.println("Select which setting to change with the setting flag."
+ " For example, to change the POP3 settings, use --setting pop"
+ " (allowed values are filter, sendas, label, forwarding, pop, imap,"
+ " vacation, signature, general, language, and webclip.)");
System.out.println();
System.out.println("By default the selected setting will be enabled, "
+ "but with the --disable flag it will be disabled.");
System.out.println();
System.out.println("**For retrieving settings...");
System.out.println("To retrieve settings, use the --get=true option and"
+ " mandatorily specify a single --destination_user."
+ " For example, to get the signature settings, use"
+ " --get true --settings signature --destination_user joe"
+ " (allowed values are label, sendas, forwarding, pop, imap, vacation,"
+ " and signature).");
System.out.println();
System.exit(1);
}
/**
* Main entry point. Parses arguments and creates and invokes the
* GmailSettingsClient
*
* Usage: java GmailSettingsClient --username &lt;user&gt;
* --password &lt;pass&gt; --domain &lt;domain&gt; --setting &lt;setting&gt;
* [--get true --destination_user &lt;destination_user&gt;] [--disable]
*
* &lt;setting&gt; should be one of:
* <ul>
* <li>filter</li>
* <li>sendas<li>
* <li>label</li>
* <li>forwarding</li>
* <li>pop</li>
* <li>imap</li>
* <li>vacation</li>
* <li>signature</li>
* <li>general</li>
* <li>language</li>
* <li>webclip</li>
* </ul>
*/
public static void main(String[] arg) {
SimpleCommandLineParser parser = new SimpleCommandLineParser(arg);
// Parse command-line flags
String username = parser.getValue("username");
String password = parser.getValue("password");
String domain = parser.getValue("domain");
String destinationUser = parser.getValue("destination_user");
String setting = parser.getValue("setting");
String get = parser.getValue("get");
boolean help = parser.containsKey("help");
boolean enable = !parser.containsKey("disable");
boolean doGet = (get != null && get.equalsIgnoreCase("true"));
if (help || (username == null) || (password == null) || (domain == null)
|| (setting == null) || (doGet && destinationUser == null)) {
printUsageAndExit();
}
// --setting flag is quite accepting - case-insensitive and startsWith
// mean that not just "pop" but also "POP3" works
setting = setting.trim().toLowerCase();
try {
GmailSettingsService settings = new GmailSettingsService("exampleCo-exampleApp-1", domain,
username, password);
List<String> users = new ArrayList<String>();
users.add(destinationUser);
if (setting.startsWith("filter")) {
if (doGet) {
System.out.println("Retrieving filter settings is not supported.\n");
printUsageAndExit();
} else {
settings.createFilter(users,
Defaults.FILTER_FROM,
Defaults.FILTER_TO,
Defaults.FILTER_SUBJECT,
Defaults.FILTER_HAS_THE_WORD,
Defaults.FILTER_DOES_NOT_HAVE_THE_WORD,
Defaults.FILTER_HAS_ATTACHMENT,
Defaults.FILTER_SHOULD_MARK_AS_READ,
Defaults.FILTER_SHOULD_ARCHIVE,
Defaults.FILTER_LABEL);
}
} else if (setting.startsWith("sendas")) {
if (doGet) {
List<Map<String, String>> sendAsSettings = settings.retrieveSendAs(destinationUser);
int count = 0;
for (Map<String, String> sendAsSetting : sendAsSettings) {
System.out.println("sendAs setting " + ++count + ":");
Set<Entry<String, String>> entries = sendAsSetting.entrySet();
for (Entry<String, String> entry : entries)
System.out.println("\t" + entry.getKey() + ": " + entry.getValue());
}
} else {
settings.createSendAs(users, Defaults.SEND_AS_NAME, Defaults.SEND_AS_ADDRESS,
Defaults.SEND_AS_REPLY_TO, Defaults.SEND_AS_MAKE_DEFAULT);
}
} else if (setting.startsWith("label")) {
if (doGet) {
List<Map<String, String>> labels = settings.retrieveLabels(destinationUser);
int count = 0;
for (Map<String, String> label : labels) {
System.out.println("label " + ++count + ":");
Set<Entry<String, String>> entries = label.entrySet();
for (Entry<String, String> entry : entries)
System.out.println("\t" + entry.getKey() + ": " + entry.getValue());
}
} else {
settings.createLabel(users, Defaults.LABEL);
}
} else if (setting.startsWith("forwarding")) {
if (doGet) {
Map<String, String> forwarding = settings.retrieveForwarding(destinationUser);
System.out.println("forwarding settings:");
for (Entry<String, String> entry : forwarding.entrySet())
System.out.println("\t" + entry.getKey() + ": " + entry.getValue());
} else {
settings.changeForwarding(users, Defaults.FORWARDING_ENABLE,
Defaults.FORWARDING_FORWARD_TO, Defaults.FORWARDING_ACTION);
}
} else if (setting.startsWith("pop")) {
if (doGet) {
Map<String, String> pop = settings.retrievePop(destinationUser);
System.out.println("pop settings:");
for (Entry<String, String> entry : pop.entrySet())
System.out.println("\t" + entry.getKey() + ": " + entry.getValue());
} else {
settings.changePop(
users, Defaults.POP_ENABLE, Defaults.POP_ENABLE_FOR, Defaults.POP_ACTION);
}
} else if (setting.startsWith("imap")) {
if (doGet) {
boolean imap = settings.retrieveImap(destinationUser);
System.out.println("imap settings:");
System.out.println("\tenabled: " + imap);
} else {
settings.changeImap(users, Defaults.IMAP_ENABLE);
}
} else if (setting.startsWith("vacation")) {
if (doGet) {
Map<String, String> vacation = settings.retrieveVacation(destinationUser);
System.out.println("vacation settings:");
for (Entry<String, String> entry : vacation.entrySet())
System.out.println("\t" + entry.getKey() + ": " + entry.getValue());
} else {
settings.changeVacation(users, Defaults.VACATION_ENABLE, Defaults.VACATION_SUBJECT,
Defaults.VACATION_MESSAGE, Defaults.VACATION_CONTACTS_ONLY);
}
} else if (setting.startsWith("signature")) {
if (doGet) {
String signature = settings.retrieveSignature(destinationUser);
System.out.println("signature:");
System.out.println("\tvalue: " + signature);
} else {
settings.changeSignature(users, Defaults.SIGNATURE);
}
} else if (setting.startsWith("general")) {
if (doGet) {
System.out.println("Retrieving general settings is not supported.\n");
printUsageAndExit();
} else {
settings.changeGeneral(users,
Defaults.GENERAL_PAGE_SIZE,
Defaults.GENERAL_ENABLE_SHORTCUTS,
Defaults.GENERAL_ENABLE_ARROWS,
Defaults.GENERAL_ENABLE_SNIPPETS,
Defaults.GENERAL_ENABLE_UNICODE);
}
} else if (setting.startsWith("language")) {
if (doGet) {
System.out.println("Retrieving language settings is not supported.\n");
printUsageAndExit();
} else {
settings.changeLanguage(users, Defaults.LANGUAGE);
}
} else if (setting.startsWith("webclip")) {
if (doGet) {
System.out.println("Retrieving webclip settings is not supported.\n");
printUsageAndExit();
} else {
settings.changeWebClip(users, Defaults.WEBCLIP_ENABLE);
}
} else {
printUsageAndExit();
}
} catch (AuthenticationException e) {
System.err.println(e);
} catch (IllegalArgumentException e) {
System.err.println(e);
} catch (ServiceException e) {
System.err.println(e);
} catch (MalformedURLException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
}
}
@@ -0,0 +1,816 @@
/* 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.appsforyourdomain.gmailsettings;
import com.google.gdata.client.appsforyourdomain.AppsForYourDomainService;
import com.google.gdata.data.appsforyourdomain.generic.GenericEntry;
import com.google.gdata.data.appsforyourdomain.generic.GenericFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This is the client library for the Google Apps Gmail Settings API. It
* shows how to use the services for creating Gmail filters, send-as aliases, or
* labels or changing Gmail forwarding, POP3, IMAP, vacation-responder,
* signature, web clip or general settings.
*/
public class GmailSettingsService extends AppsForYourDomainService {
protected static final Logger logger =
Logger.getLogger(GmailSettingsService.class.getName());
protected final String domain;
/**
* Constructs a GmailSettingsService for the given domain using the given
* admin credentials.
*
* @param applicationName the name of the application making the modifications.
* @param domain the domain in which settings will be modified.
* @param username the user name (not email) of a domain administrator.
* @param password the user's password on the domain.
* @throws AuthenticationException the Exception thrown when invalid
* credentials are supplied.
*/
public GmailSettingsService(String applicationName, String domain,
String username, String password) throws AuthenticationException {
super(applicationName, Constants.PROTOCOL, Constants.APPS_APIS_DOMAIN);
this.domain = domain;
new GenericFeed().declareExtensions(getExtensionProfile());
this.setUserCredentials(username + "@" + domain, password);
}
/**
* Retrieve the specified Gmail settings as a GenericFeed
*
* @param username the user name for which to get the settings.
* @param setting the setting field to get.
* @return a GenericEntry of requested settings
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the retrieve request failed due to system
* error.
*/
public GenericFeed retrieveSettingsFeed(String username, String setting)
throws IOException, ServiceException {
URL singleUrl =
new URL(
Constants.PROTOCOL + "://" + Constants.APPS_APIS_DOMAIN + Constants.APPS_APIS_URL + "/"
+ domain + "/" + username + "/" + setting);
return getFeed(singleUrl, GenericFeed.class);
}
/**
* Retrieve the specified Gmail settings as a GenericEntry
*
* @param username the user name for which to get the settings.
* @param setting the setting field to get.
* @return a GenericEntry of requested settings
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the retrieve request failed due to system
* error.
*/
public GenericEntry retrieveSettingsEntry(String username, String setting)
throws IOException, ServiceException {
URL singleUrl =
new URL(
Constants.PROTOCOL + "://" + Constants.APPS_APIS_DOMAIN + Constants.APPS_APIS_URL + "/"
+ domain + "/" + username + "/" + setting);
return getEntry(singleUrl, GenericEntry.class);
}
/**
* Inserts a new Gmail settings entity - eg a filter.
*
* @param username the user name of a domain administrator.
* @param entry an {@link GenericEntry} object containing all the properties
* of the new entity.
* @return an entry with the result of the operation.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public GenericEntry insertSettings(String username, GenericEntry entry,
String setting) throws IOException, MalformedURLException,
ServiceException {
URL singleUrl = new URL(Constants.PROTOCOL + "://" +
Constants.APPS_APIS_DOMAIN + Constants.APPS_APIS_URL + "/" + domain +
"/" + username + "/" + setting);
return insert(singleUrl, entry);
}
/**
* Update Gmail settings.
*
* @param username the user name of a domain administrator.
* @param entry a {@link GenericEntry} object containing the new Gmail
* settings.
* @return an entry with the result of the operation.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the insert request failed due to system error.
*/
public GenericEntry updateSettings(String username, GenericEntry entry,
String setting) throws IOException, MalformedURLException,
ServiceException {
URL singleUrl = new URL(Constants.PROTOCOL + "://" +
Constants.APPS_APIS_DOMAIN + Constants.APPS_APIS_URL + "/" + domain +
"/" + username + "/" + setting);
return update(singleUrl, entry);
}
/**
* Creates a filter.
*
* @param users a list of the users to create the filter for.
* @param from the email must come from this address in order to be filtered.
* @param to the email must be sent to this address in order to be filtered.
* @param subject a string the email must have in it's subject line to be
* filtered.
* @param hasTheWord a string the email can have anywhere in it's subject or
* body.
* @param doesNotHaveTheWord a string that the email cannot have anywhere in
* its subject or body.
* @param hasAttachment a boolean representing whether or not the email
* contains an attachment. Values are "true" or "false".
* @param shouldMarkAsRead a boolean field that represents automatically
* moving the message to. "Archived" state if it matches the specified
* filter criteria.
* @param shouldArchive a boolean field that represents automatically moving
* the message to. "Archived" state if it matches the specified filter
* criteria.
* @param label a string that represents the name of the label to apply if a
* message matches the specified filter criteria.
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void createFilter(List<String> users, String from, String to,
String subject, String hasTheWord, String doesNotHaveTheWord,
boolean hasAttachment, boolean shouldMarkAsRead, boolean shouldArchive,
String label) throws IllegalArgumentException, ServiceException,
MalformedURLException, IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
entry.addProperty(Constants.FROM, from);
entry.addProperty(Constants.TO, to);
entry.addProperty(Constants.SUBJECT, subject);
entry.addProperty(Constants.HAS_THE_WORD, hasTheWord);
entry.addProperty(Constants.DOESNT_HAVE_THE_WORD, doesNotHaveTheWord);
entry.addProperty(Constants.HAS_ATTACHMENT, String.valueOf(hasAttachment));
entry.addProperty(Constants.SHOULD_MARK_AS_READ, String.valueOf(shouldMarkAsRead));
entry.addProperty(Constants.SHOULD_ARCHIVE, String.valueOf(shouldArchive));
entry.addProperty(Constants.LABEL, label);
for (String user : users) {
logger.log(Level.INFO, "Creating filter ( " +
"from: " + from +
", to: " + to +
", subject: " + subject +
", hasTheWord: " + hasTheWord +
", doesNotHaveTheWord: " + doesNotHaveTheWord +
", hasAttachment: " + hasAttachment +
", shouldMarkAsRead: " + shouldMarkAsRead +
", shouldArchive: " + shouldArchive +
", label: " + label +
" ) for user " + user + " ...");
insertSettings(user, entry, "filter");
logger.log(Level.INFO, "Successfully created filter.");
}
}
/**
* Retrieves the send-as alias settings
*
* @param user
* @return a list of send-as aliases
* @throws IllegalArgumentException if the user hasn't been passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the retrieve request failed due to system
* error.
*/
public List<Map<String, String>> retrieveSendAs(String user)
throws IllegalArgumentException, IOException, ServiceException {
if (user == null || user.length() == 0) {
throw new IllegalArgumentException();
}
logger.log(Level.INFO, "Getting send-as settings for user " + user + " ...");
GenericFeed sendAsFeed = retrieveSettingsFeed(user, Constants.SEND_AS);
if (sendAsFeed != null) {
List<Map<String, String>> sendAs = new ArrayList<Map<String, String>>();
List<GenericEntry> sendAsEntries = sendAsFeed.getEntries();
for (GenericEntry sendAsEntry : sendAsEntries) {
Map<String, String> sendAsMap = new HashMap<String, String>();
sendAsMap.put(Constants.ADDRESS, sendAsEntry.getProperty(Constants.ADDRESS));
sendAsMap.put(Constants.NAME, sendAsEntry.getProperty(Constants.NAME));
sendAsMap.put(Constants.REPLY_TO, sendAsEntry.getProperty(Constants.REPLY_TO));
sendAsMap.put(Constants.IS_DEFAULT, sendAsEntry.getProperty(Constants.IS_DEFAULT));
sendAsMap.put(Constants.VERIFIED, sendAsEntry.getProperty(Constants.VERIFIED));
sendAs.add(sendAsMap);
}
return sendAs;
}
return null;
}
/**
* Creates a send-as alias.
*
* @param users a list of the users to create the send-as alias for.
* @param name the name which e-mails sent using the alias are from.
* @param address the e-mail address which e-mails sent using the alias are
* from.
* @param replyTo (Optional) if set, this address will be included as the
* reply-to address in e-mails sent using the alias.
* @param makeDefault (Optional) if set to true, this user will have this
* send-as alias selected by default from now on.
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void createSendAs(List<String> users, String name, String address,
String replyTo, boolean makeDefault) throws IllegalArgumentException,
ServiceException, MalformedURLException, IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
entry.addProperty(Constants.NAME, name);
entry.addProperty(Constants.ADDRESS, address);
entry.addProperty(Constants.REPLY_TO, replyTo);
entry.addProperty(Constants.MAKE_DEFAULT, String.valueOf(makeDefault));
for (String user : users) {
logger.log(Level.INFO, "Creating send-as alias ( " +
"name: " + name +
", address: " + address +
", replyTo: " + replyTo +
", makeDefault: " + makeDefault +
" ) for user " + user + " ...");
insertSettings(user, entry, "sendas");
logger.log(Level.INFO, "Successfully created send-as alias.");
}
}
/**
* Retrieves all mail labels
*
* @param user
* @return List of mail labels
* @throws IllegalArgumentException if the user hasn't been passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the retrieve request failed due to system
* error.
*/
public List<Map<String, String>> retrieveLabels(String user)
throws IllegalArgumentException, IOException, ServiceException {
if (user == null || user.length() == 0) {
throw new IllegalArgumentException();
}
logger.log(Level.INFO, "Getting mail labels for user " + user + " ...");
GenericFeed labelsFeed = retrieveSettingsFeed(user, Constants.LABEL);
if (labelsFeed != null) {
List<Map<String, String>> labels = new ArrayList<Map<String, String>>();
List<GenericEntry> labelEntries = labelsFeed.getEntries();
for (GenericEntry labelEntry : labelEntries) {
Map<String, String> labelMap = new HashMap<String, String>();
labelMap.put(Constants.LABEL, labelEntry.getProperty(Constants.LABEL));
labelMap.put(Constants.UNREAD_COUNT, labelEntry.getProperty(Constants.UNREAD_COUNT));
labelMap.put(Constants.VISIBILITY, labelEntry.getProperty(Constants.VISIBILITY));
labels.add(labelMap);
}
return labels;
}
return null;
}
/**
* Creates a label.
*
* @param users a list of the users to create the label for.
* @param label a string that represents the name of the label.
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void createLabel(List<String> users, String label)
throws IllegalArgumentException, ServiceException, MalformedURLException,
IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
entry.addProperty(Constants.LABEL, label);
for (String user : users) {
logger.log(Level.INFO, "Creating label ( label: " + label + " ) for user "
+ user + " ...");
insertSettings(user, entry, Constants.LABEL);
logger.log(Level.INFO, "Successfully created label.");
}
}
/**
* Retrieves mail forwarding settings
*
* @param user
* @return The value of forwarding settings
* @throws IllegalArgumentException if the user hasn't been passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the retrieve request failed due to system
* error.
*/
public Map<String, String> retrieveForwarding(String user)
throws IllegalArgumentException, IOException, ServiceException {
if (user == null || user.length() == 0) {
throw new IllegalArgumentException();
}
logger.log(Level.INFO, "Getting forwarding settings for user " + user + " ...");
GenericEntry forwardingEntry = retrieveSettingsEntry(user, Constants.FORWARDING);
if (forwardingEntry != null) {
Map<String, String> forwarding = new HashMap<String, String>();
forwarding.put(Constants.ENABLE, forwardingEntry.getProperty(Constants.ENABLE));
forwarding.put(Constants.FORWARD_TO, forwardingEntry.getProperty(Constants.FORWARD_TO));
forwarding.put(Constants.ACTION, forwardingEntry.getProperty(Constants.ACTION));
return forwarding;
}
return null;
}
/**
* Changes forwarding settings.
*
* @param users a list of the users to change the forwarding for.
* @param enable whether to enable forwarding of incoming mail.
* @param forwardTo the email will be forwarded to this address.
* @param action what Gmail should do with its copy of the e-mail after
* forwarding it on.
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void changeForwarding(List<String> users, boolean enable,
String forwardTo, String action) throws IllegalArgumentException,
ServiceException, MalformedURLException, IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
if (enable) {
entry.addProperty(Constants.ENABLE, Constants.TRUE);
entry.addProperty(Constants.FORWARD_TO, forwardTo);
entry.addProperty(Constants.ACTION, action);
} else {
entry.addProperty(Constants.ENABLE, Constants.FALSE);
}
for (String user : users) {
if (enable) {
logger.log(Level.INFO, "Updating forwarding settings ( " +
"enable: true" +
", forwardTo: " + forwardTo +
", action: " + action +
" ) for user" +
user + " ...");
} else {
logger.log(Level.INFO, "Updating forwarding settings ( enable: false ) " +
"for user" + user + " ...");
}
updateSettings(user, entry, Constants.FORWARDING);
logger.log(Level.INFO, "Successfully updated forwarding settings.");
}
}
/**
* Retrieves POP3 settings
*
* @param user
* @return The POP settings
* @throws IllegalArgumentException if the user hasn't been passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the retrieve request failed due to system
* error.
*/
public Map<String, String> retrievePop(String user)
throws IllegalArgumentException, IOException, ServiceException {
if (user == null || user.length() == 0) {
throw new IllegalArgumentException();
}
logger.log(Level.INFO, "Getting POP settings for user " + user + " ...");
GenericEntry popEntry = retrieveSettingsEntry(user, Constants.POP);
if (popEntry != null) {
Map<String, String> pop = new HashMap<String, String>();
pop.put(Constants.ENABLE, popEntry.getProperty(Constants.ENABLE));
pop.put(Constants.ACTION, popEntry.getProperty(Constants.ACTION));
return pop;
}
return null;
}
/**
* Changes POP3 settings.
*
* @param users a list of the users to change the POP3 settings for.
* @param enable whether to enable POP3 access.
* @param enableFor whether to enable POP3 for all mail, or mail from now on.
* @param action what Gmail should do with its copy of the e-mail after it is
* retrieved using POP.
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void changePop(List<String> users, boolean enable, String enableFor,
String action) throws IllegalArgumentException, ServiceException,
MalformedURLException, IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
if (enable) {
entry.addProperty(Constants.ENABLE, Constants.TRUE);
entry.addProperty(Constants.ENABLE_FOR, enableFor);
entry.addProperty(Constants.ACTION, action);
} else {
entry.addProperty(Constants.ENABLE, Constants.FALSE);
}
for (String user : users) {
if (enable) {
logger.log(Level.INFO, "Updating POP3 settings ( " +
"enable: true" +
", enableFor: " + enableFor +
", action: " + action +
" ) for user " + user + " ...");
} else {
logger.log(Level.INFO, "Updating POP3 settings ( enable: false ) for " +
"user " + user + " ...");
}
updateSettings(user, entry, Constants.POP);
logger.log(Level.INFO, "Successfully updated POP3 settings.");
}
}
/**
* Retrieves IMAP settings
*
* @param user
* @return A boolean indicating whether IMAP settings are enabled
* @throws IllegalArgumentException if the user hasn't been passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the retrieve request failed due to system
* error.
*/
public boolean retrieveImap(String user)
throws IllegalArgumentException, IOException, ServiceException {
if (user == null || user.length() == 0) {
throw new IllegalArgumentException();
}
logger.log(Level.INFO, "Getting IMAP settings for user " + user + " ...");
GenericEntry imapEntry = retrieveSettingsEntry(user, Constants.IMAP);
if (imapEntry != null && imapEntry.getProperty(Constants.ENABLE).equals(Constants.TRUE))
return true;
return false;
}
/**
* Changes IMAP settings.
*
* @param users a list of the users to change the IMAP settings for.
* @param enable whether to enable IMAP access.
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void changeImap(List<String> users, boolean enable)
throws IllegalArgumentException, ServiceException, MalformedURLException,
IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
entry.addProperty(Constants.ENABLE, String.valueOf(enable));
for (String user : users) {
logger.log(Level.INFO, "Updating IMAP settings ( enable: " + enable + " ) " +
"for user " + user + " ...");
updateSettings(user, entry, Constants.IMAP);
logger.log(Level.INFO, "Successfully updated IMAP settings.");
}
}
/**
* Retrieves vacation settings
*
* @param user
* @return The vacation auto-responder settings
* @throws IllegalArgumentException if the user hasn't been passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the retrieve request failed due to system
* error.
*/
public Map<String, String> retrieveVacation(String user)
throws IllegalArgumentException, IOException, ServiceException {
if (user == null || user.length() == 0) {
throw new IllegalArgumentException();
}
logger.log(Level.INFO, "Getting vacation settings for user " + user + " ...");
GenericEntry vacationEntry = retrieveSettingsEntry(user, Constants.VACATION);
if (vacationEntry != null) {
Map<String, String> vacation = new HashMap<String, String>();
vacation.put(Constants.ENABLE, vacationEntry.getProperty(Constants.ENABLE));
vacation.put(Constants.SUBJECT, vacationEntry.getProperty(Constants.SUBJECT));
vacation.put(Constants.MESSAGE, vacationEntry.getProperty(Constants.MESSAGE));
vacation.put(Constants.CONTACTS_ONLY, vacationEntry.getProperty(Constants.CONTACTS_ONLY));
return vacation;
}
return null;
}
/**
* Changes vacation-responder settings.
*
* @param users a list of the users to change the vacation-responder for.
* @param enable whether to enable the vacation responder.
* @param subject the subject line of the vacation responder autoresponse.
* @param message the message body of the vacation responder autoresponse.
* @param contactsOnly whether to only send the autoresponse to known contacts.
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void changeVacation(List<String> users, boolean enable, String subject,
String message, boolean contactsOnly) throws IllegalArgumentException,
ServiceException, MalformedURLException, IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
if (enable) {
entry.addProperty(Constants.ENABLE, Constants.TRUE);
entry.addProperty(Constants.SUBJECT, subject);
entry.addProperty(Constants.MESSAGE, message);
entry.addProperty(Constants.CONTACTS_ONLY, String.valueOf(contactsOnly));
} else {
entry.addProperty(Constants.ENABLE, Constants.FALSE);
}
for (String user : users) {
if (enable) {
logger.log(Level.INFO, "Updating vacation-responder settings ( " +
"enable: " + enable +
", subject: " + subject +
", message: " + message +
", contactsOnly: " + contactsOnly +
" ) for user " +
user + " ...");
} else {
logger.log(Level.INFO, "Updating vacation-responder settings ( " +
"enable: false ) for user " + user + " ...");
}
updateSettings(user, entry, Constants.VACATION);
logger.log(Level.INFO, "Successfully updated vacation-responder settings.");
}
}
/**
* Retrieves signature
*
* @param user
* @return The signature
* @throws IllegalArgumentException if the user hasn't been passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the retrieve request failed due to system
* error.
*/
public String retrieveSignature(String user)
throws IllegalArgumentException, IOException, ServiceException {
if (user == null || user.length() == 0) {
throw new IllegalArgumentException();
}
logger.log(Level.INFO, "Getting signature settings for user " + user + " ...");
GenericEntry signatureEntry = retrieveSettingsEntry(user, Constants.SIGNATURE);
if (signatureEntry != null)
return signatureEntry.getProperty(Constants.SIGNATURE);
return null;
}
/**
* Changes signature.
*
* @param users a list of the users to change the signature for.
* @param signature the signature to be appended to outgoing messages. Don't
* want a signature? Set the signature to "" (empty string).
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void changeSignature(List<String> users, String signature)
throws IllegalArgumentException, ServiceException, MalformedURLException,
IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
entry.addProperty(Constants.SIGNATURE, signature);
for (String user : users) {
logger.log(Level.INFO, "Updating signature ( signature: " + signature +
" ) for user " + user + " ...");
updateSettings(user, entry, Constants.SIGNATURE);
logger.log(Level.INFO, "Successfully updated signature.");
}
}
/**
* Changes general settings.
*
* @param users a list of the users to change the general settings for.
* @param pageSize the number of conversations to be shown per page.
* @param enableShortcuts whether to enable keyboard shortcuts
* @param enableArrows whether to display arrow-shaped personal indicators
* next to emails that were sent specifically to the user. (> and >>).
* @param enableSnippets whether to display snippets of messages in the inbox
* and when searching.
* @param enableUnicode whether to use UTF-8 (unicode) encoding for all
* outgoing messages, instead of the default text encoding.
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void changeGeneral(List<String> users, String pageSize,
boolean enableShortcuts, boolean enableArrows, boolean enableSnippets,
boolean enableUnicode) throws IllegalArgumentException, ServiceException,
MalformedURLException, IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
entry.addProperty(Constants.PAGE_SIZE, pageSize);
entry.addProperty(Constants.SHORTCUTS, String.valueOf(enableShortcuts));
entry.addProperty(Constants.ARROWS, String.valueOf(enableArrows));
entry.addProperty(Constants.SNIPPETS, String.valueOf(enableSnippets));
entry.addProperty(Constants.UNICODE, String.valueOf(enableUnicode));
for (String user : users) {
logger.log(Level.INFO, "Updating general settings ( " +
"pageSize: " + pageSize +
", shortcuts: " + enableShortcuts +
", arrows: " + enableArrows +
", snippets: " + enableSnippets +
", unicode: " + enableUnicode +
" ) for user " + user +
" ...");
updateSettings(user, entry, "general");
logger.log(Level.INFO, "Successfully updated general settings.");
}
}
/**
* Changes language settings.
*
* @param users a list of the users to change the language for.
* @param language Gmail's display language.
* @throws IllegalArgumentException if no users are passed in.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws ServiceException if the insert request failed due to system error.
*/
public void changeLanguage(List<String> users, String language)
throws IllegalArgumentException, ServiceException, MalformedURLException,
IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
entry.addProperty(Constants.LANGUAGE, language);
for (String user : users) {
logger.log(Level.INFO, "Updating language settings ( language: " +
language + " ) for user " + user + " ...");
updateSettings(user, entry, Constants.LANGUAGE);
logger.log(Level.INFO, "Successfully updated language settings.");
}
}
/**
* Change web clip settings.
*
* @param users a list of the users to change the web clip settings for.
* @param enable whether to enable web clip.
* @throws IllegalArgumentException if no users are passed in.
* @throws ServiceException if an error occurs while communicating with the
* GData service.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws IOException if the insert request failed due to system error.
*/
public void changeWebClip(List<String> users, boolean enable)
throws IllegalArgumentException, ServiceException, MalformedURLException,
IOException {
if (users.size() == 0) {
throw new IllegalArgumentException();
}
GenericEntry entry = new GenericEntry();
entry.addProperty(Constants.ENABLE, String.valueOf(enable));
for (String user : users) {
logger.log(Level.INFO, "Updating web clip settings ( enable: " + enable +
" ) for user " + user + " ...");
updateSettings(user, entry, "webclip");
logger.log(Level.INFO, "Successfully updated web clip settings.");
}
}
}
@@ -0,0 +1,25 @@
/* 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.appsforyourdomain.gmailsettings;
/**
* Exception to be thrown when an operation on an invalid user is attempted.
*/
public class InvalidUserException extends Exception {
public InvalidUserException() {};
public InvalidUserException(String msg) { super(msg); }
}
@@ -0,0 +1,68 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.GmailSettingsService;
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
/**
* This is the example GUI client for the Google Apps Gmail Settings API.
*/
public class GmailSettingsClient {
public static final String APP_TITLE = "GUI Gmail Settings Client";
public static final String ERROR_AUTHENTICATION_REQUIRED = "You must authenticate first.";
protected static final int DEFAULT_APP_HEIGHT = 350;
protected static final int DEFAULT_APP_WIDTH = 600;
protected static final int DEFAULT_PANE_DIVIDER_LOCATION = 150;
public static GmailSettingsService settings;
public static UsersPanel users;
/**
* Prevents the class from being instantiated.
*/
private GmailSettingsClient() {}
/**
* Entry point for Graphical GMail Settings Client.
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
UIManager.put("swing.boldMetal", Boolean.FALSE);
JFrame frame = new JFrame(APP_TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(DEFAULT_APP_WIDTH, DEFAULT_APP_HEIGHT);
users = new UsersPanel();
TabbedPane settingTabs = new TabbedPane();
JSplitPane splitpane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, users, settingTabs);
splitpane.setDividerLocation(DEFAULT_PANE_DIVIDER_LOCATION);
frame.add(splitpane);
frame.setVisible(true);
}
});
}
}
@@ -0,0 +1,71 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import javax.swing.JPanel;
/**
* Stores some common information for the tabs.
*/
public class Tab extends JPanel {
protected String name;
protected String tooltip;
/**
* @param name The name to assign to the tab.
* @param tooltip The tooltip to be used for the tab.
*/
public Tab(String name, String tooltip) {
setName(name);
setTooltip(tooltip);
}
/**
* @Return the name of the tab
*/
@Override
public String getName() {
return this.name;
}
/**
* Sets the name of the tab.
*
* @param name The name to assign to the tab.
*/
@Override
public void setName(String name) {
this.name = name;
}
/**
* @return The current value for tooltip.
*/
public String getTooltip() {
return this.tooltip;
}
/**
* Sets the tooltop for the tab.
*
* @param tooltip The tooltip to be used for the tab.
*/
public void setTooltip(String tooltip) {
this.tooltip = tooltip;
}
}
@@ -0,0 +1,107 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Constants;
import sample.appsforyourdomain.gmailsettings.GmailSettingsService;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
/**
* Tab containing all the authentication information.
*/
public class TabAuthentication extends Tab {
protected SpringLayout layout;
protected JLabel domainLabel;
protected JTextField domain;
protected JLabel usernameLabel;
protected JTextField username;
protected JLabel passwordLabel;
protected JPasswordField password;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabAuthentication() {
super("Authentication", "Authenticate with a server");
layout = new SpringLayout();
setLayout(layout);
domainLabel = new JLabel("Domain: ");
domain = new JTextField(12);
domain.setText(Constants.DEFAULT_DOMAIN);
usernameLabel = new JLabel("Admin username: ");
username = new JTextField(12);
username.setText(Constants.DEFAULT_USERNAME);
passwordLabel = new JLabel("Admin password: ");
password = new JPasswordField(12);
password.setText(Constants.DEFAULT_PASSWORD);
submit = new JButton("Update");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
GmailSettingsClient.settings = new GmailSettingsService(GmailSettingsClient.APP_TITLE,
domain.getText(), username.getText(), new String (password.getPassword()));
GmailSettingsClient.users.refresh(domain.getText(), username.getText(),
new String (password.getPassword()));
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, domainLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, domainLabel, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, domain, 5, SpringLayout.EAST, domainLabel);
layout.putConstraint(SpringLayout.NORTH, domain, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, usernameLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, usernameLabel, 5, SpringLayout.SOUTH, domain);
layout.putConstraint(SpringLayout.WEST, username, 5, SpringLayout.EAST, usernameLabel);
layout.putConstraint(SpringLayout.NORTH, username, 5, SpringLayout.SOUTH, domain);
layout.putConstraint(SpringLayout.WEST, passwordLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, passwordLabel, 5, SpringLayout.SOUTH, username);
layout.putConstraint(SpringLayout.WEST, password, 5, SpringLayout.EAST, passwordLabel);
layout.putConstraint(SpringLayout.NORTH, password, 5, SpringLayout.SOUTH, username);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, password);
add(domainLabel);
add(domain);
add(usernameLabel);
add(username);
add(passwordLabel);
add(password);
add(submit);
}
}
@@ -0,0 +1,182 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
/**
* Tab containing all the filter information.
*/
public class TabFilter extends Tab {
protected SpringLayout layout;
protected JLabel fromLabel;
protected JTextField from;
protected JLabel toLabel;
protected JTextField to;
protected JLabel subjectLabel;
protected JTextField subject;
protected JLabel hasTheWordLabel;
protected JTextField hasTheWord;
protected JLabel doesNotHaveTheWordLabel;
protected JTextField doesNotHaveTheWord;
protected JCheckBox hasAttachment;
protected JCheckBox shouldMarkAsRead;
protected JCheckBox shouldArchive;
protected JLabel labelLabel;
protected JTextField label;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabFilter() {
super("Filters", "");
layout = new SpringLayout();
setLayout(layout);
fromLabel = new JLabel("From: ");
from = new JTextField(Defaults.FILTER_FROM, 25);
toLabel = new JLabel("To: ");
to = new JTextField(Defaults.FILTER_TO, 25);
subjectLabel = new JLabel("Subject: ");
subject = new JTextField(Defaults.FILTER_SUBJECT, 25);
hasTheWordLabel = new JLabel("Has the word: ");
hasTheWord = new JTextField(Defaults.FILTER_HAS_THE_WORD, 25);
doesNotHaveTheWordLabel = new JLabel("Does not have the word: ");
doesNotHaveTheWord = new JTextField(Defaults.FILTER_DOES_NOT_HAVE_THE_WORD, 25);
hasAttachment = new JCheckBox("Has attachment:", Defaults.FILTER_HAS_ATTACHMENT);
shouldMarkAsRead = new JCheckBox("Should mark as read:", Defaults.FILTER_SHOULD_MARK_AS_READ);
shouldArchive = new JCheckBox("Should archive:", Defaults.FILTER_SHOULD_ARCHIVE);
labelLabel = new JLabel("Label: ");
label = new JTextField(Defaults.FILTER_LABEL, 25);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.createFilter(GmailSettingsClient.users.
getSelectedUsers(), from.getText(), to.getText(), subject.getText(),
hasTheWord.getText(), doesNotHaveTheWord.getText(), hasAttachment.isSelected(),
shouldMarkAsRead.isSelected(), shouldArchive.isSelected(), label.getText());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, fromLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, fromLabel, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, from, 5, SpringLayout.EAST, fromLabel);
layout.putConstraint(SpringLayout.NORTH, from, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, toLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, toLabel, 5, SpringLayout.SOUTH, from);
layout.putConstraint(SpringLayout.WEST, to, 5, SpringLayout.EAST, toLabel);
layout.putConstraint(SpringLayout.NORTH, to, 5, SpringLayout.SOUTH, from);
layout.putConstraint(SpringLayout.WEST, subjectLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, subjectLabel, 5, SpringLayout.SOUTH, to);
layout.putConstraint(SpringLayout.WEST, subject, 5, SpringLayout.EAST, subjectLabel);
layout.putConstraint(SpringLayout.NORTH, subject, 5, SpringLayout.SOUTH, to);
layout.putConstraint(SpringLayout.WEST, hasTheWordLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, hasTheWordLabel, 5, SpringLayout.SOUTH, subject);
layout.putConstraint(SpringLayout.WEST, hasTheWord, 5, SpringLayout.EAST, hasTheWordLabel);
layout.putConstraint(SpringLayout.NORTH, hasTheWord, 5, SpringLayout.SOUTH, subject);
layout.putConstraint(SpringLayout.WEST, doesNotHaveTheWordLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, doesNotHaveTheWordLabel, 5, SpringLayout.SOUTH,
hasTheWord);
layout.putConstraint(SpringLayout.WEST, doesNotHaveTheWord, 5, SpringLayout.EAST,
doesNotHaveTheWordLabel);
layout.putConstraint(SpringLayout.NORTH, doesNotHaveTheWord, 5, SpringLayout.SOUTH, hasTheWord);
layout.putConstraint(SpringLayout.WEST, hasAttachment, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, hasAttachment, 5, SpringLayout.SOUTH,
doesNotHaveTheWord);
layout.putConstraint(SpringLayout.WEST, shouldMarkAsRead, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, shouldMarkAsRead, 5, SpringLayout.SOUTH,
hasAttachment);
layout.putConstraint(SpringLayout.WEST, shouldArchive, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, shouldArchive, 5, SpringLayout.SOUTH,
shouldMarkAsRead);
layout.putConstraint(SpringLayout.WEST, labelLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, labelLabel, 5, SpringLayout.SOUTH, shouldArchive);
layout.putConstraint(SpringLayout.WEST, label, 5, SpringLayout.EAST, labelLabel);
layout.putConstraint(SpringLayout.NORTH, label, 5, SpringLayout.SOUTH, shouldArchive);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, label);
add(fromLabel);
add(from);
add(toLabel);
add(to);
add(subjectLabel);
add(subject);
add(hasTheWordLabel);
add(hasTheWord);
add(doesNotHaveTheWordLabel);
add(doesNotHaveTheWord);
add(hasAttachment);
add(shouldMarkAsRead);
add(shouldArchive);
add(labelLabel);
add(label);
add(submit);
}
}
@@ -0,0 +1,117 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Constants;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
/**
* Tab containing the forwarding information.
*/
public class TabForwarding extends Tab {
protected SpringLayout layout;
protected JCheckBox enable;
protected JLabel forwardToLabel;
protected JTextField forwardTo;
protected JLabel actionLabel;
protected JComboBox action;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabForwarding() {
super("Forwarding", "");
layout = new SpringLayout();
setLayout(layout);
enable = new JCheckBox("Enable:", Defaults.FORWARDING_ENABLE);
forwardToLabel = new JLabel("Forward To: ");
forwardTo = new JTextField(Defaults.FORWARDING_FORWARD_TO, 25);
actionLabel = new JLabel("Action: ");
action = new JComboBox(Constants.FORWARDING_ACTION);
action.setSelectedItem(Defaults.FORWARDING_ACTION);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.changeForwarding(GmailSettingsClient.users.
getSelectedUsers(), enable.isSelected(), forwardTo.getText(),
action.getSelectedItem().toString());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, enable, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enable, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, forwardToLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, forwardToLabel, 5, SpringLayout.SOUTH, enable);
layout.putConstraint(SpringLayout.WEST, forwardTo, 5, SpringLayout.EAST, forwardToLabel);
layout.putConstraint(SpringLayout.NORTH, forwardTo, 5, SpringLayout.SOUTH, enable);
layout.putConstraint(SpringLayout.WEST, actionLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, actionLabel, 5, SpringLayout.SOUTH, forwardTo);
layout.putConstraint(SpringLayout.WEST, action, 5, SpringLayout.EAST, actionLabel);
layout.putConstraint(SpringLayout.NORTH, action, 5, SpringLayout.SOUTH, forwardTo);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, action);
add(enable);
add(forwardToLabel);
add(forwardTo);
add(actionLabel);
add(action);
add(submit);
}
}
@@ -0,0 +1,127 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Constants;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SpringLayout;
/**
* Tab containing all the general information.
*/
public class TabGeneral extends Tab {
protected SpringLayout layout;
protected JLabel pageSizeLabel;
protected JComboBox pageSize;
protected JCheckBox enableShortcuts;
protected JCheckBox enableArrows;
protected JCheckBox enableSnippets;
protected JCheckBox enableUnicode;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabGeneral() {
super("General", "");
layout = new SpringLayout();
setLayout(layout);
pageSizeLabel = new JLabel("Page size: ");
pageSize = new JComboBox(Constants.GENERAL_ALLOWED_PAGE_SIZES);
enableShortcuts = new JCheckBox("Enable shortcuts:", Defaults.GENERAL_ENABLE_SHORTCUTS);
enableArrows = new JCheckBox("Enable arrows:", Defaults.GENERAL_ENABLE_ARROWS);
enableSnippets = new JCheckBox("Enable snippets:", Defaults.GENERAL_ENABLE_SNIPPETS);
enableUnicode = new JCheckBox("Enable unicode:", Defaults.GENERAL_ENABLE_UNICODE);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.changeGeneral(GmailSettingsClient.users.
getSelectedUsers(), pageSize.getSelectedItem().toString(),
enableShortcuts.isSelected(), enableArrows.isSelected(),
enableSnippets.isSelected(),
enableUnicode.isSelected());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, pageSizeLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, pageSizeLabel, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, pageSize, 5, SpringLayout.EAST, pageSizeLabel);
layout.putConstraint(SpringLayout.NORTH, pageSize, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, enableShortcuts, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enableShortcuts, 5, SpringLayout.SOUTH, pageSize);
layout.putConstraint(SpringLayout.WEST, enableArrows, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enableArrows, 5, SpringLayout.SOUTH, enableShortcuts);
layout.putConstraint(SpringLayout.WEST, enableSnippets, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enableSnippets, 5, SpringLayout.SOUTH, enableArrows);
layout.putConstraint(SpringLayout.WEST, enableUnicode, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enableUnicode, 5, SpringLayout.SOUTH, enableSnippets);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, enableUnicode);
add(pageSizeLabel);
add(pageSize);
add(enableShortcuts);
add(enableArrows);
add(enableSnippets);
add(enableUnicode);
add(submit);
}
}
@@ -0,0 +1,87 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.SpringLayout;
/**
* Tab containing all the IMAP information.
*/
public class TabImap extends Tab {
protected SpringLayout layout;
protected JCheckBox imapEnabled;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabImap() {
super("Imap", "");
layout = new SpringLayout();
setLayout(layout);
imapEnabled = new JCheckBox("Enable IMAP:", Defaults.IMAP_ENABLE);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.changeImap(GmailSettingsClient.users.
getSelectedUsers(), imapEnabled.isSelected());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, imapEnabled, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, imapEnabled, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, imapEnabled);
add(imapEnabled);
add(submit);
}
}
@@ -0,0 +1,94 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
/**
* Tab containing all the label information.
*/
public class TabLabel extends Tab {
protected SpringLayout layout;
protected JLabel labelLabel;
protected JTextField label;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabLabel() {
super("Label", "");
layout = new SpringLayout();
setLayout(layout);
labelLabel = new JLabel("Label: ");
label = new JTextField(Defaults.LABEL, 25);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null,
GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.createLabel(GmailSettingsClient.users.
getSelectedUsers(), label.getText());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, labelLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, labelLabel, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, label, 5, SpringLayout.EAST, labelLabel);
layout.putConstraint(SpringLayout.NORTH, label, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, label);
add(labelLabel);
add(label);
add(submit);
}
}
@@ -0,0 +1,95 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Constants;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SpringLayout;
/**
* Tab containing all the language information.
*/
public class TabLanguage extends Tab {
protected SpringLayout layout;
protected JLabel languagesLabel;
protected JComboBox languages;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabLanguage() {
super("Language", "");
layout = new SpringLayout();
setLayout(layout);
languagesLabel = new JLabel("Languages: ");
languages = new JComboBox(Constants.LANGUAGE_VALID_KEY);
languages.setSelectedItem(Defaults.LANGUAGE);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.changeLanguage(GmailSettingsClient.users.
getSelectedUsers(), languages.getSelectedItem().toString());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, languagesLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, languagesLabel, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, languages, 5, SpringLayout.EAST, languagesLabel);
layout.putConstraint(SpringLayout.NORTH, languages, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, languages);
add(languagesLabel);
add(languages);
add(submit);
}
}
@@ -0,0 +1,117 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Constants;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SpringLayout;
/**
* Tab containing all the POP information.
*/
public class TabPop extends Tab {
protected SpringLayout layout;
protected JCheckBox enable;
protected JLabel enableForLabel;
protected JComboBox enableFor;
protected JLabel actionLabel;
protected JComboBox action;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabPop() {
super("Pop","");
layout = new SpringLayout();
setLayout(layout);
enable = new JCheckBox("Enable:",Defaults.POP_ENABLE);
enableForLabel = new JLabel("Enable for: ");
enableFor = new JComboBox(Constants.POP_ENABLE_FOR);
enableFor.setSelectedItem(Defaults.POP_ENABLE_FOR);
actionLabel = new JLabel("Action: ");
action = new JComboBox(Constants.POP_ACTION);
action.setSelectedItem(Defaults.POP_ACTION);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.changePop(GmailSettingsClient.users.
getSelectedUsers(), enable.isSelected(), enableFor.getSelectedItem().toString(),
action.getSelectedItem().toString());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, enable, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enable, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, enableForLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enableForLabel, 5, SpringLayout.SOUTH, enable);
layout.putConstraint(SpringLayout.WEST, enableFor, 5, SpringLayout.EAST, enableForLabel);
layout.putConstraint(SpringLayout.NORTH, enableFor, 5, SpringLayout.SOUTH, enable);
layout.putConstraint(SpringLayout.WEST, actionLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, actionLabel, 5, SpringLayout.SOUTH, enableFor);
layout.putConstraint(SpringLayout.WEST, action, 5, SpringLayout.EAST, actionLabel);
layout.putConstraint(SpringLayout.NORTH, action, 5, SpringLayout.SOUTH, enableFor);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, action);
add(enable);
add(enableForLabel);
add(enableFor);
add(actionLabel);
add(action);
add(submit);
}
}
@@ -0,0 +1,126 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
/**
* Tab containing all the send as information.
*/
public class TabSendAs extends Tab {
protected SpringLayout layout;
protected JLabel nameLabel;
protected JTextField nameField;
protected JLabel addressLabel;
protected JTextField address;
protected JLabel replyToLabel;
protected JTextField replyTo;
protected JCheckBox makeDefault;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabSendAs() {
super("Send As", "");
layout = new SpringLayout();
setLayout(layout);
nameLabel = new JLabel("Name: ");
nameField = new JTextField(Defaults.SEND_AS_NAME, 25);
addressLabel = new JLabel("Address: ");
address = new JTextField(Defaults.SEND_AS_ADDRESS, 25);
replyToLabel = new JLabel("Send As: ");
replyTo = new JTextField(Defaults.SEND_AS_REPLY_TO, 25);
makeDefault = new JCheckBox("Make Default:", Defaults.SEND_AS_MAKE_DEFAULT);
submit = new JButton("Set Send As");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.createSendAs(GmailSettingsClient.users.
getSelectedUsers(), nameField.getText(), address.getText(), replyTo.getText(),
makeDefault.isSelected());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, nameLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, nameLabel, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, nameField, 5, SpringLayout.EAST, nameLabel);
layout.putConstraint(SpringLayout.NORTH, nameField, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, addressLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, addressLabel, 5, SpringLayout.SOUTH, nameField);
layout.putConstraint(SpringLayout.WEST, address, 5, SpringLayout.EAST, addressLabel);
layout.putConstraint(SpringLayout.NORTH, address, 5, SpringLayout.SOUTH, nameField);
layout.putConstraint(SpringLayout.WEST, replyToLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, replyToLabel, 5, SpringLayout.SOUTH, address);
layout.putConstraint(SpringLayout.WEST, replyTo, 5, SpringLayout.EAST, replyToLabel);
layout.putConstraint(SpringLayout.NORTH, replyTo, 5, SpringLayout.SOUTH, address);
layout.putConstraint(SpringLayout.WEST, makeDefault, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, makeDefault, 5, SpringLayout.SOUTH, replyTo);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, makeDefault);
add(nameLabel);
add(nameField);
add(addressLabel);
add(address);
add(replyToLabel);
add(replyTo);
add(makeDefault);
add(submit);
}
}
@@ -0,0 +1,96 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SpringLayout;
/**
* Tab containing all the signature information.
*/
public class TabSignature extends Tab {
protected SpringLayout layout;
protected JLabel signatureLabel;
protected JTextArea signature;
protected JScrollPane signaturePane;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabSignature() {
super("Signature", "Change a users's signature.");
layout = new SpringLayout();
setLayout(layout);
signatureLabel = new JLabel("Signature: ");
signature = new JTextArea(Defaults.SIGNATURE, 4, 25);
signaturePane = new JScrollPane(signature);
submit = new JButton("Set Signature");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.changeSignature(GmailSettingsClient.users.
getSelectedUsers(), signature.getText());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, signatureLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, signatureLabel, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, signaturePane, 5, SpringLayout.EAST, signatureLabel);
layout.putConstraint(SpringLayout.NORTH, signaturePane, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, signaturePane);
add(signatureLabel);
add(signaturePane);
add(submit);
}
}
@@ -0,0 +1,122 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
/**
* Tab containing all the vacation information.
*/
public class TabVacation extends Tab {
protected SpringLayout layout;
protected JCheckBox enable;
protected JLabel subjectLabel;
protected JTextField subject;
protected JLabel messageLabel;
protected JTextField message;
protected JLabel contactsOnlyLabel;
protected JCheckBox contactsOnly;
protected JButton submit;
/**
* Setup all the components on the tab.
*/
public TabVacation() {
super("Vacation Responder", "");
layout = new SpringLayout();
setLayout(layout);
enable = new JCheckBox("Enable:", Defaults.VACATION_ENABLE);
subjectLabel = new JLabel("Subject: ");
subject = new JTextField(Defaults.VACATION_SUBJECT, 25);
messageLabel = new JLabel("Message: ");
message = new JTextField(Defaults.VACATION_MESSAGE, 25);
contactsOnly = new JCheckBox("Contacts only:", Defaults.VACATION_CONTACTS_ONLY);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.changeVacation(GmailSettingsClient.users.
getSelectedUsers(), enable.isSelected(), subject.getText(), message.getText(),
contactsOnly.isSelected());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, enable, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enable, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, subjectLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, subjectLabel, 5, SpringLayout.SOUTH, enable);
layout.putConstraint(SpringLayout.WEST, subject, 5, SpringLayout.EAST, subjectLabel);
layout.putConstraint(SpringLayout.NORTH, subject, 5, SpringLayout.SOUTH, enable);
layout.putConstraint(SpringLayout.WEST, messageLabel, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, messageLabel, 5, SpringLayout.SOUTH, subject);
layout.putConstraint(SpringLayout.WEST, message, 5, SpringLayout.EAST, messageLabel);
layout.putConstraint(SpringLayout.NORTH, message, 5, SpringLayout.SOUTH, subject);
layout.putConstraint(SpringLayout.WEST, contactsOnly, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, contactsOnly, 5, SpringLayout.SOUTH, message);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, contactsOnly);
add(enable);
add(subjectLabel);
add(subject);
add(messageLabel);
add(message);
add(contactsOnly);
add(submit);
}
}
@@ -0,0 +1,82 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import sample.appsforyourdomain.gmailsettings.Defaults;
import com.google.gdata.util.ServiceException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.SpringLayout;
/**
* Tab containing all the web clip information.
*/
public class TabWebClip extends Tab {
protected SpringLayout layout;
protected JCheckBox webClipEnabled;
protected JButton submit;
public TabWebClip() {
super("WebClip", "");
layout = new SpringLayout();
setLayout(layout);
webClipEnabled = new JCheckBox("Enable Web clip:", Defaults.WEBCLIP_ENABLE);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if (GmailSettingsClient.settings == null) {
JOptionPane.showMessageDialog(null, GmailSettingsClient.ERROR_AUTHENTICATION_REQUIRED,
GmailSettingsClient.APP_TITLE, JOptionPane.ERROR_MESSAGE);
return;
}
try {
GmailSettingsClient.settings.changeWebClip(GmailSettingsClient.users.getSelectedUsers(),
webClipEnabled.isSelected());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
});
layout.putConstraint(SpringLayout.WEST, webClipEnabled, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, webClipEnabled, 5, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, submit, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, submit, 15, SpringLayout.SOUTH, webClipEnabled);
add(webClipEnabled);
add(submit);
}
}
@@ -0,0 +1,82 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import javax.swing.JTabbedPane;
/**
* Handles adding all the tabs needed.
*/
public class TabbedPane extends JTabbedPane {
protected Tab authenticationTab;
protected Tab signatureTab;
protected Tab labelTab;
protected Tab filtersTab;
protected Tab sendasTab;
protected Tab popTab;
protected Tab forwardingTab;
protected Tab imapTab;
protected Tab vacationTab;
protected Tab languageTab;
protected Tab generalTab;
protected Tab webClipTab;
/**
* Create an instance of all tabs required, and add them to the pane.
*/
public TabbedPane() {
super(JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
authenticationTab = new TabAuthentication();
signatureTab = new TabSignature();
labelTab = new TabLabel();
filtersTab = new TabFilter();
sendasTab = new TabSendAs();
popTab = new TabPop();
forwardingTab = new TabForwarding();
imapTab = new TabImap();
vacationTab = new TabVacation();
languageTab = new TabLanguage();
generalTab = new TabGeneral();
webClipTab = new TabWebClip();
addTab(authenticationTab);
addTab(signatureTab);
addTab(labelTab);
addTab(filtersTab);
addTab(sendasTab);
addTab(popTab);
addTab(forwardingTab);
addTab(imapTab);
addTab(vacationTab);
addTab(languageTab);
addTab(generalTab);
addTab(webClipTab);
this.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
}
/**
* Helper method for adding tabs to the pane.
*
* @param tab The tab to be added to the JTabbedPane
*/
protected void addTab(Tab tab) {
super.addTab(tab.getName(), null, tab, tab.getTooltip());
}
}
@@ -0,0 +1,140 @@
/* 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.appsforyourdomain.gmailsettings.gui;
import com.google.gdata.client.appsforyourdomain.AppsForYourDomainQuery;
import com.google.gdata.client.appsforyourdomain.UserService;
import com.google.gdata.data.Link;
import com.google.gdata.data.appsforyourdomain.provisioning.UserEntry;
import com.google.gdata.data.appsforyourdomain.provisioning.UserFeed;
import com.google.gdata.util.ServiceException;
import java.awt.GridLayout;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
/**
* Panel that uses the provisioning API to display all the users from a domain.
*/
public class UsersPanel extends JPanel {
protected JList users;
protected DefaultListModel usersListModel;
protected JScrollPane usersPane;
/**
* Sets up the panel.
*/
public UsersPanel() {
usersListModel = new DefaultListModel();
users = new JList();
users.setModel(usersListModel);
usersPane = new JScrollPane(users);
setLayout(new GridLayout(1, 1));
add(usersPane);
}
/**
* @return Returns a list of all the users that were selected in the panel.
*/
public List<String> getSelectedUsers() {
Object[] tmp = users.getSelectedValues();
List<String> susers = new ArrayList<String>();
for (int i = 0; i < tmp.length; i++) {
susers.add(tmp[i].toString());
}
return susers;
}
/**
* Refreshes the panel to display the users.
*
* @param domain The domain in which settings will be modified.
* @param username The user name (not email) of a domain administrator.
* @param password The user's password on the domain.
*/
public void refresh(String domain, String username, String password) {
try {
UserFeed usersFeed = getUsers(domain, username, password);
usersListModel.clear();
Iterator<UserEntry> userIterator = usersFeed.getEntries().iterator();
while (userIterator.hasNext()) {
usersListModel.addElement(userIterator.next().getLogin().getUserName());
}
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
} catch (ServiceException e) {
JOptionPane.showMessageDialog(null, e, GmailSettingsClient.APP_TITLE,
JOptionPane.ERROR_MESSAGE);
}
}
/**
* Retrieves the first 100 users from the domain.
*
* @param domain The domain in which settings will be modified.
* @param username The user name (not email) of a domain administrator.
* @param password The user's password on the domain.
* @return UserFeed containing all the user accounts in the domain.
* @throws MalformedURLException if the batch feed URL cannot be constructed.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the insert request failed due to system error.
*/
protected UserFeed getUsers(String domain, String username, String password)
throws MalformedURLException, IOException, ServiceException {
String domainUrlBase = null;
UserFeed allUsers = null;
UserService userService = new UserService(GmailSettingsClient.APP_TITLE);
userService.setUserCredentials(username + "@" + domain, password);
domainUrlBase = "https://www.google.com/a/feeds/" + domain + "/";
URL retrieveUrl = new URL(domainUrlBase + "user/2.0/");
AppsForYourDomainQuery query = new AppsForYourDomainQuery(retrieveUrl);
query.setStartUsername(null);
allUsers = new UserFeed();
UserFeed currentPage;
Link nextLink;
do {
currentPage = userService.query(query, UserFeed.class);
allUsers.getEntries().addAll(currentPage.getEntries());
nextLink = currentPage.getLink(Link.Rel.NEXT, Link.Type.ATOM);
if (nextLink != null) {
retrieveUrl = new URL(nextLink.getHref());
}
} while (nextLink != null);
return allUsers;
}
}
@@ -0,0 +1,532 @@
/* 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.appsforyourdomain.labs.provisioning;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.gdata.client.appsforyourdomain.AppsPropertyService;
import com.google.gdata.data.Link;
import com.google.gdata.data.appsforyourdomain.AppsForYourDomainException;
import com.google.gdata.data.appsforyourdomain.generic.GenericEntry;
import com.google.gdata.data.appsforyourdomain.generic.GenericFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
/**
* This is a sample client with helper methods that demonstrates the usage of
* Organization Management APIs. These APIs help you create organization units
* and manage your units/users.
*
* An OrgUnit path is the URL-encoding (e.g., using URLEncoder.encode) of an
* OrgUnit's lineage, concatenated together with the slash ('/') character.
* E.g.,
*
* path = URLEncode.encode(parentName, "UTF-8") + "/" +
* URLEncode.encode(childName, "UTF-8");
*
*
*
*/
public class OrgManagementSampleClient {
public enum OrgUnitProperty {
NAME, DESCRIPTION, PARENT_ORG_UNIT_PATH, BLOCK_INHERTANCE, USERS_TO_MOVE
}
private AppsPropertyService service;
private String domain = null;
public static Logger LOGGER = Logger.getLogger(OrgManagementSampleClient.class.getName());
/**
* Parameterized constructor for authentication.
*
* @param adminEmail Domain administrator's email address
* @param password admin account password
* @param domain the primary domain name
* @param appName application identifier
* @throws AuthenticationException If an authentication error occurs.
*/
public OrgManagementSampleClient(String adminEmail, String password, String domain,
String appName)
throws AuthenticationException {
this(domain, appName);
service.setUserCredentials(adminEmail, password);
}
/**
* Parameterized constructor for authentication.
*
* @param domain the primary domain name
* @param appName application identifier
* @throws AuthenticationException If an authentication error occurs.
*/
public OrgManagementSampleClient(String domain, String appName) throws AuthenticationException {
service = new AppsPropertyService(appName);
this.domain = domain;
}
/**
* A utility method to create an OrgPath from a list of OrgUnits with parent
* as first list item, first child as second item and so on.
*
* @param orgUnits
* @return a OrgUnitPath from a given list of OrgUnit names.
* @throws UnsupportedEncodingException
*/
public String createOrgPathFromOrgUnits(List<String> orgUnits)
throws UnsupportedEncodingException {
StringBuilder path = new StringBuilder();
for (String orgUnit : orgUnits) {
if (path.length() != 0) {
path.append('/');
}
path.append(URLEncoder.encode(orgUnit, "UTF-8"));
}
return path.toString();
}
/**
* Retrieves the customer Id that will be used for all other operations.
*
* @param domain
* @return a GenericEntry
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public GenericEntry retrieveCustomerId(String domain) throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
GenericEntry entry =
service.getEntry(new URL("https://apps-apis.google.com/a/feeds/customer/2.0/customerId"),
GenericEntry.class);
return entry;
}
/**
* Create a new organization unit under the given parent.
*
* @param customerId the unique Id of the customer retrieved through customer
* feed.
* @param orgUnitName the new organization name.
* @param parentOrgUnitPath the path of the parent organization unit where '/'
* denotes the root of the organization hierarchy. For any OrgUnits to
* be created directly under root, specify '/' as parent path.
* @param description a description for the organization unit created.
* @param blockInheritance if true, blocks inheritance of policies from parent
* units.
* @return a GenericEntry instance of the newly created org unit.
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public GenericEntry createOrganizationUnit(String customerId, String orgUnitName,
String parentOrgUnitPath, String description, boolean blockInheritance)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
GenericEntry entry = new GenericEntry();
entry.addProperty("parentOrgUnitPath", parentOrgUnitPath);
entry.addProperty("description", description);
entry.addProperty("name", orgUnitName);
entry.addProperty("blockInheritance", String.valueOf(blockInheritance));
entry =
service.insert(new URL("https://apps-apis.google.com/a/feeds/orgunit/2.0/" + customerId),
entry);
return entry;
}
/**
* Retrieves an organization unit from the customer's domain.
*
* @param customerId
* @param orgUnitPath the path of the unit to be retrieved for e.g /corp
* @return a GenericEntry instance.
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public GenericEntry retrieveOrganizationUnit(String customerId, String orgUnitPath)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
GenericEntry entry =
service.getEntry(new URL("https://apps-apis.google.com/a/feeds/orgunit/2.0/" + customerId
+ "/" + orgUnitPath), GenericEntry.class);
return entry;
}
/**
* Retrieves all organization units for the given customer account.
*
* @param customerId
* @return a List of organization unit entries
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public List<GenericEntry> retrieveAllOrganizationUnits(String customerId)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
return retrieveAllPages(new URL("https://apps-apis.google.com/a/feeds/orgunit/2.0/"
+ customerId + "?get=all"));
}
/**
* Utility method that follows the next link and retrieves all pages of a
* feed.
*
* @param feedUrl Url of the feed.
* @return a List of GenericEntries in the feed queried.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
private List<GenericEntry> retrieveAllPages(URL feedUrl) throws IOException, ServiceException {
List<GenericEntry> allEntries = new ArrayList<GenericEntry>();
try {
do {
GenericFeed feed = service.getFeed(feedUrl, GenericFeed.class);
allEntries.addAll(feed.getEntries());
feedUrl = (feed.getNextLink() == null) ? null : new URL(feed.getNextLink().getHref());
} while (feedUrl != null);
} catch (ServiceException se) {
AppsForYourDomainException ae = AppsForYourDomainException.narrow(se);
throw (ae != null) ? ae : se;
}
return allEntries;
}
/**
* Retrieves all the child units of the given organization unit.
*
* @param customerId
* @param orgUnitPath
* @return a List of GenericEntry instances.
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public List<GenericEntry> retrieveChildOrganizationUnits(String customerId, String orgUnitPath)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
return retrieveAllPages(new URL("https://apps-apis.google.com/a/feeds/orgunit/2.0/"
+ customerId + "?get=children&orgUnitPath=" + URLEncoder.encode(orgUnitPath, "UTF-8")));
}
/**
* Deletes the given organization unit. The unit must not have any OrgUsers or
* any child OrgUnits to be deleted.
*
* @param customerId
* @param orgUnitPath
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public void deleteOrganizationUnit(String customerId, String orgUnitPath)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
service.delete(new URL("https://apps-apis.google.com/a/feeds/orgunit/2.0/" + customerId + "/"
+ orgUnitPath));
}
/**
* Updates the given organization attributes. USERS_TO_MOVE is a comma
* separated list of email addresses that are to be moved across orgUnits
*
* @param customerId
* @param orgUnitPath
* @param attributes a map of <code>OrgUnitProperty</code> and value to be
* updated.
* @return the updated GenericEntry
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public GenericEntry updateOrganizationUnit(String customerId, String orgUnitPath,
Map<OrgUnitProperty, String> attributes) throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
GenericEntry entry = new GenericEntry();
for (Map.Entry<OrgUnitProperty, String> mapEntry : attributes.entrySet()) {
String value = mapEntry.getValue();
if (value == null || value.length() == 0) {
continue;
}
switch (mapEntry.getKey()) {
case NAME:
entry.addProperty("name", value);
break;
case PARENT_ORG_UNIT_PATH:
entry.addProperty("parentUnitPath", value);
break;
case DESCRIPTION:
entry.addProperty("description", value);
break;
case BLOCK_INHERTANCE:
entry.addProperty("blockInheritance", value);
break;
case USERS_TO_MOVE:
entry.addProperty("usersToMove", value);
break;
default:
break;
}
}
return service.update(new URL("https://apps-apis.google.com/a/feeds/orgunit/2.0/" + customerId
+ "/" + orgUnitPath), entry);
}
/**
* Updates the organization of the given user in a given organization.
*
* @param customerId
* @param orgUserEmail the email address of the user
* @param oldOrgUnitPath optional: the old organization unit path. If
* specified, validates the OrgUser's current path.
* @param newOrgUnitPath the new organization unit path.
* @return a GenericEntry with the updated organization user.
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public GenericEntry updateOrganizationUser(String customerId, String orgUserEmail,
String oldOrgUnitPath, String newOrgUnitPath) throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
GenericEntry entry = new GenericEntry();
if (oldOrgUnitPath != null && oldOrgUnitPath.length() != 0) {
entry.addProperty("oldOrgUnitPath", oldOrgUnitPath);
}
entry.addProperty("orgUnitPath", newOrgUnitPath);
return service.update(new URL("https://apps-apis.google.com/a/feeds/orguser/2.0/" + customerId
+ "/" + orgUserEmail), entry);
}
/**
* Retrieves the details of a given organization user.
*
* @param customerId
* @param orgUserEmail the email address of the organization user.
* @return a GenericEntry instance
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public GenericEntry retrieveOrganizaionUser(String customerId, String orgUserEmail)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
return service.getEntry(new URL("https://apps-apis.google.com/a/feeds/orguser/2.0/"
+ customerId + "/" + orgUserEmail), GenericEntry.class);
}
/**
* Retrieves the first page of OrgUnit entries. For subsequent pages, use
* <code>retrieveNextPage</code>.
*
* @param customerId
* @return a GenericFeed with a single page of entries.
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public GenericFeed retrieveFirstPageOfOrganizationUsers(String customerId)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
return service.getFeed(new URL("https://apps-apis.google.com/a/feeds/orguser/2.0/" + customerId
+ "?get=all"), GenericFeed.class);
}
/**
* Retrieves a single page of entries given an atom:link.
*
* @param next the next atom:link which can be obtained from a feed
* <code>GenericFeed.getNextLink()</code>
* @return a GenericFeed with a single page of entries.
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public GenericFeed retrieveNextPage(Link next) throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
return service.getFeed(new URL(next.getHref()), GenericFeed.class);
}
/**
* Retrieves all the users from all the organizations of the customer. If you
* have more than a few hundred of OrgUsers, you should use pagination methods
* - <code>retrieveFirstPageOfOrganizationUsers</code> and
* <code>retrieveNextPage</code>
*
* @param customerId
* @return a List of GenericEntry instances
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public List<GenericEntry> retrieveAllOrganizationUsers(String customerId)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
return retrieveAllPages(new URL("https://apps-apis.google.com/a/feeds/orguser/2.0/"
+ customerId + "?get=all"));
}
/**
* Retrieves the first page of OrgUser entries in a given OrgUnit. For
* subsequent pages, use
* <code>retrieveNextPage(GenericFeed.getNextLink())</code>.
*
* @param customerId
* @param orgUnitPath
* @return a GenericFeed with a single page of entries.
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public GenericFeed retrieveFirstPageOfOrganizationUsersByOrgUnit(String customerId,
String orgUnitPath) throws AppsForYourDomainException, MalformedURLException, IOException,
ServiceException {
return service.getFeed(new URL("https://apps-apis.google.com/a/feeds/orguser/2.0/" + customerId
+ "?get=children&orgUnitPath=" + URLEncoder.encode(orgUnitPath, "UTF-8")),
GenericFeed.class);
}
/**
* Retrieves all the users under a given organization unit. If you have more
* than a few hundred of OrgUsers, you should use pagination methods -
* <code>retrieveFirstPageOfOrganizationUsersByOrgUnit</code> and
* <code>retrieveNextPage</code>
*
* @param customerId
* @param orgUnitPath
* @return a List of organization users.
* @throws AppsForYourDomainException
* @throws MalformedURLException
* @throws IOException
* @throws ServiceException
*/
public List<GenericEntry> retrieveAllOrganizationUsersByOrgUnit(String customerId,
String orgUnitPath) throws AppsForYourDomainException, MalformedURLException, IOException,
ServiceException {
return retrieveAllPages(new URL("https://apps-apis.google.com/a/feeds/orguser/2.0/"
+ customerId + "?get=children&orgUnitPath=" + URLEncoder.encode(orgUnitPath, "UTF-8")));
}
/**
* @param args
* @throws AuthenticationException
*/
public static void main(String[] args) throws AuthenticationException {
try {
if (args.length != 4) {
System.out
.println("Usage: java OrgManagementSampleClient <admin@example.com> <adminpassword> "
+ "<domain> <testUserEmail>");
System.exit(1);
}
String adminEmail = args[0];
String adminPassword = args[1];
String domain = args[2];
String user = args[3];
String customerId = null;
OrgManagementSampleClient client =
new OrgManagementSampleClient(adminEmail, adminPassword, domain, "org-api-sample-"
+ domain);
GenericEntry entry = null;
GenericFeed feed = null;
entry = client.retrieveCustomerId(customerId);
customerId = entry.getProperty("customerId");
LOGGER.log(Level.INFO, "Retrieved Customer ID - " + customerId);
entry =
client.createOrganizationUnit(customerId, "system", "/", "System Organization", false);
LOGGER.log(Level.INFO, "Created new OrgUnit - " + entry.getAllProperties());
entry = client.retrieveOrganizationUnit(customerId, "system");
LOGGER.log(Level.INFO, "Retrieved OrgUnit - " + entry.getAllProperties());
List<GenericEntry> allUnits = client.retrieveAllOrganizationUnits(customerId);
LOGGER.log(Level.INFO, "Retrieved all OrgUnits - " + allUnits.size());
allUnits = client.retrieveChildOrganizationUnits(customerId, "/");
LOGGER.log(Level.INFO, "Retrieved all child units - " + allUnits.size());
LOGGER.log(Level.INFO, "Updating OrgUnit 'system'");
Map<OrgUnitProperty, String> attributes = new HashMap<OrgUnitProperty, String>();
attributes.put(OrgUnitProperty.DESCRIPTION, "testchanged");
entry = client.updateOrganizationUnit(customerId, "system", attributes);
LOGGER.log(Level.INFO, "Updated OrgUnit description - " + entry.getAllProperties());
client.retrieveOrganizaionUser(customerId, user);
LOGGER.log(Level.INFO, "Retrieved OrgUser - " + entry.getAllProperties());
entry = client.updateOrganizationUser(customerId, user, "/", "system");
LOGGER.log(Level.INFO, "Updated OrgUser - " + entry.getAllProperties());
// For pagination, use retrieveFirstPageOfOrganizationUsers() and
// retrieveNextPage(feed.getNextLink())
List<GenericEntry> allUsers = client.retrieveAllOrganizationUsers(customerId);
LOGGER.log(Level.INFO, "Retrieved User count: " + allUsers.size());
allUsers = client.retrieveAllOrganizationUsersByOrgUnit(customerId, "system");
LOGGER.log(Level.INFO, "Retrieved User count: " + allUsers.size());
LOGGER.log(Level.INFO, "OrgPath construction - "
+ client.createOrgPathFromOrgUnits(Arrays.asList("parent", "firstChild",
"childOfFirstChild")));
// cleanup
client.updateOrganizationUser(customerId, user, "system", "/");
// cleanup
client.deleteOrganizationUnit(customerId, "system");
} catch (AppsForYourDomainException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ServiceException e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,503 @@
/* 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.appsforyourdomain.labs.provisioning;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.gdata.client.appsforyourdomain.AppsPropertyService;
import com.google.gdata.data.Link;
import com.google.gdata.data.appsforyourdomain.AppsForYourDomainException;
import com.google.gdata.data.appsforyourdomain.generic.GenericEntry;
import com.google.gdata.data.appsforyourdomain.generic.GenericFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
/**
* Sample client that uses multi-domain feeds to create users, aliases in one of
* the user's domains.
*
*
*
*/
public class ProvisioningApiMultiDomainSampleClient {
private AppsPropertyService service;
private String domain = null;
public enum UserProperty {
USER_EMAIL, PASSWORD, FIRST_NAME, LAST_NAME, HASH_FUNCTION, ADMIN, SUSPENDED,
CHANGE_PASSWORD_AT_NEXT_LOGIN, QUOTA, IP_WHITELIST
}
public static Logger LOGGER =
Logger.getLogger(ProvisioningApiMultiDomainSampleClient.class.getName());
/**
* Parameterized constructor for authentication.
*
* @param adminEmail Domain administrator's email address
* @param password admin account password
* @param domain the primary domain name
* @param appName application identifier
* @throws AuthenticationException If an authentication error occurs.
*/
public ProvisioningApiMultiDomainSampleClient(String adminEmail, String password, String domain,
String appName) throws AuthenticationException {
this(domain, appName);
service.setUserCredentials(adminEmail, password);
}
/**
* Constructor for credential-less services - OAuth.
*/
public ProvisioningApiMultiDomainSampleClient(String domain, String appName) {
service = new AppsPropertyService(appName);
this.domain = domain;
}
/**
* Creates an alias email for the user identified by the given email address.
*
* @param aliasEmail The alias email to create for the given user.
* @param userEmail User's primary email address.
* @return the newly created alias GenericEntry instance.
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericEntry createAlias(String aliasEmail, String userEmail)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
GenericEntry entry = new GenericEntry();
entry.addProperty("userEmail", userEmail);
entry.addProperty("aliasEmail", aliasEmail);
return service.insert(new URL("https://apps-apis.google.com/a/feeds/alias/2.0/" + domain),
entry);
}
/**
* Retrieves the alias entry for the given email alias.
*
* @param aliasEmail the user email alias.
* @return GenericEntry
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericEntry retrieveAlias(String aliasEmail) throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
return service.getEntry(new URL("https://apps-apis.google.com/a/feeds/alias/2.0/" + domain
+ "/" + aliasEmail), GenericEntry.class);
}
/**
* Utility method that follows the next link and retrieves all pages of a
* feed.
*
* @param feedUrl Url of the feed.
* @return a List of GenericEntries in the feed queried.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
private List<GenericEntry> retrieveAllPages(URL feedUrl) throws IOException, ServiceException {
List<GenericEntry> allEntries = new ArrayList<GenericEntry>();
try {
do {
GenericFeed feed = service.getFeed(feedUrl, GenericFeed.class);
allEntries.addAll(feed.getEntries());
feedUrl = (feed.getNextLink() == null) ? null : new URL(feed.getNextLink().getHref());
} while (feedUrl != null);
} catch (ServiceException se) {
AppsForYourDomainException ae = AppsForYourDomainException.narrow(se);
throw (ae != null) ? ae : se;
}
return allEntries;
}
/**
* Retrieves all email aliases created in the customer domain. If you have more than
* a few hundred aliases, you must use <code>retrieveFirstPageOfAliases</code> and
* <code>retrieveNextPage</code>.
*
* @return a List of GenericEntry objects.
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public List<GenericEntry> retrieveAllAliases() throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
return retrieveAllPages(new URL("https://apps-apis.google.com/a/feeds/alias/2.0/" + domain));
}
/**
* Retrieves first page of email aliases created in the customer domain. To
* retrieve subsequent pages, use <code>retrieveNextPage</code> with
* <code>GenericFeed.getNextLink()</code>
*
* @return a List of GenericEntry objects.
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericFeed retrieveFirstPageOfAliases() throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
return service.getFeed(new URL("https://apps-apis.google.com/a/feeds/alias/2.0/" + domain),
GenericFeed.class);
}
/**
* Retrieves all aliases created for the user identified by the given email
* address.
*
* @param userEmail
* @return a List of GenericEntry objects
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public List<GenericEntry> retrieveAllUserAliases(String userEmail)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
return retrieveAllPages(new URL("https://apps-apis.google.com/a/feeds/alias/2.0/" + domain
+ "/" + userEmail));
}
/**
* Deletes the given alias.
*
* @param aliasEmail
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public void deleteAlias(String aliasEmail) throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
service.delete(new URL("https://apps-apis.google.com/a/feeds/alias/2.0/" + domain + "/"
+ aliasEmail));
}
/**
* Creates a new user with the given email address in the customer domain.
*
* @param email User email of the new account.
* @param password
* @param firstName
* @param lastName
* @return a GenericEntry instance of the newly created user.
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericEntry createUser(String email, String password, String firstName, String lastName)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
GenericEntry entry = new GenericEntry();
entry.addProperty("userEmail", email);
entry.addProperty("password", password);
entry.addProperty("firstName", firstName);
entry.addProperty("lastName", lastName);
return service
.insert(new URL("https://apps-apis.google.com/a/feeds/user/2.0/" + domain), entry);
}
/**
* Creates a user with one or more optional attributes set.
*
* @param email
* @param password
* @param firstName
* @param lastName
* @param optionalAttributes a hashmap of user property
* <code>UserProperty</code> and values.
* @return a GenericEntry instance of the newly created user.
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericEntry createUser(String email, String password, String firstName, String lastName,
Map<UserProperty, String> optionalAttributes) throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
GenericEntry entry = new GenericEntry();
entry.addProperty("userEmail", email);
entry.addProperty("password", password);
entry.addProperty("firstName", firstName);
entry.addProperty("lastName", lastName);
for (Map.Entry<UserProperty, String> mapEntry : optionalAttributes.entrySet()) {
String value = mapEntry.getValue();
if (value == null || value.length() == 0) {
continue;
}
switch (mapEntry.getKey()) {
case HASH_FUNCTION:
entry.addProperty("name", value);
break;
case ADMIN:
entry.addProperty("isAdmin", value);
break;
case SUSPENDED:
entry.addProperty("isSuspended", value);
break;
case CHANGE_PASSWORD_AT_NEXT_LOGIN:
entry.addProperty("isChangePasswordAtNextLogin", value);
break;
case QUOTA:
entry.addProperty("quotaInGb", value);
break;
case IP_WHITELIST:
entry.addProperty("ipWhitelisted", value);
break;
default:
break;
}
}
return service
.insert(new URL("https://apps-apis.google.com/a/feeds/user/2.0/" + domain), entry);
}
/**
*
* @param email
* @return a GenricEntry instance
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericEntry retrieveUser(String email) throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
return service.getEntry(new URL("https://apps-apis.google.com/a/feeds/user/2.0/" + domain + "/"
+ email), GenericEntry.class);
}
/**
* Retrieves a feed of all users in the customer domain. If you have more than
* a few hundred users, you must use <code>retrieveFirstPageOfUsers</code> and
* <code>retrieveNextPage</code>.
*
* @return a list of GenericEntry objects
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public List<GenericEntry> retrieveAllUsers() throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
return retrieveAllPages(new URL("https://apps-apis.google.com/a/feeds/user/2.0/" + domain));
}
/**
* Retrieves the first page of users. To retrieve subsequent pages, use
* <code>retrieveNextPage</code> with <code>GenericFeed.getNextLink()</code>
*
* @return a page of user entries.
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericFeed retrieveFirstPageOfUsers() throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
return service.getFeed(new URL("https://apps-apis.google.com/a/feeds/user/2.0/" + domain),
GenericFeed.class);
}
/**
* Retrieves a single page of entries given an atom:link.
*
* @param next the next atom:link which can be obtained from a feed
* <code>GenericFeed.getNextLink()</code>
* @return a GenericFeed with a single page of entries.
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericFeed retrieveNextPage(Link next) throws AppsForYourDomainException,
MalformedURLException, IOException, ServiceException {
return service.getFeed(new URL(next.getHref()), GenericFeed.class);
}
/**
* Updates the given user attributes.
*
* @param email
* @param updatedAttributes a key-Value map of attributes to be updated
* @return updated GenericEntry
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericEntry updateUser(String email, Map<String, String> updatedAttributes)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
GenericEntry entry = new GenericEntry();
entry.addProperties(updatedAttributes);
return service.update(new URL("https://apps-apis.google.com/a/feeds/user/2.0/" + domain + "/"
+ email), entry);
}
/**
* deletes the given user account from the customer domain.
*
* @param email
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public void deleteUser(String email) throws AppsForYourDomainException, MalformedURLException,
IOException, ServiceException {
service
.delete(new URL("https://apps-apis.google.com/a/feeds/user/2.0/" + domain + "/" + email));
}
/**
* changes the primary email address of the user to the given email address
*
* @param oldEmailAddress
* @param newEmailAddress
* @return the updated GenericEntry
* @throws AppsForYourDomainException If a Provisioning API specific error
* occurs.
* @throws ServiceException If a generic GData framework error occurs.
* @throws IOException If an error occurs communicating with the GData
* service.
*/
public GenericEntry updateEmailAddress(String oldEmailAddress, String newEmailAddress)
throws AppsForYourDomainException, MalformedURLException, IOException, ServiceException {
GenericEntry entry = new GenericEntry();
entry.addProperty("userEmail", oldEmailAddress);
entry.addProperty("newEmail", newEmailAddress);
return service.update(new URL("https://apps-apis.google.com/a/feeds/user/userEmail/2.0/"
+ domain + "/" + oldEmailAddress), entry);
}
/**
* The main driver for the sample.
*
* @param args java ProvisioningApiMultiDomainSampleClient [admin@example.com]
* [adminpassword] [primarydomain] [secondarydomain]
*/
public static void main(String[] args) {
if (args.length != 4) {
System.out
.println("Usage: java ProvisioningApiMultiDomainSampleClient <admin@example.com> "
+ "<adminpassword> <primarydomain> <secondarydomain>");
System.exit(1);
}
String adminEmail = args[0];
String adminPassword = args[1];
String primaryDomain = args[2];
String secondaryDomain = args[3];
try {
ProvisioningApiMultiDomainSampleClient client =
new ProvisioningApiMultiDomainSampleClient(adminEmail, adminPassword, primaryDomain,
"multidomain-api-sample-" + primaryDomain);
long time = System.currentTimeMillis();
String userEmail = "test-" + time + "@" + secondaryDomain;
GenericEntry entry = client.createUser(userEmail, "p@ssw0rd", "firstName", "lastName");
LOGGER.log(Level.INFO, "Created user - " + entry.getProperty("userEmail"));
entry = client.retrieveUser(userEmail);
LOGGER.log(Level.INFO, "Retrieved user - " + entry.getProperty("userEmail"));
// create user with optional attributes
Map<UserProperty, String> optionalAttributes = new HashMap<UserProperty, String>();
optionalAttributes.put(UserProperty.ADMIN, String.valueOf(true));
optionalAttributes.put(UserProperty.SUSPENDED, String.valueOf(false));
optionalAttributes.put(UserProperty.HASH_FUNCTION, "MD5");
entry =
client.createUser("test2-" + time + "@" + secondaryDomain,
"0f359740bd1cda994f8b55330c86d845", "firstName", "lastName", optionalAttributes);
LOGGER.log(Level.INFO, "Created user with optional attributes- "
+ entry.getProperty("userEmail"));
Map<String, String> updatedAttributes = new HashMap<String, String>();
updatedAttributes.put("lastName", "Smith");
updatedAttributes.put("isSuspended", "true");
entry = client.updateUser(userEmail, updatedAttributes);
LOGGER.log(Level.INFO, "Updated user - " + entry.getProperty("lastName"));
List<GenericEntry> users = client.retrieveAllUsers();
LOGGER.log(Level.INFO, "Retrieved all users - " + users.size());
// Alias operations
String aliasEmail = "alias-" + time + "@" + secondaryDomain;
entry = client.createAlias(aliasEmail, userEmail);
LOGGER.log(Level.INFO, "Created alias - " + entry.getProperty("aliasEmail"));
entry = client.retrieveAlias(aliasEmail);
LOGGER.log(Level.INFO, "Retrieved alias - " + entry.getProperty("aliasEmail"));
List<GenericEntry> aliases = client.retrieveAllAliases();
LOGGER.log(Level.INFO, "Retrieved all aliases - " + users.size());
// cleanup
client.deleteAlias(aliasEmail);
LOGGER.log(Level.INFO, "Deleted - " + aliasEmail);
client.deleteUser(userEmail);
LOGGER.log(Level.INFO, "Deleted - " + userEmail);
client.deleteUser("test2-" + time + "@" + secondaryDomain);
} catch (AuthenticationException e) {
e.printStackTrace();
} catch (AppsForYourDomainException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ServiceException e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,310 @@
/* 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.appsforyourdomain.migration;
import com.google.gdata.client.appsforyourdomain.migration.MailItemService;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.data.appsforyourdomain.migration.Label;
import com.google.gdata.data.appsforyourdomain.migration.MailItemEntry;
import com.google.gdata.data.appsforyourdomain.migration.MailItemFeed;
import com.google.gdata.data.appsforyourdomain.migration.MailItemProperty;
import com.google.gdata.data.appsforyourdomain.migration.Rfc822Msg;
import com.google.gdata.data.batch.BatchStatus;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.util.ServiceException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This is the client library for the Google Apps Email Migration API. It
* shows how the MailItemService can be used to migrate mail into GMail.
*/
public class AppsForYourDomainMigrationClient {
private static final Logger LOGGER =
Logger.getLogger(AppsForYourDomainMigrationClient.class.getName());
// Number of email messages to insert.
private static final int ITEMS_TO_BATCH = 5;
// The mail message to migrate.
private static String rfcTxt =
"Received: by 10.143.160.15 with HTTP; Mon, 16 Jul 2007 10:12:26 -0700 (P"
+ "DT)\r\n"
+ "Message-ID: <c8acb6980707161012i5d395392p5a6d8d14a8582613@mail."
+ "gmail.com>\r\n"
+ "Date: Mon, 16 Jul 2007 10:12:26 -0700\r\n"
+ "From: \"Mr. Serious\" <serious@domain.com>\r\n"
+ "To: \"Mr. Admin\" <admin@domain.com>\r\n"
+ "Subject: Subject \r\n"
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/plain; charset=ISO-8859-1; format=flowed\r\n"
+ "Content-Transfer-Encoding: 7bit\r\n"
+ "Content-Disposition: inline\r\n"
+ "Delivered-To: admin@domain.com\r\n"
+ "\r\n"
+ "This is a message delivered via the Email Migration API\r\n"
+ "\r\n";
private static final String MIGRATED_LABEL = "Migrated Email";
private final String domain;
private final String destinationUser;
private final MailItemService mailItemService;
/**
* Constructs an AppsForYourDomainMigrationClient for the given domain using
* the given admin credentials.
*
* @param username The username (not email) of a domain user or administrator
* @param password The user's password on the domain
* @param domain The domain in which mail is being migrated
* @param destinationUser the destination user to whom mail should be migrated
*/
public AppsForYourDomainMigrationClient(String username, String password,
String domain, String destinationUser) throws Exception {
this.domain = domain;
if (destinationUser == null) {
this.destinationUser = username;
} else {
this.destinationUser = destinationUser;
}
// Set up the mail item service.
mailItemService = new MailItemService("exampleCo-exampleApp-1");
mailItemService.setUserCredentials(username + "@" + domain, password);
// Run the sample.
runSample();
}
/**
* Main driver for the sample; migrates a batch feed of email messages
* and prints the results.
*/
private void runSample() {
// Create labels for mail items to be inserted.
List<String> labels = new ArrayList<String>();
labels.add(MIGRATED_LABEL);
// Set properties for mail items to be inserted. We want all these
// mail items to be unread and sent to the inbox (in addition to being
// labeled).
List<MailItemProperty> properties = new ArrayList<MailItemProperty>();
properties.add(MailItemProperty.UNREAD);
properties.add(MailItemProperty.INBOX);
MailItemEntry[] entries = new MailItemEntry[ITEMS_TO_BATCH];
for (int i = 0; i < entries.length; i++) {
entries[i] = setupMailItem(rfcTxt, properties, labels);
}
// Send several emails in a batch.
LOGGER.log(Level.INFO, "Inserting " + Integer.toString(ITEMS_TO_BATCH)
+ " mail items in a batch.");
try {
MailItemFeed feed = batchInsertMailItems(entries);
// Check for failure in the returned entries.
int failedInsertions = 0, successfulInsertions = 0;
for (MailItemEntry returnedEntry : feed.getEntries()) {
if (BatchUtils.isFailure(returnedEntry)) {
BatchStatus status = BatchUtils.getBatchStatus(returnedEntry);
LOGGER.log(Level.SEVERE, "Entry "
+ BatchUtils.getBatchId(returnedEntry) + " failed insertion: "
+ status.getCode() + " " + status.getReason());
failedInsertions++;
} else {
successfulInsertions++;
}
}
LOGGER.log(Level.INFO, "Batch insertion: "
+ Integer.toString(successfulInsertions) + " succeeded, "
+ Integer.toString(failedInsertions) + " failed.");
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Caught IOException: " + e.toString());
e.printStackTrace();
} catch (ServiceException e) {
LOGGER.log(Level.SEVERE, "Caught ServiceException: " + e.toString());
e.printStackTrace();
}
}
/**
* Inserts one or more MailItem entries in a single batch operation. Using
* batch insertion is helpful in reducing HTTP overhead.
*
* @param mailItems one or more {@link MailItemEntry} objects
* @return a feed with the result of each operation in a separate
* {@link MailItemEntry} object.
* @throws IOException if an error occurs while communicating with the GData
* service.
* @throws ServiceException if the insert request failed due to system error.
*/
private MailItemFeed batchInsertMailItems(MailItemEntry ... mailItems)
throws ServiceException, IOException {
LOGGER.log(Level.INFO, "Batch inserting " + Integer.toString(
mailItems.length) + " mailItems");
MailItemFeed feed = new MailItemFeed();
for (int i = 0; i < mailItems.length; i++) {
BatchUtils.setBatchId(mailItems[i], Integer.toString(i));
feed.getEntries().add(mailItems[i]);
}
return mailItemService.batch(domain, destinationUser, feed);
}
/**
* Helper method to read a file and return its contents as a text string,
* with lines separated by "\r\n" (CR+LF) style newlines.
* @param location the path to the file
* @return the String contents of the file
* @throws IOException if an error occurs reading the file
*/
private static String readFile(String location) throws IOException {
FileInputStream is = new FileInputStream(new File(location));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuffer fileContents = new StringBuffer();
String newLine = br.readLine();
while (newLine != null) {
fileContents.append(newLine);
fileContents.append("\r\n");
newLine = br.readLine();
}
br.close();
return fileContents.toString();
}
/**
* Helper method to set up a new MailItemEntry with the given values.
*
* @param rfcText the RFC822 text of the message
* @param properties a list of properties to be applied to the message
* @param labels a list of labels the message should have when inserted into
* Gmail
* @return the {@code MailItemEntry} set up with the message, labels and
* properties
*/
private MailItemEntry setupMailItem(String rfcText,
List<MailItemProperty> properties, List<String> labels) {
// Unique subject and message id are required so that GMail does not
// suppress duplicate messages
String randomFactor = Integer.toString(100000 +
(new Random()).nextInt(900000));
rfcText = rfcText.replace("Subject: Subject",
"Subject: Unique Subject " + randomFactor);
rfcText = rfcText.replace("Message-ID: <", "Message-ID: <" + randomFactor);
Rfc822Msg rfcMsg = new Rfc822Msg(rfcText);
// create MailItemEntry with appropriate data
MailItemEntry mailItem = new MailItemEntry();
mailItem.setRfc822Msg(rfcMsg);
for (String label : labels) {
mailItem.addLabel(new Label(label));
}
for (MailItemProperty property : properties) {
mailItem.addMailProperty(property);
}
return mailItem;
}
/**
* Prints the command line usage of this sample application.
*/
private static void usage() {
System.out.println("Usage: java AppsForYourDomainMigrationClient"
+ " --username <username> --password <password> --domain <domain>\n"
+ " [--destination_user <destination_user>] [--data_file <file>]");
System.out.println();
System.out.println("A simple application that demonstrates how to migrate"
+ " email mesages to a Google Apps email account. Authenticates using"
+ " the provided login credentials, then migrates a sample message to"
+ " your own account (if you are a user) or to the specified"
+ " destination account (if you are a domain administrator).");
System.out.println();
System.out.println("If --data_file is specified, an RFC822 message will be"
+ " read from the given file; otherwise, a sample message will be"
+ "used.");
System.out.println();
System.out.println("Specify username and destination_user as just the name,"
+ " not email address. For example, to migrate mail to joe@example.com"
+ " use these options: --username joe --password your_password"
+ " --domain example.com");
}
/**
* Main entry point. Parses arguments and creates and invokes the
* AppsForYourDomainMigrationClient.
*
* Usage: java AppsForYourDomainMigrationClient --username &lt;user&gt;
* --password &lt;pass&gt; --domain &lt;domain&gt;
* [--destination_user &lt;destination_user&gt;] [--data_file &lt;file&gt;]
*/
public static void main(String[] arg) throws Exception {
SimpleCommandLineParser parser = new SimpleCommandLineParser(arg);
// Parse command-line flags
String username = parser.getValue("username");
String password = parser.getValue("password");
String domain = parser.getValue("domain");
String destinationUser = parser.getValue("destination_user");
String emailFileName = parser.getValue("data_file");
boolean help = parser.containsKey("help");
if (help || (username == null) || (password == null)
|| (domain == null)) {
usage();
System.exit(1);
}
// If the user supplied a filename, read the email data from it.
if (emailFileName != null) {
// Read email text
LOGGER.log(Level.INFO, "Reading email data from file");
rfcTxt = readFile(emailFileName);
LOGGER.log(Level.INFO, "Finished reading email data");
}
new AppsForYourDomainMigrationClient(username, password, domain,
destinationUser);
}
}
@@ -0,0 +1,35 @@
AppsForYourDomainMigrationClient: A simple application that
demonstrates how to migrate email messages to a Google Apps
email account.
To migrate mail as a Google Apps user, invoke as follows:
java AppsForYourDomainMigrationClient --username <user>
--password <password> --domain <domain>
For example:
java AppsForYourDomainMigrationClient --username jdoe
--password mypass --domain example.com
To migrate mail as a Google Apps administrator, also specify
the destination mailbox (username) for the mail upload:
java AppsForYourDomainMigrationClient --username <user>
--password <password> --domain <domain>
--destination_user <username>
For example:
java AppsForYourDomainMigrationClient --username admin
--password mypass --domain example.com --destination_user jdoe
By default, the sample application will migrate a simple,
example email message. You can also specify a message on disk,
assuming it is already in the RFC822 standard format, by passing
the --data_file argument:
java AppsForYourDomainMigrationClient --username jdoe
--password mypass --domain example.com
--data_file /home/jdoe/my_rfc822_message.txt
+96
View File
@@ -0,0 +1,96 @@
AuthSub Java Sample - README.txt
--------------------------------
The AuthSub sample is a simple Tomcat web-application that demonstrates usage
of the Google Authentication Proxy Interface, AuthSub, to access a user's
private Calendar feed. AuthSub enables a web-application to access a user's
data without ever handling the user's account login information. The provided
sample will retrieve an AuthSub token for the current user, authenticate to
Calendar using the AuthSub token, and retrieve the private calendar feed.
Overview of the sample
----------------------
The sample consists of two main parts. The Java files in src/ handle the
retrieval, (basic) storage, and usage of the AuthSub token for authentication.
The javascript files in the web/ directory handle the parsing and rendering of
the retrieved Calendar data.
The Java files mainly use the com.google.gdata.client.http.AuthSubUtil utility
class to interface with AuthSub. LoginServlet.java forms the URL to redirect
to the Google Accounts page to request an AuthSub token.
HandleTokenServlet.java handles the retrieval of the AuthSub token when Google
Accounts redirects back to the web application. RetrieveFeedServlet.java is a
simple proxy to retrieve the requested feed using the AuthSub token for
authentication. (The proxy is a solution for the same origin policy of
Javascript).
Deploying the sample web application
------------------------------------
The sample web application can be easily deployed on a running instance of
Tomcat. The dist/authsub_sample.war web archive file can just be dropped into
the webapps/ directory of your Tomcat installation. Tomcat should
automatically deploy the web application. The application should be accessible
at the '/authsub_sample' path of your Tomcat server
(eg. 'http://localhost:8080/authsub_sample').
Note: If the application needs to be rebuilt, the servlet.jar property defined
in the build-samples/build.properties file should be updated to point to the
jar file with the servlet definitions.
Securing against URL command attacks
------------------------------------
Due to the same origin policy of Javascript, a basic proxy is required to
retrieve the private Calendar feed. (The proxy's functionality is implemented
in src/RetrieveFeedServlet.java.) The requested URL is specified as a query
parameter. The proxy will use the AuthSub token of the respective user to
retrieve the feed at the provided URL. The proxy also takes a token as another
query parameter to ensure that the request is from an authorized host.
A URL command attack is a cross site scripting vulnerability. It is applicable
when cookies are used for authentication and user commands are done through
HTTP requests (GET or POST). This attack is illustrated through the following
example. Assume goodsite.com and evilsite.com. Assume goodsite.com offers a URL
of the following form http://goodsite.com/addtophonebook?email=hello@gmail.com
that adds hello@gmail.com to the current logged in user's phonebook.
An attack may look like this:
1. User logs into goodsite.com and gets an login cookie
2. User goes to evilsite.com
3. On evilsite.com there is an HTML element with a URL source to some
command for goodsite.com (perhaps through an invisible image) that accesses
http://goodsite.com/addtophonebook?email=viagra@spam.com
4. The browser will fetch the URL and the login cookie will go along with
it
5. The user's account is now modified by an evil site
Thus to protect the GData URL proxy, we require requests to the GData proxy
servlet to contain a secure token that is a hash of the user's login cookie
issued by the web service and the URL to be accessed. Since evilsite.com does
not have access to the login cookie, it will not be able to generate a valid
secure token for this user.
The token used to secure the URL has the following format:
token = HMAC<sub>SHA1(login-cookie)</sub>({data})
where {data} is a string formed in the following manner:
data = http-url SP http-method SP timestamp
SP is a single ASCII space character.
http-url is the GData feed URl being requested.
timestamp is an integer representing the time
the request was sent, in seconds since Jan 1, 1970 UTC,
formatted as an ASCII string (in decimal).
The token used in the URL will be Base64 encoded. The above functionality is
implemented in src/SecureUrl.java. The token is checked in
src/RetrieveFeedServlet.java and generated through JSP in web/main.jsp.
Limitations
-----------
The sample shows the basic structure of how a server that uses AuthSub should
be setup. The current sample may not work well with secure AuthSub with
signatures if the Calendar server sends redirects with the gsessionid in the
URL. In this case, the client should handle the 302, recalculate the signature
for the new URL, and then issue the request.
Binary file not shown.
@@ -0,0 +1,119 @@
/* 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.authsub.src;
import com.google.gdata.client.http.AuthSubUtil;
import com.google.gdata.util.AuthenticationException;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Handles the processing of an AuthSub token.
* <p>
* The user will login to the Google account and lend permission for
* this service to impersonate the user. Upon completion of the login
* and permission-grant, the user will be redirected to this servlet
* with the token in the URL.
*
*
*/
public class HandleTokenServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Retrieve the AuthSub token assigned by Google
String token = AuthSubUtil.getTokenFromReply(req.getQueryString());
if (token == null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"No token specified.");
return;
}
// Exchange the token for a session token
String sessionToken;
try {
sessionToken =
AuthSubUtil.exchangeForSessionToken(token,
Utility.getPrivateKey());
} catch (IOException e1) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Exception retrieving session token.");
return;
} catch (GeneralSecurityException e1) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Security error while retrieving session token.");
return;
} catch (AuthenticationException e) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Server rejected one time use token.");
return;
}
try {
// Sanity checking usability of token
Map<String, String> info =
AuthSubUtil.getTokenInfo(sessionToken, Utility.getPrivateKey());
for (Iterator<String> iter = info.keySet().iterator(); iter.hasNext();) {
String key = iter.next();
System.out.println("\t(key, value): (" + key + ", " + info.get(key)
+ ")");
}
} catch (IOException e1) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Exception retrieving info for session token.");
return;
} catch (GeneralSecurityException e1) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Security error while retrieving session token info.");
return;
} catch (AuthenticationException e) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Auth error retrieving info for session token: " +
e.getMessage());
return;
}
// Retrieve the authentication cookie to identify user
String principal =
Utility.getCookieValueWithName(req.getCookies(), Utility.LOGIN_COOKIE_NAME);
if (principal == null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Unidentified principal.");
return;
}
// Store the token
TokenManager.storeToken(principal, sessionToken);
// Redirect to main.jsp where the token will be used
StringBuffer continueUrl = req.getRequestURL();
int index = continueUrl.lastIndexOf("/");
continueUrl.delete(index, continueUrl.length());
continueUrl.append(LoginServlet.NEXT_URL);
resp.sendRedirect(continueUrl.toString());
}
}
@@ -0,0 +1,134 @@
/* 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.authsub.src;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.client.http.AuthSubUtil;
import com.google.gdata.util.common.util.Base64;
import java.io.IOException;
import java.security.SecureRandom;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Logging into this application is trivial and just consists of visiting
* this servlet. This servlet will set an authentication cookie for the
* user and redirect to the page to authorize to Google. Typically, the
* user will be authenticated to the server via the login cookie prior to
* accessing this servlet.
*
*
*/
public class LoginServlet extends HttpServlet {
// On successfully acquiring a token, the servlet will redirect the user to
// the following next URL
/*package*/ static final String NEXT_URL = "/main.jsp";
private static final SecureRandom srng = new SecureRandom();
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// State to indicate if the user parameters have changed.
boolean stateChanged = false;
// Retrieve user specified hosted domain.
boolean useDefaultDomain =
Boolean.parseBoolean(req.getParameter("defaultdomain"));
boolean useSsl =
Boolean.parseBoolean(req.getParameter("secure"));
String userDomain = req.getParameter("domain");
// Save any persistent data to user session
String calendarFeedRootUrl = CalendarService.CALENDAR_ROOT_URL;
if (useSsl && !calendarFeedRootUrl.startsWith("https")) {
calendarFeedRootUrl = calendarFeedRootUrl.replaceFirst("http", "https");
}
HttpSession userSession = req.getSession(true);
String currentRootUrl =
(String) userSession.getAttribute("feedRootUrl");
String currentDomain =
(String) userSession.getAttribute("userDomain");
if ((currentRootUrl != null && !currentRootUrl.equals(calendarFeedRootUrl))
|| (currentDomain != null && !currentDomain.equals(userDomain))) {
stateChanged = true;
}
userSession.putValue("feedRootUrl", calendarFeedRootUrl);
userSession.putValue("userDomain", userDomain);
String authSubToken = null;
String principal =
Utility.getCookieValueWithName(req.getCookies(), Utility.LOGIN_COOKIE_NAME);
if (!stateChanged && (principal != null)) {
authSubToken = TokenManager.retrieveToken(principal);
}
// Form continue URL
StringBuffer continueUrl = req.getRequestURL();
int index = continueUrl.lastIndexOf("/");
continueUrl.delete(index, continueUrl.length());
// If the user doesn't have an AuthSub token yet, redirect the user to
// the Google page to request an AuthSub token. Otherwise redirect to
// the main page
if (authSubToken == null) {
continueUrl.append("/HandleTokenServlet");
// Check whether to use https for authentication
boolean secure = (Utility.getPrivateKey() != null);
String authSubLogin;
if (useDefaultDomain) {
authSubLogin = AuthSubUtil.getRequestUrl(continueUrl.toString(),
calendarFeedRootUrl,
secure,
true /*session*/);
} else {
authSubLogin = AuthSubUtil.getRequestUrl(req.getParameter("domain"),
continueUrl.toString(),
calendarFeedRootUrl,
secure,
true /*session*/);
}
// Set "authentication" cookie. Typically, a user would have an
// login-cookie for the web service which should be associated to the
// AuthSub token retrieved from Google. For this example, a random
// authentication cookie is assigned.
byte[] randomBytes = new byte[12];
srng.nextBytes(randomBytes);
String cookieValue = Base64.encodeWebSafe(randomBytes, false);
resp.addCookie(new Cookie(Utility.LOGIN_COOKIE_NAME, cookieValue));
resp.sendRedirect(authSubLogin);
} else {
continueUrl.append(NEXT_URL);
resp.sendRedirect(continueUrl.toString());
}
}
}
@@ -0,0 +1,251 @@
/* 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.authsub.src;
import com.google.gdata.client.http.AuthSubUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.GeneralSecurityException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Acts as a proxy and retrieves the requested feed.
* <p>
* The identity of the user is determined using the provided authentication
* cookie. The authentication cookie will be mapped to the associated Google
* AuthSub token. The token will be used to retrieve the feed.
* <p>
* Special care must be taken to ensure the following:
* - the requested feed belongs to a pre-specified approved list
* - since cookies are used and GData URLs aren't protected, the URL being
* requested by the client should contain a secure hash. This is primarily
* required for POST/PUT/DELETE but shown in the GET example below as an
* example.
*
*
*/
public class RetrieveFeedServlet extends HttpServlet {
private static String[] acceptedFeedPrefixList = {
"http://www.google.com/calendar/feeds",
"https://www.google.com/calendar/feeds"
};
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Retrieve the authentication cookie to identify user
String principal =
Utility.getCookieValueWithName(req.getCookies(), Utility.LOGIN_COOKIE_NAME);
if (principal == null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Unidentified principal.");
return;
}
// Check that the user has an AuthSub token
String authSubToken = TokenManager.retrieveToken(principal);
if (authSubToken == null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"User isn't authorized through AuthSub.");
return;
}
// If no query string, complain
if (req.getQueryString() == null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Query string is required.");
return;
}
// Parse the query parameters
String queryString = URLDecoder.decode(req.getQueryString(), "UTF-8");
Map<String,String> queryParams = Utility.parseQueryString(queryString);
String queryUri = queryParams.get("href");
String token = queryParams.get("token");
String timestamp = queryParams.get("timestamp");
if ((queryUri == null) || (token == null) || (timestamp == null)) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Missing a query parameter.");
return;
}
// Verify the feed by checking that it's from a known list of feeds and
// that the secure token hasn't expired and is valid.
if (!verifyFeedRequest(principal, queryUri, token, timestamp, "GET")) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Request failed validation.");
return;
}
// Handle a GET request
handleGetRequest(req, resp, queryUri, authSubToken);
}
/**
* Handles a GET request by issuing a GET to the requested feed with the
* AuthSub token attached in a header. The output from the server will
* be proxied back to the requestor.
* POST/PUT/DELETE can be handled in a similar manner except that the XML
* sent as part of the request should be sent to the server.
*/
private void handleGetRequest(HttpServletRequest req,
HttpServletResponse resp,
String queryUri,
String authSubToken)
throws ServletException, IOException {
HttpURLConnection connection = null;
try {
connection = openConnectionFollowRedirects(queryUri, authSubToken);
} catch (GeneralSecurityException e) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Error creating authSub header.");
return;
} catch (MalformedURLException e) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Malformed URL - " + e.getMessage());
return;
} catch (IOException e) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"IOException - " + e.getMessage());
return;
}
int respCode = connection.getResponseCode();
// Handle error from remote server
if (respCode != HttpServletResponse.SC_OK) {
Map<String, List<String>> headers = connection.getHeaderFields();
StringBuffer errorMessage = new StringBuffer(
"Failed to retrive calendar feed from: ");
errorMessage.append(queryUri);
errorMessage.append(".\nServer Error Response:\n");
errorMessage.append(connection.getResponseMessage());
for (Iterator<String> iter = headers.keySet().iterator() ;
iter.hasNext();) {
String header = iter.next();
List<String> headerValues = headers.get(header);
for (Iterator<String> headerIter = headerValues.iterator() ;
headerIter.hasNext(); ) {
String headerVal = headerIter.next();
errorMessage.append(header + ": " + headerVal + ", ");
}
}
resp.sendError(respCode, errorMessage.toString());
return;
}
// Handle success reply from remote server
try {
BufferedReader reader =
new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while((line = reader.readLine()) != null) {
resp.getWriter().write(line);
}
} catch(IOException e) {
// Ignore
}
}
/**
* Open a HTTP connection to the provided URL with the AuthSub token specified
* in the header. Follow redirects returned by the server - a new AuthSub
* signature will be computed for each of the redirected-to URLs.
*/
private HttpURLConnection openConnectionFollowRedirects(String urlStr,
String authSubToken)
throws MalformedURLException, GeneralSecurityException, IOException {
boolean redirectsDone = false;
HttpURLConnection connection = null;
while (!redirectsDone) {
URL url = new URL(urlStr);
// Open connection to requested feed
connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
// Form AuthSub authentication header
String authHeader = null;
authHeader = AuthSubUtil.formAuthorizationHeader(authSubToken,
Utility.getPrivateKey(),
url,
"GET");
connection.setRequestProperty("Authorization", authHeader);
connection.setInstanceFollowRedirects(false);
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_MOVED_PERM ||
responseCode == HttpURLConnection.HTTP_MOVED_TEMP) {
urlStr = connection.getHeaderField("Location");
// If "Location" is not specified, stop following redirects, and
// propagate error to the client of the proxy
if (urlStr == null) {
redirectsDone = true;
}
} else {
redirectsDone = true;
}
}
return connection;
}
/**
* Verifies the request for a feed by:
* a. validating that the request belongs to a known list of feeds
* b. validating the token (to protect against url command attacks)
*<p>
* This verification is in order to prevent the proxy from URL command attacks
* which is a cross site scripting problem.
*/
private boolean verifyFeedRequest(String cookie,
String feed,
String token,
String timestamp,
String method) {
// Check the list of accepted feed URLs that we are proxying
int url_i;
for (url_i = 0; url_i < acceptedFeedPrefixList.length; url_i++) {
if(feed.toLowerCase().startsWith(
acceptedFeedPrefixList[url_i].toLowerCase())) {
break;
}
}
if (url_i == acceptedFeedPrefixList.length) {
return false;
}
return SecureUrl.isTokenValid(token, cookie, feed, method, timestamp);
}
}
@@ -0,0 +1,161 @@
/* 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.authsub.src;
import com.google.gdata.util.common.util.Base64;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.MessageDigest;
import java.util.Date;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* Generates and verifies tokens to protect URLs.
*
* The URL command attack is a cross site scripting vulnerability. It
* is applicable when cookies are used for authentication and user commands
* are done through HTTP requests (GET or POST).
* This attack is illustrated through the following
* example. Assume goodsite.com and evilsite.com. Assume goodsite.com offers a
* URL of the following form
* http://goodsite.com/addtophonebook?email=hello@gmail.com that adds
* hello@gmail.com to the current logged in user's phonebook.
* An attack may look like this:
* <p>
* 1. User logs into goodsite.com and gets an login cookie
* 2. User goes to evilsite.com
* 3. On evilsite.com there is an HTML element with a URL source to some
* command for goodsite.com (Perhaps through an invisible image).
* 4. The browser will fetch the URL and the login cookie will go along with
* it
* 5. The user's account is now modified by an evil site
* <p>
* This can happen when URL's aren't protected.
* eg. http://goodsite.com/add=temp@gmail.com
* <p>
* Thus to protect the GData URL proxy, we require requests to the GData proxy
* servlet to contain a secure token that is a hash of the user's login cookie
* issued by the web service and the URL to be accessed. Since evilsite.com
* does not have access to the login cookie, it will not be able to generate a
* valid secure token for this user.
* <p>
* The token used to secure the URL has the following format:
* token = HMAC<sub>SHA1(login-cookie)</sub>({data})
* <p>
* where <code>{data}</code> is a string formed in the following manner:
* data = http-url SP http-method SP timestamp
* <code>SP</code> is a single ASCII space character.
* <code>http-url</code> is the GData feed URl being requested.
* <code>timestamp</code> is an integer representing the time
* the request was sent, in seconds since Jan 1, 1970 UTC,
* formatted as an ASCII string (in decimal).
* <p>
* The token used in the URL will be Base64 encoded.
*
*
*/
public class SecureUrl {
private static final int TOKEN_LIFE_SECONDS = 30 * 60;
/**
* Generates a secure token to be used to protect a URL.
*
* @param cookie the authentication cookie of the user
* @param url the URL to protect
* @param method the HTTP method used against the URL
* @param currentTimeSecs the current time in seconds
* @return the secure token
*/
public static String generateToken(String cookie,
String url,
String method,
long currentTimeSecs) {
// Form the data to be HMAC'ed
String data = url + " " + method + " " + currentTimeSecs;
// Compute SHA1-HMAC
byte[] hmac;
try {
hmac = computeSHA1HMac(data, cookie);
} catch (GeneralSecurityException e) {
throw new RuntimeException("Security exception - " + e.getMessage());
}
return Base64.encodeWebSafe(hmac, true);
}
/**
* Checks the validity of the secure token to ensure that it was not created
* by a malicious third party.
*
* @param token the token to verify
* @param cookie the cookie of the user
* @param url the URL requested
* @param method the HTTP method used to request the URL
* @param timestamp the timestamp of the token
*/
public static boolean isTokenValid(String token,
String cookie,
String url,
String method,
String timestamp) {
long createTime = Long.parseLong(timestamp);
long currentTime = (new Date()).getTime() / 1000;
if ((currentTime - createTime) > TOKEN_LIFE_SECONDS) {
return false;
}
String data = url + " " + method + " " + createTime;
byte[] hmac;
try{
hmac = computeSHA1HMac(data, cookie);
} catch (GeneralSecurityException e) {
throw new RuntimeException("Security exception - " + e.getMessage());
}
String hmacEnc = Base64.encodeWebSafe(hmac, true);
return hmacEnc.equals(token);
}
/**
* Computes a SHA1-HMAC. A SHA1 hash of the cookie is used as the key to
* MAC the data.
*
* @param data the data to MAC
* @param cookie the authentication cookie of the user
* @return the SHA1-HMAC of the data given the cookie
*/
public static byte[] computeSHA1HMac(String data,
String cookie)
throws GeneralSecurityException {
// Compute SHA-1 hash of the cookie
byte[] hash;
MessageDigest digest = MessageDigest.getInstance("SHA-1");
hash = digest.digest(cookie.getBytes());
// Compute the HMAC of the data using hash(cookie) as the key
byte[] hmacResult;
Mac hm;
hm = Mac.getInstance("HMacSHA1");
Key k1 = new SecretKeySpec(hash, 0, hash.length, "HMacSHA1");
hm.init(k1);
return hm.doFinal(data.getBytes());
}
}
@@ -0,0 +1,52 @@
/* 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.authsub.src;
import java.util.Hashtable;
/**
* Manages and stores AuthSub tokens.
*
* The TokenManager currently just uses a Hashtable to store the tokens
* in-memory. This is just for the purposes of the sample. Ideally, the
* token should be stored in a database with the same security restrictions
* as other sensitive material like user passwords. Google limits the
* number of AuthSub tokens generated per user per target and thus the tokens
* have to be stored permanently and reused.
*
*
*/
public class TokenManager {
private static Hashtable<String, String> tokenMap;
static {
tokenMap = new Hashtable<String, String>();
}
public static synchronized void storeToken(String principal, String token) {
tokenMap.put(principal, token);
}
public static synchronized String retrieveToken(String principal) {
return tokenMap.get(principal);
}
public static synchronized void removeToken(String principal) {
tokenMap.remove(principal);
}
}
+115
View File
@@ -0,0 +1,115 @@
/* 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.authsub.src;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.Cookie;
/**
* A class with a set of utility functions.
*
*
*/
public class Utility {
public static final String LOGIN_COOKIE_NAME = "AuthSubSampleCookie";
private static PrivateKey privateKey;
// Make class uninstantiable
private Utility() {
}
/**
* Retrieves the value of the cookie with the corresponding name.
*/
public static String getCookieValueWithName(Cookie[] cookies, String name) {
for (int cookie_i = 0; cookie_i < cookies.length; cookie_i++) {
if (cookies[cookie_i].getName().equals(name)) {
return cookies[cookie_i].getValue();
}
}
return null;
}
/**
* Parse a query string using the '&' character as the delimiter. Handles
* quoted values and is thus different than HttpUtils.parseQueryString.
*/
public static Map<String, String> parseQueryString(String queryString) {
StringBuilder query = new StringBuilder(queryString);
Map<String,String> hash = new HashMap<String,String>();
while (query.length() > 0) {
char c = query.charAt(0);
if (c == '&') {
query.deleteCharAt(0);
continue;
}
int equals = query.indexOf("=");
String key = query.substring(0, equals);
String value;
query.delete(0, equals + 1);
if (query.charAt(0) == '\"') {
int nextQuote = query.indexOf("\"", 1);
if (nextQuote == -1) {
// mismatched quotes -- try to be accommodating
value = query.toString();
query.delete(0, query.length());
} else {
value = query.substring(1, nextQuote);
query.delete(0, nextQuote + 1);
}
} else {
int ampIndex = query.indexOf("&");
if (ampIndex == -1) {
ampIndex = query.length();
}
value = query.substring(0, ampIndex);
query.delete(0, ampIndex);
}
hash.put(key, value);
}
return hash;
}
/**
* Return the private key to use to sign the AuthSub request.
*
* Note: Currently configured to use AuthSub without signatures. Uncomment
* the function below if AuthSub requests need to be signed.
*/
public static PrivateKey getPrivateKey() {
/**
* if (privateKey == null) {
* try {
* privateKey = AuthSubUtil.
* getPrivateKeyFromKeystore("/usr/etc/gdata_keys/AuthSub.jks",
* "passwd",
* "AuthSubAliasName",
* "passwd");
* } catch (Exception e) {
* throw new RuntimeException("Error reading from keystore file - ", e);
* }
* }
*/
return privateKey;
}
}
Binary file not shown.
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>AuthSub Demo Application</display-name>
<description>
This is a simple web application that demonstrates AuthSub
usage.
</description>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>sample.authsub.src.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>HandleTokenServlet</servlet-name>
<servlet-class>sample.authsub.src.HandleTokenServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HandleTokenServlet</servlet-name>
<url-pattern>/HandleTokenServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>RetrieveFeedServlet</servlet-name>
<servlet-class>sample.authsub.src.RetrieveFeedServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RetrieveFeedServlet</servlet-name>
<url-pattern>/RetrieveFeedServlet</url-pattern>
</servlet-mapping>
</web-app>
@@ -0,0 +1,101 @@
/* The main chrome containing the calendar is spaced this far from the side */
.datePickerDiv {
background: #c3d9ff;
padding: 0px 0px 9px 9px;
line-height: 1em;
}
.DP_monthtable {
width: 100%;
background: #fff;
padding: 0px;
border-bottom: 1px #A2BBDD solid;
font-size: 83%;
}
.DP_monthtable TD {
text-align: center;
padding: 2px;
font-family: Verdana;
font-size: 85%;
}
.DP_heading {
cursor: pointer;
background: rgb(195, 217, 255);
color: #112ABB;
vertical-align: middle;
}
.DP_days {
background: rgb(195, 217, 255);
}
.DP_dayh {
cursor: default;
font-size: 78%;
}
.DP_cur {
font:bold 78%/1em Verdana,Sans-serif;
padding-bottom: 4px;
text-align: center;
}
.DP_prev, .DP_next {
font-size: 125%;
padding-bottom: 6px;
cursor: pointer;
}
.DP_prev { text-align: right; }
.DP_next { text-align: left; }
/* today */
.DP_today {
background : #9ab !important;
border: 1px solid !important;
border-color: #567 #abc #abc #567 !important;
color: #fff;
}
.DP_today_selected {
background : #579 !important;
border: 1px solid !important;
border-color: #246 #9bd #9bd #246 !important;
color: #fff;
}
/* weekday is Gmail blue when selected */
.DP_weekday {
background: rgb(255, 255, 255);
}
.DP_weekday_selected {
background: rgb(170, 204, 238);
}
/* weekend goes from gray to dark blue when selected */
.DP_weekend {
background: #E8EEF7;
}
.DP_weekend_selected {
background: rgb(153, 187, 221);
}
.DP_onmonth {
}
.DP_offmonth {
color: #888;
}
.DP_day_top {
border-top: 1px #A2BBDD solid;
}
.DP_day_right {
border-right: 1px #A2BBDD solid;
}
.DP_day_left {
border-left: 1px #A2BBDD solid;
}
@@ -0,0 +1,178 @@
body {
font-family: arial, sans-serif;
font-size: 83%;
}
.leftcontent {
float:left;
width:175px;
background:#fff;
}
.topimage {
margin-left:13px;
margin-top:0px;
padding:0px;
}
.footerimage {
margin-left:15px;
margin-top:20px;
padding:0px;
}
.toc {
color: #ddad08;
font-weight:bold;
}
.rightcontent {
background:#fff;
margin-left: 199px;
}
p {
margin-right: 5%;
margin-left:3%;
}
ol, ul {
margin-right: 5%;
margin-left:3%;
}
h1 {
font-size:130%;
font-weight:bold;
margin-left:3%;
margin-top:2em;
}
h2 {
font-size:120%;
font-weight:bold;
margin-left:3%;
margin-top:2em;
}
h3 {
font-size:100%;
font-weight:bold;
margin-left:3%;
margin-top:2em;
}
h4 {
font-size:90%;
font-weight:bold;
margin-left:3%;
margin-top:1.5em;
}
.title {
background-color: #FEFADE;
border-top:1px solid #ddad08;
font-weight:bold;
font-size:120%;
text-align:left;
margin-left:0;
}
.subtitle {
background-color: #FEFADE;
border-top:1px solid #ddad08;
font-weight:bold;
font-size:120%;
text-align:left;
}
.toclinks, ul {
margin-bottom:0px;
margin-top:0px;
}
.footer {
text-align: center;
}
code {
font-family:Courier, monospace;
}
pre {
font-family:Courier, monospace;
margin-left:3%;
text-align:left;
}
.content {
border-left:thin dotted #000;
}
table {
margin-left:3%;
border: 1px solid #c3d9ff;
border-spacing:0;
}
th {
font-weight:bold;
text-align:left;
margin-left:3%;
border-right: 1px solid #C3d9ff;
border-bottom: 1px solid #C3d9ff;
border-top: 1px solid #C3d9ff;
text-align: left;
padding: 6px 6px 6px 12px;
background: #aac8f6;
}
td {
border-right: 1px solid #C3d9ff;
border-bottom: 1px solid #C3d9ff;
text-align:left;
margin-left:3%;
padding: 6px 6px 6px 12px;
vertical-align:top;
}
td.alt {
background: #e8eefa;
vertical-align:top;
}
font {
margin-right: 5%;
vertical-align:bottom;
margin-left:3%;
}
.tdfooter {
margin-right: 5%;
text-align:right;
}
.i {
margin-left: 1em;
margin-right: 2em;
}
.q {
margin: 0 10px 0 5px;
padding: 10px 0 0 10px;
color: #000;
background: url("../../images/quote.gif") no-repeat top left;
}
.d {
color:#999999;
text-decoration:italics;
font-size:83%;
}
.tdheading {
font-weight:bold;
font-size:120%;
margin-left:3%;
}
@@ -0,0 +1,44 @@
body { background-color: white; }
h1 td, h1, h2, h3, h4, h5, h6, div.topnav,
div.sidenav, div.sidesearch, div.sidequote, div.bottomnav, div.footer, small,
td#sidebartitle { font-family: arial,sans-serif; }
/* rules for the bottom navigation on the results page */
div.bottomnav { margin-top: 1ex; }
div.bottomnav a, span.bottomnav { font-size: 10pt; }
div.bottomnav a, span.big { font-size: 12pt; color: #0000cc; }
/* standard link colors */
a:link { color: #0000cc; }
a:visited { color: #551a8b; }
a:active { color: #ff0000; }
/* top part of the page */
div.topnav { margin-bottom: 0.1ex; }
h1 td { font-size: .95em; font-weight: bolder; }
h1 td { background-color: #669900; color: white; border: none; padding: 2pt; }
div.side { margin-right: 3ex; padding: 2pt; }
div.sidenav { }
div.sidesearch { margin-top: 1em; font-size: 0.75em; }
div.sidequote { text-align: center; margin-top: 1.5in; border-color: red; border-style: solid; border-top-width: 1px; border-bottom-width: 1px; border-left-width: 0px; border-right-width: 0px; }
div.footer { text-align: center; color: #6f6f6f; padding: 3pt; }
/* sidebar on the right */
table.sidebarborder { margin: 3pt; margin-top: 1pt; }
td#sidebarcontent { background-color: #ffffff; }
/* color schemes for different sections of the site */
body.corporate h1 td, body.corporate table.sidebarborder td { background-color: #339966; }
body.corporate td#sidebartitle { background-color: #d8f1e4; }
body.siteowners h1 td, body.siteowners table.sidebarborder td { background-color: #ddad08; }
body.siteowners td#sidebartitle { background-color: #f1e4d8; }
body.search h1 td, body.search table.sidebarborder td { background-color: #336699; }
body.search td#sidebartitle { background-color: #d8e4f1; }
body.zealots h1 td, body.zealots table.sidebarborder td { background-color: #aa1002; }
body.zealots td#sidebartitle { background-color: #f1e4d8; }
body.gsa h1 td, body.gsa table.sidebarborder td { background-color: #F0C000; }
body.gsa td#sidebartitle { background-color: #fbeab5; }
@@ -0,0 +1,4 @@
ul, ol {
margin-left:3%;
padding-left:3%;
}
+188
View File
@@ -0,0 +1,188 @@
.pbox {
/* position: relative; */
top: 1px;
width: 15em;
/* height: 18em; */
line-height: 1.2em;
margin:0 10px 10px 0;
font-size: 85%;
}
/* =Menu borders (top and bottom) creates rounded corners
----------------------------------------------- */
.pbox .t2, .pbox .b2, .pbox .sb2 {
background-color:#BBBBBB; /* D */
position:relative;
top:-1px;
height:1px;
margin:0 1px;
font-size:1px;
line-height:1px;
}
.pbox .offset, .pbox .b2 {
border-right:1px solid #666666; /* A */
}
.pbox .t2 {
margin-right:2px;
}
.pbox .b2 {
background-color:#BBBBBB; /* D */
}
.pbox .sb2 {
display:block;
background-color:#666666;/* A */
margin-left:2px;
}
.boxbody {
background-color:#DDDDDD; /* E */
position:relative;
top:-1px;
border:solid #BBBBBB; /* D */
border-width:0 1px;
}
.boxbody ul, .boxbody li {
margin:0;
padding:0;
list-style:none;
}
/* =QuickAdd
----------------------------------------------- */
.quick {
width:30em;
font-size:100%;
color:#fff;
z-Index: 42;
}
.quick .t2 {
background-color:#8ac;
}
.quick .b2 {
background-color:#468;
}
.quick .sb2 {
background-color:#246;
}
.quick .offset, .pbox .quick .b2 {
border-right:1px solid #246; /* A */
}
.quick .boxbody {
background-color:#68a;
border-left-color:#8ac;
border-right-color:#468;
padding-left: 6px;
}
.quick form {
margin:0;
padding:2px 0px;
}
.quick label {
display:block;
padding:1px 1px 2px;
}
.quick .txt {
width:27em;
border:1px solid;
border-color:#468 #8ac #8ac #468;
font:100% Arial,Sans-serif;
}
.quick .imgbtn {
vertical-align:middle;
}
.quick p {
margin:0;
padding:2px;
font-size:85%;
line-height:1.2em;
}
/* =Options
----------------------------------------------- */
ul.caloptions {
border-bottom:1px solid #BBBBBB; /* D */
}
.caloptions li {
width:100%;
}
.caloptions li a {
display:block;
padding:3px 8px;
color:#222;
text-decoration:none;
}
* html .caloptions li a {
height:1.2em;
}
.caloptions li a:hover {
background-color:#BBBBBB; /* D */
/*bolinfest*/
text-decoration:underline;
color:#222;
}
/*bolinfest*/
.caloptions li a:visited {
color:#222;
}
/* =CalColor
----------------------------------------------- */
.calcolor {
padding:7px 8px 0;
}
.calcolor ul {
position:relative;
float:left;
width:100%;
padding-bottom:3px;
}
* html .calcolor ul {
padding-bottom:7px;
}
.calcolor li {
display:inline;
font-size:1px;
line-height:1px;
}
.calcolor li a {
float:left;
display:block;
width:13px;
height:13px;
margin:0 4px 4px 0;
border:1px solid #fff;
text-decoration:none;
}
.calcolor li a:hover {
border-color:#000;
}
.cal1 a.cal1-b, .cal1 a.cal1-b:hover,
.cal2 a.cal2-b, .cal2 a.cal2-b:hover,
.cal3 a.cal3-b, .cal3 a.cal3-b:hover,
.cal4 a.cal4-b, .cal4 a.cal4-b:hover,
.cal5 a.cal5-b, .cal5 a.cal5-b:hover,
.cal6 a.cal6-b, .cal6 a.cal6-b:hover,
.cal7 a.cal7-b, .cal7 a.cal7-b:hover,
.cal8 a.cal8-b, .cal8 a.cal8-b:hover,
.cal9 a.cal9-b, .cal9 a.cal9-b:hover,
.cal10 a.cal10-b, .cal10 a.cal10-b:hover,
.cal11 a.cal11-b, .cal11 a.cal11-b:hover,
.cal12 a.cal12-b, .cal12 a.cal12-b:hover,
.cal13 a.cal13-b, .cal13 a.cal13-b:hover,
.cal14 a.cal14-b, .cal14 a.cal14-b:hover,
.cal15 a.cal15-b, .cal15 a.cal15-b:hover,
.cal16 a.cal16-b, .cal16 a.cal16-b:hover,
.cal17 a.cal17-b, .cal17 a.cal17-b:hover,
.cal18 a.cal18-b, .cal18 a.cal18-b:hover,
.cal19 a.cal19-b, .cal19 a.cal19-b:hover,
.cal20 a.cal20-b, .cal20 a.cal20-b:hover,
.cal21 a.cal21-b, .cal21 a.cal21-b:hover {
background-image:url("images/icon_check3.gif");
background-position:-13px 0;
background-repeat:no-repeat;
cursor:default;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 B

+68
View File
@@ -0,0 +1,68 @@
<html>
<head>
<title>Google Calendar AuthSub demo</title>
<link rel="stylesheet" type="text/css" href="css/google.css">
<link rel="stylesheet" type="text/css" href="css/frameless.css">
<!--[if IE]>
<link rel="stylesheet" type="text/css" href="css/ieonly.css" />
<![endif]-->
</head>
<body>
<div class="leftcontent">
<p class="topimage"><a href="http://www.google.com/">
<img src="http://www.google.com/images/google_sm.gif" border="0" alt="Return to Google homepage" /></a>
</p>
</div>
<%
StringBuffer continueUrl = request.getRequestURL();
int index = continueUrl.lastIndexOf("/");
continueUrl.delete(index, continueUrl.length());
continueUrl.append("/LoginServlet");
%>
<FORM NAME=index METHOD=POST ACTION="<%=continueUrl.toString()%>">
<div class="rightcontent">
<p class=title>Google AuthSub Demo </p>
<div class="content">
<h1>Google AuthSub Demo</h1>
<p>
This page demonstrates a basic version of AuthSub in action.</p>
<p>
The AuthSub token is first retrieved from Google and then used to retrieve your Calendar entries.
</p>
<p>
Note: <br>
If your user account is registered to a domain other than 'gmail.com', specify the domain name as well.
If the calendar service in your domain requires secure connection (ssl) for retrieving feeds, make sure to check the ssl option.
</p>
<p>
<br><b>Specify user domain:</b>
<br>
<input type="radio" name="defaultdomain" value="true" onclick="javascript:document.index.domain.disabled=true" checked>
Use default domain (gmail.com)
<br>
<input type="radio" name="defaultdomain" value="false" onclick="javascript:document.index.domain.disabled=false">
Use my application domain (ex: mydomain.com): <input type=text name=domain disabled>
<br>
<br>
<input type="checkbox" name="secure" value="true">Use secure connection to retrieve calendar feed.
<p><input type=submit value="Authenticate">
</p>
</div>
</div>
</FORM>
<div class="leftcontent">
<p class="footerimage"><img src="http://www.google.com/images/art.gif">
</p></div><div class="rightcontent">
<p>
<img src="http://www.google.com/images/cleardot.gif" width="1" height="45">
</p> </div>
</body>
</html>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,260 @@
Function.prototype.bind=function(a){if(typeof this!="function"){throw new Error("Bind must be called as a method of a function object.");}var b=this;var c=Array.prototype.splice.call(arguments,1,arguments.length);return function(){var d=c.concat();for(var e=0;e<arguments.length;e++){d.push(arguments[e])}return b.apply(a,d)}
}
;var Ta;var Ya;(function(){var a={};var b=0;function c(f){if(!f.Da){f.Da=++b}return f.Da}
function d(f,h,l,n){var k=c(f);var q=c(l);n=!(!n);var s=k+"_"+h+"_"+q+"_"+n;return s}
Ta=function(f,h,l,n){var k=d(f,h,l,n);if(k in a){return k}var q=e.bind(null,k);a[k]={listener:l,proxy:q};if(f.addEventListener){f.addEventListener(h,q,n)}else if(f.attachEvent){f.attachEvent("on"+h,q)}else{throw new Error("Node {"+f+"} does not support event listeners.");}return k}
;Ya=function(f,h,l,n){var k=d(f,h,l,n);if(!(k in a)){return false}var q=a[k].proxy;if(f.removeEventListener){f.removeEventListener(h,q,n)}else if(f.detachEvent){f.detachEvent("on"+h,q)}delete a[k];return true}
;function e(f){var h=Array.prototype.splice.call(arguments,1,arguments.length);return a[f].listener.apply(null,h)}
}
)();var oa=["Su","M","Tu","W","Th","F","Sa"];var Z=[,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];var aa=[,"January","February","March","April","May","June","July","August","September","October","November","December"];var Aa;var Qa;var Ba;var Ca;var W;var Sa;var Ra;(function(){var a=navigator.userAgent.toLowerCase();Aa=a.indexOf("msie")!=-1;Qa=a.indexOf("msie 5")!=-1&&document.all;Ba=a.indexOf("konqueror")!=-1;Ca=a.indexOf("safari")!=-1||Ba;W=!Aa&&!Ca&&a.indexOf("mozilla"
)!=-1;Sa=a.indexOf("win")!=-1;Ra=!(!window.opera)}
)();function na(a,b){}
;function ca(a){if(!a)return"";return a.replace(/&#(\d+);/g,function(b,c){return String.fromCharCode(parseInt(c,10))}
).replace(/&#x([a-f0-9]+);/gi,function(b,c){return String.fromCharCode(parseInt(c,16))}
).replace(/&(\w+);/g,function(b,c){c=c.toLowerCase();return c in ca.unesc?ca.unesc[c]:"?"}
)}
ca.unesc={lt:"<",gt:">",quot:'"',nbsp:" ",amp:"&"};function Y(a){return Y.Ba[a]}
function ma(a){if(!Y.Ba){var b={};b["\\"]="\\\\";b["'"]="\\047";b["\u0008"]="\\b";b['"']="\\042";b["<"]="\\074";b[">"]="\\076";b["&"]="\\046";b["\n"]="\\n";b["\r"]="\\r";b["\u0085"]="\\205";b["\u2028"]="\\u2028";b["\u2029"]="\\u2029";Y.Ba=b}return"'"+a.toString().replace(/[\'\\\r\n\b\"<>&\u0085\u2028\u2029]/g,Y)+"'"}
function Ea(a){var b={};b.clientX=a.clientX;b.clientY=a.clientY;b.pageX=a.pageX;b.pageY=a.pageY;b.type=a.type;b.srcElement=a.srcElement;b.target=a.target;b.cancelBubble=a.cancelBubble;b.explicitOriginalTarget=a.explicitOriginalTarget;return b}
function Oa(a){return document.getElementById(a)}
function Pa(a){return document.all[a]}
var z=document.getElementById?Oa:Pa;function ba(a){var b;if(!("name" in a)){var c=/\W*function\s+([\w\$]+)\(/.exec(a);if(!c){throw new Error("Cannot extract name from function: "+a);}b=c[1];a.name=b}else{b=a.name}if(!b||b=="anonymous"){throw new Error("Anonymous function has no name: "+a);}return a.name}
function _showLogWindow(){}
function N(a){return a<0?-1:1}
function X(a){return a|0}
function ta(a){DumpError(a);throw a;}
function p(a,b){var c=a.toString();while(c.length<b){c="0"+c}return c}
var ea=[undefined,31,undefined,31,30,31,30,31,31,30,31,30,31];function H(a,b){if(2!==b){return ea[b]}var c=a<<4;var d=ea[c];if(!d){d=Math.round((Date.UTC(a,2,1)-Date.UTC(a,1,1))/86400000);ea[c]=d}return d}
var ua=new Object;function Ka(a,b){var c=a<<4|b;var d=ua[c];if(!d){d=(new Date(a,b-1,1,0,0,0,0)).getDay();ua[c]=d}return d}
function fa(a){return(a.date-1+Ka(a.year,a.month))%7}
function ra(a,b,c,d,e,f){var h;if(a===d){if((h=b-e)===0){return c-f}else if(h<0){h=c-f;do{h-=H(a,b++)}while(b<e);return h}else{h=c-f;do{h+=H(d,e++)}while(e<b);return h}}else{return Math.round((Date.UTC(a,b-1,c)-Date.UTC(d,e-1,f))/86400000)}}
function sa(a,b){return ra(a.year,a.month,a.date,b.year,b.month,b.date)}
function y(a,b,c,d,e,f){if(!isNaN(a)){this.year=a}if(!isNaN(b)){this.month=b}if(!isNaN(c)){this.date=c}if(!isNaN(d)){this.hour=d}if(!isNaN(e)){this.minute=e}if(!isNaN(f)){this.second=f}}
y.prototype.year=NaN;y.prototype.month=NaN;y.prototype.date=NaN;y.prototype.hour=NaN;y.prototype.minute=NaN;y.prototype.second=NaN;y.prototype.Ya=function(){return fa(this)}
;y.prototype.toString=function(){if(this.l!==undefined)return this.l;this.l=this.D();return this.l}
;function K(){}
K.prototype=new y;K.prototype.constructor=K;function j(a,b,c){y.call(this,a,b,c,NaN,NaN,NaN)}
j.prototype=new K;j.prototype.constructor=j;j.now=function(){var a=new Date;return j.create(a.getFullYear(),a.getMonth()+1,a.getDate())}
;j.prototype.type="Date";j.prototype.i=function(){return this}
;j.prototype.P=function(){return new t(this.year,this.month,this.date,0,0,0)}
;j.prototype.a=function(){if(undefined===this.e){this.e=j.wa(this.year,this.month,this.date)}return this.e}
;j.wa=function(a,b,c){return this.e=(((a-1970)*12+b<<5)+c)*86400}
;j.prototype.da=function(){return true}
;j.prototype.D=function(){return p(this.year,4)+p(this.month,2)+p(this.date,2)}
;j.prototype.equals=function(a){return this.constructor===a.constructor&&this.date===a.date&&this.month===a.month&&this.year===a.year}
;j.V={};j.Ra=0;j.Ma=200;j.create=function(a,b,c){var d=j.wa(a,b,c);if(d in j.V){return j.V[d]}else{var e=new j(a,b,c);e.e=d;if(j.Ra<j.Ma){j.V[d]=e}return e}}
;function t(a,b,c,d,e,f){y.call(this,a,b,c,d,e,f)}
t.prototype=new K;t.prototype.constructor=t;t.now=function(){var a=new Date;return new t(a.getFullYear(),a.getMonth()+1,a.getDate(),a.getHours(),a.getMinutes(),a.getSeconds())}
;t.prototype.type="DateTime";t.prototype.i=function(){return j.create(this.year,this.month,this.date)}
;t.prototype.P=function(){return this}
;t.prototype.La=function(){return new F(this.hour,this.minute,this.second)}
;t.prototype.a=function(){if(undefined===this.e){this.e=(((((this.year-1970)*12+this.month<<5)+this.date)*24+this.hour)*60+this.minute)*60+this.second}return this.e}
;t.prototype.da=function(){return true}
;t.prototype.D=function(){return p(this.year,4)+p(this.month,2)+p(this.date,2)+"T"+p(this.hour,2)+p(this.minute,2)+p(this.second,2)}
;t.prototype.equals=function(a){return this.constructor===a.constructor&&this.date===a.date&&this.month===a.month&&this.year===a.year&&this.hour===a.hour&&this.minute===a.minute&&this.second===a.second}
;t.prototype.clone=function(){var a=new t(this.year,this.month,this.date,this.hour,this.minute,this.second);if(this.l!==undefined)a.l=this.l;return a}
;function F(a,b,c){y.call(this,NaN,NaN,NaN,a,b,c)}
F.prototype=new y;F.prototype.constructor=F;F.prototype.type="Time";F.prototype.La=function(){return this}
;F.prototype.D=function(){return"T"+p(this.hour,2)+p(this.minute,2)+p(this.second,2)}
;F.prototype.equals=function(a){return this.constructor===a.constructor&&this.hour===a.hour&&this.minute===a.minute&&this.second===a.second}
;F.prototype.a=function(){return(this.hour*60+this.minute)*60+this.second}
;function E(a,b,c,d){var e=d+60*(c+60*(b+24*a));var f=X(e/86400);e-=f*86400;var h=X(e/3600);e-=h*3600;var l=X(e/60);e-=l*60;var n=X(e);y.call(this,NaN,NaN,f,h,l,n)}
E.prototype=new y;E.prototype.constructor=E;E.prototype.type="Duration";E.prototype.Wb=function(){return this.date}
;E.prototype.Xb=function(){return this.date*24+this.hour}
;E.prototype.Yb=function(){return 1440*this.date+this.hour*60+this.minute}
;E.prototype.Zb=function(){return this.second+this.minute*60+this.hour*3600+86400*this.date}
;E.prototype.a=function(){if(undefined===this.e){this.e=((this.date*24+this.hour)*60+this.minute)*60+this.second}return this.e}
;E.prototype.D=function(){var a=this.year?N(this.year):(this.month?N(this.month):(this.date?N(this.date):(this.hour?N(this.hour):(this.minute?N(this.minute):(this.second?N(this.second):0)))));var b=a<0?"-P":"P";if(this.year){b+=a*this.year+"Y"}if(this.month){b+=a*this.month+"N"}if(this.date){b+=this.date%7?a*this.date+"D":a*this.date/7+"W"}if(this.hour||this.minute||this.second){b+="T"}if(this.hour){b+=a*this.hour+"H"}if(this.minute){b+=a*this.minute+"M"}if(this.second){b+=a*this.second+"S"}if(!a)
{b+="0D"}return b}
;E.prototype.equals=function(a){return this.constructor===a.constructor&&this.date===a.date&&this.hour===a.hour&&this.minute===a.minute&&this.second===a.second}
;function Q(a){var b=new o;b.year=a.year||0;b.month=a.month||0;b.date=a.date||0;b.hour=a.hour||0;b.minute=a.minute||0;b.second=a.second||0;return b}
function $(a,b,c){na(!(isNaN(a)|isNaN(b)|isNaN(c)));var d=new o;d.year=a||0;d.month=b||0;d.date=c||0;return d}
function o(){}
o.prototype=new y;o.prototype.constructor=o;o.prototype.type="DTBuilder";o.prototype.year=(o.prototype.month=(o.prototype.date=(o.prototype.hour=(o.prototype.minute=(o.prototype.second=0)))));o.prototype.a=function(){this.normalize()}
;o.prototype.advance=function(a){if(a.date){this.date+=a.date}if(a.hour){this.hour+=a.hour}if(a.minute){this.minute+=a.minute}if(a.second){this.second+=a.second}}
;o.prototype.normalize=function(){this.ib();this.ia();var a=H(this.year,this.month);while(this.date<1){this.month-=1;this.ia();a=H(this.year,this.month);this.date+=a}while(this.date>a){this.date-=a;this.month+=1;this.ia();a=H(this.year,this.month)}}
;o.prototype.ib=function(){var a;if(this.second<0){a=Math.ceil(this.second/-60);this.second+=60*a;this.minute-=a}else if(this.second>=60){a=Math.floor(this.second/60);this.second-=60*a;this.minute+=a}if(this.minute<0){a=Math.ceil(this.minute/-60);this.minute+=60*a;this.hour-=a}else if(this.minute>=60){a=Math.floor(this.minute/60);this.minute-=60*a;this.hour+=a}if(this.hour<0){a=Math.ceil(this.hour/-24);this.hour+=24*a;this.date-=a}else if(this.hour>=24){a=Math.floor(this.hour/24);this.hour-=24*a;
this.date+=a}}
;o.prototype.ia=function(){var a;if(this.month<1){a=Math.ceil((this.month-1)/-12);this.month+=12*a;this.year-=a}else if(this.month>12){a=Math.floor((this.month-1)/12);this.month-=12*a;this.year+=a}}
;o.prototype.i=function(){this.normalize();return j.create(this.year,this.month,this.date)}
;o.prototype.P=function(){this.normalize();return new t(this.year,this.month,this.date,this.hour,this.minute,this.second)}
;o.prototype.Ja=function(){this.normalize();return new B(isFinite(this.year)?this.year:undefined,isFinite(this.month)?this.month:undefined,isFinite(this.date)?this.date:undefined)}
;o.prototype.Ka=function(){this.normalize();return new C(isFinite(this.year)?this.year:undefined,isFinite(this.month)?this.month:undefined,isFinite(this.date)?this.date:undefined,isFinite(this.hour)?this.hour:undefined,isFinite(this.minute)?this.minute:undefined,isFinite(this.second)?this.second:undefined)}
;o.prototype.La=function(){this.normalize();return new F(this.hour,this.minute,this.second)}
;o.prototype.rb=function(){if(this.year||this.month){ta("Can't convert months or years to ICAL_Duration");return undefined}else{return new E(this.date,this.hour,this.minute,this.second)}}
;o.prototype.sb=function(){return"number"==typeof this.year&&1+this.year%1===1&&"number"==typeof this.month&&1+this.month%1===1&&"number"==typeof this.date&&1+this.date%1===1}
;o.prototype.$b=function(){return this.sb()&&this.tb()}
;o.prototype.tb=function(){return"number"==typeof this.hour&&1+this.hour%1===1&&"number"==typeof this.minute&&1+this.minute%1===1&&"number"==typeof this.second&&1+this.second%1===1}
;o.prototype.toString=function(){return"["+(undefined!==this.year?p(this.year,4):"????")+"/"+(undefined!==this.month?p(this.month,2):"??")+"/"+(undefined!==this.date?p(this.date,2):"??")+" "+(undefined!==this.hour?p(this.hour,2):"??")+" "+(undefined!==this.minute?p(this.minute,2):"??")+" "+(undefined!==this.second?p(this.second,2):"??")+"]"}
;o.prototype.equals=function(a){return this.constructor===a.constructor&&this.date===a.date&&this.month===a.month&&this.year===a.year&&this.hour===a.hour&&this.minute===a.minute&&this.second===a.second}
;function M(a,b){this.start=a;if(b.constructor==E){var c=Q(a);c.advance(b);this.end=this.start instanceof t?c.P():c.i()}else{this.end=b}this.duration=pa(this.end,this.start)}
M.prototype.type="PeriodOfTime";M.prototype.toString=function(){if(this.l!==undefined)return this.l;this.l=this.start+"/"+this.end;return this.l}
;M.prototype.equals=function(a){return this.constructor===a.constructor&&this.start.equals(a.start)&&this.end.equals(a.end)}
;M.prototype.overlaps=function(a){return a.end.a()>this.start.a()&&a.start.a()<this.end.a()}
;M.prototype.Kb=function(a,b){return b.a()>this.start.a()&&a.a()<this.end.a()}
;M.prototype.contains=function(a){return this.start.a()<=a.start.a()&&this.end.a()>=a.end.a()}
;function da(a,b){this.start=a;this.end=b;try{this.duration=pa(this.end,this.start)}catch(c){this.duration=null}}
da.prototype.type="PartialPeriodOfTime";da.prototype.D=function(){return this.start+"/"+this.end}
;da.prototype.equals=function(a){return this.constructor===a.constructor&&this.start.equals(a.start)&&this.end.equals(a.end)}
;function pa(a,b){if(isNaN(a.year)!=isNaN(b.year)||isNaN(a.hour)!=isNaN(b.hour)){ta("diff("+a+", "+b+")");return undefined}var c=Q(a);if(isNaN(a.year)){c.hour-=b.hour;c.minute-=b.minute;c.second-=b.second}else{c.year=NaN;c.month=NaN;c.date=ra(a.year,a.month,a.date,b.year,b.month,b.date);if(!isNaN(a.hour)){c.hour-=b.hour;c.minute-=b.minute;c.second-=b.second}}return c.rb()}
function B(a,b,c){this.year=a;this.month=b;this.date=c}
B.prototype=new K;B.prototype.constructor=B;B.prototype.type="PartialDate";B.prototype.i=function(){return j.create(this.year||0,this.month||1,this.date||1)}
;B.prototype.P=function(){return new t(this.year||0,this.month||1,this.date||1,0,0,0)}
;B.prototype.Ja=function(){return this}
;B.prototype.Ka=function(){return new C(this.year,this.month,this.date,0,0,0)}
;B.prototype.da=function(){return!isNaN(this.a())}
;B.prototype.a=function(){if(undefined===this.e){this.e=(((this.year-1970)*12+this.month<<5)+this.date)*86400}return this.e}
;B.prototype.equals=function(a){return this.constructor===a.constructor&&(this.date===a.date||isNaN(this.date)&&isNaN(a.date))&&(this.month===a.month||isNaN(this.month)&&isNaN(a.month))&&(this.year===a.year||isNaN(this.year)&&isNaN(a.year))}
;B.prototype.D=function(){return(undefined!==this.year?p(this.year,4):"????")+(undefined!==this.month?p(this.month,2):"??")+(undefined!==this.date?p(this.date,2):"??")}
;function C(a,b,c,d,e,f){this.year=a;this.month=b;this.date=c;this.hour=d;this.minute=e;this.second=f}
C.prototype=new K;C.prototype.constructor=C;C.prototype.type="PartialDateTime";C.prototype.i=function(){return j.create(this.year||0,this.month||1,this.date||1)}
;C.prototype.P=function(){return new t(this.year||0,this.month||1,this.date||1,this.hour||0,this.minute||0,this.second||0)}
;C.prototype.Ja=function(){return new B(this.year,this.month,this.date)}
;C.prototype.Ka=function(){return this}
;C.prototype.da=function(){return!isNaN(this.a())}
;C.prototype.a=function(){if(undefined===this.e){this.e=(((((this.year-1970)*12+this.month<<5)+this.date)*24+this.hour)*60+this.minute)*60+this.second}return this.e}
;C.prototype.equals=function(a){return this.constructor===a.constructor&&(this.date===a.date||isNaN(this.date)&&isNaN(a.date))&&(this.month===a.month||isNaN(this.month)&&isNaN(a.month))&&(this.year===a.year||isNaN(this.year)&&isNaN(a.year))&&(this.hour===a.hour||isNaN(this.hour)&&isNaN(a.hour))&&(this.minute===a.minute||isNaN(this.minute)&&isNaN(a.minute))&&(this.second===a.second||isNaN(this.second)&&isNaN(a.second))}
;C.prototype.D=function(){return(undefined!==this.year?p(this.year,4):"????")+(undefined!==this.month?p(this.month,2):"??")+(undefined!==this.date?p(this.date,2):"??")+"T"+(undefined!==this.hour?p(this.hour,2):"??")+(undefined!==this.minute?p(this.minute,2):"??")+(undefined!==this.second?p(this.second,2):"??")}
;var S=undefined;var va=[];function qa(a,b,c){var d=b>2&&29===H(a,2);return qa.Na[b]+d+c-1}
qa.Na=[undefined,0,31,59,90,120,151,181,212,243,273,304,334];function Da(){var a=new Date;var b=S;S=j.create(a.getFullYear(),a.getMonth()+1,a.getDate());if(b&&!b.equals(S)){for(var c=0;c<va.length;++c){var d=va[c];try{d(S)}catch(e){}}}var f=new Date(a.getFullYear(),a.getMonth(),a.getDate(),0,0,0,0);f.setDate(f.getDate()+1);var h=f.getTime()-a.getTime();if(h<0||h>=1800000){h=1800000}setTimeout(Da,h)}
Da();function P(a,b,c){this.x=a;this.y=b;this.coordinateFrame=c}
P.prototype.toString=function(){return"[P "+this.x+","+this.y+"]"}
;P.prototype.clone=function(){return new P(this.x,this.y,this.coordinateFrame)}
;function Ia(a,b){this.dx=a;this.dy=b}
Ia.prototype.toString=function(){return"[D "+this.dx+","+this.dy+"]"}
;function L(a,b,c,d,e){this.x=a;this.y=b;this.w=c;this.h=d;this.coordinateFrame=e}
L.prototype.contains=function(a){return this.x<=a.x&&a.x<this.x+this.w&&this.y<=a.y&&a.y<this.y+this.h}
;L.prototype.toString=function(){return"[R "+this.w+"x"+this.h+"+"+this.x+"+"+this.y+"]"}
;L.prototype.clone=function(){return new L(this.x,this.y,this.w,this.h,this.coordinateFrame)}
;function Ua(a){var b=a.ownerDocument;if(W&&b){var c=b.getBoxObjectFor(a);return new L(c.x,c.y,c.width,c.height,window)}var d=0;var e=0;for(var f=a;f.offsetParent;f=f.offsetParent){d+=f.offsetLeft;e+=f.offsetTop}return new L(d,e,a.offsetWidth,a.offsetHeight,window)}
function Va(a){var b=a.ownerDocument;if(W&&b){var c=b.getBoxObjectFor(a);return c.height}else{return a.offsetHeight}}
function Xa(a){var b=a.ownerDocument;if(W&&b){var c=b.getBoxObjectFor(a);return c.width}else{return a.offsetWidth}}
function Wa(a){var b=a.ownerDocument;if(W&&b){var c=b.getBoxObjectFor(a);return new P(c.x,c.y,window)}var d=0;var e=0;while(a.offsetParent){d+=a.offsetLeft;e+=a.offsetTop;a=a.offsetParent}return new P(d,e,window)}
function Ja(a){var b=0;var c=0;if(a.pageX||a.pageY){b=a.pageX;c=a.pageY}else if(a.clientX||a.clientY){b=a.clientX+document.body.scrollLeft;c=a.clientY+document.body.scrollTop}return new P(b,c,window)}
function g(a,b,c,d,e){this.Q=a;this.g=c?c:this.Q.id+"_";this.c=d?d:"DP_";this.Qa();g.K[this.g]=this;if(e){this.j=e}else{this.j=j.now()}this.r=j.create(this.j.year,this.j.month,1);this.L=0;this.Ua=!(!b);this.T=false;this.Fa=null;this.Ea=null;this.J={};this.t={};this.F={};this.b={};this.n=null;this.N=null;this.ka=new J(this);this.ga=new J(this);this.pa=false;this.G=false;this.f=new G;this.ya=false;this.A=0;this.E=null;this.X=null;this.na=true;this.ja=null;this.W=null;this.ha=null;this.p();this.qa=false;
this.pb(0);this.Ga(0);this.ba=false;this.o=null;this.d=null;this.m=null;this.I=null;this.H=null;this.Ca=null;this.M=false;this.ta=null;this.sa=null;var f=this;var h=function(l){var n=l.startDate;var k=l.endDate;var q;if(!n){q=R[this.O]}else if(!k||n.equals(k)){q="Selected: "+f.$(n,true)}else{q="Selected: "+f.$(n)+" - "+f.$(k)}f.jb(q)}
;if(this.pa)this.ua(h);this.fa=new J(this)}
;g.prototype.Qa=function(){var a=this.c+"day_top ",b=this.c+"day_left ",c=this.c+"day_right ",d=this.c+"onmonth ",e=this.c+"onmonth ",f=this.c+"month_top ",h=this.c+"month_left ",l=this.c+"weekend ",n=this.c+"weekday ",k=this.c+"weekend_selected ",q=this.c+"weekday_selected ";var s={};s[0]="";s[1]=a;s[3]=a+b;s[5]=a+c;s[2]=b;s[4]=c;var u={};for(var i in s){u[i|16|256]=s[i]+d+l;u[i|16|512]=s[i]+d+n;u[i|32|256]=s[i]+e+l;u[i|32|512]=s[i]+e+n;u[i|16|1024]=s[i]+d+k;u[i|16|2048]=s[i]+d+q;u[i|32|1024]=s[
i]+e+k;u[i|32|2048]=s[i]+e+q}var v={};for(var i in u){v[i]=u[i];v[i|64]=u[i]+f;v[i|64|128]=u[i]+f+h}this._classMap=v}
;var R={};R[0]="Select a date";R[1]="Select a range of dates";R[2]="Select dates";R[3]="&nbsp;";g.prototype.Ga=function(a,b){if(a!=0&&a!=1&&a!=7&&a!=30&&a!=-1&&!(b instanceof Function)){throw new Error("Invalid click mode: "+a);}this.Ta=a;this.xa=b}
;g.prototype.Hb=function(){return this.T}
;g.prototype.qb=function(a){if(a!=this.T){this.T=a;this.p()}}
;g.prototype.Wa=function(){return this.Ta}
;g.prototype.pb=function(a){if(this.O==a){return}this.O=a;this.u()}
;g.prototype.aa=function(){return this.O}
;g.prototype.show=function(){this.G=true;this.p()}
;g.prototype.hide=function(){this.Q.innerHTML="";this.G=false}
;g.prototype.gb=function(){return this.G}
;g.prototype.Cb=function(a){return this.t[a.id]}
;g.prototype.Eb=function(a){return this.F[a.id]}
;g.prototype.Xa=function(a){return this.b[a.id]}
;g.prototype.Fb=function(){return z(this.g+"tbl")}
;g.prototype.mb=function(a){this.L=a;this.p()}
;g.prototype.Aa=function(){return this.L}
;g.prototype.Pb=function(a){this.E=a;this.p();return true}
;g.prototype.lb=function(a){this.X=a}
;g.prototype.yb=function(){return this.E}
;g.prototype.Ab=function(){return this.n}
;g.prototype.$a=function(){if(!this.G)return null;return this.b[this.n.id]}
;g.prototype.ab=function(){if(!this.G)return null;var a=z(this.g+"day_"+(this.A-1)+"_6");return this.b[a.id]}
;g.prototype.Ub=function(a){if(a!=this.na){this.na=a;this.p()}}
;g.prototype.ob=function(a){this.ja=a}
;g.prototype.Ob=function(a){this.W=a}
;g.prototype.nb=function(a){this.ha=a}
;g.prototype.bb=function(){return Z}
;g.prototype.Bb=function(){return aa}
;g.prototype.p=function(){if(!this.G){return}var a=this.g;var b;var c=this.r.month;var d=this.r.year;var e=oa.length;var f=[c==1?12:c-1,c,c==12?1:c+1];var h=j.create(this.j.year,this.j.month,1);var l=$(d,c-1,1).i();var n=$(d,c+1,1).i();if(this.ja){f[0]=this.ja(l)}else{var k=l.a()>=h.a()?"&laquo;":"&lsaquo;&nbsp;";f[0]=k+Z[f[0]]}if(this.W){f[1]=this.W(this.r)}else{f[1]=aa[f[1]]+" "+d}if(this.ha){f[2]=this.ha(n)}else{var q=n.a()-h.a()<=0?"&raquo;":"&nbsp;&rsaquo;";f[2]=Z[f[2]]+q}var s=H(d,c);var u=
H(l.year,l.month);var i=new Array(49);var v=this.r.Ya()-this.L;if(v<0)v+=7;if(s<30||v<5)v+=7;for(var r=0;r<v;++r){i[r]=j.create(l.year,l.month,u-v+r+1)}for(var r=v,m=0;m<s;++r){i[r]=j.create(d,c,++m)}var A=v+s;for(var r=A,m=0;r<i.length;++r){i[r]=j.create(n.year,n.month,++m)}this.ta=i[0];this.sa=i[i.length-1];var D=new Array;var O=this.Ua?[2,3,2]:[1,5,1];D.push('<table cols=7 cellspacing="0" cellpadding="3" id="',a,'tbl"',' class="',this.c,'monthtable" ',' style="-moz-user-select:none; cursor:pointer;">'
,'<tr class="',this.c,'heading" id="',a,'header">',"<td colspan=",O[0]," unselectable=on",' onmousedown="'+ba(Ha)+"(",ma(this.g),')"',' id="',a,'mhl" class="',this.c,'prev">',f[0],"</td>","<td colspan=",O[1],' unselectable="on"',' id="',a,'mhc" class="',this.c,'cur">',f[1],"</td>","<td colspan=",O[2],' unselectable="on"',' onmousedown="'+ba(Ga)+"(",ma(this.g),')"',' id="',a,'mhr" class="',this.c,'next">',f[2],"</td>","</tr>");if(this.T){D.push('<tr class="',this.c,'days" id="',a,'dow">');for(var r=
0;r<e;++r){D.push('<td unselectable="on"',' class="',this.c,'dayh" id="',a,"day_",r,'">',oa[(r+this.L)%7],"</td>")}D.push("</tr>")}var T=(7-this.L)%7;var La=(T+6)%7;this.J={};var b=null;var w=null;var Ma=ba(Fa);var wa;var w;var ga=null;if(this.X){ga=this.X.call(null,this.ta,this.sa)}for(var r=0,m=-1;r<7;++r){D.push('<tr id="',a,"week_",r,'">');for(var I=0;I<e;++I){++m;var ha=this.f.contains(i[m]);w=0;if(r==0)w|=1;if(I==0)w|=2;else if(I==6)w|=4;w|=I==T||I==La?(ha?1024:256):(ha?2048:512);if(m<v||m>=
A){w|=32;if(i[m].date<=7){w|=64;if(i[m].date==1&&I!=0){w|=128}}w=this._classMap[w]}else{w|=16;if(i[m].date<=7){w|=64;if(i[m].date==1&&I!=0){w|=128}}if(i[m].date==this.j.date&&c==this.j.month&&d==this.j.year){w=this._classMap[w]+(this.c+"today"+(ha?"_selected ":" "))}else{w=this._classMap[w]}}D.push('<td id="',a,"day_",r,"_",I,'"',' class="',w,'"');if(ga&&(wa=ga[i[m]])){D.push(' style="',wa,'"')}D.push(' onclick="',Ma,'(this)"',' unselectable="on">',i[m].date,"</td>")}D.push("</tr>")}if(this.pa){D.push(
'<tr class="',this.c,'months">','<td colspan="7" id="',a,'sel"></td></tr>')}D.push("</table>");this.Q.innerHTML=D.join("");this.n=z(a+"day_0_0");this.N=z(a+"day_6_6");var b=this.n;var U=b.parentNode;var ia=null;var xa=null;var m=-1;var ja=-1;while(U!=null){++ja;if(ja==7)break;var ya=-1;while(b!=null){++m;++ya;var ka=a+"day_"+ja+"_"+ya;this.b[ka]=i[m];this.J[i[m].toString()]=b;this.F[ka]=ia;if(ia)this.t[xa]=b;ia=b;xa=ka;b=b.nextSibling}U=U.nextSibling;if(U!=null){b=U.firstChild}}this.A=7;if(!this.na)
{var Na=z(a+"week_4");var za=z(a+"week_5");var la=z(a+"week_6");if(this.b[a+"day_4_0"].month!=c){Na.style.display="none";za.style.display="none";la.style.display="none";this.A=4}else if(this.b[a+"day_5_0"].month!=c){za.style.display="none";la.style.display="none";this.A=5}else if(this.b[a+"day_6_0"].month!=c){la.style.display="none";this.A=6}}this.Fa=l;this.Ea=n;if(this.E){this.E.call(null,this)}this.Oa()}
;g.prototype.refresh=function(){if(this.E){this.E.call(null,this)}}
;g.prototype.ua=function(a){return this.ka.add(a)}
;g.prototype.Nb=function(a){return this.ka.remove(a)}
;g.prototype.u=function(a){a=arguments.length===0||a;var b=this.f.U();for(var c=0;c<b.length;++c){var d=this.J[b[c].toString()];this.C(d,false)}this.f.clear();if(!this.M){this.Ha(null);this.la(null)}if(a)this.z()}
;g.prototype.Jb=function(a){return this.f.contains(a)}
;g.prototype.Sa=function(a){if(this.xa){this.xa.call(null,a);return}var b=z(a);var c=this.f;switch(this.O){case 1:var d=this.Wa();if(d==0)break;if(d!=1&&(d!=-1||!c.contains(this.b[a]))){var e=this.b[b.id];var f;switch(d){case -1:if(c.s()>7&&this.R()){var h=b.id.substr(b.id.length-3,1);e=this.b[this.g+"day_"+h+"_0"]}f=c.s()-1;break;case 7:var h=b.id.substr(b.id.length-3,1);e=this.b[this.g+"day_"+h+"_0"];f=6;break;case 30:e=this.b[b.id];e=j.create(e.year,e.month,1);var l=Q(e);f=H(e.year,e.month)-1;
break;default:}var l=Q(e);l.date+=f;var n=l.i();this.ma(e,n);return}na(d==1||d==-1&&c.contains(this.b[a]),"not a case for single date selection");this.u(false);case 0:if(c.s()>0){var k=c.U()[0];c.remove(k);var q=this.J[k.toString()];if(q)this.C(q,false)}c.add(this.b[b.id]);this.C(b);this.z(this.b[b.id]);break;case 2:break;case 3:default:break}}
;g.prototype.Ha=function(a){this.d=a;this.I=a?this.b[a.id]:null}
;g.prototype.la=function(a){this.m=a;this.H=a?this.b[a.id]:null}
;g.prototype.fb=function(){return this.M}
;g.prototype.Vb=function(a,b){this.u(false);this.M=true;this.Ha(this.Y(a));var c=this.b[this.d.id];this.f.add(c);this.C(this.d);this.ma(c);this.la(this.d)}
;g.prototype.xb=function(a,b,c){this.M=false;this.m=this.Y(a);if(this.R()){this.z(this.I,this.H,false);return}var d,e;if(this.b[this.m.id].a()<this.b[this.d.id].a()){d=this.b[this.m.id];e=this.b[this.d.id]}else{d=this.b[this.d.id];e=this.b[this.m.id]}this.z(d,e,false)}
;g.prototype.Ib=function(a,b,c,d){this.Ca=Ea(a);if(this.O!=1||this.ba)return;this.ba=true;var e=this;setTimeout(function(){try{if(e.M){e.Va.call(e,b,c,d)}}finally{e.ba=false}}
,50)}
;g.prototype.Sb=function(a){if(this.qa==a)return;this.qa=!(!a);this.u()}
;g.prototype.R=function(){return this.qa}
;g.prototype.Va=function(a,b,c){var d=this.Ca;var e=this.Y(d);if(e===this.m)return;var f=this.m;this.la(e);var h=this.b;var l=h[f.id].a()<h[e.id].a();var n=h[f.id].a()<h[this.d.id].a();var k=h[e.id].a()<h[this.d.id].a();var q=h[this.d.id].a()<h[e.id].a();var s=h[this.d.id].a()<h[f.id].a();var u,i;var v,r;var m=k?this.m:this.d;var A=k?this.d:this.m;if(this.R()){var D=sa(h[A.id],h[m.id]);if(D>=7){var O,T;O=parseInt(m.id.charAt(m.id.length-3),10);T=parseInt(A.id.charAt(A.id.length-3),10);m=z(this.g+
"day_"+O+"_0");A=z(this.g+"day_"+T+"_6")}this.B(this.n,m,false);this.B(A,this.N,false);this.B(m,A,true);this.I=h[m.id];this.H=h[A.id]}else{if(l){if(n){i=k?this.F[e.id]:this.F[this.d.id];this.B(f,i,false)}if(q){u=s?this.t[f.id]:this.t[this.d.id];this.B(u,e,true)}}else{if(s){u=q?this.t[e.id]:this.t[this.d.id];this.B(u,f,false)}if(k){i=k?this.F[this.d.id]:this.F[f.id];this.B(e,i,true)}}}v=h[m.id];r=h[A.id];this.z(v,r,true)}
;g.prototype.B=function(a,b,c){var d=false;while(a){if(c){d=this.f.add(this.b[a.id])}else{d=this.f.remove(this.b[a.id])}if(d){this.C(a,c)}if(a.id===b.id)break;a=this.t[a.id]}}
;g.LAST_DAY_OF_WEEK={4:"day_3_6",5:"day_4_6",6:"day_5_6",7:"day_6_6"};g.prototype.Rb=function(a){if(a){this.o={};this.o.x=a.x;this.o.y=a.y}else{this.o=null}}
;g.prototype.Pa=function(a,b){if(!this.o)return;if(b){a.x-=this.o.x;a.y-=this.o.y}else{a.x+=this.o.x;a.y+=this.o.y}}
;g.prototype.Y=function(a){var b=Xa(this.n);var c=Va(this.n);var d=this.db();var e=Ja(a);this.Pa(e);var f=7;var h=this.za(d.x,b,f,e.x);var l=this.za(d.y,c,this.A,e.y);return z(this.g+"day_"+l+"_"+h)}
;g.prototype.za=function(a,b,c,d){if(d<a)return 0;var e=Math.floor((d-a)/b);return e>=c?c-1:e}
;g.prototype.db=function(){var a=this.g;var b=this.A;var c=Wa(this.n);var d=Ua(z(a+g.LAST_DAY_OF_WEEK[b]));return new L(c.x,c.y,d.x+d.w-c.x,d.y+d.h-c.y,c.coordinateFrame)}
;g.prototype.$=function(a,b){var c=b?aa:Z;return c[a.month]+" "+a.date}
;g.prototype.z=function(a,b,c){var d={};d.startDate=a;d.endDate=b||a;d.fb=!(!c);d.mode=this.aa();this.ka.Z(d)}
;g.prototype.Gb=function(){return this.j}
;g.prototype.Tb=function(a){if(a.equals(this.j))return;this.j=a;this.p()}
;g.prototype.va=function(a){if(a instanceof j)return a;if(a instanceof t){return j.create(a.year,a.month,a.date)}}
;g.prototype.Qb=function(a){this.ya=!(!a)}
;g.prototype.ma=function(a,b,c){var d=this.aa();c=c!==false;if(a)a=this.va(a);if(b)b=this.va(b);if(a)this.Ia(a);if(!a||d==3){this.u(c);return}if(d==0){this.u(false);var e=this.J[a.toString()];this.f.add(a);this.C(e);if(c)this.z(a)}else if(d==1){if(!b)b=a;var f=sa(b,a);var h=false;if(this.R()&&f>=7){var l=fa(a)+7;var n=fa(b)+7;l=(l-this.Aa())%7;n=(n-this.Aa())%7;var k;k=$(a.year,a.month,a.date-l);a=k.i();k=$(b.year,b.month,b.date+(6-n));b=k.i();h=this.Ia(a)}if(h){this.u(false)}var e=this.n;this.I=
a;this.H=b;var q=this.N;var s=a.a();var u=b.a();var i=new G;for(;e;e=this.t[e.id]){var v=this.b[e.id];var r=this.f.contains(v);var m=v.a()>=s&&v.a()<=u;if(r!=m){this.C(e,m)}if(m){i.add(v)}}this.f=i;if(this.b[q.id].a()<u){q=this.N;var k=Q(this.b[this.N.id]);var A=null;do{k.date+=1;A=k.i();this.f.add(A)}while(!A.equals(b))}if(c)this.z(a,b)}}
;g.prototype.oa=function(a,b,c){if(this.r.month==a.month&&this.r.year==a.year&&!c)return false;b=arguments.length==1||b;this.r=j.create(a.year,a.month,1);this.p();if(b)this.ga.Z();return true}
;g.prototype.Za=function(){return this.r}
;g.prototype.Ia=function(a,b){if(a.a()>=this.ta.a()&&a.a()<=this.sa.a()){return false}return this.oa(a,b)}
;g.prototype.cb=function(){switch(this.aa()){case 0:if(this.f.s()){return this.f.U()[0]}else{return null}case 1:var a=this.I?this.I:null;var b=this.H?this.H:null;if(!a||!b)return null;return[a,b];case 2:return null;case 3:default:return null}}
;g.prototype.Db=function(){return this.f.s()}
;g.prototype.jb=function(a){if(this.pa){z(this.g+"sel").innerHTML=a}}
;g.prototype.C=function(a,b){if(this.ya||!a)return;if(!(typeof b!="undefined"))b=true;var c=[];var d=[];var e=" "+a.className+" ";var f=" "+this.c;if(b){if(-1!=e.indexOf(f+"today ")){c.push(f+"today ");d.push(f+"today_selected ")}if(-1!=e.indexOf(f+"weekday ")){c.push(f+"weekday ");d.push(f+"weekday_selected ")}else if(-1!=e.indexOf(f+"weekend ")){c.push(f+"weekend ");d.push(f+"weekend_selected ")}}else{if(-1!=e.indexOf(f+"today_selected ")){d.push(f+"today ");c.push(f+"today_selected ")}if(-1!=e.indexOf(
f+"weekday_selected ")){d.push(f+"weekday ");c.push(f+"weekday_selected ")}else if(-1!=e.indexOf(f+"weekend_selected ")){d.push(f+"weekend ");c.push(f+"weekend_selected ")}}for(var h=0;h<c.length;++h){e=e.replace(c[h],d[h])}if(c.length!=0){a.className=e}}
;g.prototype.wb=function(a){this.ga.add(a)}
;g.prototype.Mb=function(a){this.ga.remove(a)}
;g.K=new Object;g.prototype.ub=function(){return this.g}
;g.staticGetPickerById=function(a){return g.K[a]}
;function Ha(a){var b=g.K[a];return b.oa(b.Fa)}
function Ga(a){var b=g.K[a];return b.oa(b.Ea)}
function Fa(a){var b=a.id;var c=b.match(/(.*)day_\d+_\d+/);var d=g.K[c[1]];return d.Sa(b)}
g.prototype.Oa=function(){if(this.hb===true)return;this.hb=true}
;g.prototype.vb=function(a){return this.fa.add(a)}
;g.prototype.Lb=function(a){return this.fa.remove(a)}
;g.prototype.log=function(){this.fa.Z(arguments)}
;g.prototype.zb=function(){return this.Q}
;function G(){this.q={};this.S=0}
G.prototype.s=function(){return this.S}
;G.prototype.add=function(a){var b=this.ra(a);if(b in this.q)return false;this.q[b]=a.i();++this.S;return true}
;G.prototype.remove=function(a){var b=this.ra(a);if(!(b in this.q))return false;delete this.q[b];--this.S;return true}
;G.prototype.clear=function(a){this.q={};this.S=0}
;G.prototype.contains=function(a){var b=this.ra(a);return b in this.q}
;G.prototype.U=function(){var a=new Array(this.s());var b=-1;for(var c in this.q)a[++b]=this.q[c];return a}
;G.prototype.ra=function(a){return a.toString().substr(0,9)}
;function J(a){this.kb=a;this.k=[]}
J.prototype.add=function(a){if(!a)return false;for(var b=0;b<this.k.length;++b){if(a===this.k[b])return false}this.k.push(a);return true}
;J.prototype.remove=function(a){if(!a)return false;for(var b=0;b<this.k.length;++b){if(a===this.k[b]){this.k.splice(b,1);return true}}return false}
;J.prototype.Z=function(){for(var a=0;a<this.k.length;++a){this.k[a].apply(this.kb,arguments)}}
;J.prototype.s=function(){return this.k.length}
;J.prototype.iterator=function(){return new V(this)}
;function V(a){this.ea=a;this.ca=0;this.v=null}
V.prototype.eb=function(){return this.ca<this.ea.s()}
;V.prototype.next=function(){if(this.eb()){this.v=this.ea.k[this.ca++]}else{this.v=null}return this.v}
;V.prototype.current=function(){return this.v}
;V.prototype.remove=function(){if(!this.v)throw new Error("no current element!");this.ea.remove(this.v);this.v=null;--this.ca}
;var x=null;function _InitializeDatePicker(a,b,c,d,e){var f=z(a);x=new g(f,false);x.qb(true);x.ob(function(){return"&laquo;"}
);x.nb(function(){return"&raquo;"}
);x.lb(b);x.Ga(1,c);x.mb(d["Sunday"]);x.ua(e);z("pickerContainer").style.display="";x.show()}
function _DatePickerSetSelection(a){x.ma(a)}
function _DatePickerGetSelection(){return x.cb()}
function _DatePickerGetDateForCell(a){return x.Xa(a)}
function _DatePickerGetMonths(){return x.bb()}
function _DatePickerGetFirstDate(){return x.$a()}
function _DatePickerGetLastDate(){return x.ab()}
function _DatePickerPopulateHtml(){return x.p()}
function _DatePickerIsVisible(){return x.gb()}
function _DatePickerGetDisplayedMonth(){return x.Za()}
function _ICAL_Date_create(a,b,c){return j.create(a,b,c)}
function _ICAL_ToDate(a){return a.i()}
function _ICAL_GetComparable(a){return a.a()}
var _ICAL_DateTime=t;var _forid=z;var _ICAL_todaysDate=S;var _ical_builderCopy=Q;var _ToJSString=ma;
+457
View File
@@ -0,0 +1,457 @@
<html>
<head>
<title>Google Calendar AuthSub demo</title>
<!--
This is the page that uses the AuthSub token retrieved from Google for the
respective user. The web service will redirect to this page once an
AuthSub token has been successfully retrieved.
This page makes the following assumptions:
- User has been assigned an login cookie by the web service
- The web service has retrieved from Google a valid AuthSub token for the
respective user
This page displays a calendar widget. The widget is populated with
information retrieved from Google Calendar using the user's private default
feed.
Note: The URL is secured on the server using the token generated in the
formProxyFeedUrl() function.
-->
<link rel="stylesheet" type="text/css" href="css/google.css">
<link rel="stylesheet" type="text/css" href="css/frameless.css">
<!--[if IE]>
<link rel="stylesheet" type="text/css" href="css/ieonly.css" />
<![endif]-->
<link href="css/datepicker.css" type="text/css" rel="stylesheet">
<link href="css/pbox.css" type="text/css" rel="stylesheet">
<script language="JavaScript" type="text/javascript"
src="javascript/util.js" ></script>
<script language="JavaScript" type="text/javascript"
src="javascript/gdata_condensed.js" ></script>
<script language="JavaScript" type="text/javascript">
var dateData = {};
var firstDayMap = {
Sunday : 0,
Monday : 1,
Saturday : 6
};
// The following function generates the URL for the proxy. A secure token
// is first generated using JSP. The token is appended as a query
// parameter to the RetrieveFeed request
function formProxyFeedUrl() {
<%
String feedUrl = (String)(request.getSession(false)).getAttribute("feedRootUrl")
+ "default/private/full";
// Secure the URL by generating a secure token before sending the request
// to the proxy server
long currentTimeSeconds = ((new java.util.Date()).getTime()) / 1000;
String cookie = sample.authsub.src.Utility.getCookieValueWithName(
request.getCookies(), sample.authsub.src.Utility.LOGIN_COOKIE_NAME);
String token = sample.authsub.src.SecureUrl.generateToken(cookie,
feedUrl,
"GET",
currentTimeSeconds);
// Pass values to javascript
feedUrl = "\"" + feedUrl + "\"";
token = "\"" + token + "\"";
%>
return "/authsub_sample/RetrieveFeedServlet?href=\"" + <%=feedUrl%>
+ "\"&timestamp=\"" + <%=currentTimeSeconds%> + "\"&token=\"" +
<%=token%> +"\"";
}
// @param date {ICAL_Date}
// @return {GD_Entry[]} entries for date, sorted
function getEntriesFor(date) {
var data = dateData[date];
var entries = [];
for (var e in data) entries.push(data[e]);
entries.sort(compareEntry);
return entries;
}
// a before b <=> -1
// @param a {GD_Entry}
// @param b {GD_Entry}
// @return {number} satisfying "Comparable" contract for GD_Entry
function compareEntry(a, b) {
var cmp = IsAllDay(b) - IsAllDay(a);
if (cmp) return cmp;
cmp = _ICAL_GetComparable(parseTemporal(a.getStartTime())) -
_ICAL_GetComparable(parseTemporal(b.getStartTime()));
if (cmp) return cmp;
var at = a.getTitle(), bt = b.getTitle();
if (at < bt) return -1;
return (at == bt) ? 0 : 1;
}
function AgendaPopup() {
this.div_ = _forid('agendaDiv');
document.body.appendChild(this.div_);
this.isVisible_ = false;
}
// @param date {ICAL_Date}
// @param cell {Element}
AgendaPopup.prototype.show = function(date, cell) {
_DatePickerSetSelection(date);
}
function _OpenUrl(url) {
open(url, "_BLANK");
}
var HOVER_LINK_JS = ' onmouseout="this.style.textDecoration=\'none\'" ' +
'onmouseover="this.style.textDecoration=\'underline\'" ';
// @param date {ICAL_Date}
// @param entry {GD_Entry}
// @param html {string[]}
function AddEventHtml(date, entry, html) {
html.push("<TR>");
var title = entry.getTitle();
if (IsAllDay(entry)) {
html.push('<TD colspan="2" ',
'style="background-color:#668CD9; color:white; width:100%">');
} else {
html.push('<TD style="text-align: right;" class="eventChip">');
var titlePrefix = "";
var startDateTime = parseDateTime(entry.getStartTime());
if (_ICAL_ToDate(startDateTime).equals(date)) {
// event starts today! show start time
titlePrefix = HumanTime(startDateTime) + "&nbsp;";
} else {
}
html.push(titlePrefix, '</TD><TD style="width:100%">');
}
var onclick = "\"_OpenUrl(" + _ToJSString(entry.getEventPageUrl()) + ")\"";
html.push('<SPAN onclick=', onclick, HOVER_LINK_JS,
'style="cursor:pointer" class="eventChip">', title, '</SPAN>');
html.push("</TD></TR>");
}
var gAgendaPopup;
function _GetAgendaPopup() {
if (!gAgendaPopup) gAgendaPopup = new AgendaPopup();
return gAgendaPopup;
}
// @param cellId {string}
function popupAgenda(cellId) {
var cell = _forid(cellId);
var dt = _DatePickerGetDateForCell(cell);
_GetAgendaPopup().show(dt, cell);
}
// authentication token for reading XAPI feeds
var token;
// @param start {ICAL_Date}
// @param end {ICAL_Date}
function calendarInlineDecorator(start, end) {
var decs = {};
var builder = _ical_builderCopy(start);
for (var dt = _ICAL_ToDate(builder);
_ICAL_GetComparable(dt) <= _ICAL_GetComparable(end);
builder.date += 1, dt = _ICAL_ToDate(builder)) {
var str = dt.toString();
if (str in dateData) decs[str] = 'font-weight:bold';
}
return decs;
}
// @param date {ICAL_Date}
// @return {string} XAPI Date
function formatDate(date) {
var m = date.month;
if (m < 10) m = "0" + m;
var d = date.date;
if (d < 10) d = "0" + d;
return date.year + "-" + m + "-" + d;
}
// @param date {ICAL_Date}
// @return mm dd[, yyyy]
function HumanDate(date) {
var humanDate = _DatePickerGetMonths()[date.month] + " " + date.date;
if (_ICAL_todaysDate.year !== date.year) {
humanDate += ", " + date.year;
}
return humanDate;
}
// @param time {ICAL_DateTime}
// @return hh:mm{a,p}m
function HumanTime(time) {
var h = time.hour;
var m = time.minute;
if (m < 10) m = "0" + m;
var a = (h < 12) ? "am" : "pm";
if (h > 12) {
h -= 12;
} else if (h === 0) {
h = 12;
}
return h + ":" + m + a;
}
// @param yyyy_mm_dd_date {string}
function parseDate(yyyy_mm_dd_date) {
var parts = yyyy_mm_dd_date.substring(0, 10).split('-');
for (var i = 0; i < 3; ++i) {
parts[i] = parseInt(parts[i], 10);
}
return _ICAL_Date_create(parts[0], parts[1], parts[2]);
}
function parseDateTime(str) {
var m = str.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/);
for(var i = 1; i < 7; ++i) {
m[i] = parseInt(m[i], 10);
}
return new _ICAL_DateTime(m[1], m[2], m[3], m[4], m[5], m[6]);
}
function parseTemporal(str) {
if (str.length === 10) return parseDate(str);
return parseDateTime(str);
}
// @param month {ICAL_Date}
function loadEventsForMonth(month) {
loadEventsForRange(_DatePickerGetFirstDate(), _DatePickerGetLastDate());
}
// @param start {ICAL_Date}
// @param end {ICAL_Date}
function loadEventsForRange(start, end) {
loadFeed(formatDate(start), formatDate(end));
}
function IsAllDay(entry) {
if ('allday' in entry) return entry.allday;
var allday = (entry.getStartTime().length == 10);
return (entry.allday = allday);
}
// @param start {string}
// @param end {string}
function loadFeed(start, end) {
var feedUrl = formProxyFeedUrl();
new GD_EventFeed(feedUrl, createLoadFeedCallback());
}
function createLoadFeedCallback() {
return function(feed) {
var entries = feed.getEntries();
for (var i = 0; i < entries.length; ++i) {
var entry = entries[i];
var status = entry.getEventStatus();
if (status == GD_EventEntry.CANCELED) continue;
var startTime = entry.getStartTime();
var endTime = entry.getEndTime();
var startDate = parseDate(startTime);
var endDate = parseDate(endTime);
var endDateCmp;
var builder;
if (IsAllDay(entry)) {
endDateCmp = _ICAL_GetComparable(endDate);
} else {
builder = _ical_builderCopy(endDate);
builder.date += 1;
endDateCmp = _ICAL_GetComparable(_ICAL_ToDate(builder));
}
builder = _ical_builderCopy(startDate);
for (var dt = _ICAL_ToDate(builder);
_ICAL_GetComparable(dt) < endDateCmp;
builder.date += 1, dt = _ICAL_ToDate(builder)) {
var events;
if (dt in dateData) {
events = dateData[dt];
} else {
events = {};
dateData[dt] = events;
}
events[entry.getId()] = entry;
}
}
_DatePickerPopulateHtml();
}
}
function firstLoad() {
if (_DatePickerIsVisible()) {
loadEventsForMonth(_DatePickerGetDisplayedMonth());
} else {
var today = _ICAL_todaysDate;
var builder = _ical_builderCopy(_ICAL_todaysDate);
var start, end;
builder.date -= 14;
start = _ICAL_ToDate(builder);
builder.date += 28;
end = _ICAL_ToDate(builder);
// load 2 weeks before and after the current date
loadEventsForRange(start, end);
}
_nav(0);
}
/**
* Navigate the current selection on the datepicker.
* @param period {int} must be -1, 0, or 1;
* corresponds to previous day, today, next day
*/
function _nav(period) {
if (period === 0) {
// go to today
_DatePickerSetSelection(_ICAL_todaysDate);
} else {
var selectedDate = _DatePickerGetSelection();
var builder = _ical_builderCopy(selectedDate);
builder.date += period;
_DatePickerSetSelection(_ICAL_ToDate(builder));
}
}
function handleDatePickerSelection(event) {
populateAgenda(event.startDate);
}
var gAgendaInitialized = false;
/**
* Initializes the agenda view.
*/
function initAgenda() {
if (!gAgendaInitialized) {
_forid('prevB').src = "images/btn_prev.gif";
_forid('nextB').src = "images/btn_next.gif";
_forid('agenda').style.display = ''; // block
gAgendaInitialized = true;
}
return true;
}
function populateAgenda(opt_date) {
if (!initAgenda()) return;
var date = opt_date || _ICAL_todaysDate;
var entries = getEntriesFor(date);
var html = [];
if (entries.length) {
for (var i = 0; i < entries.length; ++i) {
var entry = entries[i];
AddEventHtml(date, entry, html);
}
} else {
html.push("<TR><TD><I>Nothing to do today!</I></TD></TR>");
}
_forid('selectedDate').innerHTML = HumanDate(date);
_forid('agendaTable').innerHTML = html.join("");
}
function MyOnLoad() {
_InitializeDatePicker('picker', calendarInlineDecorator, popupAgenda,
firstDayMap, handleDatePickerSelection);
firstLoad();
}
</script>
</head>
<body onload="MyOnLoad()">
<div class="leftcontent">
<p class="topimage">
<a href="http://www.google.com/">
<img src="http://www.google.com/images/google_sm.gif" border="0"
alt="Return to Google homepage" /></a></p>
</div>
<div class="rightcontent">
<p class=title>Google AuthSub Demo </p>
<div class="content">
<h1>Google AuthSub Demo</h1>
<p>This page demonstrates a basic version of AuthSub in action.</p>
<p>The AuthSub token is first retrieved from Google and then used
to retrieve your Calendar feed.
</p>
<center>
<table width="65%" border="3">
<tr>
<td height="100%" valign="top">
<center>
<div id="pickerContainer" align="center" style="display:none; width: 13em">
<div id="picker"></div>
</div>
</center>
</td>
</tr>
<tr>
<td height="100%" valign="top">
<center>
<div id="agenda" style="display:none">
<table width="100%" cellspacing="0" cellpadding="0" id="navButtons"><tr>
<td><div align="center" valign="middle">
<img id="prevB" width="33px" height="17px" onmousedown="_nav(-1)"></div></td>
<td><div align="center" valign="middle">
<img id="nextB" width="33px" height="17px" onmousedown="_nav(1)"></div></td>
<td><div align="center" valign="middle">
<button id="todayB" onmousedown="_nav(0)">Today</button></div></td>
<td id="selectedDate" style="padding-left: 1em; font-weight: bold;"></td>
</tr></table>
<table width="100%" id="agendaTable" cellspacing="1"></table>
</div>
</center>
</td>
</tr>
</table>
</center>
<div id="agendaDiv"
style="display:none; position:absolute; width: 20em; background-color: #666666;
padding: 3px 0px 2px 0px; font-size: 83%">
<div style="border: 1px solid gray; background-color:white; width: 100%; margin: -6px 0 0 -4px;">
</div>
</div>
</div>
</div>
<div class="leftcontent">
<p class="footerimage"><img src="http://www.google.com/images/art.gif"></p>
</div>
<div class="rightcontent">
<p><img src="http://www.google.com/images/cleardot.gif" width="1" height="45"></p>
</div>
</body>
</html>
@@ -0,0 +1,426 @@
/* 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.blogger;
import com.google.gdata.client.Query;
import com.google.gdata.client.blogger.BloggerService;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Entry;
import com.google.gdata.data.Feed;
import com.google.gdata.data.Person;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.TextContent;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.URL;
/**
* Demonstrates how to use the Google Data API's Java client library to
* interface with the Blogger service. There are examples for the following
* operations:
*
* <ol>
* <li>Retrieving the list of all the user's blogs</li>
* <li>Retrieving all posts on a single blog</li>
* <li>Performing a date-range query for posts on a blog</li>
* <li>Creating draft posts and publishing posts</li>
* <li>Updating posts</li>
* <li>Retrieving comments</li>
* <li>Deleting posts</li>
* </ol>
*
*
*/
public class BloggerClient {
private static final String METAFEED_URL =
"http://www.blogger.com/feeds/default/blogs";
private static final String FEED_URI_BASE = "http://www.blogger.com/feeds";
private static final String POSTS_FEED_URI_SUFFIX = "/posts/default";
private static final String COMMENTS_FEED_URI_SUFFIX = "/comments/default";
private static String feedUri;
/**
* Utility classes should not have a public or default constructor.
*/
private BloggerClient() {
// do nothing
}
/**
* Parses the metafeed to get the blog ID for the authenticated user's default
* blog.
*
* @param myService An authenticated GoogleService object.
* @return A String representation of the blog's ID.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If the URL is malformed.
*/
private static String getBlogId(BloggerService myService)
throws ServiceException, IOException {
// Get the metafeed
final URL feedUrl = new URL(METAFEED_URL);
Feed resultFeed = myService.getFeed(feedUrl, Feed.class);
// If the user has a blog then return the id (which comes after 'blog-')
if (resultFeed.getEntries().size() > 0) {
Entry entry = resultFeed.getEntries().get(0);
return entry.getId().split("blog-")[1];
}
throw new IOException("User has no blogs!");
}
/**
* Prints a list of all the user's blogs.
*
* @param myService An authenticated GoogleService object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If the URL is malformed.
*/
public static void printUserBlogs(BloggerService myService)
throws ServiceException, IOException {
// Request the feed
final URL feedUrl = new URL(METAFEED_URL);
Feed resultFeed = myService.getFeed(feedUrl, Feed.class);
// Print the results
System.out.println(resultFeed.getTitle().getPlainText());
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
Entry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Creates a new post on a blog. The new post can be stored as a draft or
* published based on the value of the isDraft paramter. The method creates an
* Entry for the new post using the title, content, authorName and isDraft
* parameters. Then it uses the given GoogleService to insert the new post. If
* the insertion is successful, the added post will be returned.
*
* @param myService An authenticated GoogleService object.
* @param title Text for the title of the post to create.
* @param content Text for the content of the post to create.
* @param authorName Display name of the author of the post.
* @param userName username of the author of the post.
* @param isDraft True to save the post as a draft, False to publish the post.
* @return An Entry containing the newly-created post.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If the URL is malformed.
*/
public static Entry createPost(BloggerService myService, String title,
String content, String authorName, String userName, Boolean isDraft)
throws ServiceException, IOException {
// Create the entry to insert
Entry myEntry = new Entry();
myEntry.setTitle(new PlainTextConstruct(title));
myEntry.setContent(new PlainTextConstruct(content));
Person author = new Person(authorName, null, userName);
myEntry.getAuthors().add(author);
myEntry.setDraft(isDraft);
// Ask the service to insert the new entry
URL postUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX);
return myService.insert(postUrl, myEntry);
}
/**
* Displays the titles of all the posts in a blog. First it requests the posts
* feed for the blogs and then is prints the results.
*
* @param myService An authenticated GoogleService object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If the URL is malformed.
*/
public static void printAllPosts(BloggerService myService)
throws ServiceException, IOException {
// Request the feed
URL feedUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX);
Feed resultFeed = myService.getFeed(feedUrl, Feed.class);
// Print the results
System.out.println(resultFeed.getTitle().getPlainText());
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
Entry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Displays the title and modification time for any posts that have been
* created or updated in the period between the startTime and endTime
* parameters. The method creates the query, submits it to the GoogleService,
* then displays the results.
*
* Note that while the startTime is inclusive, the endTime is exclusive, so
* specifying an endTime of '2007-7-1' will include those posts up until
* 2007-6-30 11:59:59PM.
*
* @param myService An authenticated GoogleService object.
* @param startTime DateTime object specifying the beginning of the search
* period (inclusive).
* @param endTime DateTime object specifying the end of the search period
* (exclusive).
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If the URL is malformed.
*/
public static void printDateRangeQueryResults(BloggerService myService,
DateTime startTime, DateTime endTime) throws ServiceException,
IOException {
// Create query and submit a request
URL feedUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX);
Query myQuery = new Query(feedUrl);
myQuery.setUpdatedMin(startTime);
myQuery.setUpdatedMax(endTime);
Feed resultFeed = myService.query(myQuery, Feed.class);
// Print the results
System.out.println(resultFeed.getTitle().getPlainText() + " posts between "
+ startTime + " and " + endTime);
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
Entry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
System.out.println("\t" + entry.getUpdated().toStringRfc822());
}
System.out.println();
}
/**
* Updates the title of the given post. The Entry object is updated with the
* new title, then a request is sent to the GoogleService. If the insertion is
* successful, the updated post will be returned.
*
* Note that other characteristics of the post can also be modified by
* updating the values of the entry object before submitting the request.
*
* @param myService An authenticated GoogleService object.
* @param entryToUpdate An Entry containing the post to update.
* @param newTitle Text to use for the post's new title.
* @return An Entry containing the newly-updated post.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If the URL is malformed.
*/
public static Entry updatePostTitle(BloggerService myService,
Entry entryToUpdate, String newTitle) throws ServiceException,
IOException {
entryToUpdate.setTitle(new PlainTextConstruct(newTitle));
URL editUrl = new URL(entryToUpdate.getEditLink().getHref());
return myService.update(editUrl, entryToUpdate);
}
/**
* Adds a comment to the specified post. First the comment feed's URI is built
* using the given post ID. Then an Entry is created for the comment and
* submitted to the GoogleService.
*
* NOTE: This functionality is not officially supported yet.
*
* @param myService An authenticated GoogleService object.
* @param postId The ID of the post to comment on.
* @param commentText Text to store in the comment.
* @return An entry containing the newly-created comment.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If the URL is malformed.
*/
public static Entry createComment(BloggerService myService, String postId,
String commentText) throws ServiceException, IOException {
// Build the comment feed URI
String commentsFeedUri = feedUri + "/" + postId + COMMENTS_FEED_URI_SUFFIX;
URL feedUrl = new URL(commentsFeedUri);
// Create a new entry for the comment and submit it to the GoogleService
Entry myEntry = new Entry();
myEntry.setContent(new PlainTextConstruct(commentText));
return myService.insert(feedUrl, myEntry);
}
/**
* Displays all the comments for the given post. First the comment feed's URI
* is built using the given post ID. Then the method requests the comments
* feed and displays the results.
*
* @param myService An authenticated GoogleService object.
* @param postId The ID of the post to view comments on.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If there is an error communicating with the server.
*/
public static void printAllComments(BloggerService myService, String postId)
throws ServiceException, IOException {
// Build comment feed URI and request comments on the specified post
String commentsFeedUri = feedUri + "/" + postId + COMMENTS_FEED_URI_SUFFIX;
URL feedUrl = new URL(commentsFeedUri);
Feed resultFeed = myService.getFeed(feedUrl, Feed.class);
// Display the results
System.out.println(resultFeed.getTitle().getPlainText());
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
Entry entry = resultFeed.getEntries().get(i);
System.out.println("\t" +
((TextContent) entry.getContent()).getContent().getPlainText());
System.out.println("\t" + entry.getUpdated().toStringRfc822());
}
System.out.println();
}
/**
* Removes the comment specified by the given editLinkHref.
*
* @param myService An authenticated GoogleService object.
* @param editLinkHref The URI given for editing the comment.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If there is an error communicating with the server.
*/
public static void deleteComment(BloggerService myService, String editLinkHref)
throws ServiceException, IOException {
URL deleteUrl = new URL(editLinkHref);
myService.delete(deleteUrl);
}
/**
* Removes the post specified by the given editLinkHref.
*
* @param myService An authenticated GoogleService object.
* @param editLinkHref The URI given for editing the post.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If there is an error communicating with the server.
*/
public static void deletePost(BloggerService myService, String editLinkHref)
throws ServiceException, IOException {
URL deleteUrl = new URL(editLinkHref);
myService.delete(deleteUrl);
}
/**
* Runs through all the examples using the given GoogleService instance.
*
* @param myService An authenticated GoogleService object.
* @param userName username of user to authenticate (e.g. jdoe@gmail.com).
* @param userPassword password to use for authentication.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException If there is an error communicating with the server.
*/
public static void run(BloggerService myService, String userName,
String userPassword) throws ServiceException, IOException {
// Authenticate using ClientLogin
myService.setUserCredentials(userName, userPassword);
// Get the blog ID from the metatfeed.
String blogId = getBlogId(myService);
feedUri = FEED_URI_BASE + "/" + blogId;
// Demonstrate retrieving a list of the user's blogs.
printUserBlogs(myService);
// Demonstrate how to create a draft post.
Entry draftPost = createPost(myService, "Snorkling in Aruba",
"<p>We had so much fun snorkling in Aruba<p>", "Post author", userName,
true);
System.out.println("Successfully created draft post: "
+ draftPost.getTitle().getPlainText());
// Demonstrate how to publish a public post.
Entry publicPost = createPost(myService, "Back from vacation",
"<p>I didn't want to leave Aruba, but I ran out of money :(<p>",
"Post author", userName, false);
System.out.println("Successfully created public post: "
+ publicPost.getTitle().getPlainText());
// Demonstrate various feed queries.
printAllPosts(myService);
printDateRangeQueryResults(myService, DateTime.parseDate("2007-04-04"),
DateTime.parseDate("2007-04-06"));
// Demonstrate two ways of updating posts.
draftPost.setTitle(new PlainTextConstruct("Swimming with the fish"));
draftPost.update();
System.out.println("Post's new title is \""
+ draftPost.getTitle().getPlainText() + "\".\n");
publicPost = updatePostTitle(myService, publicPost, "The party's over");
System.out.println("Post's new title is \""
+ publicPost.getTitle().getPlainText() + "\".\n");
// Demonstrate how to add a comment on a post
// Get the post ID and build the comments feed URI for the specified post
System.out.println("Creating comment");
String selfLinkHref = publicPost.getSelfLink().getHref();
String[] tokens = selfLinkHref.split("/");
String postId = tokens[tokens.length - 1];
Entry comment = createComment(myService, postId, "Did you see any sharks?");
// Demonstrate how to retrieve the comments for a post
printAllComments(myService, postId);
// Demonstrate how to delete a comment from a post
System.out.println("Deleting comment");
deleteComment(myService, comment.getEditLink().getHref());
// Demonstrate two ways of deleting posts.
System.out.println("Deleting draft post");
draftPost.delete();
System.out.println("Deleting published post");
deletePost(myService, publicPost.getEditLink().getHref());
}
/**
* Uses the command line arguments to authenticate the GoogleService and build
* the basic feed URI, then invokes all the other methods to demonstrate how
* to interface with the Blogger service.
*
* @param args See the usage method.
*/
public static void main(String[] args) {
// Set username, password and feed URI from command-line arguments.
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String userName = parser.getValue("username", "user", "u");
String userPassword = parser.getValue("password", "pass", "p");
boolean help = parser.containsKey("help", "h");
if (help || (userName == null) || (userPassword == null)) {
usage();
System.exit(1);
}
BloggerService myService = new BloggerService("exampleCo-exampleApp-1");
try {
run(myService, userName, userPassword);
} catch (ServiceException se) {
se.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Prints the command line usage of this sample application.
*/
private static void usage() {
System.out.println("Usage: BloggerClient --username <username>"
+ " --password <password>");
System.out.println("\nA simple application that creates, queries,\n"
+ "updates and deletes posts and comments on the\n"
+ "specified blog using the provided username and\n"
+ "password for authentication.");
}
}
+19
View File
@@ -0,0 +1,19 @@
Google Blogger data API Java Sample - README.txt
-------------------------------------------------
The Java Blogger sample is a simple application that shows sample usage to
create/read/update/delete data on Blogger using the GData Java client
library.
The application can be built and run using the provided Ant build file found at
gdata/java/build-samples.xml. The sample can be run in the following manner:
1. Edit gdata/java/build-samples/build.properties to enter your
Google Account username and password with which you want to test the sample.
2. Invoke the sample using the following commandline:
ant -f gdata/java/build-samples.xml sample.blogger.run
NOTE: This sample will insert, update, and delete blog entries using the
read-write feed. When finished, the sample will clean up after itself.
Binary file not shown.
+471
View File
@@ -0,0 +1,471 @@
/* 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.books;
import com.google.gdata.client.Service;
import com.google.gdata.client.books.BooksService;
import com.google.gdata.client.books.VolumeQuery;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.data.Category;
import com.google.gdata.data.books.BooksCategory;
import com.google.gdata.data.books.VolumeEntry;
import com.google.gdata.data.books.VolumeFeed;
import com.google.gdata.data.dublincore.Creator;
import com.google.gdata.data.dublincore.Title;
import com.google.gdata.data.extensions.Rating;
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.net.URL;
import java.util.List;
/**
* Demonstrates Books API operations using the Java client library.
*/
public class BooksClient {
protected BooksClient() {}
/**
* Input stream for reading user input.
*/
private static final BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(System.in));
/**
* The name of the server hosting the YouTube GDATA feeds.
*/
public static final String BOOKS_GDATA_SERVER = "http://books.google.com";
/**
* The URL of the volumes feed
*/
public static final String VOLUMES_FEED = BOOKS_GDATA_SERVER
+ "/books/feeds/volumes";
/**
* The URL of the user library feeds
*/
public static final String USER_LIBRARY_FEED = BOOKS_GDATA_SERVER
+ "/books/feeds/users/me/collections/library/volumes";
/**
* The URL of the user annotation feed
*/
public static final String USER_ANNOTATION_FEED = BOOKS_GDATA_SERVER
+ "/books/feeds/users/me/volumes";
/**
* Searches the VOLUMES_FEED for search terms and print each resulting
* VolumeEntry.
*
* @param service a BooksService object.
* @param authenticated whether the user is authenticated.
* @throws ServiceException
* If the service is unable to handle the request.
* @throws IOException error sending request or reading the feed.
*/
private static void searchVolumes(BooksService service,
boolean authenticated)
throws IOException, ServiceException {
VolumeQuery query = new VolumeQuery(new URL(VOLUMES_FEED));
// exclude no-preview book (by default, they are included)
query.setMinViewability(VolumeQuery.MinViewability.PARTIAL);
System.out.println("\nEnter search terms: ");
String searchTerms = readLine();
System.out.println();
query.setFullTextQuery(searchTerms);
printUnderlined("Running Search for '" + searchTerms + "'");
VolumeFeed volumeFeed = service.query(query, VolumeFeed.class);
printVolumeFeed(volumeFeed);
if (authenticated) {
handleSearchVolumes(service, volumeFeed);
}
}
/**
* Handle options after displaying a search feed, specifically reviewing or
* adding to the user's library.
*
* @param service a BooksService object.
* @param volumeFeed a volume feed object.
* @throws ServiceException
* If the service is unable to handle the request.
* @throws IOException error sending request or reading the feed.
*/
private static void handleSearchVolumes(BooksService service,
VolumeFeed volumeFeed)
throws IOException, ServiceException {
while (true) {
System.out.println("\nWhat would you like to do?");
System.out.println("\t1) Add a volume to my library");
System.out.println("\t2) Submit a rating for a volume");
System.out.println("\t0) Back to main menu");
System.out.println("\nEnter Number (0-2): ");
int choice = readInt();
String volumeId;
switch (choice) {
case 1:
volumeId = readVolumeId(volumeFeed);
if (!volumeId.equals("")) {
addToLibrary(service, volumeId);
}
break;
case 2:
volumeId = readVolumeId(volumeFeed);
System.out.println("Please input a rating value (1-5)");
int rating = readInt();
if (rating >= 1 && rating <= 5 && !volumeId.equals("")) {
addRating(service, volumeId, rating);
}
break;
case 0:
default:
return;
}
}
}
/**
* Prints a String, a newline, and a number of '-' characters equal to the
* String's length.
*
* @param stringToUnderline - the string to print underlined
*/
private static void printUnderlined(String stringToUnderline) {
System.out.println(stringToUnderline);
for (int i = 0; i < stringToUnderline.length(); ++i) {
System.out.print("-");
}
System.out.println("\n");
}
/**
* Adds a volume to the user's library
*
* @param service a BooksService object.
* @param volumeId The volume id to insert
* @throws IOException Error sending request or reading the feed.
* @throws ServiceException If the service is unable to handle the request.
*/
private static void addToLibrary(BooksService service, String volumeId)
throws IOException, ServiceException {
VolumeEntry newEntry = new VolumeEntry();
newEntry.setId(volumeId);
try {
service.insert(new URL(USER_LIBRARY_FEED), newEntry);
} catch (ServiceException se) {
System.out.println("There was an error adding your volume.\n");
return;
}
System.out.println("Added " + volumeId);
}
/**
* Adds a rating for a volume
*
* @param service a BooksService object.
* @param volumeId The volume id to rate
* @param value The rating to insert
* @throws IOException Error sending request or reading the feed.
* @throws ServiceException If the service is unable to handle the request.
*/
private static void addRating(BooksService service,
String volumeId, int value)
throws IOException, ServiceException {
VolumeEntry newEntry = new VolumeEntry();
newEntry.setId(volumeId);
Rating rating = new Rating();
rating.setMin(1);
rating.setMax(5);
rating.setValue(value);
newEntry.setRating(rating);
try {
service.insert(new URL(USER_ANNOTATION_FEED), newEntry);
} catch (ServiceException se) {
System.out.println("There was an error adding your rating.\n");
return;
}
System.out.println("Added rating for " + volumeId);
}
/**
* Prints a VolumeEntry
*
* @param entry The VolumeEntry to be printed
* @throws IOException Error sending request or reading the feed.
* @throws ServiceException If the service is unable to handle the request.
*/
private static void printVolumeEntry(VolumeEntry entry) throws IOException,
ServiceException {
System.out.print("Title: ");
for (Title t : entry.getTitles()) {
System.out.print(t.getValue() + "\t");
}
System.out.println();
System.out.print("Author: ");
for (Creator c : entry.getCreators()) {
System.out.print(c.getValue() + "\t");
}
System.out.println();
if (entry.hasRating()) {
System.out.println("Rating: " + entry.getRating().getAverage());
}
if (entry.hasReview()) {
System.out.println("Review: " + entry.getReview().getValue());
}
boolean firstLabel = true;
if (entry.getCategories().size() > 0) {
for (Category c : entry.getCategories()) {
if (c.getScheme() == BooksCategory.Scheme.LABELS_SCHEME) {
if (firstLabel) {
System.out.print("Labels: ");
firstLabel = false;
}
System.out.print(c.getTerm() + "\t");
}
}
if (!firstLabel) {
System.out.println();
}
}
if (entry.hasViewability()) {
System.out.println("Viewability: " + entry.getViewability().getValue());
}
System.out.println();
}
/**
* Show the feed of user annotations.
*
* @param service A BooksService object.
* @throws IOException Error sending request or reading the feed.
* @throws ServiceException If the service is unable to handle the request.
*/
private static void showUserAnnotations(Service service)
throws IOException, ServiceException {
VolumeFeed volumeFeed = service.getFeed(new URL(USER_ANNOTATION_FEED),
VolumeFeed.class);
printVolumeFeed(volumeFeed);
}
/**
* Show the feed of user annotations.
*
* @param service A BooksService object.
* @throws IOException Error sending request or reading the feed.
* @throws ServiceException If the service is unable to handle the request.
*/
private static void showUserLibrary(Service service)
throws IOException, ServiceException {
VolumeFeed volumeFeed = service.getFeed(new URL(USER_LIBRARY_FEED),
VolumeFeed.class);
printVolumeFeed(volumeFeed);
}
/**
* Reads a line of text from the standard input.
*
* @throws IOException If unable to read a line from the standard input.
* @return A line of text read from the standard input.
*/
private static String readLine() throws IOException {
return bufferedReader.readLine();
}
/**
* Reads a line of text from the standard input and returns the parsed
* integer representation.
*
* @throws IOException If unable to read a line from the standard input.
* @return An integer read from the standard input.
*/
private static int readInt() throws IOException {
String input = readLine();
try {
return Integer.parseInt(input);
} catch (NumberFormatException nfe) {
return 0;
}
}
/**
* Solicits the user for the index of a volume in a list
*
* @param volumeFeed A volume Feed.
* @return String containing a volume ID.
* @throws IOException If there are problems reading user input.
*/
private static String readVolumeId(VolumeFeed volumeFeed) throws IOException {
System.out.println("Input the index of one of the volumes listed above (1-"
+ volumeFeed.getEntries().size() + ")");
int input = readInt();
if (input == 0) {
return "";
}
return volumeFeed.getEntries().get(input - 1).getId();
}
/**
* Displays a menu of the main activities a user can perform.
*/
private static void printMenu() {
System.out.println("\n");
System.out.println("Choose one of the following demo options:");
System.out.println("\t1) Search for books");
System.out.println("\t2) My list of books (requires authentication)");
System.out.println("\t3) My annotations (requires authentication)");
System.out.println("\t0) Exit");
System.out.println("\nEnter Number (0-3): ");
}
/**
* Shows the usage of how to run the sample from the command-line.
*/
private static void printUsage() {
System.out.println("Usage:\n java BooksClient.jar");
System.out.println("or with authentication:\n java BooksClient.jar "
+ " --username <user@gmail.com> " + " --password <pass> ");
}
/**
* Print a volume feed of entries as a numbered list
*
* @param volumeFeed A feed of volumes
* @throws IOException Error sending request or reading the feed.
* @throws ServiceException If the service is unable to handle the request.
*/
private static void printVolumeFeed(VolumeFeed volumeFeed)
throws IOException, ServiceException {
String title = volumeFeed.getTitle().getPlainText();
System.out.println(title);
List<VolumeEntry> volumeEntries = volumeFeed.getEntries();
if (volumeEntries.size() == 0) {
System.out.println("This feed contains no entries.");
return;
}
System.out.println("Results " + volumeFeed.getStartIndex() + " - " +
(volumeFeed.getStartIndex() + volumeEntries.size() - 1) +
" of " + volumeFeed.getTotalResults());
System.out.println();
int count = 1;
for (VolumeEntry entry : volumeEntries) {
System.out.println("(Volume #" + String.valueOf(count) + ")");
printVolumeEntry(entry);
count++;
}
System.out.println();
}
/**
* BooksClient is a sample command line application that
* demonstrates many features of the Books Data API using the Java Client
* library.
*
* This sample demonstrates both search and social activities in the API.
* Social activities are only available to authenticated users.
*
* @param args Used to pass the username and password of a test account.
*/
public static void main(String[] args) {
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");
boolean authenticated = (username != null) && (password != null);
if (help) {
printUsage();
System.exit(1);
}
BooksService service = new BooksService("gdataSample-Books-1");
if (authenticated) {
try {
service.setUserCredentials(username, password);
} catch (AuthenticationException e) {
System.out.println("Invalid login credentials.");
System.exit(1);
}
}
while (true) {
try {
printMenu();
int choice = readInt();
switch (choice) {
case 1:
// Search for books
searchVolumes(service, authenticated);
break;
case 2:
// View the user's library
if (authenticated) {
showUserLibrary(service);
} else {
System.out.println("You need to specify a user account");
printUsage();
}
break;
case 3:
// View the user's annotations
if (authenticated) {
showUserAnnotations(service);
} else {
System.out.println("You need to specify a user account");
printUsage();
}
break;
case 0:
default:
System.out.println("Bye!");
System.exit(0);
}
} catch (IOException e) {
// Communications error
System.err.println(
"There was a problem communicating with the service.");
e.printStackTrace();
} catch (ServiceException e) {
// Server side error
System.err.println("The server had a problem handling your request.");
e.printStackTrace();
}
}
}
}
+23
View File
@@ -0,0 +1,23 @@
Google Books Data API Java Samples - README.txt
-------------------------------------------------
The Java Books sample is a simple application that shows sample usage
of the various feeds that comprise the Book Search Data API. It works
in two modes. On the one hand as a readonly sample that allows
anonymous searching for volumes; on the other hand as an authenticated
application that performs read and write on the user's annotation and
my library feeds.
The application can be built and run using the provided Ant build file found at
gdata/java/build-samples.xml. The sample can be run in the following manner:
1. Invoke the samples using the appropriate command line:
ant -f gdata/java/build-samples.xml sample.books.run
or
ant -f gdata/java/build-samples.xml sample.books.run --username
<username> --password <password>
Binary file not shown.
+251
View File
@@ -0,0 +1,251 @@
/* 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.calendar;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.Link;
import com.google.gdata.data.acl.AclEntry;
import com.google.gdata.data.acl.AclFeed;
import com.google.gdata.data.acl.AclNamespace;
import com.google.gdata.data.acl.AclRole;
import com.google.gdata.data.acl.AclScope;
import com.google.gdata.data.calendar.CalendarAclRole;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Demonstrates basic Calendar Data API operations on the ACL feed using the
* Java client library:
*
* <ul>
* <li>Parsing the metafeed for ACL feed URLs.</li>
* <li>Retrieving access control lists (ACLs) for each calendar.</li>
* <li>Adding users to access control lists.</li>
* <li>Updating users on access control lists.</li>
* <li>Removing users from access control lists.</li>
* </ul>
*/
public class AclFeedDemo {
// The base URL for a user's calendar metafeed (needs a username appended).
private static final String METAFEED_URL_BASE =
"https://www.google.com/calendar/feeds/";
// The string to add to the user's metafeedUrl to access the ACL feed for
// their primary calendar.
private static final String ACL_FEED_URL_SUFFIX = "/acl/full";
// The URL for the metafeed of the specified user.
// (e.g. http://www.google.com/feeds/calendar/jdoe@gmail.com)
private static URL metafeedUrl = null;
// The URL for the ACL feed of the specified user's primary calendar.
// (e.g. http://www.googe.com/feeds/calendar/jdoe@gmail.com/acl/full)
private static URL aclFeedUrl = null;
/**
* Retrieves the calendar metafeed to get the ACL feed URLs for each calendar.
* Then prints the access control lists for each of the user's calendars.
*
* @param service An authenticated CalendarService object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void printAclList(CalendarService service)
throws ServiceException, IOException {
CalendarFeed calendarFeed = service
.getFeed(metafeedUrl, CalendarFeed.class);
// After accessing the meta-feed, get the ACL link for each calendar.
System.out.println("Access control lists for your calendars:");
for (CalendarEntry calEntry : calendarFeed.getEntries()) {
Link link = calEntry.getLink(AclNamespace.LINK_REL_ACCESS_CONTROL_LIST,
Link.Type.ATOM);
// For each calendar that exposes an access control list, retrieve its ACL
// feed. If link is null, then we are not the owner of that calendar
// (e.g., it is a public calendar) and its ACL feed cannot be accessed.
if (link != null) {
AclFeed aclFeed = service.getFeed(new URL(link.getHref()),
AclFeed.class);
System.out.println("\tCalendar \"" + calEntry.getTitle().getPlainText()
+ "\":");
for (AclEntry aclEntry : aclFeed.getEntries()) {
System.out.println("\t\tScope: Type=" + aclEntry.getScope().getType()
+ " (" + aclEntry.getScope().getValue() + ")");
System.out.println("\t\tRole: " + aclEntry.getRole().getValue());
}
}
}
}
/**
* Adds a user in the read-only role to the calendar's access control list.
* Note that this method will not run by default.
*
* @param service An authenticated CalendarService object.
* @param userEmail The email address of the user with whom to share the
* calendar.
* @param role The access privileges to grant this user.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void addAccessControl(CalendarService service,
String userEmail, AclRole role) throws ServiceException, IOException {
AclEntry entry = new AclEntry();
entry.setScope(new AclScope(AclScope.Type.USER, userEmail));
entry.setRole(role);
AclEntry insertedEntry = service.insert(aclFeedUrl, entry);
System.out.println("Added user to access control list:");
System.out.println("\tScope: Type=" + insertedEntry.getScope().getType()
+ " (" + insertedEntry.getScope().getValue() + ")");
System.out.println("\tRole: " + insertedEntry.getRole().getValue());
}
/**
* Updates a user to have new access permissions over a calendar. Note that
* this method will not run by default.
*
* @param service An authenticated CalendarService object.
* @param userEmail The email address of the user to update.
* @param newRole The new access privileges to grant this user.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void updateAccessControl(CalendarService service,
String userEmail, AclRole newRole) throws ServiceException, IOException {
AclFeed aclFeed = service.getFeed(aclFeedUrl, AclFeed.class);
for (AclEntry aclEntry : aclFeed.getEntries()) {
if (userEmail.equals(aclEntry.getScope().getValue())) {
aclEntry.setRole(newRole);
AclEntry updatedEntry = aclEntry.update();
System.out.println("Updated user's access control:");
System.out.println("\tScope: Type=" + updatedEntry.getScope().getType()
+ " (" + updatedEntry.getScope().getValue() + ")");
System.out.println("\tRole: " + updatedEntry.getRole().getValue());
break;
}
}
}
/**
* Deletes a user from a calendar's access control list, preventing that user
* from accessing the calendar. Note that this method will not run by default.
*
* @param service An authenticated CalendarService object.
* @param userEmail The email address of the user to remove from the ACL.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void deleteAccessControl(CalendarService service,
String userEmail) throws ServiceException, IOException {
AclFeed aclFeed = service.getFeed(aclFeedUrl, AclFeed.class);
for (AclEntry aclEntry : aclFeed.getEntries()) {
if (userEmail.equals(aclEntry.getScope().getValue())) {
aclEntry.delete();
System.out.println("Deleted " + userEmail + "'s access control.");
break;
}
}
}
/**
* Instantiates a CalendarService object and uses the command line arguments
* to authenticate. The CalendarService object is used to demonstrate
* interactions with the Calendar data API's ACL feed.
*
* @param args Must be length 2 or 3 and contain a valid username/password
*/
public static void main(String[] args) {
String userToShareWith = null;
// Set username, password and feed URI from command-line arguments.
if (args.length < 2 || args.length > 3) {
usage();
return;
} else if (args.length == 3) {
userToShareWith = args[2];
}
CalendarService myService = new CalendarService("demo-AclFeedDemo-1");
String userName = args[0];
String userPassword = args[1];
// Create necessary URL objects
try {
metafeedUrl = new URL(METAFEED_URL_BASE + userName);
aclFeedUrl = new URL(METAFEED_URL_BASE + userName + ACL_FEED_URL_SUFFIX);
} catch (MalformedURLException e) {
// Bad URL
System.err.println("Uh oh - you've got an invalid URL.");
e.printStackTrace();
return;
}
try {
myService.setUserCredentials(userName, userPassword);
// Demonstrate retrieving access control list feeds.
printAclList(myService);
if (userToShareWith != null) {
// Allow given user to see free/busy information on this calendar.
addAccessControl(myService, userToShareWith, CalendarAclRole.FREEBUSY);
// Allow given user to have full read access on this calendar.
updateAccessControl(myService, userToShareWith, CalendarAclRole.READ);
// Remove given user's access to this calendar.
deleteAccessControl(myService, userToShareWith);
}
} catch (IOException e) {
// Communications error
System.err.println("There was a problem communicating with the service.");
e.printStackTrace();
} catch (ServiceException e) {
// Server side error
System.err.println("The server had a problem handling your request.");
e.printStackTrace();
}
}
/**
* Prints the command line usage of this sample application.
*/
private static void usage() {
System.out.println("Syntax: AclFeedDemo <username> <password>"
+ " [userToShareWith]");
System.out.println("\nThe username and password are used for "
+ "authentication. The 'userToShareWith' is an optional parameter "
+ "that specifies a second user to share the first user's primary "
+ "calendar with. If this parameter is not given then the first "
+ "user's ACL will not be modified.");
}
}
@@ -0,0 +1,304 @@
/* 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.calendar;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.data.calendar.ColorProperty;
import com.google.gdata.data.calendar.HiddenProperty;
import com.google.gdata.data.calendar.SelectedProperty;
import com.google.gdata.data.calendar.TimeZoneProperty;
import com.google.gdata.data.extensions.Where;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Demonstrates interactions with the Calendar data API's calendar feeds using
* the Java client library:
*
* <ul>
* <li>Retrieving the metafeed list of all the user's calendars</li>
* <li>Retrieving the allcalendars list of calendars</li>
* <li>Retrieving the owncalendars list of calendars</li>
* <li>Creating a new calendar</li>
* <li>Updating an existing calendar</li>
* <li>Deleting a calendar</li>
* <li>Subscribing to an existing calendar</li>
* <li>Updating a subscription</li>
* <li>Deleting a subscription</li>
* </ul>
*/
public class CalendarFeedDemo {
// The base URL for a user's calendar metafeed (needs a username appended).
private static final String METAFEED_URL_BASE =
"https://www.google.com/calendar/feeds/";
// The string to add to the user's metafeedUrl to access the allcalendars
// feed.
private static final String ALLCALENDARS_FEED_URL_SUFFIX =
"/allcalendars/full";
// The string to add to the user's metafeedUrl to access the owncalendars
// feed.
private static final String OWNCALENDARS_FEED_URL_SUFFIX =
"/owncalendars/full";
// The URL for the metafeed of the specified user.
// (e.g. http://www.google.com/feeds/calendar/jdoe@gmail.com)
private static URL metafeedUrl = null;
// The URL for the allcalendars feed of the specified user.
// (e.g. http://www.googe.com/feeds/calendar/jdoe@gmail.com/allcalendars/full)
private static URL allcalendarsFeedUrl = null;
// The URL for the owncalendars feed of the specified user.
// (e.g. http://www.googe.com/feeds/calendar/jdoe@gmail.com/owncalendars/full)
private static URL owncalendarsFeedUrl = null;
// The calendar ID of the public Google Doodles calendar
private static final String DOODLES_CALENDAR_ID =
"c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com";
// The HEX representation of red, blue and green
private static final String RED = "#A32929";
private static final String BLUE = "#2952A3";
private static final String GREEN = "#0D7813";
/**
* Utility classes should not have a public or default constructor.
*/
protected CalendarFeedDemo() {
}
/**
* Prints the titles of calendars in the feed specified by the given URL.
*
* @param service An authenticated CalendarService object.
* @param feedUrl The URL of a calendar feed to retrieve.
* @throws IOException If there is a problem communicating with the server.
* @throws ServiceException If the service is unable to handle the request.
*/
private static void printUserCalendars(CalendarService service, URL feedUrl)
throws IOException, ServiceException {
// Send the request and receive the response:
CalendarFeed resultFeed = service.getFeed(feedUrl, CalendarFeed.class);
// Print the title of each calendar
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
CalendarEntry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
}
/**
* Creates a new secondary calendar using the owncalendars feed.
*
* @param service An authenticated CalendarService object.
* @return The newly created calendar entry.
* @throws IOException If there is a problem communicating with the server.
* @throws ServiceException If the service is unable to handle the request.
*/
private static CalendarEntry createCalendar(CalendarService service)
throws IOException, ServiceException {
System.out.println("Creating a secondary calendar");
// Create the calendar
CalendarEntry calendar = new CalendarEntry();
calendar.setTitle(new PlainTextConstruct("Little League Schedule"));
calendar.setSummary(new PlainTextConstruct(
"This calendar contains the practice schedule and game times."));
calendar.setTimeZone(new TimeZoneProperty("America/Los_Angeles"));
calendar.setHidden(HiddenProperty.FALSE);
calendar.setColor(new ColorProperty(BLUE));
calendar.addLocation(new Where("", "", "Oakland"));
// Insert the calendar
return service.insert(owncalendarsFeedUrl, calendar);
}
/**
* Updates the title, color, and selected properties of the given calendar
* entry using the owncalendars feed. Note that the title can only be updated
* with the owncalendars feed.
*
* @param calendar The calendar entry to update.
* @return The newly updated calendar entry.
* @throws IOException If there is a problem communicating with the server.
* @throws ServiceException If the service is unable to handle the request.
*/
private static CalendarEntry updateCalendar(CalendarEntry calendar)
throws IOException, ServiceException {
System.out.println("Updating the secondary calendar");
calendar.setTitle(new PlainTextConstruct("New title"));
calendar.setColor(new ColorProperty(GREEN));
calendar.setSelected(SelectedProperty.TRUE);
return calendar.update();
}
/**
* Deletes the given calendar entry.
*
* @param calendar The calendar entry to delete.
* @throws IOException If there is a problem communicating with the server.
* @throws ServiceException If the service is unable to handle the request.
*/
private static void deleteCalendar(CalendarEntry calendar)
throws IOException, ServiceException {
System.out.println("Deleting the secondary calendar");
calendar.delete();
}
/**
* Subscribes to the public Google Doodles calendar using the allcalendars
* feed.
*
* @param service An authenticated CalendarService object.
* @return The newly created calendar entry.
* @throws IOException If there is a problem communicating with the server.
* @throws ServiceException If the service is unable to handle the request.
*/
private static CalendarEntry createSubscription(CalendarService service)
throws IOException, ServiceException {
System.out.println("Subscribing to the Google Doodles calendar");
CalendarEntry calendar = new CalendarEntry();
calendar.setId(DOODLES_CALENDAR_ID);
return service.insert(allcalendarsFeedUrl, calendar);
}
/**
* Updated the color property of the given calendar entry.
*
* @param calendar The calendar entry to update.
* @return The newly updated calendar entry.
* @throws IOException If there is a problem communicating with the server.
* @throws ServiceException If the service is unable to handle the request.
*/
private static CalendarEntry updateSubscription(CalendarEntry calendar)
throws IOException, ServiceException {
System.out.println("Updating the display color of the Doodles calendar");
calendar.setColor(new ColorProperty(RED));
return calendar.update();
}
/**
* Deletes the given calendar entry.
*
* @param calendar The calendar entry to delete
* @throws IOException If there is a problem communicating with the server.
* @throws ServiceException If the service is unable to handle the request.
*/
private static void deleteSubscription(CalendarEntry calendar)
throws IOException, ServiceException {
System.out.println("Deleting the subscription to the Doodles calendar");
calendar.delete();
}
/**
* Instantiates a CalendarService object and uses the command line arguments
* to authenticate. The CalendarService object is used to demonstrate
* interactions with the Calendar data API's calendar feeds.
*
* @param args Must be length 2 and contain a valid username/password
*/
public static void main(String[] args) {
// Set username and password from command-line arguments.
if (args.length != 2) {
usage();
return;
}
String userName = args[0];
String userPassword = args[1];
// Create necessary URL objects
try {
metafeedUrl = new URL(METAFEED_URL_BASE + userName);
allcalendarsFeedUrl = new URL(METAFEED_URL_BASE + userName +
ALLCALENDARS_FEED_URL_SUFFIX);
owncalendarsFeedUrl = new URL(METAFEED_URL_BASE + userName +
OWNCALENDARS_FEED_URL_SUFFIX);
} catch (MalformedURLException e) {
// Bad URL
System.err.println("Uh oh - you've got an invalid URL.");
e.printStackTrace();
return;
}
// Create CalendarService and authenticate using ClientLogin
CalendarService service = new CalendarService("demo-CalendarFeedDemo-1");
try {
service.setUserCredentials(userName, userPassword);
} catch (AuthenticationException e) {
// Invalid credentials
e.printStackTrace();
}
// Demonstrate retrieving various calendar feeds.
try {
System.out.println("Calendars in metafeed");
printUserCalendars(service, metafeedUrl);
System.out.println("Calendars in allcalendars feed");
printUserCalendars(service, allcalendarsFeedUrl);
System.out.println("Calendars in owncalendars feed");
printUserCalendars(service, owncalendarsFeedUrl);
// Create a new secondary calendar, update it, then delete it.
CalendarEntry newCalendar = createCalendar(service);
CalendarEntry updatedCalendar = updateCalendar(newCalendar);
deleteCalendar(newCalendar);
// Subscribe to the Google Doodles calendar, update the personalization
// settings, then delete the subscription.
CalendarEntry newSubscription = createSubscription(service);
CalendarEntry updatedSubscription = updateSubscription(newSubscription);
deleteSubscription(newSubscription);
} catch (IOException e) {
// Communications error
System.err.println("There was a problem communicating with the service.");
e.printStackTrace();
} catch (ServiceException e) {
// Server side error
System.err.println("The server had a problem handling your request.");
e.printStackTrace();
}
}
/**
* Prints the command line usage of this sample application.
*/
private static void usage() {
System.out.println("Syntax: CalendarFeedDemo <username> <password>");
System.out.println("\nThe username and password are used for "
+ "authentication. The sample application will modify the specified "
+ "user's calendars so you may want to use a test account.");
}
}
@@ -0,0 +1,550 @@
/* 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.calendar;
import com.google.gdata.client.Query;
import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Link;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.batch.BatchOperationType;
import com.google.gdata.data.batch.BatchStatus;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.data.calendar.WebContent;
import com.google.gdata.data.extensions.ExtendedProperty;
import com.google.gdata.data.extensions.Recurrence;
import com.google.gdata.data.extensions.Reminder;
import com.google.gdata.data.extensions.Reminder.Method;
import com.google.gdata.data.extensions.When;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
/**
* Demonstrates basic Calendar Data API operations on the event feed using the
* Java client library:
*
* <ul>
* <li>Retrieving the list of all the user's calendars</li>
* <li>Retrieving all events on a single calendar</li>
* <li>Performing a full-text query on a calendar</li>
* <li>Performing a date-range query on a calendar</li>
* <li>Creating a single-occurrence event</li>
* <li>Creating a recurring event</li>
* <li>Creating a quick add event</li>
* <li>Creating a web content event</li>
* <li>Updating events</li>
* <li>Adding reminders and extended properties</li>
* <li>Deleting events via batch request</li>
* </ul>
*/
public class EventFeedDemo {
// The base URL for a user's calendar metafeed (needs a username appended).
private static final String METAFEED_URL_BASE =
"https://www.google.com/calendar/feeds/";
// The string to add to the user's metafeedUrl to access the event feed for
// their primary calendar.
private static final String EVENT_FEED_URL_SUFFIX = "/private/full";
// The URL for the metafeed of the specified user.
// (e.g. http://www.google.com/feeds/calendar/jdoe@gmail.com)
private static URL metafeedUrl = null;
// The URL for the event feed of the specified user's primary calendar.
// (e.g. http://www.googe.com/feeds/calendar/jdoe@gmail.com/private/full)
private static URL eventFeedUrl = null;
/**
* Prints a list of all the user's calendars.
*
* @param service An authenticated CalendarService object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server
*/
private static void printUserCalendars(CalendarService service)
throws IOException, ServiceException {
// Send the request and receive the response:
CalendarFeed resultFeed = service.getFeed(metafeedUrl, CalendarFeed.class);
System.out.println("Your calendars:");
System.out.println();
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
CalendarEntry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Prints the titles of all events on the calendar specified by
* {@code feedUri}.
*
* @param service An authenticated CalendarService object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void printAllEvents(CalendarService service)
throws ServiceException, IOException {
// Send the request and receive the response:
CalendarEventFeed resultFeed = service.getFeed(eventFeedUrl,
CalendarEventFeed.class);
System.out.println("All events on your calendar:");
System.out.println();
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
CalendarEventEntry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Prints the titles of all events matching a full-text query.
*
* @param service An authenticated CalendarService object.
* @param query The text for which to query.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void fullTextQuery(CalendarService service, String query)
throws ServiceException, IOException {
Query myQuery = new Query(eventFeedUrl);
myQuery.setFullTextQuery("Tennis");
CalendarEventFeed resultFeed = service.query(myQuery,
CalendarEventFeed.class);
System.out.println("Events matching " + query + ":");
System.out.println();
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
CalendarEventEntry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Prints the titles of all events in a specified date/time range.
*
* @param service An authenticated CalendarService object.
* @param startTime Start time (inclusive) of events to print.
* @param endTime End time (exclusive) of events to print.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void dateRangeQuery(CalendarService service,
DateTime startTime, DateTime endTime) throws ServiceException,
IOException {
CalendarQuery myQuery = new CalendarQuery(eventFeedUrl);
myQuery.setMinimumStartTime(startTime);
myQuery.setMaximumStartTime(endTime);
// Send the request and receive the response:
CalendarEventFeed resultFeed = service.query(myQuery,
CalendarEventFeed.class);
System.out.println("Events from " + startTime.toString() + " to "
+ endTime.toString() + ":");
System.out.println();
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
CalendarEventEntry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Helper method to create either single-instance or recurring events. For
* simplicity, some values that might normally be passed as parameters (such
* as author name, email, etc.) are hard-coded.
*
* @param service An authenticated CalendarService object.
* @param eventTitle Title of the event to create.
* @param eventContent Text content of the event to create.
* @param recurData Recurrence value for the event, or null for
* single-instance events.
* @param isQuickAdd True if eventContent should be interpreted as the text of
* a quick add event.
* @param wc A WebContent object, or null if this is not a web content event.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createEvent(CalendarService service,
String eventTitle, String eventContent, String recurData,
boolean isQuickAdd, WebContent wc) throws ServiceException, IOException {
CalendarEventEntry myEntry = new CalendarEventEntry();
myEntry.setTitle(new PlainTextConstruct(eventTitle));
myEntry.setContent(new PlainTextConstruct(eventContent));
myEntry.setQuickAdd(isQuickAdd);
myEntry.setWebContent(wc);
// If a recurrence was requested, add it. Otherwise, set the
// time (the current date and time) and duration (30 minutes)
// of the event.
if (recurData == null) {
Calendar calendar = new GregorianCalendar();
DateTime startTime = new DateTime(calendar.getTime(), TimeZone
.getDefault());
calendar.add(Calendar.MINUTE, 30);
DateTime endTime = new DateTime(calendar.getTime(),
TimeZone.getDefault());
When eventTimes = new When();
eventTimes.setStartTime(startTime);
eventTimes.setEndTime(endTime);
myEntry.addTime(eventTimes);
} else {
Recurrence recur = new Recurrence();
recur.setValue(recurData);
myEntry.setRecurrence(recur);
}
// Send the request and receive the response:
return service.insert(eventFeedUrl, myEntry);
}
/**
* Creates a single-occurrence event.
*
* @param service An authenticated CalendarService object.
* @param eventTitle Title of the event to create.
* @param eventContent Text content of the event to create.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createSingleEvent(CalendarService service,
String eventTitle, String eventContent) throws ServiceException,
IOException {
return createEvent(service, eventTitle, eventContent, null, false, null);
}
/**
* Creates a quick add event.
*
* @param service An authenticated CalendarService object.
* @param quickAddContent The quick add text, including the event title, date
* and time.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createQuickAddEvent(
CalendarService service, String quickAddContent) throws ServiceException,
IOException {
return createEvent(service, null, quickAddContent, null, true, null);
}
/**
* Creates a web content event.
*
* @param service An authenticated CalendarService object.
* @param title The title of the web content event.
* @param type The MIME type of the web content event, e.g. "image/gif"
* @param url The URL of the content to display in the web content window.
* @param icon The icon to display in the main Calendar user interface.
* @param width The width of the web content window.
* @param height The height of the web content window.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createWebContentEvent(
CalendarService service, String title, String type, String url,
String icon, String width, String height) throws ServiceException,
IOException {
WebContent wc = new WebContent();
wc.setHeight(height);
wc.setWidth(width);
wc.setTitle(title);
wc.setType(type);
wc.setUrl(url);
wc.setIcon(icon);
return createEvent(service, title, null, null, false, wc);
}
/**
* Creates a new recurring event.
*
* @param service An authenticated CalendarService object.
* @param eventTitle Title of the event to create.
* @param eventContent Text content of the event to create.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createRecurringEvent(
CalendarService service, String eventTitle, String eventContent)
throws ServiceException, IOException {
// Specify a recurring event that occurs every Tuesday from May 1,
// 2007 through September 4, 2007. Note that we are using iCal (RFC 2445)
// syntax; see http://www.ietf.org/rfc/rfc2445.txt for more information.
String recurData = "DTSTART;VALUE=DATE:20070501\r\n"
+ "DTEND;VALUE=DATE:20070502\r\n"
+ "RRULE:FREQ=WEEKLY;BYDAY=Tu;UNTIL=20070904\r\n";
return createEvent(service, eventTitle, eventContent, recurData, false,
null);
}
/**
* Updates the title of an existing calendar event.
*
* @param entry The event to update.
* @param newTitle The new title for this event.
* @return The updated CalendarEventEntry object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry updateTitle(CalendarEventEntry entry,
String newTitle) throws ServiceException, IOException {
entry.setTitle(new PlainTextConstruct(newTitle));
return entry.update();
}
/**
* Adds a reminder to a calendar event.
*
* @param entry The event to update.
* @param numMinutes Reminder time, in minutes.
* @param methodType Method of notification (e.g. email, alert, sms).
* @return The updated EventEntry object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry addReminder(CalendarEventEntry entry,
int numMinutes, Method methodType) throws ServiceException, IOException {
Reminder reminder = new Reminder();
reminder.setMinutes(numMinutes);
reminder.setMethod(methodType);
entry.getReminder().add(reminder);
return entry.update();
}
/**
* Adds an extended property to a calendar event.
*
* @param entry The event to update.
* @return The updated EventEntry object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry addExtendedProperty(
CalendarEventEntry entry) throws ServiceException, IOException {
// Add an extended property "id" with value 1234 to the EventEntry entry.
// We specify the complete schema URL to avoid namespace collisions with
// other applications that use the same property name.
ExtendedProperty property = new ExtendedProperty();
property.setName("http://www.example.com/schemas/2005#mycal.id");
property.setValue("1234");
entry.addExtension(property);
return entry.update();
}
/**
* Makes a batch request to delete all the events in the given list. If any of
* the operations fails, the errors returned from the server are displayed.
* The CalendarEntry objects in the list given as a parameters must be entries
* returned from the server that contain valid edit links (for optimistic
* concurrency to work). Note: You can add entries to a batch request for the
* other operation types (INSERT, QUERY, and UPDATE) in the same manner as
* shown below for DELETE operations.
*
* @param service An authenticated CalendarService object.
* @param eventsToDelete A list of CalendarEventEntry objects to delete.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void deleteEvents(CalendarService service,
List<CalendarEventEntry> eventsToDelete) throws ServiceException,
IOException {
// Add each item in eventsToDelete to the batch request.
CalendarEventFeed batchRequest = new CalendarEventFeed();
for (int i = 0; i < eventsToDelete.size(); i++) {
CalendarEventEntry toDelete = eventsToDelete.get(i);
// Modify the entry toDelete with batch ID and operation type.
BatchUtils.setBatchId(toDelete, String.valueOf(i));
BatchUtils.setBatchOperationType(toDelete, BatchOperationType.DELETE);
batchRequest.getEntries().add(toDelete);
}
// Get the URL to make batch requests to
CalendarEventFeed feed = service.getFeed(eventFeedUrl,
CalendarEventFeed.class);
Link batchLink = feed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
URL batchUrl = new URL(batchLink.getHref());
// Submit the batch request
CalendarEventFeed batchResponse = service.batch(batchUrl, batchRequest);
// Ensure that all the operations were successful.
boolean isSuccess = true;
for (CalendarEventEntry entry : batchResponse.getEntries()) {
String batchId = BatchUtils.getBatchId(entry);
if (!BatchUtils.isSuccess(entry)) {
isSuccess = false;
BatchStatus status = BatchUtils.getBatchStatus(entry);
System.out.println("\n" + batchId + " failed (" + status.getReason()
+ ") " + status.getContent());
}
}
if (isSuccess) {
System.out.println("Successfully deleted all events via batch request.");
}
}
/**
* Instantiates a CalendarService object and uses the command line arguments
* to authenticate. The CalendarService object is used to demonstrate
* interactions with the Calendar data API's event feed.
*
* @param args Must be length 2 and contain a valid username/password
*/
public static void main(String[] args) {
CalendarService myService = new CalendarService("exampleCo-exampleApp-1");
// Set username and password from command-line arguments.
if (args.length != 2) {
usage();
return;
}
String userName = args[0];
String userPassword = args[1];
// Create the necessary URL objects.
try {
metafeedUrl = new URL(METAFEED_URL_BASE + userName);
eventFeedUrl = new URL(METAFEED_URL_BASE + userName
+ EVENT_FEED_URL_SUFFIX);
} catch (MalformedURLException e) {
// Bad URL
System.err.println("Uh oh - you've got an invalid URL.");
e.printStackTrace();
return;
}
try {
myService.setUserCredentials(userName, userPassword);
// Demonstrate retrieving a list of the user's calendars.
printUserCalendars(myService);
// Demonstrate various feed queries.
System.out.println("Printing all events");
printAllEvents(myService);
System.out.println("Full text query");
fullTextQuery(myService, "Tennis");
dateRangeQuery(myService, DateTime.parseDate("2007-01-05"), DateTime
.parseDate("2007-01-07"));
// Demonstrate creating a single-occurrence event.
CalendarEventEntry singleEvent = createSingleEvent(myService,
"Tennis with Mike", "Meet for a quick lesson.");
System.out.println("Successfully created event "
+ singleEvent.getTitle().getPlainText());
// Demonstrate creating a quick add event.
CalendarEventEntry quickAddEvent = createQuickAddEvent(myService,
"Tennis with John April 11 3pm-3:30pm");
System.out.println("Successfully created quick add event "
+ quickAddEvent.getTitle().getPlainText());
// Demonstrate creating a web content event.
CalendarEventEntry webContentEvent = createWebContentEvent(myService,
"World Cup", "image/gif",
"http://www.google.com/logos/worldcup06.gif",
"http://www.google.com/calendar/images/google-holiday.gif", "276",
"120");
System.out.println("Successfully created web content event "
+ webContentEvent.getTitle().getPlainText());
// Demonstrate creating a recurring event.
CalendarEventEntry recurringEvent = createRecurringEvent(myService,
"Tennis with Dan", "Weekly tennis lesson.");
System.out.println("Successfully created recurring event "
+ recurringEvent.getTitle().getPlainText());
// Demonstrate updating the event's text.
singleEvent = updateTitle(singleEvent, "Important meeting");
System.out.println("Event's new title is \""
+ singleEvent.getTitle().getPlainText() + "\".");
// Demonstrate adding a reminder. Note that this will only work on a
// primary calendar.
singleEvent = addReminder(singleEvent, 15, Method.EMAIL);
System.out.println("Set a "
+ singleEvent.getReminder().get(0).getMinutes()
+ " minute " + singleEvent.getReminder().get(0).getMethod()
+ " reminder for the event.");
// Demonstrate adding an extended property.
singleEvent = addExtendedProperty(singleEvent);
// Demonstrate deleting the entries with a batch request.
List<CalendarEventEntry> eventsToDelete =
new ArrayList<CalendarEventEntry>();
eventsToDelete.add(singleEvent);
eventsToDelete.add(quickAddEvent);
eventsToDelete.add(webContentEvent);
eventsToDelete.add(recurringEvent);
deleteEvents(myService, eventsToDelete);
} catch (IOException e) {
// Communications error
System.err.println("There was a problem communicating with the service.");
e.printStackTrace();
} catch (ServiceException e) {
// Server side error
System.err.println("The server had a problem handling your request.");
e.printStackTrace();
}
}
/**
* Prints the command line usage of this sample application.
*/
private static void usage() {
System.out.println("Syntax: EventFeedDemo <username> <password>");
System.out.println("\nThe username and password are used for "
+ "authentication. The sample application will modify the specified "
+ "user's calendars so you may want to use a test account.");
}
}
@@ -0,0 +1,249 @@
/* 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.calendar;
import com.google.gdata.client.Query;
import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.extensions.Who;
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;
/**
* Demonstrates partial query and patch capabilities in Calendar Data API by
* <ul>
* <li>Retrieving current attendeeStatus for the authenticated user using partial
* query and
* <li>update the attendeeStatus using partial patch.
* </ul>
*
*
*/
public class EventFeedPartialDemo {
private static final String CALENDAR_FEEDS_PREFIX =
"https://www.google.com/calendar/feeds/";
/** Input stream for reading user input. */
private static final BufferedReader IN
= new BufferedReader(new InputStreamReader(System.in));
/** Output stream to print output. */
private static final PrintStream OUT = System.out;
/** Service instance to talk to calendar server */
private final CalendarService service;
/** Constructor */
private EventFeedPartialDemo(CalendarService service) {
this.service = service;
}
/**
* Displays a menu of the main activities a user can perform.
*/
private void printMenu() {
OUT.println("\n");
OUT.println("Choose one of the following demo options:");
OUT.println("\t1) Retrieve my next week's events");
OUT.println("\t2) Update my attendee status for an event");
OUT.println("\t0) Exit");
OUT.println("\nEnter Number (0-2): ");
}
/**
* Prints user's attendeeStatus for next week's events.
*
* @param uname username whose attendeeStatus is required.
*/
private void printAttendeeStatus(String uname)
throws IOException, ServiceException {
String eventsFeedUrl = CALENDAR_FEEDS_PREFIX
+ uname + "/private/composite";
String fields = "entry(@gd:etag,id,title,gd:who[@email='" + uname + "'])";
CalendarQuery partialQuery = new CalendarQuery(new URL(eventsFeedUrl));
partialQuery.setFields(fields);
DateTime startTime = DateTime.now();
partialQuery.setMinimumStartTime(startTime);
partialQuery.setMaximumStartTime(
new DateTime(startTime.getValue() + 604800000, startTime.getTzShift()));
CalendarEventFeed events = service.query(
partialQuery, CalendarEventFeed.class);
for (CalendarEventEntry event : events.getEntries()) {
String eventId = event.getId()
.substring(event.getId().lastIndexOf("/") + 1);
String attendeeStatus =
event.getParticipants().get(0).getAttendeeStatus();
OUT.println(eventId + ": " + event.getTitle().getPlainText()
+ ": (" + (attendeeStatus != null ? attendeeStatus : "no status")
+ ")");
}
}
/**
* Updates user's response for a specific event using partial patch.
*
* @param uname username whose attendeeStatus need to be updated.
*/
private void updateAttendeeStatus(String uname)
throws IOException, ServiceException {
OUT.println("Enter the id of event to update: ");
String eventId = IN.readLine();
OUT.println("Enter event response (1:Yes, 2:No, 3:Maybe)");
String selection;
switch(readInt()) {
case 1:
selection = Who.AttendeeStatus.EVENT_ACCEPTED;
break;
case 2:
selection = Who.AttendeeStatus.EVENT_DECLINED;
break;
case 3:
selection = Who.AttendeeStatus.EVENT_TENTATIVE;
break;
default:
OUT.println("Invalid selection.");
return;
}
// URL of calendar entry to update.
String eventEntryUrl = CALENDAR_FEEDS_PREFIX + uname
+ "/private/full/" + eventId;
// Selection criteria to fetch only the attendee status of specified user.
String selectAttendee =
"@gd:etag,title,gd:who[@email='" + uname + "']";
Query partialQuery = new Query(new URL(eventEntryUrl));
partialQuery.setFields(selectAttendee);
CalendarEventEntry event = service.getEntry(partialQuery.getUrl(),
CalendarEventEntry.class);
// The participant list will contain exactly one attendee matching
// above partial query selection criteria.
event.getParticipants().get(0).setAttendeeStatus(selection);
// Field selection to update attendeeStatus only.
String toUpdateFields = "gd:who/gd:attendeeStatus";
// Make patch request which returns full representation for the event.
event = service.patch(
new URL(eventEntryUrl), toUpdateFields, event);
// Print the updated attendee status.
OUT.println(event.getTitle().getPlainText() + " updated to: "
+ event.getParticipants().get(0).getAttendeeStatus());
}
/** Program entry point */
public static void main(String args[]) throws IOException, ServiceException {
// Set username and password from command-line arguments.
if (args.length != 2) {
usage();
return;
}
String uname = args[0];
String upassword = args[1];
CalendarService myService = new CalendarService(
"gdata-CalendarPartialDemo");
myService.setUserCredentials(uname, upassword);
EventFeedPartialDemo demo = new EventFeedPartialDemo(myService);
while (true) {
try {
demo.printMenu();
int choice = readInt();
switch (choice) {
case 1:
// Prints out the user's uploaded videos
demo.printAttendeeStatus(uname);
break;
case 2:
demo.updateAttendeeStatus(uname);
break;
case 0:
System.exit(1);
break;
}
} catch (IOException e) {
// Communications error
System.err.println(
"There was a problem communicating with the service.");
e.printStackTrace();
} catch (ServiceException e) {
// Server side error
System.err.println("The server had a problem handling your request.");
e.printStackTrace();
}
}
}
/**
* Prints the command line usage of this sample application.
*/
private static void usage() {
OUT.println("Syntax: EventFeedPartialDemo <username> <password>");
OUT.println("\nThe username and password are used for "
+ "authentication. The sample application will retrieve list of"
+ "user's calendar events and provides option to change event response."
);
}
/**
* Reads a line of text from the standard input.
*
* @throws IOException If unable to read a line from the standard input.
* @return A line of text read from the standard input.
*/
private static String readLine() throws IOException {
return IN.readLine();
}
/**
* Reads a line of text from the standard input and returns the parsed
* integer representation.
*
* @throws IOException If unable to read a line from the standard input.
* @return An integer read from the standard input.
*/
private static int readInt() throws IOException {
String input = readLine();
try {
return Integer.parseInt(input);
} catch (NumberFormatException nfe) {
return 0;
}
}
}
+20
View File
@@ -0,0 +1,20 @@
Google Calendar data API Java Sample - README.txt
-------------------------------------------------
The Java Calendar sample is a simple application that shows sample usage to
create/read/update/delete data on Google Calendar using the GData Java client
library.
The application can be built and run using the provided Ant build file found at
gdata/java/build.xml. The sample can be run in the following manner:
1. Edit gdata/java/build.properties to enter your Google Account username and
password, as well as the feed URI on which you want to test the sample.
2. Invoke the sample using the following commandline:
ant -f gdata/java/build.xml sample.calendar.run
NOTE: This sample will insert, update, and delete events. Thus it will use the
read-write feed. It will clean up after itself.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,159 @@
/* 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.codesearch;
import com.google.gdata.client.codesearch.CodeSearchService;
import com.google.gdata.util.common.xml.XmlWriter;
import com.google.gdata.data.codesearch.CodeSearchFeed;
import com.google.gdata.data.codesearch.CodeSearchEntry;
import com.google.gdata.data.codesearch.Match;
import sample.util.SimpleCommandLineParser;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.URL;
/**
* An application that serves as a sample to show how the CodeSearchService
* can be used to retrieve data from Google Code Search.
*
*
*/
public class CodeSearchClient {
private static final String CODESEARCH_FEEDS_URL =
"https://www.google.com/codesearch/feeds/search?";
private CodeSearchService codesearchService;
private URL privateFeedUrl;
public CodeSearchClient(String query, String nresults, String start)
throws Exception {
codesearchService = new CodeSearchService("gdata-sample-codesearch");
privateFeedUrl = new URL(CODESEARCH_FEEDS_URL + "q=" + query
+ "&start-index=" + start +
"&max-results="+ nresults);
}
/**
* Driver for the sample.
*
* @param out outputStream to which to write status and messages
*/
public void run(PrintStream out) throws Exception {
retrieveFeed(out);
}
/**
* Retrieves a query feed.
*
* @param out outputStream on which to write status info
* @throws Exception if error in retrieving feed
*/
private void retrieveFeed(PrintStream out)
throws Exception {
PrintWriter writer = new PrintWriter(out);
XmlWriter xmlWriter = new XmlWriter(writer);
CodeSearchFeed myFeed =
codesearchService.getFeed(privateFeedUrl, CodeSearchFeed.class);
out.println("Retrieved feed: ");
out.println("Title: " + myFeed.getTitle().getPlainText());
out.println("Entries: " + myFeed.getEntries().size());
out.println("Updated: " + myFeed.getUpdated());
out.println("Start in: " + myFeed.getStartIndex());
out.println("Entries:");
for (CodeSearchEntry entry: myFeed.getEntries() ){
// Default Gdata elements
out.println("\tId: " + entry.getId());
out.println("\tTitle: " + entry.getTitle());
out.println("\tLink: " + entry.getHtmlLink().getHref());
out.println("\tUpdated: " + entry.getUpdated());
out.println("\tAuthor: " + entry.getAuthors().get(0).getName());
if (entry.getRights() != null)
out.println("\tLicense:" + entry.getRights().getPlainText());
// Codesearch Elements
out.println("\tPackage: ");
out.println("\t\t Name:" +
entry.getPackage().getName());
out.println("\t\t URI:" +
entry.getPackage().getUri());
entry.getPackage().generate(
xmlWriter,
codesearchService.getExtensionProfile());
out.println("XML: ");
writer.flush();
out.println("");
out.println("\tFile: " + entry.getFile().getName());
entry.getFile().generate(
xmlWriter,
codesearchService.getExtensionProfile());
out.println("XML: ");
writer.flush();
out.println("");
out.println("\tMatches: ");
for (Match m : entry.getMatches()) {
out.println(m.getLineNumber() + ": " +
m.getLineText().getPlainText());
m.generate(
xmlWriter,
codesearchService.getExtensionProfile());
out.println("XML: ");
writer.flush();
out.println("");
}
}
}
/**
* Main entry point. Parses arguments and creates and invokes the
* CodeSearchClient.
*/
public static void main(String[] arg)
throws Exception {
SimpleCommandLineParser parser = new SimpleCommandLineParser(arg);
String query = parser.getValue("query", "query", "q");
String nresults = parser.getValue("nresults", "nresults", "nr");
String start = parser.getValue("start", "index", "start");
boolean help = parser.containsKey("help", "h");
if (help || (query == null)) {
usage();
System.exit(1);
}
CodeSearchClient client = new CodeSearchClient(query, nresults, start);
client.run(System.out);
}
/**
* Prints usage of this application.
*/
private static void usage() {
System.out.println(
"Usage: java CodeSearchClient --query query_regex [--nresults number_of_results]"
+ " [--start start_index] ");
System.out.println(
"\nA simple application that uses the provided query\n" +
"and returns the results provided by the Google CodeSearch Service\n");
}
}
@@ -0,0 +1,618 @@
/* 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.contacts;
import com.google.gdata.client.Query;
import com.google.gdata.client.Service;
import com.google.gdata.client.contacts.ContactsService;
import com.google.gdata.client.http.HttpGDataRequest;
import sample.contacts.ContactsExampleParameters.Actions;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Link;
import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.contacts.ContactFeed;
import com.google.gdata.data.contacts.ContactGroupEntry;
import com.google.gdata.data.contacts.ContactGroupFeed;
import com.google.gdata.data.extensions.ExtendedProperty;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.NoLongerAvailableException;
import com.google.gdata.util.ServiceException;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Example command-line utility that demonstrates how to use the Google Data API
* Java client libraries for Contacts. The example allows to run all the basic
* contact related operations such as adding new contact, listing all contacts,
* updating existing contacts, deleting the contacts.
* <p/>
* Full documentation about the API can be found at:
* http://code.google.com/apis/contacts/
*
*
*
*
*/
public class ContactsExample {
private enum SystemGroup {
MY_CONTACTS("Contacts", "My Contacts"),
FRIENDS("Friends", "Friends"),
FAMILY("Family", "Family"),
COWORKERS("Coworkers", "Coworkers");
private final String systemGroupId;
private final String prettyName;
SystemGroup(String systemGroupId, String prettyName) {
this.systemGroupId = systemGroupId;
this.prettyName = prettyName;
}
static SystemGroup fromSystemGroupId(String id) {
for(SystemGroup group : SystemGroup.values()) {
if (id.equals(group.systemGroupId)) {
return group;
}
}
throw new IllegalArgumentException("Unrecognized system group id: " + id);
}
@Override
public String toString() {
return prettyName;
}
}
/**
* Base URL for the feed
*/
private final URL feedUrl;
/**
* Service used to communicate with contacts feed.
*/
private final ContactsService service;
/**
* Projection used for the feed
*/
private final String projection;
/**
* The ID of the last added contact or group.
* Used in case of script execution - you can add and remove contact just
* created.
*/
private static String lastAddedId;
/**
* Reference to the logger for setting verbose mode.
*/
private static final Logger httpRequestLogger =
Logger.getLogger(HttpGDataRequest.class.getName());
/**
* Contacts Example.
*
* @param parameters command line parameters
*/
public ContactsExample(ContactsExampleParameters parameters)
throws MalformedURLException, AuthenticationException {
projection = parameters.getProjection();
String url = parameters.getBaseUrl()
+ (parameters.isGroupFeed() ? "groups/" : "contacts/")
+ parameters.getUserName() + "/" + projection;
feedUrl = new URL(url);
service = new ContactsService("Google-contactsExampleApp-3");
String userName = parameters.getUserName();
String password = parameters.getPassword();
if (userName == null || password == null) {
return;
}
service.setUserCredentials(userName, password);
}
/**
* Deletes a contact or a group
*
* @param parameters the parameters determining contact to delete.
*/
private void deleteEntry(ContactsExampleParameters parameters)
throws IOException, ServiceException {
if (parameters.isGroupFeed()) {
// get the Group then delete it
ContactGroupEntry group = getGroupInternal(parameters.getId());
if (group == null) {
System.err.println("No Group found with id: " + parameters.getId());
return;
}
group.delete();
} else {
// get the contact then delete them
ContactEntry contact = getContactInternal(parameters.getId());
if (contact == null) {
System.err.println("No contact found with id: " + parameters.getId());
return;
}
contact.delete();
}
}
/**
* Updates a contact or a group. Presence of any property of a given kind
* (im, phone, mail, etc.) causes the existing properties of that kind to be
* replaced.
*
* @param parameters parameters storing updated contact values.
*/
public void updateEntry(ContactsExampleParameters parameters)
throws IOException, ServiceException {
if (parameters.isGroupFeed()) {
ContactGroupEntry group = buildGroup(parameters);
// get the group then update it
ContactGroupEntry canonicalGroup = getGroupInternal(parameters.getId());
canonicalGroup.setTitle(group.getTitle());
canonicalGroup.setContent(group.getContent());
// update fields
List<ExtendedProperty> extendedProperties =
canonicalGroup.getExtendedProperties();
extendedProperties.clear();
if (group.hasExtendedProperties()) {
extendedProperties.addAll(group.getExtendedProperties());
}
printGroup(canonicalGroup.update());
} else {
ContactEntry contact = buildContact(parameters);
// get the contact then update it
ContactEntry canonicalContact = getContactInternal(parameters.getId());
ElementHelper.updateContact(canonicalContact, contact);
printContact(canonicalContact.update());
}
}
/**
* Gets a contact by it's id.
*
* @param id the id of the contact.
* @return the ContactEntry or null if not found.
*/
private ContactEntry getContactInternal(String id)
throws IOException, ServiceException {
return service.getEntry(
new URL(id.replace("/base/", "/" + projection + "/")),
ContactEntry.class);
}
/**
* Gets a Group by it's id.
*
* @param id the id of the group.
* @return the GroupEntry or null if not found.
*/
private ContactGroupEntry getGroupInternal(String id)
throws IOException, ServiceException {
return service.getEntry(
new URL(id.replace("/base/", "/" + projection + "/")),
ContactGroupEntry.class);
}
/**
* Print the contents of a ContactEntry to System.err.
*
* @param contact The ContactEntry to display.
*/
private static void printContact(ContactEntry contact) {
System.err.println("Id: " + contact.getId());
if (contact.getTitle() != null) {
System.err.println("Contact name: " + contact.getTitle().getPlainText());
} else {
System.err.println("Contact has no name");
}
System.err.println("Last updated: " + contact.getUpdated().toUiString());
if (contact.hasDeleted()) {
System.err.println("Deleted:");
}
ElementHelper.printContact(System.err, contact);
Link photoLink = contact.getLink(
"http://schemas.google.com/contacts/2008/rel#photo", "image/*");
System.err.println("Photo link: " + photoLink.getHref());
String photoEtag = photoLink.getEtag();
System.err.println(" Photo ETag: "
+ (photoEtag != null ? photoEtag : "(No contact photo uploaded)"));
System.err.println("Self link: " + contact.getSelfLink().getHref());
System.err.println("Edit link: " + contact.getEditLink().getHref());
System.err.println("ETag: " + contact.getEtag());
System.err.println("-------------------------------------------\n");
}
/**
* Prints the contents of a GroupEntry to System.err
*
* @param groupEntry The GroupEntry to display
*/
private static void printGroup(ContactGroupEntry groupEntry) {
System.err.println("Id: " + groupEntry.getId());
System.err.println("Group Name: " + groupEntry.getTitle().getPlainText());
System.err.println("Last Updated: " + groupEntry.getUpdated());
System.err.println("Extended Properties:");
for (ExtendedProperty property : groupEntry.getExtendedProperties()) {
if (property.getValue() != null) {
System.err.println(" " + property.getName() + "(value) = " +
property.getValue());
} else if (property.getXmlBlob() != null) {
System.err.println(" " + property.getName() + "(xmlBlob) = " +
property.getXmlBlob().getBlob());
}
}
System.err.print("Which System Group: ");
if (groupEntry.hasSystemGroup()) {
SystemGroup systemGroup
= SystemGroup.fromSystemGroupId(groupEntry.getSystemGroup().getId());
System.err.println(systemGroup);
} else {
System.err.println("(Not a system group)");
}
System.err.println("Self Link: " + groupEntry.getSelfLink().getHref());
if (!groupEntry.hasSystemGroup()) {
// System groups are not modifiable, and thus don't have an edit link.
System.err.println("Edit Link: " + groupEntry.getEditLink().getHref());
}
System.err.println("-------------------------------------------\n");
}
/**
* Processes script consisting of sequence of parameter lines in the same
* form as command line parameters.
*
* @param example object controlling the execution
* @param parameters parameters passed from command line
*/
private static void processScript(ContactsExample example,
ContactsExampleParameters parameters) throws IOException,
ServiceException {
BufferedReader reader =
new BufferedReader(new FileReader(parameters.getScript()));
try {
String line;
while ((line = reader.readLine()) != null) {
ContactsExampleParameters newParams =
new ContactsExampleParameters(parameters, line);
processAction(example, newParams);
if (lastAddedId != null) {
parameters.setId(lastAddedId);
lastAddedId = null;
}
}
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Performs action specified as action parameter.
*
* @param example object controlling the execution
* @param parameters parameters from command line or script
*/
private static void processAction(ContactsExample example,
ContactsExampleParameters parameters) throws IOException,
ServiceException {
Actions action = parameters.getAction();
System.err.println("Executing action: " + action);
switch (action) {
case LIST:
example.listEntries(parameters);
break;
case QUERY:
example.queryEntries(parameters);
break;
case ADD:
example.addEntry(parameters);
break;
case DELETE:
example.deleteEntry(parameters);
break;
case UPDATE:
example.updateEntry(parameters);
break;
default:
System.err.println("No such action");
}
}
/**
* Query entries (Contacts/Groups) according to parameters specified.
*
* @param parameters parameter for contact quest
*/
private void queryEntries(ContactsExampleParameters parameters)
throws IOException, ServiceException {
Query myQuery = new Query(feedUrl);
if (parameters.getUpdatedMin() != null) {
DateTime startTime = DateTime.parseDateTime(parameters.getUpdatedMin());
myQuery.setUpdatedMin(startTime);
}
if (parameters.getMaxResults() != null) {
myQuery.setMaxResults(parameters.getMaxResults().intValue());
}
if (parameters.getStartIndex() != null) {
myQuery.setStartIndex(parameters.getStartIndex());
}
if (parameters.isShowDeleted()) {
myQuery.setStringCustomParameter("showdeleted", "true");
}
if (parameters.getRequireAllDeleted() != null) {
myQuery.setStringCustomParameter("requirealldeleted",
parameters.getRequireAllDeleted());
}
if (parameters.getSortorder() != null) {
myQuery.setStringCustomParameter("sortorder", parameters.getSortorder());
}
if (parameters.getOrderBy() != null) {
myQuery.setStringCustomParameter("orderby", parameters.getOrderBy());
}
if (parameters.getGroup() != null) {
myQuery.setStringCustomParameter("group", parameters.getGroup());
}
try {
if (parameters.isGroupFeed()) {
ContactGroupFeed groupFeed = service.query(
myQuery, ContactGroupFeed.class);
for (ContactGroupEntry entry : groupFeed.getEntries()) {
printGroup(entry);
}
System.err.println("Total: " + groupFeed.getEntries().size()
+ " entries found");
} else {
ContactFeed resultFeed = service.query(myQuery, ContactFeed.class);
for (ContactEntry entry : resultFeed.getEntries()) {
printContact(entry);
}
System.err.println("Total: " + resultFeed.getEntries().size()
+ " entries found");
}
} catch (NoLongerAvailableException ex) {
System.err.println(
"Not all placehorders of deleted entries are available");
}
}
/**
* List Contacts or Group entries (no parameter are taken into account)
* Note! only 25 results will be returned - this is default.
*
* @param parameters
*/
private void listEntries(ContactsExampleParameters parameters)
throws IOException, ServiceException {
if (parameters.isGroupFeed()) {
ContactGroupFeed groupFeed =
service.getFeed(feedUrl, ContactGroupFeed.class);
System.err.println(groupFeed.getTitle().getPlainText());
for (ContactGroupEntry entry : groupFeed.getEntries()) {
printGroup(entry);
}
System.err.println("Total: " + groupFeed.getEntries().size() +
" groups found");
} else {
ContactFeed resultFeed = service.getFeed(feedUrl, ContactFeed.class);
// Print the results
System.err.println(resultFeed.getTitle().getPlainText());
for (ContactEntry entry : resultFeed.getEntries()) {
printContact(entry);
// Since 2.0, the photo link is always there, the presence of an actual
// photo is indicated by the presence of an ETag.
Link photoLink = entry.getLink(
"http://schemas.google.com/contacts/2008/rel#photo", "image/*");
if (photoLink.getEtag() != null) {
Service.GDataRequest request =
service.createLinkQueryRequest(photoLink);
request.execute();
InputStream in = request.getResponseStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
RandomAccessFile file = new RandomAccessFile(
"/tmp/" + entry.getSelfLink().getHref().substring(
entry.getSelfLink().getHref().lastIndexOf('/') + 1), "rw");
byte[] buffer = new byte[4096];
for (int read = 0; (read = in.read(buffer)) != -1;
out.write(buffer, 0, read)) {}
file.write(out.toByteArray());
file.close();
in.close();
request.end();
}
}
System.err.println("Total: " + resultFeed.getEntries().size()
+ " entries found");
}
}
/**
* Adds contact or group entry according to the parameters specified.
*
* @param parameters parameters for contact adding
*/
private void addEntry(ContactsExampleParameters parameters)
throws IOException, ServiceException {
if (parameters.isGroupFeed()) {
ContactGroupEntry addedGroup =
service.insert(feedUrl, buildGroup(parameters));
printGroup(addedGroup);
lastAddedId = addedGroup.getId();
} else {
ContactEntry addedContact =
service.insert(feedUrl, buildContact(parameters));
printContact(addedContact);
// Store id of the added contact so that scripts can use it in next steps
lastAddedId = addedContact.getId();
}
}
/**
* Build ContactEntry from parameters.
*
* @param parameters parameters
* @return A contact.
*/
private static ContactEntry buildContact(
ContactsExampleParameters parameters) {
ContactEntry contact = new ContactEntry();
ElementHelper.buildContact(contact, parameters.getElementDesc());
return contact;
}
/**
* Builds GroupEntry from parameters
*
* @param parameters ContactExamplParameters
* @return GroupEntry Object
*/
private static ContactGroupEntry buildGroup(
ContactsExampleParameters parameters) {
ContactGroupEntry groupEntry = new ContactGroupEntry();
ElementHelper.buildGroup(groupEntry, parameters.getElementDesc());
return groupEntry;
}
/**
* Displays usage information.
*/
private static void displayUsage() {
String usageInstructions =
"USAGE:\n"
+ " -----------------------------------------------------------\n"
+ " Basic command line usage:\n"
+ " ContactsExample [<options>] <authenticationInformation> "
+ "<--contactfeed|--groupfeed> "
+ "--action=<action> [<action options>] "
+ "(default contactfeed)\n"
+ " Scripting commands usage:\n"
+ " contactsExample [<options>] <authenticationInformation> "
+ "<--contactfeed|--groupfeed> --script=<script file> "
+ "(default contactFeed) \n"
+ " Print usage (this screen):\n"
+ " --help\n"
+ " -----------------------------------------------------------\n\n"
+ " Options: \n"
+ " --base-url=<url to connect to> "
+ "(default http://www.google.com/m8/feeds/) \n"
+ " --projection=[thin|full|property-KEY] "
+ "(default thin)\n"
+ " --verbose : dumps communication information\n"
+ " Authentication Information (obligatory on command line): \n"
+ " --username=<username email> --password=<password>\n"
+ " Actions: \n"
+ " * list list all contacts\n"
+ " * query query contacts\n"
+ " options:\n"
+ " --showdeleted : shows also deleted contacts\n"
+ " --updated-min=YYYY-MM-DDTHH:MM:SS : only updated "
+ "after the time specified\n"
+ " --requre-all-deleted=[true|false] : specifies "
+ "server behaviour in case of placeholders for deleted entries are"
+ "lost. Relevant only if --showdeleted and --updated-min also "
+ "provided.\n"
+ " --orderby=lastmodified : order by last modified\n"
+ " --sortorder=[ascending|descending] : sort order\n"
+ " --max-results=<n> : return maximum n results\n"
+ " --start-index=<n> : return results starting from "
+ "the starting index\n"
+ " --querygroupid=<groupid> : return results from the "
+ "group\n"
+ " * add add new contact\n"
+ " options:\n"
+ ElementHelper.getUsageString()
+ " * delete delete contact\n"
+ " options:\n"
+ " --id=<contact id>\n"
+ " * update updates contact\n"
+ " options:\n"
+ " --id=<contact id>\n"
+ ElementHelper.getUsageString()
;
System.err.println(usageInstructions);
}
/**
* Run the example program.
*
* @param args Command-line arguments.
*/
public static void main(String[] args) throws ServiceException, IOException {
ContactsExampleParameters parameters = new ContactsExampleParameters(args);
if (parameters.isVerbose()) {
httpRequestLogger.setLevel(Level.FINEST);
ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.FINEST);
httpRequestLogger.addHandler(handler);
httpRequestLogger.setUseParentHandlers(false);
}
if (parameters.numberOfParameters() == 0 || parameters.isHelp()
|| (parameters.getAction() == null && parameters.getScript() == null)) {
displayUsage();
return;
}
if (parameters.getUserName() == null || parameters.getPassword() == null) {
System.err.println("Both username and password must be specified.");
return;
}
// Check that at most one of contactfeed and groupfeed has been provided
if (parameters.isContactFeed() && parameters.isGroupFeed()) {
throw new RuntimeException("Only one of contactfeed / groupfeed should" +
"be specified");
}
ContactsExample example = new ContactsExample(parameters);
if (parameters.getScript() != null) {
processScript(example, parameters);
} else {
processAction(example, parameters);
}
System.out.flush();
}
}
@@ -0,0 +1,300 @@
/* 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.contacts;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* Keeps structured command line parameters for ContactsExample program.
*
*
*
*/
public class ContactsExampleParameters {
/**
* Actions that can be executed with the sample application.
* They are all lowercase because they are passed as parameters
* and then converted using valueOf() method.
*/
public enum Actions {
LIST,
QUERY,
ADD,
DELETE,
UPDATE;
}
private static final String DEFAULT_FEED = "https://www.google.com/m8/feeds/";
private static final String DEFAULT_PROJECTION = "thin";
/**
* Keeps map of parameter -> value.
* Note! Tree Map is used to keep sequence of fields.
*/
private SortedMap<String, String> parameterValueMap =
new TreeMap<String,String>();
/**
* List of command line parameters likely to be the description of an
* element.
* Those parameters are added to the list, what are not recognized as a valid
* command line argument (nor an action or option).
* These parameters are later parsed by {@link ElementParser} and processed by
* {@link ElementHelper}.
*/
private List<String> elementDesc = new LinkedList<String>();
/**
* Stores names of parameters.
*/
public enum ParameterNames {
SCRIPT("script"),
ACTION("action"),
BASE_URL("base-url"),
USERNAME("username"),
PASSWORD("password"),
CONTACTFEED("contactfeed"),
GROUPFEED("groupfeed"),
SHOWDELETED("showdeleted"),
REQUIRE_ALL_DELETED("require-all-deleted"),
UPDATED_MIN("updated-min"),
OREDERBY("orderby"),
SORTORDER("sortorder"),
MAX_RESULTS("max-results"),
START_INDEX("start-index"),
HELP("help"),
PROJECTION("projection"),
VERBOSE("verbose"),
ID("id"),
GROUP("querygroupid"),
;
private final String parameterName;
ParameterNames(String parameterName) {
this.parameterName = parameterName;
}
public String getParameterName() {
return parameterName;
}
}
/**
* Constructor used in case script parameter is used.
*
* @param commandLineParams command line parameters
* @param scriptLine line read from a file
*/
public ContactsExampleParameters(ContactsExampleParameters commandLineParams,
String scriptLine) {
parameterValueMap.putAll(commandLineParams.parameterValueMap);
elementDesc.addAll(commandLineParams.elementDesc);
fillFromArguments(scriptLine.split(" "));
}
/**
* Constructor used when no script is passed at command line
* only the command line parameters are used.
*
* @param arguments arguments in form of array
*/
public ContactsExampleParameters(String arguments[]) {
fillFromArguments(arguments);
}
/**
* Parse arguments.
*
* @param arguments arguments in form of array
*/
private void fillFromArguments(String[] arguments) {
for (String string : arguments) {
if (!string.startsWith("--")) {
throw new IllegalArgumentException("illegal parameter: " + string);
}
String param = string.substring(2);
String params[] = param.split("=", 2);
boolean found = false;
for (ParameterNames parameterName : ParameterNames.values()) {
String name = parameterName.getParameterName().toLowerCase();
if (name.equals(params[0])) {
if (params.length == 1) {
parameterValueMap.put(params[0], "");
} else {
parameterValueMap.put(params[0], params[1]);
}
found = true;
break;
}
}
if (!found) {
elementDesc.add(string);
}
}
verifyAllParameters();
}
/**
* Verify if we understand all parameters.
*
* @throws IllegalArgumentException in case there
* is a parameter which is not expected.
*/
private void verifyAllParameters() {
for (String parameter : parameterValueMap.keySet()) {
verifyParameter(parameter);
}
}
private void verifyParameter(String name) {
for (ParameterNames parameter : ParameterNames.values()) {
if (name.equals(parameter.getParameterName())) {
return;
}
}
throw new IllegalArgumentException(
"Parameter " + name + " is not correct.");
}
String getParameter(ParameterNames parameters) {
return parameterValueMap.get(parameters.getParameterName());
}
String getScript() {
return getParameter(ParameterNames.SCRIPT);
}
Actions getAction() {
String actionString = getParameter(ParameterNames.ACTION);
if (actionString == null) {
return null;
}
return Actions.valueOf(actionString.toUpperCase());
}
String getBaseUrl() {
String url = getParameter(ParameterNames.BASE_URL);
if (url == null) {
url = DEFAULT_FEED;
}
return url;
}
String getUserName() {
return getParameter(ParameterNames.USERNAME);
}
String getPassword() {
return getParameter(ParameterNames.PASSWORD);
}
boolean isContactFeed() {
return getParameter(ParameterNames.CONTACTFEED) != null;
}
boolean isGroupFeed() {
return getParameter(ParameterNames.GROUPFEED) != null;
}
boolean isShowDeleted() {
return getParameter(ParameterNames.SHOWDELETED) != null;
}
String getRequireAllDeleted() {
return getParameter(ParameterNames.REQUIRE_ALL_DELETED);
}
String getUpdatedMin() {
return getParameter(ParameterNames.UPDATED_MIN);
}
String getOrderBy() {
return getParameter(ParameterNames.OREDERBY);
}
String getSortorder() {
return getParameter(ParameterNames.SORTORDER);
}
Integer getMaxResults() {
String maxResString = getParameter(ParameterNames.MAX_RESULTS);
if (maxResString != null) {
Integer val = Integer.parseInt(maxResString);
if (val.intValue() < 1) {
throw new RuntimeException(
ParameterNames.MAX_RESULTS + " should be > 0" );
}
return val;
}
return null;
}
Integer getStartIndex() {
String startIndexString = getParameter(ParameterNames.START_INDEX);
if (startIndexString != null) {
Integer val = Integer.parseInt(startIndexString);
if (val.intValue() < 1) {
throw new RuntimeException(
ParameterNames.START_INDEX + " should be > 0" );
}
return val;
}
return null;
}
boolean isHelp() {
return (getParameter(ParameterNames.HELP) != null);
}
boolean isVerbose() {
return (getParameter(ParameterNames.VERBOSE) != null);
}
String getId() {
return getParameter(ParameterNames.ID);
}
void setId(String id) {
parameterValueMap.put(ParameterNames.ID.getParameterName(), id);
}
String getProjection() {
String projection = getParameter(ParameterNames.PROJECTION);
if (projection == null) {
projection = DEFAULT_PROJECTION;
}
return projection;
}
String getGroup() {
return getParameter(ParameterNames.GROUP);
}
List<String> getElementDesc() {
return elementDesc;
}
int numberOfParameters() {
return parameterValueMap.size();
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,83 @@
/* 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.contacts;
import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.contacts.ContactGroupEntry;
import java.io.PrintStream;
/**
* Interface to define the common methods of the {@link ElementHelper}.
*
*
*/
public interface ElementHelperInterface {
/**
* Parses an element from the textual description, and sets or adds it to
* the contact entry.
*
* @param contact the contact the parsed element should be added or set.
* @param parser the parser used for the parsing of the description.
*
* @see ElementParser
*/
public void parse(ContactEntry contact, ElementParser parser);
/**
* Parses an element from the textual description, and sets or adds it to
* the group entry.
*
* @param group the group the parsed element should be added or set.
* @param parser the parser used for the parsing of the description.
*
* @throws UnsupportedOperationException in case the specific element
* can not be set on a ContactGroupEntry.
*
* @see ElementParser
*/
public void parseGroup(ContactGroupEntry group, ElementParser parser);
/**
* Prints the content of the element to a stream.
*
* @param out output stream.
* @param contact the contact containing the element to print.
*/
public void print(PrintStream out, ContactEntry contact);
/**
* Updates element of destination contact with data from source contact.
* If the source contact entry does not has the specific element, it should
* leave the destination contact entry as is, otherwise is should copy the
* element from the source to the destination contact entry.
*
* @param dest the destination contact entry.
* @param src the source contact entry.
*/
public void update(ContactEntry dest, ContactEntry src);
/**
* Returns the usage help text regarding the formating of an element
* description.
*
* @return the usage help text for the element description.
*/
public String getUsage();
}
@@ -0,0 +1,96 @@
/* 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.contacts;
import java.util.EnumMap;
import java.util.Map;
/**
* Parser to tokenize element descriptions.
* The general format of an element specification looks like:
* [<value>]|[<name_1>:<value_1>][,<name_2>:<value_2>]...[,<name_n>:<value_n>]
*
* For convenience a single unnamed value can be specified. It is treated as
* "value:<value>", and the parsed value can be accessed with the VALUE key.
*
*
*/
class ElementParser {
// Map of parsed property names and values.
private Map<PropertyName, String> propertyMap;
/**
* Constructor.
* Parses the element description, and fills the propertyMap.
*
* @param elementDesc the element description.
* @throws IllegalArgumentException on badly formated element description.
*/
ElementParser(String elementDesc) throws IllegalArgumentException {
propertyMap = new EnumMap<PropertyName, String>(PropertyName.class);
for (String propertyDesc : elementDesc.split(",")) {
String nameValuePair[] = propertyDesc.split(":", 2);
if (nameValuePair.length == 1) {
propertyMap.put(PropertyName.VALUE, propertyDesc);
} else if (nameValuePair.length == 2){
propertyMap.put(
PropertyName.valueOf(nameValuePair[0].toUpperCase()),
nameValuePair[1]);
} else {
throw new IllegalArgumentException("Badly formated property:"
+ propertyDesc);
}
}
}
/**
* Checks if the given property has a parsed in value.
*
* @param property the property.
* @return {@code true} if the given property has a parsed in value,
* otherwise {@code false}
*/
boolean has(PropertyName property) {
return propertyMap.containsKey(property);
}
/**
* Retrieves the parsed in value for the given property.
*
* @param property the property.
* @return the parsed in value for the given property, or {@code null} if
* the given property was not specified in the element description
* string.
*/
String get(PropertyName property) {
return propertyMap.get(property);
}
/**
* Convenience method to check the value of a boolean property.
*
* @param property the property.
* @return {@code true} if the parsed in value of the given property is "true"
* {@code false} in any other cases.
*/
boolean is(PropertyName property) {
String value = propertyMap.get(property);
return (value != null) && (value.toLowerCase().equals("true"));
}
}
@@ -0,0 +1,58 @@
/* 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.contacts;
/**
* The property names.
* The parser matches the arguments passed to the actual name of the enums.
*
*
*/
enum PropertyName {
VALUE,
TITLE,
PRIMARY,
PROTOCOL,
LABEL,
REL,
FILE,
TEXT,
HREF,
DELETED,
KEY,
FULL,
GIVEN,
FAMILY,
ADDITIONAL,
PREFIX,
SUFFIX,
URI,
DEPARTMENT,
DESCRIPTION,
SYMBOL,
WHERE,
WHEN,
CITY,
COUNTRY,
FORMATTED,
NEIGHBORHOOD,
POBOX,
POSTCODE,
REGION,
STREET,
}
+22
View File
@@ -0,0 +1,22 @@
Google Contacts data API Java Sample - README.txt
-------------------------------------------------
The Java ContactExample is simple application that shows sample usage to
create/read/update/delete data on feeds from Google Contacts using the
GData Java client library.
The applications can be built and run using the provided Ant build file found at
gdata/java/build-samples.xml. The sample can be run in the following manner:
1. Invoke the samples using the appropriate command:
ant -f gdata/java/build-samples.xml sample.contacts.run
NOTE: These samples will insert, update, and delete contact entries using
read-write feed for the account specified. They will clean up after
themselves, but it is recommended that you use a test account.
You need to edit appropriate variables for username and password inx
build-samples/build.properties (sample.credentials.username and
sample.credentials.password)
@@ -0,0 +1,4 @@
--action=add --name=TestScriptGroup4
--action=query --orderby=lastmodified --sortorder=descending --max-results=1
--action=update --name=changegroup
--action=delete
Binary file not shown.
+37
View File
@@ -0,0 +1,37 @@
--action=add --name=TestChange5 --notes=Notes --phone1=456,rel:http://schemas.google.com/g/2005#home,primary:true
--action=query --orderby=lastmodified --sortorder=descending --max-results=1
--action=update --phone1=456,rel:http://schemas.google.com/g/2005#home,primary:false
--action=query --orderby=lastmodified --sortorder=descending --max-results=1
--action=update --phone1=456,rel:http://schemas.google.com/g/2005#home,primary:true
--action=query --orderby=lastmodified --sortorder=descending --max-results=1
--action=update --billing_information=none
--action=update --birthday=2000-01-01
--action=update --calendar_link1=calendar.foo.com,label:work,primary:true --calendar_link2=calendar.bar.com,label:home
--action=update --directory_server=directory.foo.com
--action=update --email1=foo@foo.com,label:work,primary:true --email2=foo@bar.com,label:home
--action=update --event1=2010-01-01,label:newyear --event2=1999-12-31,label:past
--action=update --external_id1=foo,label:work --external_id2=bar,label:work
--action=update --gender=male
--action=update --hobby1=cooking --hobby2=reading
--action=update --im1=foo@foo.com,label:work,protocol:gtalk,primary:true --im2=foo@bar.com,label:home
--action=update --initials=T
--action=update --jot1=something,rel:work --jot2=another,rel:home
--action=update --language1=english --language2=polish
--action=update --where=somewhere
--action=update --maiden_name=Ewa
--action=update --mileage=100
--action=update --name=Foo,given:foo,family:bar,additional:ho,prefix:mr,suffix:phd
--action=update --nickname=Fooy
--action=update --notes=nothing
--action=update --occupation=engineer
--action=update --organization1=Google,label:KRK,primary:true,department:contacts,symbol:GOOG,title:Engineer,where:Krakow
--action=update --phone1=123,label:work,primary:true --phone2=123,label:home
--action=update --priority=high
--action=update --relation=good,label:personal
--action=update --sensitivity=normal
--action=update --short_name=foo
--action=update --postal1=label:home,primary:true,city:Krakow,country:Poland,formatted:formated,neighborhood:good,pobox:123,postcode:321,region:lesser,street:rynek
--action=update --subject=beer
--action=update --user_defined_field1=value1,key:key1 --user_defined_field2=value2,key:key2
--action=update --website1=www.foo.com,label:work,primary:true --website2=www.bar.com,label:home
--action=delete
+951
View File
@@ -0,0 +1,951 @@
/* 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.docs;
import com.google.gdata.client.GoogleAuthTokenFactory.UserToken;
import com.google.gdata.client.GoogleService;
import com.google.gdata.client.Query;
import com.google.gdata.client.docs.DocsService;
import com.google.gdata.data.MediaContent;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.acl.AclEntry;
import com.google.gdata.data.acl.AclFeed;
import com.google.gdata.data.acl.AclRole;
import com.google.gdata.data.acl.AclScope;
import com.google.gdata.data.docs.DocumentEntry;
import com.google.gdata.data.docs.DocumentListEntry;
import com.google.gdata.data.docs.DocumentListFeed;
import com.google.gdata.data.docs.FolderEntry;
import com.google.gdata.data.docs.PresentationEntry;
import com.google.gdata.data.docs.RevisionFeed;
import com.google.gdata.data.docs.SpreadsheetEntry;
import com.google.gdata.data.media.MediaSource;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* An application that serves as a sample to show how the Documents List Service
* can be used to search your documents, upload and download files, change
* sharing permission, file documents in folders, and view revisions history.
*
*
*
*/
public class DocumentList {
public DocsService service;
public GoogleService spreadsheetsService;
public static final String DEFAULT_HOST = "docs.google.com";
public static final String SPREADSHEETS_SERVICE_NAME = "wise";
public static final String SPREADSHEETS_HOST = "spreadsheets.google.com";
private final String URL_FEED = "/feeds";
private final String URL_DOWNLOAD = "/download";
private final String URL_DOCLIST_FEED = "/private/full";
private final String URL_DEFAULT = "/default";
private final String URL_FOLDERS = "/contents";
private final String URL_ACL = "/acl";
private final String URL_REVISIONS = "/revisions";
private final String URL_CATEGORY_DOCUMENT = "/-/document";
private final String URL_CATEGORY_SPREADSHEET = "/-/spreadsheet";
private final String URL_CATEGORY_PDF = "/-/pdf";
private final String URL_CATEGORY_PRESENTATION = "/-/presentation";
private final String URL_CATEGORY_STARRED = "/-/starred";
private final String URL_CATEGORY_TRASHED = "/-/trashed";
private final String URL_CATEGORY_FOLDER = "/-/folder";
private final String URL_CATEGORY_EXPORT = "/Export";
private final String PARAMETER_SHOW_FOLDERS = "showfolders=true";
private String host;
private final Map<String, String> DOWNLOAD_DOCUMENT_FORMATS;
{
DOWNLOAD_DOCUMENT_FORMATS = new HashMap<String, String>();
DOWNLOAD_DOCUMENT_FORMATS.put("doc", "doc");
DOWNLOAD_DOCUMENT_FORMATS.put("txt", "txt");
DOWNLOAD_DOCUMENT_FORMATS.put("odt", "odt");
DOWNLOAD_DOCUMENT_FORMATS.put("pdf", "pdf");
DOWNLOAD_DOCUMENT_FORMATS.put("png", "png");
DOWNLOAD_DOCUMENT_FORMATS.put("rtf", "rtf");
DOWNLOAD_DOCUMENT_FORMATS.put("html", "html");
DOWNLOAD_DOCUMENT_FORMATS.put("zip", "zip");
}
private final Map<String, String> DOWNLOAD_PRESENTATION_FORMATS;
{
DOWNLOAD_PRESENTATION_FORMATS = new HashMap<String, String>();
DOWNLOAD_PRESENTATION_FORMATS.put("pdf", "pdf");
DOWNLOAD_PRESENTATION_FORMATS.put("png", "png");
DOWNLOAD_PRESENTATION_FORMATS.put("ppt", "ppt");
DOWNLOAD_PRESENTATION_FORMATS.put("swf", "swf");
DOWNLOAD_PRESENTATION_FORMATS.put("txt", "txt");
}
private final Map<String, String> DOWNLOAD_SPREADSHEET_FORMATS;
{
DOWNLOAD_SPREADSHEET_FORMATS = new HashMap<String, String>();
DOWNLOAD_SPREADSHEET_FORMATS.put("xls", "xls");
DOWNLOAD_SPREADSHEET_FORMATS.put("ods", "ods");
DOWNLOAD_SPREADSHEET_FORMATS.put("pdf", "pdf");
DOWNLOAD_SPREADSHEET_FORMATS.put("csv", "csv");
DOWNLOAD_SPREADSHEET_FORMATS.put("tsv", "tsv");
DOWNLOAD_SPREADSHEET_FORMATS.put("html", "html");
}
/**
* Constructor.
*
* @param applicationName name of the application.
*
* @throws DocumentListException
*/
public DocumentList(String applicationName) throws DocumentListException {
this(applicationName, DEFAULT_HOST);
}
/**
* Constructor
*
* @param applicationName name of the application
* @param host the host that contains the feeds
*
* @throws DocumentListException
*/
public DocumentList(String applicationName, String host) throws DocumentListException {
if (host == null) {
throw new DocumentListException("null passed in required parameters");
}
service = new DocsService(applicationName);
// Creating a spreadsheets service is necessary for downloading spreadsheets
spreadsheetsService = new GoogleService(SPREADSHEETS_SERVICE_NAME, applicationName);
this.host = host;
}
/**
* Set user credentials based on a username and password.
*
* @param user username to log in with.
* @param pass password for the user logging in.
*
* @throws AuthenticationException
* @throws DocumentListException
*/
public void login(String user, String pass) throws AuthenticationException,
DocumentListException {
if (user == null || pass == null) {
throw new DocumentListException("null login credentials");
}
service.setUserCredentials(user, pass);
spreadsheetsService.setUserCredentials(user, pass);
}
/**
* Allow a user to login using an AuthSub token.
*
* @param token the token to be used when logging in.
*
* @throws AuthenticationException
* @throws DocumentListException
*/
public void loginWithAuthSubToken(String token) throws AuthenticationException,
DocumentListException {
if (token == null) {
throw new DocumentListException("null login credentials");
}
service.setAuthSubToken(token);
spreadsheetsService.setAuthSubToken(token);
}
/**
* Create a new item in the DocList.
*
* @param title the title of the document to be created.
* @param type the type of the document to be created. One of "spreadsheet",
* "presentation", or "document".
*
* @throws DocumentListException
* @throws ServiceException
* @throws IOException
* @throws MalformedURLException
*/
public DocumentListEntry createNew(String title, String type) throws MalformedURLException,
IOException, ServiceException,
DocumentListException {
if (title == null || type == null) {
throw new DocumentListException("null title or type");
}
DocumentListEntry newEntry = null;
if (type.equals("document")) {
newEntry = new DocumentEntry();
} else if (type.equals("presentation")) {
newEntry = new PresentationEntry();
} else if (type.equals("spreadsheet")) {
newEntry = new SpreadsheetEntry();
} else if (type.equals("folder")) {
newEntry = new FolderEntry();
}
newEntry.setTitle(new PlainTextConstruct(title));
return service.insert(buildUrl(URL_DEFAULT + URL_DOCLIST_FEED), newEntry);
}
/**
* Gets a feed containing the documents.
*
* @param category what types of documents to list:
* "all": lists all the doc objects (documents, spreadsheets, presentations)
* "folders": lists all doc objects including folders.
* "documents": lists only documents.
* "spreadsheets": lists only spreadsheets.
* "pdfs": lists only pdfs.
* "presentations": lists only presentations.
* "starred": lists only starred objects.
* "trashed": lists trashed objects.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public DocumentListFeed getDocsListFeed(String category) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
if (category == null) {
throw new DocumentListException("null category");
}
URL url;
if (category.equals("all")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED);
} else if (category.equals("folders")) {
String[] parameters = {PARAMETER_SHOW_FOLDERS};
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_FOLDER, parameters);
} else if (category.equals("documents")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_DOCUMENT);
} else if (category.equals("spreadsheets")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_SPREADSHEET);
} else if (category.equals("pdfs")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_PDF);
} else if (category.equals("presentations")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_PRESENTATION);
} else if (category.equals("starred")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_STARRED);
} else if (category.equals("trashed")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_TRASHED);
} else {
return null;
}
return service.getFeed(url, DocumentListFeed.class);
}
/**
* Gets the entry for the provided object id.
*
* @param resourceId the resource id of the object to fetch an entry for.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public DocumentListEntry getDocsListEntry(String resourceId) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
if (resourceId == null) {
throw new DocumentListException("null resourceId");
}
URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId);
return service.getEntry(url, DocumentListEntry.class);
}
/**
* Gets the feed for all the objects contained in a folder.
*
* @param folderResourceId the resource id of the folder to return the feed
* for the contents.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public DocumentListFeed getFolderDocsListFeed(String folderResourceId) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
if (folderResourceId == null) {
throw new DocumentListException("null folderResourceId");
}
URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + folderResourceId
+ URL_FOLDERS);
return service.getFeed(url, DocumentListFeed.class);
}
/**
* Gets a feed containing the documents.
*
* @param resourceId the resource id of the object to fetch revisions for.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public RevisionFeed getRevisionsFeed(String resourceId) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
if (resourceId == null) {
throw new DocumentListException("null resourceId");
}
URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId
+ URL_REVISIONS);
return service.getFeed(url, RevisionFeed.class);
}
/**
* Search the documents, and return a feed of docs that match.
*
* @param searchParameters parameters to be used in searching criteria.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public DocumentListFeed search(Map<String, String> searchParameters) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
return search(searchParameters, null);
}
/**
* Search the documents, and return a feed of docs that match.
*
* @param searchParameters parameters to be used in searching criteria.
* accepted parameters are:
* "q": Typical search query
* "alt":
* "author":
* "updated-min": Lower bound on the last time a document' content was changed.
* "updated-max": Upper bound on the last time a document' content was changed.
* "edited-min": Lower bound on the last time a document was edited by the
* current user. This value corresponds to the app:edited value in the
* Atom entry, which represents changes to the document's content or metadata.
* "edited-max": Upper bound on the last time a document was edited by the
* current user. This value corresponds to the app:edited value in the
* Atom entry, which represents changes to the document's content or metadata.
* "title": Specifies the search terms for the title of a document.
* This parameter used without title-exact will only submit partial queries, not exact
* queries.
* "title-exact": Specifies whether the title query should be taken as an exact string.
* Meaningless without title. Possible values are true and false.
* "opened-min": Bounds on the last time a document was opened by the current user.
* Use the RFC 3339 timestamp format. For example: 2005-08-09T10:57:00-08:00
* "opened-max": Bounds on the last time a document was opened by the current user.
* Use the RFC 3339 timestamp format. For example: 2005-08-09T10:57:00-08:00
* "owner": Searches for documents with a specific owner.
* Use the email address of the owner.
* "writer": Searches for documents which can be written to by specific users.
* Use a single email address or a comma separated list of email addresses.
* "reader": Searches for documents which can be read by specific users.
* Use a single email address or a comma separated list of email addresses.
* "showfolders": Specifies whether the query should return folders as well as documents.
* Possible values are true and false.
* @param category define the category to search. (documents, spreadsheets, presentations,
* starred, trashed, folders)
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public DocumentListFeed search(Map<String, String> searchParameters, String category)
throws IOException, MalformedURLException, ServiceException, DocumentListException {
if (searchParameters == null) {
throw new DocumentListException("searchParameters null");
}
URL url;
if (category == null || category.equals("")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED);
} else if (category.equals("documents")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_DOCUMENT);
} else if (category.equals("spreadsheets")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_SPREADSHEET);
} else if (category.equals("presentations")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_PRESENTATION);
} else if (category.equals("starred")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_STARRED);
} else if (category.equals("trashed")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_TRASHED);
} else if (category.equals("folders")) {
url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_FOLDER);
} else {
throw new DocumentListException("invaild category");
}
Query qry = new Query(url);
for (String key : searchParameters.keySet()) {
qry.setStringCustomParameter(key, searchParameters.get(key));
}
return service.query(qry, DocumentListFeed.class);
}
/**
* Upload a file.
*
* @param filepath path to uploaded file.
* @param title title to use for uploaded file.
*
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws DocumentListException
*/
public DocumentListEntry uploadFile(String filepath, String title)
throws IOException, ServiceException, DocumentListException {
if (filepath == null || title == null) {
throw new DocumentListException("null passed in for required parameters");
}
File file = new File(filepath);
String mimeType = DocumentListEntry.MediaType.fromFileName(file.getName())
.getMimeType();
DocumentEntry newDocument = new DocumentEntry();
newDocument.setFile(file, mimeType);
newDocument.setTitle(new PlainTextConstruct(title));
return service
.insert(buildUrl(URL_DEFAULT + URL_DOCLIST_FEED), newDocument);
}
/**
* Trash an object.
*
* @param resourceId the resource id of object to be trashed.
* @param delete true to delete the permanently, false to move it to the
* trash.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public void trashObject(String resourceId, boolean delete) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
if (resourceId == null) {
throw new DocumentListException("null resourceId");
}
String feedUrl = URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId;
if (delete) {
feedUrl += "?delete=true";
}
service.delete(buildUrl(feedUrl), getDocsListEntry(resourceId).getEtag());
}
/**
* Remove an object from a folder.
*
* @param resourceId the resource id of an object to be removed from the
* folder.
* @param folderResourceId the resource id of the folder to remove the object
* from.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public void removeFromFolder(String resourceId, String folderResourceId)
throws IOException, MalformedURLException, ServiceException,
DocumentListException {
if (resourceId == null || folderResourceId == null) {
throw new DocumentListException("null passed in for required parameters");
}
URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + folderResourceId
+ URL_FOLDERS + "/" + resourceId);
service.delete(url, getDocsListEntry(resourceId).getEtag());
}
/**
* Downloads a file.
*
* @param exportUrl the full url of the export link to download the file from.
* @param filepath path and name of the object to be saved as.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public void downloadFile(URL exportUrl, String filepath) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
if (exportUrl == null || filepath == null) {
throw new DocumentListException("null passed in for required parameters");
}
MediaContent mc = new MediaContent();
mc.setUri(exportUrl.toString());
MediaSource ms = service.getMedia(mc);
InputStream inStream = null;
FileOutputStream outStream = null;
try {
inStream = ms.getInputStream();
outStream = new FileOutputStream(filepath);
int c;
while ((c = inStream.read()) != -1) {
outStream.write(c);
}
} finally {
if (inStream != null) {
inStream.close();
}
if (outStream != null) {
outStream.flush();
outStream.close();
}
}
}
/**
* Downloads a spreadsheet file.
*
* @param filepath path and name of the object to be saved as.
* @param resourceId the resource id of the object to be downloaded.
* @param format format to download the file to. The following file types are
* supported: spreadsheets: "ods", "pdf", "xls", "csv", "html", "tsv"
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public void downloadSpreadsheet(String resourceId, String filepath,
String format) throws IOException, MalformedURLException,
ServiceException, DocumentListException {
if (resourceId == null || filepath == null || format == null) {
throw new DocumentListException("null passed in for required parameters");
}
UserToken docsToken = (UserToken) service.getAuthTokenFactory()
.getAuthToken();
UserToken spreadsheetsToken = (UserToken) spreadsheetsService
.getAuthTokenFactory().getAuthToken();
service.setUserToken(spreadsheetsToken.getValue());
HashMap<String, String> parameters = new HashMap<String, String>();
parameters
.put("key", resourceId.substring(resourceId.lastIndexOf(':') + 1));
parameters.put("exportFormat", format);
// If exporting to .csv or .tsv, add the gid parameter to specify which
// sheet to export
if (format.equals(DOWNLOAD_SPREADSHEET_FORMATS.get("csv"))
|| format.equals(DOWNLOAD_SPREADSHEET_FORMATS.get("tsv"))) {
parameters.put("gid", "0"); // download only the first sheet
}
URL url = buildUrl(SPREADSHEETS_HOST, URL_DOWNLOAD + "/spreadsheets"
+ URL_CATEGORY_EXPORT, parameters);
downloadFile(url, filepath);
// Restore docs token for our DocList client
service.setUserToken(docsToken.getValue());
}
/**
* Downloads a document.
*
* @param filepath path and name of the object to be saved as.
* @param resourceId the resource id of the object to be downloaded.
* @param format format to download the file to. The following file types are
* supported: documents: "doc", "txt", "odt", "png", "pdf", "rtf",
* "html"
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public void downloadDocument(String resourceId, String filepath, String format)
throws IOException, MalformedURLException, ServiceException,
DocumentListException {
if (resourceId == null || filepath == null || format == null) {
throw new DocumentListException("null passed in for required parameters");
}
String[] parameters = {"docID=" + resourceId, "exportFormat=" + format};
URL url = buildUrl(URL_DOWNLOAD + "/documents" + URL_CATEGORY_EXPORT,
parameters);
downloadFile(url, filepath);
}
/**
* Downloads a presentation.
*
* @param filepath path and name of the object to be saved as.
* @param resourceId the resource id of the object to be downloaded.
* @param format format to download the file to. The following file types are
* supported: presentations: "pdf", "ppt", "png", "swf", "txt"
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public void downloadPresentation(String resourceId, String filepath,
String format) throws IOException, MalformedURLException,
ServiceException, DocumentListException {
if (resourceId == null || filepath == null || format == null) {
throw new DocumentListException("null passed in for required parameters");
}
String[] parameters = {"docID=" + resourceId, "exportFormat=" + format};
URL url = buildUrl(URL_DOWNLOAD + "/presentations" + URL_CATEGORY_EXPORT,
parameters);
downloadFile(url, filepath);
}
/**
* Moves a object to a folder.
*
* @param resourceId the resource id of the object to be moved to the folder.
* @param folderId the id of the folder to move the object to.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public DocumentListEntry moveObjectToFolder(String resourceId, String folderId)
throws IOException, MalformedURLException, ServiceException, DocumentListException {
if (resourceId == null || folderId == null) {
throw new DocumentListException("null passed in for required parameters");
}
DocumentListEntry doc = new DocumentListEntry();
doc.setId(buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId).toString());
URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + folderId + URL_FOLDERS);
return service.insert(url, doc);
}
/**
* Gets the access control list for a object.
*
* @param resourceId the resource id of the object to retrieve the ACL for.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public AclFeed getAclFeed(String resourceId) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
if (resourceId == null) {
throw new DocumentListException("null resourceId");
}
URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId
+ URL_ACL);
return service.getFeed(url, AclFeed.class);
}
/**
* Add an ACL role to an object.
*
* @param role the role of the ACL to be added to the object.
* @param scope the scope for the ACL.
* @param resourceId the resource id of the object to set the ACL for.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public AclEntry addAclRole(AclRole role, AclScope scope, String resourceId)
throws IOException, MalformedURLException, ServiceException,
DocumentListException {
if (role == null || scope == null || resourceId == null) {
throw new DocumentListException("null passed in for required parameters");
}
AclEntry entry = new AclEntry();
entry.setRole(role);
entry.setScope(scope);
URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId + URL_ACL);
return service.insert(url, entry);
}
/**
* Change the ACL role of a file.
*
* @param role the new role of the ACL to be updated.
* @param scope the new scope for the ACL.
* @param resourceId the resource id of the object to be updated.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public AclEntry changeAclRole(AclRole role, AclScope scope, String resourceId)
throws IOException, ServiceException, DocumentListException {
if (role == null || scope == null || resourceId == null) {
throw new DocumentListException("null passed in for required parameters");
}
URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId
+ URL_ACL);
return service.update(url, scope, role);
}
/**
* Remove an ACL role from a object.
*
* @param scope scope of the ACL to be removed.
* @param email email address to remove the role of.
* @param resourceId the resource id of the object to remove the role from.
*
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
* @throws DocumentListException
*/
public void removeAclRole(String scope, String email, String resourceId) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
if (scope == null || email == null || resourceId == null) {
throw new DocumentListException("null passed in for required parameters");
}
URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId
+ URL_ACL + "/" + scope + "%3A" + email);
service.delete(url);
}
/**
* Returns the format code based on a file extension, and object id.
*
* @param resourceId the resource id of the object you want the format for.
* @param ext extension of the file you want the format for.
*
* @throws DocumentListException
*/
public String getDownloadFormat(String resourceId, String ext) throws DocumentListException {
if (resourceId == null || ext == null) {
throw new DocumentListException("null passed in for required parameters");
}
if (resourceId.indexOf("document") == 0) {
if (DOWNLOAD_DOCUMENT_FORMATS.containsKey(ext)) {
return DOWNLOAD_DOCUMENT_FORMATS.get(ext);
}
} else if (resourceId.indexOf("presentation") == 0) {
if (DOWNLOAD_PRESENTATION_FORMATS.containsKey(ext)) {
return DOWNLOAD_PRESENTATION_FORMATS.get(ext);
}
} else if (resourceId.indexOf("spreadsheet") == 0) {
if (DOWNLOAD_SPREADSHEET_FORMATS.containsKey(ext)) {
return DOWNLOAD_SPREADSHEET_FORMATS.get(ext);
}
}
throw new DocumentListException("invalid document type");
}
/**
* Gets the suffix of the resourceId. If the resourceId is
* "document:dh3bw3j_0f7xmjhd8", "dh3bw3j_0f7xmjhd8" will be returned.
*
* @param resourceId the resource id to extract the suffix from.
*
* @throws DocumentListException
*/
public String getResourceIdSuffix(String resourceId) throws DocumentListException {
if (resourceId == null) {
throw new DocumentListException("null resourceId");
}
if (resourceId.indexOf("%3A") != -1) {
return resourceId.substring(resourceId.lastIndexOf("%3A") + 3);
} else if (resourceId.indexOf(":") != -1) {
return resourceId.substring(resourceId.lastIndexOf(":") + 1);
}
throw new DocumentListException("Bad resourceId");
}
/**
* Gets the prefix of the resourceId. If the resourceId is
* "document:dh3bw3j_0f7xmjhd8", "document" will be returned.
*
* @param resourceId the resource id to extract the suffix from.
*
* @throws DocumentListException
*/
public String getResourceIdPrefix(String resourceId) throws DocumentListException {
if (resourceId == null) {
throw new DocumentListException("null resourceId");
}
if (resourceId.indexOf("%3A") != -1) {
return resourceId.substring(0, resourceId.indexOf("%3A"));
} else if (resourceId.indexOf(":") != -1) {
return resourceId.substring(0, resourceId.indexOf(":"));
} else {
throw new DocumentListException("Bad resourceId");
}
}
/**
* Builds a URL from a patch.
*
* @param path the path to add to the protocol/host
*
* @throws MalformedURLException
* @throws DocumentListException
*/
private URL buildUrl(String path) throws MalformedURLException, DocumentListException {
if (path == null) {
throw new DocumentListException("null path");
}
return buildUrl(path, null);
}
/**
* Builds a URL with parameters.
*
* @param path the path to add to the protocol/host
* @param parameters parameters to be added to the URL.
*
* @throws MalformedURLException
* @throws DocumentListException
*/
private URL buildUrl(String path, String[] parameters)
throws MalformedURLException, DocumentListException {
if (path == null) {
throw new DocumentListException("null path");
}
return buildUrl(host, path, parameters);
}
/**
* Builds a URL with parameters.
*
* @param domain the domain of the server
* @param path the path to add to the protocol/host
* @param parameters parameters to be added to the URL.
*
* @throws MalformedURLException
* @throws DocumentListException
*/
private URL buildUrl(String domain, String path, String[] parameters)
throws MalformedURLException, DocumentListException {
if (path == null) {
throw new DocumentListException("null path");
}
StringBuffer url = new StringBuffer();
url.append("https://" + domain + URL_FEED + path);
if (parameters != null && parameters.length > 0) {
url.append("?");
for (int i = 0; i < parameters.length; i++) {
url.append(parameters[i]);
if (i != (parameters.length - 1)) {
url.append("&");
}
}
}
return new URL(url.toString());
}
/**
* Builds a URL with parameters.
*
* @param domain the domain of the server
* @param path the path to add to the protocol/host
* @param parameters parameters to be added to the URL as key value pairs.
*
* @throws MalformedURLException
* @throws DocumentListException
*/
private URL buildUrl(String domain, String path, Map<String, String> parameters)
throws MalformedURLException, DocumentListException {
if (path == null) {
throw new DocumentListException("null path");
}
StringBuffer url = new StringBuffer();
url.append("https://" + domain + URL_FEED + path);
if (parameters != null && parameters.size() > 0) {
Set<Map.Entry<String, String>> params = parameters.entrySet();
Iterator<Map.Entry<String, String>> itr = params.iterator();
url.append("?");
while (itr.hasNext()) {
Map.Entry<String, String> entry = itr.next();
url.append(entry.getKey() + "=" + entry.getValue());
if (itr.hasNext()) {
url.append("&");
}
}
}
return new URL(url.toString());
}
}
@@ -0,0 +1,846 @@
/* 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.docs;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.data.Link;
import com.google.gdata.data.MediaContent;
import com.google.gdata.data.acl.AclEntry;
import com.google.gdata.data.acl.AclFeed;
import com.google.gdata.data.acl.AclRole;
import com.google.gdata.data.acl.AclScope;
import com.google.gdata.data.docs.DocumentListEntry;
import com.google.gdata.data.docs.DocumentListFeed;
import com.google.gdata.data.docs.RevisionEntry;
import com.google.gdata.data.docs.RevisionFeed;
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.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* An application that serves as a sample to show how the Documents List
* Service can be used to search your documents and upload files.
*
*
*
*
*/
public class DocumentListDemo {
private DocumentList documentList;
private PrintStream out;
private static final String APPLICATION_NAME = "JavaGDataClientSampleAppV3.0";
/**
* The message for displaying the usage parameters.
*/
private static final String[] USAGE_MESSAGE = {
"Usage: java DocumentListDemo.jar --username <user> --password <pass>",
"Usage: java DocumentListDemo.jar --authSub <token>",
" [--host <host:port>] Where is the feed (default = docs.google.com)",
" [--log] Enable logging of requests",
""};
/**
* Welcome message, introducing the program.
*/
private final String[] WELCOME_MESSAGE = {
"", "This is a demo of the document list feed!",
"Using this interface, you can read and upload your documents.",
"Type 'help' for a list of commands.", ""};
/**
* Help on all available commands.
*/
private final String[] COMMAND_HELP_MESSAGE = {
"Commands:",
" create <object_type> <name> [[create an object]]",
" trash <resource_id> [delete] [[puts the object into the trash]]",
" download <resource_id> <file_path> [[downloads the object to the folder"
+ " specified by file_path]]",
" list [object_type] [...] [[lists objects]]",
" move <resource_id> <folder_id> [[moves an object into a folder]]",
" perms <operation> [...] [[lists or modifies file permissions]]",
" remove <resource_id> <folder_resource_id> [[removes an object from a folder]]",
" search <search_text> [[search documents for text strings]]",
" asearch <search_option> [[advanced search]]",
" upload <file_path> <title> [[uploads a object]]",
" revisions <resource_id> [[lists revisions of a document]]",
"",
" help [command] [[display this message, or info about"
+ " the specified command]]",
" exit [[exit the program]]"};
private final String[] COMMAND_HELP_CREATE = {
"create <object_type> <name>",
" object_type: document, spreadsheet, folder.",
" name: the name for the new object"};
private final String[] COMMAND_HELP_TRASH = {
"trash <resource_id> [delete]",
" resource_id: the resource id of the object to be deleted",
" \"delete\": Specify to permanently delete the document instead of just trashing it."};
private final String[] COMMAND_HELP_DOWNLOAD = {
"download <resource_id> <file_path>",
" resource_id: the resource id of the file you wish to download",
" file_path: the path to the directory to save the file in"};
private final String[] COMMAND_HELP_LIST = {
"list [object_type]",
" object_type: all, starred, documents, spreadsheets, pdfs, presentations, folders.\n"
+ " (defaults to 'all')", "list folder <folder_id>",
" folder_id: The id of the folder you want the contents list for."};
private final String[] COMMAND_HELP_MOVE = {
"move <resource_id> <folder_id>",
" resource_id: the resource id of the object to be moved",
" folder_id: the folder to move the document into"};
private final String[] COMMAND_HELP_PERMS = {
"perms list <resource_id>",
" resource_id: the resource id of the object you wish to add/list permissions for",
"perms add <role> <scope> <email> <object_id>",
" role: \"reader\", \"writer\", \"owner\"",
" scope: \"user\", \"domain\"",
" email: The user's email address or domain name (\"user@gmail.com\", \"domain.com\")",
" resource_id: The resource id of the object to change permissions for.",
"perms change <role> <scope> <email> <object_id>",
" role: \"reader\", \"writer\", \"owner\"",
" scope: \"user\", \"domain\"",
" email: The user's email address or domain name (\"user@gmail.com\", \"domain.com\")",
" object_id: The id of the object to change permissions for.",
"perms remove <scope> <email> <object_id>",
" role: \"reader\", \"writer\", \"owner\"",
" scope: \"user\", \"domain\"",
" email: The user's email address or domain name (\"user@gmail.com\", \"domain.com\")",
" object_id: The id of the object to change permissions for."};
private final String[] COMMAND_HELP_REMOVE = {
"remove <object_id> <folder_id>",
" object_id: the id of the object to remove from the folder",
" folder_id: the id of the folder to remove the object from"};
private final String[] COMMAND_HELP_SEARCH = {
"search <search_text>",
" search_text: A string to be used for a full text query"};
private final String[] COMMAND_HELP_ASEARCH = {
"asearch [<query_param>=<value>] [<query_param2>=<value2>] ...",
" query_param: title, title-exact, opened-min, opened-max, owner, writer, reader, "
+ "showfolders, etc.", " value: The value of the parameter"};
private final String[] COMMAND_HELP_UPLOAD = {
"upload <file_path> <title>", " file_path: file to upload",
" title: A title to call the document"};
private final String[] COMMAND_HELP_REVISIONS = {
"revisions <resource_id>", " resource_id: document resource id"};
private final String[] COMMAND_HELP_HELP = {
"help [command]", " Weeeeeeeeeeeeee..."};
private final String[] COMMAND_HELP_EXIT = {
"exit", " Exit the program."};
private final String[] COMMAND_HELP_ERROR = {"unknown command"};
private final Map<String, String[]> HELP_MESSAGES;
{
HELP_MESSAGES = new HashMap<String, String[]>();
HELP_MESSAGES.put("create", COMMAND_HELP_CREATE);
HELP_MESSAGES.put("trash", COMMAND_HELP_TRASH);
HELP_MESSAGES.put("download", COMMAND_HELP_DOWNLOAD);
HELP_MESSAGES.put("list", COMMAND_HELP_LIST);
HELP_MESSAGES.put("move", COMMAND_HELP_MOVE);
HELP_MESSAGES.put("perms", COMMAND_HELP_PERMS);
HELP_MESSAGES.put("remove", COMMAND_HELP_REMOVE);
HELP_MESSAGES.put("search", COMMAND_HELP_SEARCH);
HELP_MESSAGES.put("asearch", COMMAND_HELP_ASEARCH);
HELP_MESSAGES.put("upload", COMMAND_HELP_UPLOAD);
HELP_MESSAGES.put("revisions", COMMAND_HELP_REVISIONS);
HELP_MESSAGES.put("help", COMMAND_HELP_HELP);
HELP_MESSAGES.put("exit", COMMAND_HELP_EXIT);
HELP_MESSAGES.put("error", COMMAND_HELP_ERROR);
}
/**
* Constructor
*
* @param outputStream Stream to print output to.
* @throws DocumentListException
*/
public DocumentListDemo(PrintStream outputStream, String appName, String host)
throws DocumentListException {
out = outputStream;
documentList = new DocumentList(appName, host);
}
/**
* Authenticates the client using ClientLogin
*
* @param username User's email address
* @param password User's password
* @throws DocumentListException
* @throws AuthenticationException
*/
public void login(String username, String password) throws AuthenticationException,
DocumentListException {
documentList.login(username, password);
}
/**
* Authenticates the client using AuthSub
*
* @param authSubToken authsub authorization token.
* @throws DocumentListException
* @throws AuthenticationException
*/
public void login(String authSubToken)
throws AuthenticationException, DocumentListException {
documentList.loginWithAuthSubToken(authSubToken);
}
/**
* Prints out the specified document entry.
*
* @param doc the document entry to print.
*/
public void printDocumentEntry(DocumentListEntry doc) {
StringBuffer output = new StringBuffer();
output.append(" -- " + doc.getTitle().getPlainText() + " ");
if (!doc.getParentLinks().isEmpty()) {
for (Link link : doc.getParentLinks()) {
output.append("[" + link.getTitle() + "] ");
}
}
output.append(doc.getResourceId());
out.println(output);
}
/**
* Prints out the specified revision entry.
*
* @param doc the revision entry to print.
*/
public void printRevisionEntry(RevisionEntry entry) {
StringBuffer output = new StringBuffer();
output.append(" -- " + entry.getTitle().getPlainText());
output.append(", created on " + entry.getUpdated().toUiString() + " ");
output.append(" by " + entry.getModifyingUser().getName() + " - "
+ entry.getModifyingUser().getEmail() + "\n");
output.append(" " + entry.getHtmlLink().getHref());
out.println(output);
}
/**
* Prints out the specified ACL entry.
*
* @param entry the ACL entry to print.
*/
public void printAclEntry(AclEntry entry) {
out.println(" -- " + entry.getScope().getValue() + ": " + entry.getRole().getValue());
}
/**
* Executes the "create" command.
*
* @param args arguments for the "create" command.
* args[0] = "create" args[1] = object_type ("folder", "document", "spreadsheet")
* args[2] = title (what to name the document/folder)
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeCreate(String[] args) throws IOException,
MalformedURLException, ServiceException, DocumentListException {
if (args.length == 3) {
printDocumentEntry(documentList.createNew(args[2], args[1]));
} else {
printMessage(COMMAND_HELP_CREATE);
}
}
/**
* Executes the "trash" command.
*
* @param args arguments for the "trash" command.
* args[0] = "trash"
* args[1] = resourceid (the resource id of the object to be trashed)
* args[2] = delete (where to delete permanently or not)
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeTrash(String[] args) throws IOException,
ServiceException, DocumentListException {
if (args.length == 3) {
documentList.trashObject(args[1], true);
} else if (args.length == 2) {
documentList.trashObject(args[1], false);
} else {
printMessage(COMMAND_HELP_TRASH);
}
}
/**
* Executes the "download" command.
*
* @param args arguments for the "download" command.
* args[0] = "download"
* args[1] = resourceId (the resource id of the object to be downloaded)
* args[2] = filepath (the path and filename to save the object as)
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeDownload(String[] args) throws IOException,
ServiceException, DocumentListException {
if (args.length == 3) {
String docType = documentList.getResourceIdPrefix(args[1]);
if (docType.equals("spreadsheet")) {
String format = documentList.getDownloadFormat(args[1],
getTypeFromFilename(args[2]));
documentList.downloadSpreadsheet(args[1], args[2], format);
} else if (docType.equals("presentation")) {
String format = documentList.getDownloadFormat(args[1],
getTypeFromFilename(args[2]));
documentList.downloadPresentation(args[1], args[2], format);
} else if (docType.equals("document")) {
String format = documentList.getDownloadFormat(args[1],
getTypeFromFilename(args[2]));
documentList.downloadDocument(args[1], args[2], format);
} else {
MediaContent mc = (MediaContent) documentList.getDocsListEntry(args[1]).getContent();
String fileExtension = mc.getMimeType().getSubType();
URL exportUrl = new URL(mc.getUri());
// PDF file cannot be exported in different formats.
String requestedFormat = args[2]
.substring(args[2].lastIndexOf(".") + 1);
if (!requestedFormat.equals(fileExtension)) {
String[] formatWarning = {"Warning: "
+ mc.getMimeType().getMediaType() + " cannot be downloaded as a "
+ requestedFormat + ". Using ." + fileExtension + " instead."};
printMessage(formatWarning);
}
String newFilePath = args[2].substring(0, args[2].lastIndexOf(".") + 1) + fileExtension;
documentList.downloadFile(exportUrl, newFilePath);
}
} else {
printMessage(COMMAND_HELP_DOWNLOAD);
}
}
/**
* Execute the "list" command.
*
* @param args arguments for the "list" command.
* args[0] = "list"
* args[1] = category ("all", "folders", "documents", "spreadsheets", "pdfs",
* "presentations", "starred", "trashed")
* args[2] = folderId (required if args[1] is "folder")
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeList(String[] args) throws IOException,
ServiceException, DocumentListException {
DocumentListFeed feed = null;
String msg = "";
switch (args.length) {
case 1:
msg = "List of docs: ";
feed = documentList.getDocsListFeed("all");
break;
case 2:
msg = "List of all " + args[1] + ": ";
feed = documentList.getDocsListFeed(args[1]);
break;
case 3:
if (args[1].equals("folder")) {
msg = "Contents of folder_id '" + args[2] + "': ";
feed = documentList.getFolderDocsListFeed(args[2]);
}
break;
}
if (feed != null) {
out.println(msg);
for (DocumentListEntry entry : feed.getEntries()) {
printDocumentEntry(entry);
}
} else {
printMessage(COMMAND_HELP_LIST);
}
}
/**
* Execute the "move" command.
*
* @param args arguments for the "move" command.
* args[0] = "move" args[1] = resourceid (the resourceid of the object to move)
* args[2] = folderResourceId (the resource id of the folder to move the object to)
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeMove(String[] args) throws IOException,
ServiceException, DocumentListException {
if (args.length == 3) {
printDocumentEntry(documentList.moveObjectToFolder(args[1], args[2]));
} else {
printMessage(COMMAND_HELP_MOVE);
}
}
/**
* Execute the "perms" command.
*
* @param args arguments for the "perms" command.
* args[0] = "perms"
* args[1] = "list"
* args[2] = resourceId
* args[1] = "add", "change"
* args[2] = role
* args[3] = scope
* args[4] = email
* args[5] = resourceId
* args[1] = "remove"
* args[2] = scope
* args[3] = email
* args[4] = resourceId
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executePerms(String[] args) throws IOException,
ServiceException, DocumentListException {
if (args.length < 3) {
printMessage(COMMAND_HELP_PERMS);
return;
}
if (args[1].equals("list") && args.length == 3) {
AclFeed feed = documentList.getAclFeed(args[2]);
if (feed != null) {
for (AclEntry entry : feed.getEntries()) {
printAclEntry(entry);
}
}
} else if (args[1].equals("add") && args.length == 6) {
AclRole role = new AclRole(args[2]);
AclScope scope;
if (args[3].equals("user")) {
scope = new AclScope(AclScope.Type.USER, args[4]);
} else if (args[3].equals("domain")) {
scope = new AclScope(AclScope.Type.DOMAIN, args[4]);
} else {
printMessage(COMMAND_HELP_PERMS);
return;
}
printAclEntry(documentList.addAclRole(role, scope, args[5]));
} else if (args[1].equals("change") && args.length == 6) {
AclRole role = new AclRole(args[2]);
AclScope scope;
if (args[3].equals("user")) {
scope = new AclScope(AclScope.Type.USER, args[4]);
} else if (args[3].equals("domain")) {
scope = new AclScope(AclScope.Type.DOMAIN, args[4]);
} else {
printMessage(COMMAND_HELP_PERMS);
return;
}
printAclEntry(documentList.changeAclRole(role, scope, args[5]));
} else if (args[1].equals("remove") && args.length == 5) {
documentList.removeAclRole(args[2], args[3], args[4]);
} else {
printMessage(COMMAND_HELP_PERMS);
}
}
/**
* Execute the "remove" command.
*
* @param args arguments for the "remove" command.
* args[0] = "remove"
* args[1] = resourceId
* args[2] = folderReourceId
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeRemove(String[] args) throws IOException,
ServiceException, DocumentListException {
if (args.length == 3) {
documentList.removeFromFolder(args[1], args[2]);
} else {
printMessage(COMMAND_HELP_REMOVE);
}
}
/**
* Execute the "search" command.
*
* @param args arguments for the "search" command.
* args[0] = "search"
* args[1] = searchString
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeSearch(String[] args) throws IOException,
ServiceException, DocumentListException {
if (args.length == 2) {
HashMap<String, String> searchParameters = new HashMap<String, String>();
searchParameters.put("q", args[1]);
DocumentListFeed feed = documentList.search(searchParameters);
out.println("Results for [" + args[1] + "]");
for (DocumentListEntry entry : feed.getEntries()) {
printDocumentEntry(entry);
}
} else {
printMessage(COMMAND_HELP_SEARCH);
}
}
/**
* Execute the "asearch" (advanced search) command.
*
* @param args arguments for the "asearch" command.
* args[0] = "asearch"
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeAdvancedSearch(String[] args) throws IOException,
ServiceException, DocumentListException {
if (args.length <= 1) {
printMessage(COMMAND_HELP_ASEARCH);
return;
}
HashMap<String, String> searchParameters = new HashMap<String, String>();
for (int i = 1; i < args.length; ++i) {
searchParameters.put(args[i].substring(0, args[i].indexOf("=")), args[i]
.substring(args[i].indexOf("=") + 1));
}
DocumentListFeed feed = documentList.search(searchParameters);
out.println("Results for advanced search:");
for (DocumentListEntry entry : feed.getEntries()) {
printDocumentEntry(entry);
}
}
/**
* Execute the "upload" command.
*
* @param args arguments for the "upload" command.
* args[0] = "upload"
* args[1] = filepath (path and filename of the file to be uploaded)
* args[2] = title (title to be used for the uploaded file)
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeUpload(String[] args) throws IOException,
ServiceException, DocumentListException, InterruptedException {
if (args.length == 3) {
DocumentListEntry entry = documentList.uploadFile(args[1], args[2]);
printDocumentEntry(entry);
} else {
printMessage(COMMAND_HELP_UPLOAD);
}
}
/**
* Execute the "revisions" command.
*
* @param args arguments for the "upload" command.
* args[0] = "revisions"
* args[1] = resourceId (the resource id of the object to fetch revisions for)
*
* @throws IOException when an error occurs in communication with the Doclist
* service.
* @throws MalformedURLException when an malformed URL is used.
* @throws ServiceException when the request causes an error in the Doclist
* service.
* @throws DocumentListException
*/
private void executeRevisions(String[] args) throws IOException,
ServiceException, DocumentListException {
if (args.length == 2) {
RevisionFeed feed = documentList.getRevisionsFeed(args[1]);
if (feed != null) {
out.println("List of revisions...");
for (RevisionEntry entry : feed.getEntries()) {
printRevisionEntry(entry);
}
} else {
printMessage(COMMAND_HELP_REVISIONS);
}
} else {
printMessage(COMMAND_HELP_REVISIONS);
}
}
/**
* Execute the "help" command.
*
* @param args arguments for the "help" command.
* args[0] = "help"
* args[1] = command
*/
private void executeHelp(String[] args) {
if (args.length == 1) {
printMessage(COMMAND_HELP_MESSAGE);
} else if (args.length == 2) {
if (HELP_MESSAGES.containsKey(args[1])) {
printMessage(HELP_MESSAGES.get(args[1]));
} else {
printMessage(HELP_MESSAGES.get("error"));
}
} else {
printMessage(COMMAND_HELP_MESSAGE);
}
}
/**
* Gets the type of file from the extension on the filename.
*
* @param filename the filename to extract the type of file from.
*/
private String getTypeFromFilename(String filename) {
return filename.substring(filename.lastIndexOf(".") + 1);
}
/**
* Parses the command entered by the user into individual arguments.
*
* @param command the entire command entered by the user to be broken up into
* arguments.
*/
private String[] parseCommand(String command) {
// Special cases:
if (command.startsWith("search")) {
// if search command, only break into two args (command, search_string)
return command.trim().split(" ", 2);
} else if (command.startsWith("create")) {
// if create command, break into three args (command, file_type, title)
return command.trim().split(" ", 3);
} else if (command.startsWith("upload")) {
// if upload command, break into three args (command, file_path, title)
return command.trim().split(" ", 3);
}
// Default case, split into n args using a space as the separator.
return command.trim().split(" ");
}
/**
* Reads and executes one command.
*
* @param reader to read input from the keyboard
* @return false if the user quits, true on exception
* @throws IOException
* @throws ServiceException
*/
private boolean executeCommand(BufferedReader reader)
throws IOException, ServiceException, InterruptedException {
System.err.print("Command: ");
try {
String command = reader.readLine();
if (command == null) {
return false;
}
String[] args = parseCommand(command);
String name = args[0];
if (name.equals("create")) {
executeCreate(args);
} else if (name.equals("trash")) {
executeTrash(args);
} else if (name.equals("download")) {
executeDownload(args);
} else if (name.equals("list")) {
executeList(args);
} else if (name.equals("move")) {
executeMove(args);
} else if (name.equals("perms")) {
executePerms(args);
} else if (name.equals("remove")) {
executeRemove(args);
} else if (name.equals("search")) {
executeSearch(args);
} else if (name.equals("asearch")) {
executeAdvancedSearch(args);
} else if (name.equals("upload")) {
executeUpload(args);
} else if (name.equals("revisions")) {
executeRevisions(args);
} else if (name.equals("help")) {
executeHelp(args);
} else if (name.startsWith("q") || name.startsWith("exit")) {
return false;
} else {
out.println("Unknown command. Type 'help' for a list of commands.");
}
} catch (DocumentListException e) {
// Show *exactly* what went wrong.
e.printStackTrace();
}
return true;
}
/**
* Starts up the demo and prompts for commands.
*
* @throws ServiceException
* @throws IOException
*/
public void run() throws IOException, ServiceException, InterruptedException {
printMessage(WELCOME_MESSAGE);
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (executeCommand(reader)) {
}
}
/**
* Prints out a message.
*
* @param msg the message to be printed.
*/
private static void printMessage(String[] msg) {
for (String s : msg) {
System.out.println(s);
}
}
private static void turnOnLogging() {
// Configure the logging mechanisms
Logger httpLogger =
Logger.getLogger("com.google.gdata.client.http.HttpGDataRequest");
httpLogger.setLevel(Level.ALL);
Logger xmlLogger = Logger.getLogger("com.google.gdata.util.XmlParser");
xmlLogger.setLevel(Level.ALL);
// Create a log handler which prints all log events to the console
ConsoleHandler logHandler = new ConsoleHandler();
logHandler.setLevel(Level.ALL);
httpLogger.addHandler(logHandler);
xmlLogger.addHandler(logHandler);
}
/**
* Runs the demo.
*
* @param args the command-line arguments
*
* @throws DocumentListException
* @throws ServiceException
* @throws IOException
*/
public static void main(String[] args)
throws DocumentListException, IOException, ServiceException,
InterruptedException {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String authSub = parser.getValue("authSub", "auth", "a");
String user = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "p");
String host = parser.getValue("host", "s");
boolean help = parser.containsKey("help", "h");
if (host == null) {
host = DocumentList.DEFAULT_HOST;
}
if (help || (user == null || password == null) && authSub == null) {
printMessage(USAGE_MESSAGE);
System.exit(1);
}
if (parser.containsKey("log", "l")) {
turnOnLogging();
}
DocumentListDemo demo = new DocumentListDemo(System.out, APPLICATION_NAME,
host);
if (password != null) {
demo.login(user, password);
} else {
demo.login(authSub);
}
demo.run();
}
}
@@ -0,0 +1,30 @@
/* 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.docs;
/**
* Exception to be thrown when there is an issue with the DocumentList class.
*/
public class DocumentListException extends Exception {
public DocumentListException() {
super();
}
public DocumentListException(String msg) {
super(msg);
}
}
@@ -0,0 +1,508 @@
/* 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.docs;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gdata.client.media.ResumableGDataFileUploader;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.data.Link;
import com.google.gdata.data.docs.DocumentListEntry;
import com.google.gdata.data.docs.DocumentListFeed;
import com.google.gdata.data.media.MediaFileSource;
import com.google.gdata.util.ServiceException;
import com.google.gdata.client.uploader.FileUploadData;
import com.google.gdata.client.uploader.ProgressListener;
import com.google.gdata.client.uploader.ResumableHttpFileUploader;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* A console aplication to demonstrate interaction with Google Docs API to
* upload/update large media files using Resumable Upload protocol.
*
*
*/
public class DocumentResumableUploadDemo {
/** Default document list feed url. */
private static final String DEFAULT_DOCLIST_FEED_URL =
"https://docs.google.com/feeds/default/private/full";
/** Default create-media-url for uploading documents */
private static final String DEFAULT_RESUMABLE_UPLOAD_URL =
"https://docs.google.com/feeds/upload/create-session/default/private/full";
/** Maximum number of concurrent uploads */
private static final int MAX_CONCURRENT_UPLOADS = 10;
/** Time interval at which upload task will notify about the progress */
private static final int PROGRESS_UPDATE_INTERVAL = 1000;
/** Max size for each upload chunk */
private static final int DEFAULT_CHUNK_SIZE = 10000000;
/**
* Welcome message, introducing the program.
*/
private static final String[] WELCOME_MESSAGE = {
"", "This is a demo of the resumable upload feature for Docs GData API",
"Using this interface, you can upload/update large documents.", ""};
private static final String APPLICATION_NAME = "JavaGDataClientSampleAppV3.0";
private static final String[] USAGE_MESSAGE = {
"Usage: java DocumentResumableUploadDemo.jar --username <user> --password <pass>",
};
private static final String[] COMMAND_HELP_MESSAGE = {
"Commands:",
" list [object_type] "
+ " [[list objects]]",
" upload <file_path1:title1> ... <file_pathN:titleN> "
+ "[<chunk_size_in_byes>] [[uploads set of files]]",
" update <ducument_id> <updated_file_path> [<chunk_size_in_bytes>] "
+ " [[updates content of an object]]",
};
/** Instance of {@link DocumentList} */
private final DocumentList docs;
/** Steam to print status messages to. */
PrintStream output;
/**
* Constructor.
*
* @param docs {@link DocumentList} for interface to DocList API service.
* @param out printstream to output status messages to.
*/
DocumentResumableUploadDemo(DocumentList docs, PrintStream out) {
this.docs = docs;
this.output = out;
}
/**
* Prints out a message.
*
* @param msg the message to be printed.
*/
private static void printMessage(String[] msg) {
for (String s : msg) {
System.out.println(s);
}
}
private String[] parseCommand(String command) {
return command.trim().split(" ");
}
/**
* Prints out the specified document entry.
*
* @param doc the document entry to print.
*/
public void printDocumentEntry(DocumentListEntry doc) {
StringBuffer outputBuffer = new StringBuffer();
outputBuffer.append(" -- " + doc.getTitle().getPlainText() + " ");
if (!doc.getParentLinks().isEmpty()) {
for (Link link : doc.getParentLinks()) {
outputBuffer.append("[" + link.getTitle() + "] ");
}
}
outputBuffer.append(doc.getResourceId());
output.println(outputBuffer);
}
/**
* Uploads given collection of files. The call blocks until all uploads are
* done.
*
* @param url create-session url for initiating resumable uploads for
* documents API.
* @param files list of absolute filepaths to files to upload.
* @param chunkSize max size of each upload chunk.
*/
public Collection<DocumentListEntry> uploadFiles(String url,
List<String> files, int chunkSize)
throws IOException, ServiceException, InterruptedException {
// Create a listener
FileUploadProgressListener listener = new FileUploadProgressListener();
// Pool for handling concurrent upload tasks
ExecutorService executor =
Executors.newFixedThreadPool(MAX_CONCURRENT_UPLOADS);
// Create {@link ResumableGDataFileUploader} for each file to upload
List<ResumableGDataFileUploader> uploaders = Lists.newArrayList();
for (String fileName : files) {
MediaFileSource mediaFile = getMediaFileSource(fileName);
ResumableGDataFileUploader uploader =
new ResumableGDataFileUploader.Builder(
docs.service, new URL(url), mediaFile, null /*empty meatadata*/)
.title(mediaFile.getName())
.chunkSize(chunkSize).executor(executor)
.trackProgress(listener, PROGRESS_UPDATE_INTERVAL)
.build();
uploaders.add(uploader);
}
// attach the listener to list of uploaders
listener.listenTo(uploaders);
// Start the upload
for (ResumableGDataFileUploader uploader : uploaders) {
uploader.start();
}
// wait for uploads to complete
while (!listener.isDone()) {
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
listener.printResults();
throw ie; // rethrow
}
}
// print upload results
listener.printResults();
// return list of uploaded entries
return listener.getUploaded();
}
private MediaFileSource getMediaFileSource(String fileName) {
File file = new File(fileName);
MediaFileSource mediaFile = new MediaFileSource(file,
DocumentListEntry.MediaType.fromFileName(file.getName())
.getMimeType());
return mediaFile;
}
/**
* Execute 'list' command.
*/
private void executeList(String[] args) throws IOException,
ServiceException, DocumentListException {
DocumentListFeed feed = null;
String msg = "";
switch (args.length) {
case 1:
msg = "List of docs: ";
feed = docs.getDocsListFeed("all");
break;
case 2:
msg = "List of all " + args[1] + ": ";
feed = docs.getDocsListFeed(args[1]);
break;
case 3:
if (args[1].equals("folder")) {
msg = "Contents of folder_id '" + args[2] + "': ";
feed = docs.getFolderDocsListFeed(args[2]);
}
break;
}
if (feed != null) {
output.println(msg);
for (DocumentListEntry entry : feed.getEntries()) {
printDocumentEntry(entry);
}
} else {
printMessage(COMMAND_HELP_MESSAGE);
}
}
/**
* Execute 'upload' command.
*/
private void executeUpload(String[] args)
throws IOException, ServiceException, InterruptedException {
if (args.length > 1) {
int chunkSize = DEFAULT_CHUNK_SIZE;
List<String> files = Lists.newArrayList();
for (int index = 1; index < args.length; index++) {
String arg = args[index];
if (index < args.length - 1) {
files.add(arg);
continue;
}
// Last argument can be a file or chunk size
try {
chunkSize = Integer.parseInt(arg);
} catch (NumberFormatException nfe) {
files.add(arg);
}
}
uploadFiles(DEFAULT_RESUMABLE_UPLOAD_URL, files, chunkSize);
output.println("Finished upload");
}
}
/**
* Execute 'update' command.
*/
private void executeUpdate(String[] args)
throws IOException, ServiceException, InterruptedException {
String docIdToUpdate = args[1];
String filePath = args[2];
// retrieve latest entry
DocumentListEntry currentEntry = docs.service.getEntry(
new URL(DEFAULT_DOCLIST_FEED_URL + "/" + docIdToUpdate),
DocumentListEntry.class);
MediaFileSource mediaFile = getMediaFileSource(filePath);
ResumableGDataFileUploader uploader =
new ResumableGDataFileUploader
.Builder(docs.service, mediaFile, currentEntry)
.title(mediaFile.getName())
.requestType(
ResumableGDataFileUploader.RequestType.UPDATE_MEDIA_ONLY)
.build();
uploader.start();
// wait for upload to complete
while (!uploader.isDone()) {
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
output.println("Media update interrupted at: "
+ String.format("%3.0f", uploader.getProgress() * 100) + "%");
throw ie; // rethrow
}
}
DocumentListEntry updatedEntry =
uploader.getResponse(DocumentListEntry.class);
output.println("Finished update");
}
private boolean executeCommand(BufferedReader reader) throws IOException,
ServiceException, InterruptedException {
output.println("Enter a command");
try {
String command = reader.readLine();
if (command == null) {
return false;
}
String[] args = parseCommand(command);
String name = args[0];
if (name.equals("list")) {
executeList(args);
} else if (name.equals("upload")) {
executeUpload(args);
} else if (name.equals("update")) {
executeUpdate(args);
} else if (name.startsWith("q") || name.startsWith("exit")) {
return false;
} else if (name.equals("help")) {
printMessage(COMMAND_HELP_MESSAGE);
} else {
output.println("Unknown command. Type 'help' for list of commands");
}
} catch (DocumentListException e) {
e.printStackTrace();
}
return true;
}
void run() throws IOException, ServiceException, InterruptedException {
printMessage(WELCOME_MESSAGE);
printMessage(COMMAND_HELP_MESSAGE);
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
while (executeCommand(reader)) {
}
}
public static void main(String[] args) throws DocumentListException,
IOException, ServiceException, InterruptedException {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String user = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "p");
boolean help = parser.containsKey("help", "h");
if (help || (user == null || password == null)) {
printMessage(USAGE_MESSAGE);
System.exit(1);
}
// authenticate
DocumentList docs = new DocumentList(APPLICATION_NAME);
docs.login(user, password);
DocumentResumableUploadDemo demo = new DocumentResumableUploadDemo(
docs, System.out);
demo.run();
System.exit(1);
}
/**
* A {@link ProgressListener} implementation to track upload progress.
* The listener can track multiple uploads at the same time.
* Use {@link #isDone} to check if all uploads are completed and
* use {@link #getUploaded} to access results of successful uploads.
*/
private class FileUploadProgressListener implements ProgressListener {
private Collection<ResumableGDataFileUploader> trackedUploaders
= Lists.newArrayList();
private int pendingRequests;
Map<String, DocumentListEntry> uploaded = Maps.newHashMap();
Map<String, String> failed = Maps.newHashMap();
boolean processed;
public FileUploadProgressListener() {
this.pendingRequests = 0;
}
public void listenTo(Collection<ResumableGDataFileUploader> uploaders) {
this.trackedUploaders.addAll(uploaders);
this.pendingRequests = trackedUploaders.size();
}
public synchronized void progressChanged(ResumableHttpFileUploader uploader)
{
String fileId = ((FileUploadData) uploader.getData()).getFileName();
switch(uploader.getUploadState()) {
case COMPLETE:
case CLIENT_ERROR:
pendingRequests -= 1;
output.println(fileId + ": Completed");
break;
case IN_PROGRESS:
output.println(fileId + ":"
+ String.format("%3.0f", uploader.getProgress() * 100) + "%");
break;
case NOT_STARTED:
output.println(fileId + ":" + "Not Started");
break;
}
}
public synchronized boolean isDone() {
// not done if there are any pending requests.
if (pendingRequests > 0) {
return false;
}
// if all responses are processed., nothing to do.
if (processed) {
return true;
}
// check if all response streams are available.
for (ResumableGDataFileUploader uploader : trackedUploaders) {
if (!uploader.isDone()) {
return false;
}
}
// process all responses
for (ResumableGDataFileUploader uploader : trackedUploaders) {
String fileId = ((FileUploadData) uploader.getData()).getFileName();
switch(uploader.getUploadState()) {
case COMPLETE:
try {
DocumentListEntry entry =
uploader.getResponse(DocumentListEntry.class);
uploaded.put(fileId, entry);
} catch (IOException e) {
failed.put(fileId, "Upload completed, but unexpected error "
+ "reading server response");
} catch (ServiceException e) {
failed.put(fileId,
"Upload completed, but failed to parse server response");
}
break;
case CLIENT_ERROR:
failed.put(fileId, "Failed at " + uploader.getProgress());
break;
}
}
processed = true;
output.println("All requests done");
return true;
}
public synchronized Collection<DocumentListEntry> getUploaded() {
if (!isDone()) {
return null;
}
return uploaded.values();
}
public synchronized void printResults() {
if (!isDone()) {
return;
}
output.println("Result: " + uploaded.size() + ", " + failed.size());
if (uploaded.size() > 0) {
output.println(" Successfully Uploaded:");
for (Map.Entry<String, DocumentListEntry> entry : uploaded.entrySet()) {
printDocumentEntry(entry.getValue());
}
}
if (failed.size() > 0) {
output.println(" Failed to upload:");
for (Map.Entry entry : failed.entrySet()) {
output.println(" " + entry.getKey() + ":" + entry.getValue());
}
}
}
/**
* Prints out the specified document entry.
*
* @param doc the document entry to print.
*/
public void printDocumentEntry(DocumentListEntry doc) {
StringBuffer buffer = new StringBuffer();
buffer.append(" -- " + doc.getTitle().getPlainText() + " ");
if (!doc.getParentLinks().isEmpty()) {
for (Link link : doc.getParentLinks()) {
buffer.append("[" + link.getTitle() + "] ");
}
}
buffer.append(doc.getResourceId());
output.println(buffer);
}
}
}
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -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();
}
}
+641
View File
@@ -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>
&lt;feed&gt;
&lt;id&gt;http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets&lt;/id&gt;
&lt;updated&gt;2006-08-22T14:14:11.984Z&lt;/updated&gt;
&lt;title type="text"&gt;Items matching query: cars [item type : products]&lt;/title&gt;
&lt;link rel="alternate" type="text/html" href="http://base.google.com"/&gt;
&lt;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"/&gt;
&lt;link rel="self" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets?key=ABQ...9P2Y4A&amp;bq=cars+%5Bitem+type+%3A+products%5D"/&gt;
&lt;link rel="next" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets?start-index=26&amp;max-results=25&amp;key=ABQ...9P2Y4A&amp;bq=cars+%5Bitem+type+%3A+products%5D"/&gt;
&lt;generator version="1.0" uri="http://base.google.com"&gt;GoogleBase&lt;/generator&gt;
&lt;openSearch:totalResults&gt;278120&lt;/openSearch:totalResults&gt;
&lt;openSearch:itemsPerPage&gt;25&lt;/openSearch:itemsPerPage&gt;
&lt;entry&gt;
&lt;id&gt;http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets/10062394959501653657&lt;/id&gt;
&lt;published&gt;2006-06-30T21:45:12.000Z&lt;/published&gt;
&lt;updated&gt;2006-07-28T00:58:14.000Z&lt;/updated&gt;
...
</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()) &gt; 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>&lt;title&gt;</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>&lt;title&gt;</code> tag, which is the
title of the feed:</p>
<pre>
&lt;feed&gt;
...
&lt;title type="text"&gt;Items matching query: cars [item type : products]&lt;/title&gt;
...
&lt;entry&gt;
...
&lt;title type='text'&gt;Great care for sale&lt;/title&gt;
...
</pre>Atom does not mandate that the feed's <code>&lt;title&gt;</code> tag
should appear at a specific position inside the feed, so we need to make sure
we only display the <code>&lt;title&gt;</code> tags which are sub-elements of
an <code>&lt;entry&gt;</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>&lt;title&gt;</code> tag with a <code>&lt;entry&gt;</code> parent. The
<code>insideEntryTitle</code> flag is turned on each time we are inside a
<code>&lt;entry&gt;&lt;title&gt;</code> pair:</p>
<pre>
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals("title") &amp;&amp; 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>&lt;title&gt;</code> and the tag
on the top of the stack is <code>&lt;entry&gt;</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>&lt;title&gt;</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>
&lt;?xml version='1.0' encoding='UTF-8'?&gt;
&lt;feed&gt;
&lt;id&gt;http://base.google.com/base/feeds/items&lt;/id&gt;
&lt;updated&gt;2006-08-22T12:00:00.000Z&lt;/updated&gt;
&lt;title type="text"&gt;Items matching query: [customer id(int):1870031]&lt;/title&gt;
...
</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&amp;Passwd=north23AZ&amp;service=gbase&amp;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 =
"&lt;?xml version=\'1.0\'?&gt;\n" +
"&lt;entry xmlns=\'http://www.w3.org/2005/Atom\' xmlns:g=\'http://base.google.com/ns/1.0\'&gt;\n" +
" &lt;category scheme=\'http://base.google.com/categories/itemtypes\' term=\'Products\'/&gt;\n" +
" &lt;g:item_type type=\'text\'&gt;Products&lt;/g:item_type&gt;\n" +
" &lt;title type=\'text\'&gt;My cool car is for sale&lt;/title&gt;" +
" &lt;content type=\'xhtml\'&gt;Light pink, yellow seats.&lt;/content&gt;" +
"&lt;/entry&gt;";
</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
&lt;?xml version='1.0' encoding='UTF-8'?&gt;
&lt;entry&gt;
&lt;id&gt;http://base.google.com/base/feeds/items/16024998325761524417&lt;/id&gt;
&lt;published&gt;2006-08-23T15:18:55.184Z&lt;/published&gt;
&lt;updated&gt;2006-08-23T15:18:55.184Z&lt;/updated&gt;
&lt;category scheme="http://base.google.com/categories/itemtypes" term="Products"/&gt;
&lt;title type="text"&gt;My cool car is for sale&lt;/title&gt;
&lt;content type="xhtml"&gt;Light pink, yellow seats.&lt;/content&gt;
&lt;link rel="self" type="application/atom+xml" href="http://base.google.com/base/feeds/items/16024998325761524417"/&gt;
&lt;link rel="edit" type="application/atom+xml" href="http://base.google.com/base/feeds/items/16024998325761524417"/&gt;
&lt;g:item_type type="text"&gt;Products&lt;/g:item_type&gt;
&lt;/entry&gt;
</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:
&lt;?xml version='1.0'?&gt;
&lt;entry xmlns='http://www.w3.org/2005/Atom' xmlns:g='http://base.google.com/ns/1.0'&gt;
&lt;category scheme='http://base.google.com/categories/itemtypes' term='Products'/&gt;
&lt;g:item_type type='text'&gt;Products&lt;/g:item_type&gt;
&lt;title type='text'&gt;My cool car is for sale&lt;/title&gt;
&lt;content type='xhtml'&gt;Light pink, yellow seats.&lt;/content&gt;
&lt;/entry&gt;
Updating item: http://base.google.com/base/feeds/items/18020038538902937385
&lt;?xml version='1.0' encoding='UTF-8'?&gt;
&lt;entry&gt;
&lt;id&gt;http://base.google.com/base/feeds/items/18020038538902937385&lt;/id&gt;
&lt;updated&gt;2006-08-23T16:20:21.601Z&lt;/updated&gt;
&lt;category scheme="http://base.google.com/categories/itemtypes" term="Products"/&gt;
&lt;title type="text"&gt;My cool car is for sale&lt;/title&gt;
&lt;content type="xhtml"&gt;Light pink, yellow seats.&lt;/content&gt;
&lt;link rel="self" type="application/atom+xml" href="http://base.google.com/base/feeds/items/18020038538902937385"/&gt;
&lt;link rel="edit" type="application/atom+xml" href="http://base.google.com/base/feeds/items/18020038538902937385"/&gt;
&lt;g:item_type type="text"&gt;Products&lt;/g:item_type&gt;
&lt;/entry&gt;
</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>
&lt;id&gt;http://base.google.com/base/feeds/items/18020038538902937385&lt;/id&gt;
</pre>We assume that the item's id is surrounded by the first
&lt;id&gt;&lt;/id&gt; 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);
}
}

Some files were not shown because too many files have changed in this diff Show More