Inital commit
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -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 <user>
|
||||
* --password <pass> --domain <domain>
|
||||
* --destination_user <destination_user>
|
||||
*/
|
||||
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 <user>
|
||||
* --password <pass> --domain <domain> --setting <setting>
|
||||
* [--get true --destination_user <destination_user>] [--disable]
|
||||
*
|
||||
* <setting> 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 <user>
|
||||
* --password <pass> --domain <domain>
|
||||
* [--destination_user <destination_user>] [--data_file <file>]
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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%;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
After Width: | Height: | Size: 84 B |
|
After Width: | Height: | Size: 82 B |
|
After Width: | Height: | Size: 849 B |
|
After Width: | Height: | Size: 44 B |
|
After Width: | Height: | Size: 43 B |
|
After Width: | Height: | Size: 43 B |
|
After Width: | Height: | Size: 44 B |
@@ -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>
|
||||
@@ -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]=" ";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()?"«":"‹ ";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?"»":" ›";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"«"}
|
||||
);x.nb(function(){return"»"}
|
||||
);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;
|
||||
|
||||
@@ -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%>
|
||||
+ "\"×tamp=\"" + <%=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) + " ";
|
||||
} 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.");
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Add a new item to Google Base using the Google Base data API server.
|
||||
*/
|
||||
public class InsertExample {
|
||||
/**
|
||||
* URL of the authenticated customer feed.
|
||||
*/
|
||||
private static final String ITEMS_FEED = "http://base.google.com/base/feeds/items";
|
||||
|
||||
/**
|
||||
* The data item we are going to insert, in XML/Atom format.
|
||||
*/
|
||||
private static final String DATA_ITEM =
|
||||
"<?xml version='1.0'?>\n" +
|
||||
"<entry xmlns='http://www.w3.org/2005/Atom'\n" +
|
||||
" xmlns:g='http://base.google.com/ns/1.0'>\n" +
|
||||
" <g:item_type type='text'>testrecipes</g:item_type>\n" +
|
||||
" <title type='text'>Fabulous cheese cake</title>\n" +
|
||||
" <content type='xhtml'>All that you need is lots of patience.</content>\n" +
|
||||
"</entry>";
|
||||
|
||||
/**
|
||||
* URL used for authenticating and obtaining an authentication token.
|
||||
* More details about how it works:
|
||||
* <code>http://code.google.com/apis/accounts/AuthForInstalledApps.html<code>
|
||||
*/
|
||||
private static final String AUTHENTICATION_URL = "https://www.google.com/accounts/ClientLogin";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account email here.
|
||||
*/
|
||||
private static final String EMAIL = "";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account password here.
|
||||
*/
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
/**
|
||||
* The main method constructs a <code>InsertExample</code> instance, obtains an
|
||||
* authorization token and posts a new item to Google Base.
|
||||
*/
|
||||
public static void main(String[] args) throws MalformedURLException, IOException {
|
||||
InsertExample insertExample = new InsertExample();
|
||||
String token = insertExample.authenticate();
|
||||
System.out.println("Obtained authorization token: " + token);
|
||||
insertExample.postItem(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts <code>DATA_ITEM</code> by making a POST request to
|
||||
* <code>ITEMS_URL<code>.
|
||||
* @param token authentication token obtained using <code>authenticate</code>
|
||||
* @throws IOException if an I/O exception occurs while creating/writing/
|
||||
* reading the request
|
||||
*/
|
||||
public void postItem(String token) throws IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection)(new URL(ITEMS_FEED)).openConnection();
|
||||
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
// Set the properties of the connection: the Http method, the content type
|
||||
// of the POST request and the authorization header
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/atom+xml");
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
|
||||
// Post the data item
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(DATA_ITEM.getBytes());
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = connection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_CREATED) {
|
||||
inputStream = connection.getInputStream();
|
||||
} else {
|
||||
inputStream = connection.getErrorStream();
|
||||
}
|
||||
|
||||
// write the output to the console
|
||||
System.out.println(toString(inputStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authentication token for the provided set of credentials.
|
||||
* @return the authorization token that can be used to access authenticated
|
||||
* Google Base data API feeds
|
||||
*/
|
||||
public String authenticate() {
|
||||
// create the login request
|
||||
String postOutput = null;
|
||||
try {
|
||||
URL url = new URL(AUTHENTICATION_URL);
|
||||
postOutput = makeLoginRequest(url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Could not connect to authentication server: "
|
||||
+ e.toString());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Parse the result of the login request. If everything went fine, the
|
||||
// response will look like
|
||||
// HTTP/1.0 200 OK
|
||||
// Server: GFE/1.3
|
||||
// Content-Type: text/plain
|
||||
// SID=DQAAAGgA...7Zg8CTN
|
||||
// LSID=DQAAAGsA...lk8BBbG
|
||||
// Auth=DQAAAGgA...dk3fA5N
|
||||
// so all we need to do is look for "Auth" and get the token that comes after it
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(postOutput, "=\n ");
|
||||
String token = null;
|
||||
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
if (tokenizer.nextToken().equals("Auth")) {
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
token = tokenizer.nextToken();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (token == null) {
|
||||
System.out.println("Authentication error. Response from server:\n" + postOutput);
|
||||
System.exit(1);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a HTTP POST request to the provided {@code url} given the provided
|
||||
* {@code parameters}. It returns the output from the POST handler as a
|
||||
* String object.
|
||||
*
|
||||
* @param url the URL to post the request
|
||||
* @return the output from the handler
|
||||
* @throws IOException if an I/O exception occurs while
|
||||
* creating/writing/reading the request
|
||||
*/
|
||||
private String makeLoginRequest(URL url)
|
||||
throws IOException {
|
||||
// Create a login request. A login request is a POST request that looks like
|
||||
// POST /accounts/ClientLogin HTTP/1.0
|
||||
// Content-type: application/x-www-form-urlencoded
|
||||
// Email=johndoe@gmail.com&Passwd=north23AZ&service=gbase&source=Insert Example
|
||||
|
||||
// Open connection
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
|
||||
// Set properties of the connection
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoInput(true);
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("Content-Type",
|
||||
"application/x-www-form-urlencoded");
|
||||
|
||||
// Form the POST parameters
|
||||
StringBuilder content = new StringBuilder();
|
||||
content.append("Email=").append(URLEncoder.encode(EMAIL, "UTF-8"));
|
||||
content.append("&Passwd=").append(URLEncoder.encode(PASSWORD, "UTF-8"));
|
||||
content.append("&source=").append(URLEncoder.encode("Google Base data API example", "UTF-8"));
|
||||
content.append("&service=").append(URLEncoder.encode("gbase", "UTF-8"));
|
||||
|
||||
OutputStream outputStream = urlConnection.getOutputStream();
|
||||
outputStream.write(content.toString().getBytes("UTF-8"));
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = urlConnection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
inputStream = urlConnection.getInputStream();
|
||||
} else {
|
||||
inputStream = urlConnection.getErrorStream();
|
||||
}
|
||||
|
||||
return toString(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of the input stream to a <code>String<code>.
|
||||
*/
|
||||
private String toString(InputStream inputStream) throws IOException {
|
||||
String string;
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
if (inputStream != null) {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
||||
while (null != (string = reader.readLine())) {
|
||||
outputBuilder.append(string).append('\n');
|
||||
}
|
||||
}
|
||||
return outputBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* Dumps to the console the response of a Google Base data API query.
|
||||
*/
|
||||
public class QueryExample1 {
|
||||
/**
|
||||
* Url of the Google Base data API snippet feed.
|
||||
*/
|
||||
private static final String SNIPPETS_FEED = "http://base.google.com/base/feeds/snippets";
|
||||
|
||||
/**
|
||||
* The query that is sent over to the Google Base data API server.
|
||||
*/
|
||||
private static final String QUERY = "cars [item type : products]";
|
||||
|
||||
/**
|
||||
* Connect to <code>SNIPPETS_FEED</code> and display the response.
|
||||
* @throws IOException if an error occured while connecting or reading from
|
||||
* the feed
|
||||
*/
|
||||
public void displayItems() throws IOException {
|
||||
URL url = new URL(SNIPPETS_FEED + "?bq=" +
|
||||
URLEncoder.encode(QUERY, "UTF-8"));
|
||||
|
||||
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
|
||||
InputStream inputStream = httpConnection.getInputStream();
|
||||
|
||||
int ch;
|
||||
while ((ch=inputStream.read()) > 0) {
|
||||
System.out.print((char)ch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method simply creates a <code>QueryExample2</code> instance and
|
||||
* calls <code>displayItems</code>.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
new QueryExample1().displayItems();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Stack;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
/**
|
||||
* Display the titles of the Google Base items that match a specific query.
|
||||
*/
|
||||
public class QueryExample2 {
|
||||
/**
|
||||
* Url of the Google Base data API snippet feed.
|
||||
*/
|
||||
private static final String SNIPPETS_FEED = "http://base.google.com/base/feeds/snippets";
|
||||
|
||||
/**
|
||||
* The query that is sent over to the Google Base data API server.
|
||||
*/
|
||||
private static final String QUERY = "cars [item type : products]";
|
||||
|
||||
/**
|
||||
* Create a <code>QueryExample2</code> instance and
|
||||
* call <code>displayItems</code>.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException, SAXException,
|
||||
ParserConfigurationException {
|
||||
new QueryExample2().displayItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the Google Base data API server, retrieve the items that match
|
||||
* <code>QUERY</code> and call <code>DisplayTitlesHandler</code> to extract
|
||||
* and display the titles from the XML response.
|
||||
*/
|
||||
public void displayItems() throws IOException, SAXException,
|
||||
ParserConfigurationException {
|
||||
/*
|
||||
* Create a URL object, open an Http connection on it and get the input
|
||||
* stream that reads the Http response.
|
||||
*/
|
||||
URL url = new URL(SNIPPETS_FEED + "?bq=" +
|
||||
URLEncoder.encode(QUERY, "UTF-8"));
|
||||
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
|
||||
InputStream inputStream = httpConnection.getInputStream();
|
||||
|
||||
/*
|
||||
* Create a SAX XML parser and pass in the input stream to the parser.
|
||||
* The parser will use DisplayTitleHandler to extract the titles from the
|
||||
* XML stream.
|
||||
*/
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
parser.parse(inputStream, new DisplayTitlesHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple SAX event handler, which prints out the titles of all entries in the
|
||||
* Atom response feed.
|
||||
*/
|
||||
private static class DisplayTitlesHandler extends DefaultHandler {
|
||||
/**
|
||||
* Stack containing the opening XML tags of the response.
|
||||
*/
|
||||
private Stack<String> xmlTags = new Stack<String>();
|
||||
|
||||
/**
|
||||
* Counter that keeps track of the currently parsed item.
|
||||
*/
|
||||
private int itemNo = 0;
|
||||
|
||||
/**
|
||||
* True if we are inside of a data entry's title, false otherwise.
|
||||
*/
|
||||
private boolean insideEntryTitle = false;
|
||||
|
||||
/**
|
||||
* Receive notification of an opening XML tag: push the tag to
|
||||
* <code>xmlTags</code>. If the tag is a title tag inside an entry tag,
|
||||
* turn <code>insideEntryTitle</code> to <code>true</code>.
|
||||
*/
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName,
|
||||
Attributes attributes) throws SAXException {
|
||||
if (qName.equals("title") && xmlTags.peek().equals("entry")) {
|
||||
insideEntryTitle = true;
|
||||
System.out.print("Item " + ++itemNo + ": ");
|
||||
}
|
||||
xmlTags.push(qName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive notification of a closing XML tag: remove the tag from teh stack.
|
||||
* If we were inside of an entry's title, turn <code>insideEntryTitle</code>
|
||||
* to <code>false</code>.
|
||||
*/
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName)
|
||||
throws SAXException {
|
||||
// If a "title" element is closed, we start a new line, to prepare
|
||||
// printing the new title.
|
||||
xmlTags.pop();
|
||||
if (insideEntryTitle) {
|
||||
insideEntryTitle = false;
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for receiving notification of character data inside an
|
||||
* XML element.
|
||||
*/
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
// display the character data if the opening tag is "title" and its parent is
|
||||
// "entry"
|
||||
if (insideEntryTitle) {
|
||||
System.out.print(new String(ch, start, length));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Display all items of a specific customer.
|
||||
*/
|
||||
public class QueryExample3 {
|
||||
/**
|
||||
* URL of the authenticated customer feed.
|
||||
*/
|
||||
private static final String ITEMS_FEED = "http://base.google.com/base/feeds/items";
|
||||
|
||||
/**
|
||||
* URL used for authenticating and obtaining an authentication token.
|
||||
* More details about how it works:
|
||||
* <code>http://code.google.com/apis/accounts/AuthForInstalledApps.html<code>
|
||||
*/
|
||||
private static final String AUTHENTICATION_URL = "https://www.google.com/accounts/ClientLogin";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account email here.
|
||||
*/
|
||||
private static final String EMAIL = "";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account password here.
|
||||
*/
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
/**
|
||||
* Create a <code>QueryExample3</code> instance and call
|
||||
* <code>displayMyItems</code>, which displays all items that belong to the
|
||||
* currently authenticated user.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
QueryExample3 queryExample = new QueryExample3();
|
||||
String token = queryExample.authenticate();
|
||||
queryExample.displayMyItems(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authentication token for the provided set of credentials.
|
||||
* @return the authorization token that can be used to access authenticated
|
||||
* Google Base data API feeds
|
||||
*/
|
||||
public String authenticate() {
|
||||
// create the login request
|
||||
String postOutput = null;
|
||||
try {
|
||||
URL url = new URL(AUTHENTICATION_URL);
|
||||
postOutput = makeLoginRequest(url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Could not connect to authentication server: "
|
||||
+ e.toString());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Parse the result of the login request. If everything went fine, the
|
||||
// response will look like
|
||||
// HTTP/1.0 200 OK
|
||||
// Server: GFE/1.3
|
||||
// Content-Type: text/plain
|
||||
// SID=DQAAAGgA...7Zg8CTN
|
||||
// LSID=DQAAAGsA...lk8BBbG
|
||||
// Auth=DQAAAGgA...dk3fA5N
|
||||
// so all we need to do is look for "Auth" and get the token that comes after it
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(postOutput, "=\n ");
|
||||
String token = null;
|
||||
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
if (tokenizer.nextToken().equals("Auth")) {
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
token = tokenizer.nextToken();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (token == null) {
|
||||
System.out.println("Authentication error. Response from server:\n" + postOutput);
|
||||
System.exit(1);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the "items" feed, that is the feed that contains the items that
|
||||
* belong to the currently authenticated user.
|
||||
*
|
||||
* @param token the authorization token, as returned by
|
||||
* <code>authenticate<code>
|
||||
* @throws IOException if an IOException occurs while creating/reading the
|
||||
* request
|
||||
*/
|
||||
public void displayMyItems(String token) throws MalformedURLException, IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection)(new URL(ITEMS_FEED)).openConnection() ;
|
||||
// Set properties of the connection
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
inputStream = connection.getInputStream();
|
||||
} else {
|
||||
inputStream = connection.getErrorStream();
|
||||
}
|
||||
|
||||
System.out.println(toString(inputStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a HTTP POST request to the provided {@code url} given the provided
|
||||
* {@code parameters}. It returns the output from the POST handler as a
|
||||
* String object.
|
||||
*
|
||||
* @param url the URL to post the request
|
||||
* @return the output from the Google Accounts server, as string
|
||||
* @throws IOException if an I/O exception occurs while
|
||||
* creating/writing/reading the request
|
||||
*/
|
||||
private String makeLoginRequest(URL url)
|
||||
throws IOException {
|
||||
// Create a login request. A login request is a POST request that looks like
|
||||
// POST /accounts/ClientLogin HTTP/1.0
|
||||
// Content-type: application/x-www-form-urlencoded
|
||||
// Email=johndoe@gmail.com&Passwd=north23AZ&service=gbase&source=Insert Example
|
||||
|
||||
// Open connection
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
|
||||
// Set properties of the connection
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoInput(true);
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("Content-Type",
|
||||
"application/x-www-form-urlencoded");
|
||||
|
||||
// Form the POST parameters
|
||||
StringBuilder content = new StringBuilder();
|
||||
content.append("Email=").append(URLEncoder.encode(EMAIL, "UTF-8"));
|
||||
content.append("&Passwd=").append(URLEncoder.encode(PASSWORD, "UTF-8"));
|
||||
content.append("&service=").append(URLEncoder.encode("gbase", "UTF-8"));
|
||||
content.append("&source=").append(URLEncoder.encode("Google Base data API example", "UTF-8"));
|
||||
|
||||
OutputStream outputStream = urlConnection.getOutputStream();
|
||||
outputStream.write(content.toString().getBytes("UTF-8"));
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = urlConnection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
inputStream = urlConnection.getInputStream();
|
||||
} else {
|
||||
inputStream = urlConnection.getErrorStream();
|
||||
}
|
||||
|
||||
return toString(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of the input stream to a <code>String<code>.
|
||||
*/
|
||||
private String toString(InputStream inputStream) throws IOException {
|
||||
String string;
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
if (inputStream != null) {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(inputStream));
|
||||
while (null != (string = reader.readLine())) {
|
||||
outputBuilder.append(string).append('\n');
|
||||
}
|
||||
}
|
||||
return outputBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.gbase.basic;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Update a Google Base data item using the Google Base data API server.
|
||||
*/
|
||||
public class UpdateExample {
|
||||
/**
|
||||
* URL of the authenticated customer feed.
|
||||
*/
|
||||
private static final String ITEMS_FEED = "http://base.google.com/base/feeds/items";
|
||||
|
||||
/**
|
||||
* The data item we are going to insert, in XML/Atom format.
|
||||
*/
|
||||
private static final String DATA_ITEM =
|
||||
"<?xml version='1.0'?>\n" +
|
||||
"<entry xmlns='http://www.w3.org/2005/Atom'\n" +
|
||||
" xmlns:g='http://base.google.com/ns/1.0'>\n" +
|
||||
" <g:item_type type='text'>testrecipes</g:item_type>\n" +
|
||||
" <title type='text'>Fabulous cheese cake</title>\n" +
|
||||
" <content type='xhtml'>All that you need is lots of patience.</content>\n" +
|
||||
"</entry>";
|
||||
|
||||
/**
|
||||
* The updated data item, in XML/Atom format. It adds an additional label to
|
||||
* <code>DATA_ITEM</code>.
|
||||
*/
|
||||
private static final String NEW_DATA_ITEM =
|
||||
"<?xml version='1.0'?>\n" +
|
||||
"<entry xmlns='http://www.w3.org/2005/Atom'\n" +
|
||||
" xmlns:g='http://base.google.com/ns/1.0'>\n" +
|
||||
" <g:item_type type='text'>testrecipes</g:item_type>\n" +
|
||||
" <title type='text'>Yummy cheese cake</title>\n" +
|
||||
" <content type='xhtml'>All that you need is lots of patience.</content>\n" +
|
||||
" <g:main_ingredient type='text'>cheese</g:main_ingredient>\n" +
|
||||
"</entry>";
|
||||
|
||||
/**
|
||||
* URL used for authenticating and obtaining an authentication token.
|
||||
* More details about how it works:
|
||||
* <code>http://code.google.com/apis/accounts/AuthForInstalledApps.html<code>
|
||||
*/
|
||||
private static final String AUTHENTICATION_URL =
|
||||
"https://www.google.com/accounts/ClientLogin";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account email here.
|
||||
*/
|
||||
private static final String EMAIL = "";
|
||||
|
||||
/**
|
||||
* Fill in your Google Account password here.
|
||||
*/
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
/**
|
||||
* The main method constructs an <code>UpdateExample</code> instance,
|
||||
* obtains an authorization token, posts a new item to Google Base, extracts
|
||||
* the new item's id from the reponse and uses it to update the item.
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
throws MalformedURLException, IOException {
|
||||
UpdateExample updateExample = new UpdateExample();
|
||||
String token = updateExample.authenticate();
|
||||
System.out.println("Obtained authorization token: " + token);
|
||||
|
||||
System.out.println("Posting item:\n" + DATA_ITEM);
|
||||
String itemUrl = updateExample.extractItemUrlFromResponse(
|
||||
updateExample.postItem(token));
|
||||
|
||||
System.out.println("Updating item: " + itemUrl);
|
||||
String updateResponse = updateExample.updateItem(token, itemUrl);
|
||||
System.out.println(updateResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authentication token for the provided set of credentials.
|
||||
* @return the authorization token that can be used to access authenticated
|
||||
* Google Base data API feeds
|
||||
*/
|
||||
public String authenticate() {
|
||||
// create the login request
|
||||
String postOutput = null;
|
||||
try {
|
||||
URL url = new URL(AUTHENTICATION_URL);
|
||||
postOutput = makeLoginRequest(url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Could not connect to authentication server: "
|
||||
+ e.toString());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Parse the result of the login request. If everything went fine, the
|
||||
// response will look like
|
||||
// HTTP/1.0 200 OK
|
||||
// Server: GFE/1.3
|
||||
// Content-Type: text/plain
|
||||
// SID=DQAAAGgA...7Zg8CTN
|
||||
// LSID=DQAAAGsA...lk8BBbG
|
||||
// Auth=DQAAAGgA...dk3fA5N
|
||||
// so all we need to do is look for "Auth" and get the token that comes after it
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(postOutput, "=\n ");
|
||||
String token = null;
|
||||
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
if (tokenizer.nextToken().equals("Auth")) {
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
token = tokenizer.nextToken();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (token == null) {
|
||||
System.out.println("Authentication error. Response from server:\n" + postOutput);
|
||||
System.exit(1);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the POST XML response returned by <code>insertResponse</code> and
|
||||
* extract the Google Base item id of the newly created item. To keep parsing
|
||||
* simple, we assume that the first "id" tag contains the Atom item id; this
|
||||
* is true for the Google Base data API servers, but it's not enforced by Atom -
|
||||
* see how the title is parsed in {@link QueryExample2}
|
||||
* @param insertResponse the response sent by the Google Base data API server
|
||||
* after the insert operation
|
||||
* @return the Url that identifies the item, for example: <code>
|
||||
* http://base.google.com/base/feeds/items/18020038538902937385</code>
|
||||
*/
|
||||
public String extractItemUrlFromResponse(String insertResponse) {
|
||||
int startIndex = insertResponse.indexOf("<id>") + 4;
|
||||
int endIndex = insertResponse.indexOf("</id>");
|
||||
String itemUrl = insertResponse.substring(startIndex, endIndex);
|
||||
return itemUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts <code>DATA_ITEM</code> by making a POST request to
|
||||
* <code>ITEMS_FEED<code>.
|
||||
* @param token authentication token obtained using <code>authenticate</code>
|
||||
* @return the Google Base data API server's insert response
|
||||
* @throws IOException if an I/O exception occurs while creating/writing/
|
||||
* reading the request
|
||||
*/
|
||||
public String postItem(String token) throws IOException {
|
||||
return makeHttpRequest(token, ITEMS_FEED, DATA_ITEM, "POST",
|
||||
HttpURLConnection.HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates <code>NEW_DATA_ITEM</code> by making a PUT request to
|
||||
* <code>itemUrl</code>.
|
||||
*
|
||||
* @param token authentication token obtained using <code>authenticate</code>
|
||||
* @param itemUrl the identifier of the item to update, which has the form
|
||||
* <code>ITEMS_URL + "/itemId"</code>
|
||||
* @return the Google Base data API server's update response
|
||||
* @throws IOException if an I/O exception occurs while creating/writing/
|
||||
* reading the request
|
||||
*/
|
||||
public String updateItem(String token, String itemUrl)
|
||||
throws MalformedURLException, IOException {
|
||||
return makeHttpRequest(token, itemUrl, NEW_DATA_ITEM, "PUT",
|
||||
HttpURLConnection.HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an Http request to <code>url</code>, using <code>httpMethod</code>,
|
||||
* post <code>item</code> and return the response.
|
||||
*
|
||||
* @param token authentication token obtained using <code>authenticate</code>
|
||||
* @param url the identifier of the item to update, which has the form
|
||||
* <code>ITEMS_URL + "/itemId"</code>
|
||||
* @param item the item to be posted via the request
|
||||
* @param httpMethod the httpMethod to use for posting (should be PUT or POST)
|
||||
* @param expectedResponseCode the response code returned in case of a
|
||||
* successful operation
|
||||
* @return the Google Base data API update response
|
||||
* @throws IOException if an I/O exception occurs while
|
||||
* creating/writing/reading the request
|
||||
*/
|
||||
private String makeHttpRequest(String token, String url, String item,
|
||||
String httpMethod, int expectedResponseCode) throws IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection)(new URL(url)).openConnection() ;
|
||||
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
// Set the properties of the connection: the http request method, the
|
||||
// content type and the authorization header
|
||||
connection.setRequestMethod(httpMethod);
|
||||
connection.setRequestProperty("Content-Type", "application/atom+xml");
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
|
||||
// Post the data item
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(item.getBytes());
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode == expectedResponseCode) {
|
||||
return toString(connection.getInputStream());
|
||||
} else {
|
||||
throw new RuntimeException(toString(connection.getErrorStream()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes a HTTP POST request to the provided {@code url} given the provided
|
||||
* {@code parameters}. It returns the output from the POST handler as a
|
||||
* String object.
|
||||
*
|
||||
* @param url the URL to post the request
|
||||
* @return the output from the server
|
||||
* @throws IOException if an I/O exception occurs while
|
||||
* creating/writing/reading the request
|
||||
*/
|
||||
private String makeLoginRequest(URL url)
|
||||
throws IOException {
|
||||
// Create a login request. A login request is a POST request that looks like
|
||||
// POST /accounts/ClientLogin HTTP/1.0
|
||||
// Content-type: application/x-www-form-urlencoded
|
||||
// Email=johndoe@gmail.com&Passwd=north23AZ&service=gbase&source=Insert Example
|
||||
|
||||
// Open connection
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
|
||||
// Set properties of the connection
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoInput(true);
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setUseCaches(false);
|
||||
urlConnection.setRequestProperty("Content-Type",
|
||||
"application/x-www-form-urlencoded");
|
||||
|
||||
// Form the POST parameters
|
||||
StringBuilder content = new StringBuilder();
|
||||
content.append("Email=").append(URLEncoder.encode(EMAIL, "UTF-8"));
|
||||
content.append("&Passwd=").append(URLEncoder.encode(PASSWORD, "UTF-8"));
|
||||
content.append("&source=").append(URLEncoder.encode("Google Base data API example", "UTF-8"));
|
||||
content.append("&service=").append(URLEncoder.encode("gbase", "UTF-8"));
|
||||
|
||||
OutputStream outputStream = urlConnection.getOutputStream();
|
||||
outputStream.write(content.toString().getBytes("UTF-8"));
|
||||
outputStream.close();
|
||||
|
||||
// Retrieve the output
|
||||
int responseCode = urlConnection.getResponseCode();
|
||||
InputStream inputStream;
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
inputStream = urlConnection.getInputStream();
|
||||
} else {
|
||||
inputStream = urlConnection.getErrorStream();
|
||||
}
|
||||
|
||||
return toString(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of the input stream to a <code>String<code>.
|
||||
*/
|
||||
private String toString(InputStream inputStream) throws IOException {
|
||||
String lineToRead;
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
if (inputStream != null) {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
||||
while (null != (lineToRead = reader.readLine())) {
|
||||
outputBuilder.append(lineToRead).append('\n');
|
||||
}
|
||||
}
|
||||
return outputBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,641 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta name="generator" content=
|
||||
"HTML Tidy for Linux/x86 (vers 1st November 2003), see www.w3.org" />
|
||||
|
||||
<title>Google Base data API: Sample Applications</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<P>Sample standalone applications accessing Google Base data API feeds</P>
|
||||
|
||||
<h2><a name="intro" id="intro"></a>Introduction</h2>The Google Base data Java
|
||||
<a href='http://code.google.com/apis/base/sample-apps.html'>Client
|
||||
Library</a> offers a nice object oriented abstraction for accessing the
|
||||
Google Base data API. However, if you prefer to interact with the Google Base
|
||||
data API servers directly, here are a few examples that will start you up.
|
||||
|
||||
<p>This document assumes you know Java programming (including some basic
|
||||
knowledge of Http connections and SAX parsers) and that you are familiar with
|
||||
<a href="http://code.google.com/apis/base/concepts.html">Google Base
|
||||
concepts</a>. You need to understand the following concepts before you can
|
||||
take full advantage of the sample applications:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href=
|
||||
"http://code.google.com/apis/base/attrs-queries.html#queries">queries</a></li>
|
||||
|
||||
<li><a href=
|
||||
"http://code.google.com/apis/base/attrs-queries.html#gbItemTypes">item
|
||||
types</a></li>
|
||||
|
||||
<li><a href=
|
||||
"http://code.google.com/apis/base/attrs-queries.html#gbAttrs">attributes</a></li>
|
||||
</ul>
|
||||
|
||||
<p>This tutorial consists of stepping through 5 examples. The first example
|
||||
shows how to connect to a Google Base data API feed and query data. The
|
||||
second example extends this by showing how to parse the result and extract
|
||||
data of interest from the feed. The third example introduces authentication
|
||||
and demonstrates how to display your own items, rather than querying
|
||||
snippets. The fourth example demonstrates how to insert your own item into
|
||||
Google Base, while the last example shows how to update a previously inserted
|
||||
item.</p>
|
||||
|
||||
<h2><a name="queryExample1" id="queryExample1"></a>Query Example 1 - query
|
||||
the Google Base data API and display the result</h2>
|
||||
|
||||
<p><code>QueryExample1</code> is a simple Java application that runs from the
|
||||
command line. It performs an unauthenticated query on the public <a href=
|
||||
'http://code.google.com/apis/base/snippets-feed.html'>snippets feed</a>
|
||||
(<code>/feeds/snippets</code>) and it dumps the query response to the console
|
||||
(it won't look pretty!).</p>
|
||||
|
||||
<h3><a name="QE1run" id="QE1run"></a>Running
|
||||
<code>QueryExample1</code></h3>Edit QueryExample1.java and fill in the
|
||||
|
||||
Compile and run the example using your favorite editor, or using the
|
||||
command line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/QueryExample1.java
|
||||
java sample.gbase/basic/QueryExample1
|
||||
|
||||
</pre>The output (conveniently formatted) will look like:
|
||||
<pre>
|
||||
<feed>
|
||||
<id>http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets</id>
|
||||
<updated>2006-08-22T14:14:11.984Z</updated>
|
||||
<title type="text">Items matching query: cars [item type : products]</title>
|
||||
<link rel="alternate" type="text/html" href="http://base.google.com"/>
|
||||
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets"/>
|
||||
<link rel="self" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets?key=ABQ...9P2Y4A&bq=cars+%5Bitem+type+%3A+products%5D"/>
|
||||
<link rel="next" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets?start-index=26&max-results=25&key=ABQ...9P2Y4A&bq=cars+%5Bitem+type+%3A+products%5D"/>
|
||||
<generator version="1.0" uri="http://base.google.com">GoogleBase</generator>
|
||||
<openSearch:totalResults>278120</openSearch:totalResults>
|
||||
<openSearch:itemsPerPage>25</openSearch:itemsPerPage>
|
||||
<entry>
|
||||
<id>http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets/10062394959501653657</id>
|
||||
<published>2006-06-30T21:45:12.000Z</published>
|
||||
<updated>2006-07-28T00:58:14.000Z</updated>
|
||||
...
|
||||
|
||||
</pre>
|
||||
|
||||
<h3><a name="QE1stepThru" id="QE1stepThru"></a>Stepping through the
|
||||
<code>QueryExample1</code> code</h3>
|
||||
|
||||
<p>At the very beginning we define the url of the feed we are connecting to
|
||||
and the query that we are going to run:</p>
|
||||
<pre>
|
||||
private static final String SNIPPETS_FEED = "http://base.google.com/base/feeds/snippets";
|
||||
|
||||
private static final String QUERY = "cars [item type : products]";
|
||||
|
||||
</pre>Feel free to change the query to a more relevant or interesting one. Take
|
||||
a look at the <a href=
|
||||
'http://code.google.com/apis/base/query-lang-spec.htm'>Google Base Query
|
||||
Language</a> description if you need some inspiration.
|
||||
|
||||
<p>After opening a connection on the snippets feed, we grab the connection's
|
||||
input stream, and dump its content to the output, character by character:</p>
|
||||
<pre>
|
||||
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
|
||||
InputStream inputStream = httpConnection.getInputStream();
|
||||
|
||||
int ch;
|
||||
while ((ch=inputStream.read()) > 0) {
|
||||
System.out.print((char)ch);
|
||||
}
|
||||
|
||||
</pre>In the <code>main</code> method, all we do is create a
|
||||
<code>QueryExample1</code> instance, and invoke its <code>displayItems</code>
|
||||
method:
|
||||
<pre>
|
||||
public static void main(String[] args) throws IOException, SAXException,
|
||||
ParserConfigurationException {
|
||||
new QueryExample1().displayItems();
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2><a name="queryExample2" id="queryExample2"></a>Query Example 2 - query
|
||||
the Google Base data API, parse the result and display the titles of returned
|
||||
data items</h2>
|
||||
|
||||
<p>One major problem with <code>QueryExample1</code> is that it simply dumps
|
||||
the items returned for the query to the console, and the result is barely
|
||||
readable. In any real life application the query result would need to be
|
||||
parsed, interpreted and relevant information should be extracted and
|
||||
displayed to the user. In <code>QueryExample2</code> we demonstrate a
|
||||
possible way of doing this by using a SAX parser to extract each data item's
|
||||
title from the result, and display it to the console. Some very basic
|
||||
understanding of how SAX parsers work is necessary in order to fully
|
||||
understand this example.</p>
|
||||
|
||||
<p>One might argue that for this task we don't even need a SAX parser. We
|
||||
could just search for all <code><title></code> tags in the result and
|
||||
display the characters that they enclose. Unfortunately, that wouldn't work,
|
||||
as the Atom response also has a <code><title></code> tag, which is the
|
||||
title of the feed:</p>
|
||||
<pre>
|
||||
<feed>
|
||||
...
|
||||
<title type="text">Items matching query: cars [item type : products]</title>
|
||||
...
|
||||
<entry>
|
||||
...
|
||||
<title type='text'>Great care for sale</title>
|
||||
...
|
||||
|
||||
</pre>Atom does not mandate that the feed's <code><title></code> tag
|
||||
should appear at a specific position inside the feed, so we need to make sure
|
||||
we only display the <code><title></code> tags which are sub-elements of
|
||||
an <code><entry></code> tag.<br />
|
||||
<br />
|
||||
|
||||
<h3><a name="QE2run" id=
|
||||
"QE2run"></a>Running<code>QueryExample2</code></h3>
|
||||
Compile and run the example using your favorite editor, or using the
|
||||
command line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/QueryExample2.java
|
||||
java sample.gbase/basic/QueryExample2
|
||||
|
||||
</pre>The output will look like:
|
||||
<pre>
|
||||
Item 1: Johnny Lightning MUSCLE CARS R8 1967 Chevelle SS
|
||||
Item 2: Johnny Lightning MUSCLE CARS USA 2005 Ford GT
|
||||
...
|
||||
Item 25: The Cars movie Hinged tool Box Toy Organize lunch RARE
|
||||
|
||||
</pre>
|
||||
|
||||
<ul class="noindent"></ul>
|
||||
|
||||
<h3><a name="QE2stepThru" id="QE2stepThru"></a>Stepping through the
|
||||
<code>QueryExample2</code> code</h3>
|
||||
|
||||
<p>Just as in the previous example, we first send the query to the Google
|
||||
Base data API server, and obtain an <code>inputStream</code> containing the
|
||||
response:</p>
|
||||
<pre>
|
||||
URL url = new URL(SNIPPETS_FEED + "?bq=" +
|
||||
URLEncoder.encode(QUERY, "UTF-8"));
|
||||
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
|
||||
InputStream inputStream = httpConnection.getInputStream();
|
||||
</pre>
|
||||
|
||||
<p>We then use a standard SAX parser to parse the result. We obtain a
|
||||
SAXParser instance using a SAXParserFactory:</p>
|
||||
<pre>
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
</pre>We then parse the result <code>inputStream</code> using
|
||||
<code>DisplayTitlesHandler</code>, our custom SAX event handler:
|
||||
<pre>
|
||||
parser.parse(inputStream, new DisplayTitlesHandler());
|
||||
</pre>
|
||||
|
||||
<p><code>DisplayTitlesHandler</code> is derived from the no-op SAX parser,
|
||||
<code>org.xml.sax.helpers.DefaultHandler</code>. The logic inside
|
||||
<code>DisplayTitlesHandler</code> is pretty simple: we keep a stack of the
|
||||
currently open XML tags and print all character data when we are inside a
|
||||
<code><title></code> tag with a <code><entry></code> parent. The
|
||||
<code>insideEntryTitle</code> flag is turned on each time we are inside a
|
||||
<code><entry><title></code> pair:</p>
|
||||
<pre>
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if (qName.equals("title") && xmlTags.peek().equals("entry")) {
|
||||
insideEntryTitle = true;
|
||||
System.out.print("Item " + ++itemNo + ": ");
|
||||
}
|
||||
xmlTags.push(qName);
|
||||
}
|
||||
</pre>Since <code>startElement</code> is invoked each time the SAX parser
|
||||
encounters an opening XML tag, we switch on <code>insideEntryTitle</code> only
|
||||
if the currently parsed opening tag is <code><title></code> and the tag
|
||||
on the top of the stack is <code><entry></code> . We are also printing
|
||||
here the "Item no: " messages, rather than in the <code>characters</code>
|
||||
method, as <code>characters</code> can be called multiple times for different
|
||||
chunks of the title's character data.<br />
|
||||
<br />
|
||||
The <code>endElement</code> method is invoked each time an XML tag closes.
|
||||
All we need to do here is to remove the closing XML tag from the stack and,
|
||||
in case the removed XML tag was an entry's title, flip
|
||||
<code>insideEntryTitle</code> to false and go to a new line in the console,
|
||||
in preparation for printing out the next title:
|
||||
<pre>
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
xmlTags.pop();
|
||||
if (insideEntryTitle) {
|
||||
insideEntryTitle = false;
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
</pre>The <code>characters</code> method is invoked when the parser encounters
|
||||
character data inside an XML element. If we are inside the
|
||||
<code><title></code> tag, that is, if the <code>insideEntryTitle</code>
|
||||
flag is on, we display the current characters: <code>length</code> characters
|
||||
from the <code>ch</code> array, starting with <code>start</code>. As noted
|
||||
earlier, we can't use <code>println</code> here to get to a new line, as <code>
|
||||
characters</code> can be invoked multiple times for different chunks of the
|
||||
same title:
|
||||
<pre>
|
||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||
if (insideEntryTitle) {
|
||||
System.out.print(new String(ch, start, length));
|
||||
}
|
||||
}
|
||||
</pre>In the <code>main</code> method, all we do is create a
|
||||
<code>QueryExample2</code> instance, and invoke its <code>displayItems</code>
|
||||
method:
|
||||
<pre>
|
||||
public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException {
|
||||
new QueryExample2().displayItems();
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2><a name="queryExample3" id="queryExample3"></a>Query Example 3 -
|
||||
Introducing authentication. Querying your own items using the items
|
||||
feed.</h2>
|
||||
|
||||
<p>The previous two examples demonstrated how to query the Google Base data
|
||||
API public feeds, also known as snippets. Snippets are accessible to anyone
|
||||
without authentication. The downside is that snippets are the "indexable"
|
||||
version of the items and can slightly differ from the original items. It can
|
||||
also take a while for a newly inserted or updated item to show up in the
|
||||
snippets feed. Therefore, if you need to change your own items, the Google
|
||||
Base data API server exposes the customer-specific "items" feed. This feed is
|
||||
very similar to the "snippets" feed, except that:</p>
|
||||
|
||||
<ul>
|
||||
<li>it only allows you to query your own items, and thus you need to
|
||||
authenticate in order to access it</li>
|
||||
|
||||
<li>there is no delay between updating an item and being able to display it
|
||||
in the "items" feed</li>
|
||||
</ul>Read <a href='http://code.google.com/apis/base/items-feed.html'>here</a>
|
||||
more about the characteristics of the "items" feed. You will need a Google
|
||||
Account email and password in order to run this example. If you don't have a
|
||||
Google Account, sign up for one <a href=
|
||||
'https://www.google.com/accounts/NewAccount'>here</a>.
|
||||
|
||||
<p>QueryExample3 connects to your "items" feed, and dumps your items to the
|
||||
console, just as in <code>QueryExample1</code>. If you don't have any items
|
||||
in Google Base yet, use <a href='#insertRun'>InsertExample</a> to insert one,
|
||||
or go to the <a href='http://base.google.com/base/step1offer?hl=en_US'>Google
|
||||
Base Provider Frontenac</a> and insert one.</p>
|
||||
|
||||
<h3><a name="QE3run" id="QE3run"></a>Running <code>QueryExample3</code></h3>
|
||||
|
||||
<ol>
|
||||
<li>Edit QueryExample3.java and make the following changes:
|
||||
|
||||
<ul>
|
||||
<li>Enter your Google Accounts email address and your password in the
|
||||
<code>EMAIL</code> and <code>PASSWORD</code> static strings:
|
||||
<pre>
|
||||
private static final String EMAIL = "";
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Compile and run the example using your favorite editor, or the command
|
||||
line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/QueryExample3.java
|
||||
java sample.gbase/basic/QueryExample3
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>The output will look like:
|
||||
<pre>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<feed>
|
||||
<id>http://base.google.com/base/feeds/items</id>
|
||||
<updated>2006-08-22T12:00:00.000Z</updated>
|
||||
<title type="text">Items matching query: [customer id(int):1870031]</title>
|
||||
...
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h3><a name="QE3stepThru" id="QE3stepThru"></a>Stepping through the
|
||||
<code>QueryExample3</code> code</h3>
|
||||
|
||||
<p>As opposed to the previous examples, here we need to obtain an
|
||||
authorization token by authenticating with the Google Accounts server. We
|
||||
then use this authorization token to invoke <code>displayMyItems</code>:</p>
|
||||
<pre>
|
||||
public static void main(String[] args) throws IOException {
|
||||
QueryExample3 queryExample = new QueryExample3();
|
||||
String token = queryExample.authenticate();
|
||||
new QueryExample3().displayMyItems(token);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>We authenticate using <a href=
|
||||
'http://code.google.com/apis/accounts/AuthForInstalledApps.html'>authentication
|
||||
for installed applications</a>. The authentication procedure is simple. We
|
||||
make a POST request to <code>AUTHENTICATION_URL</code>:</p>
|
||||
<pre>
|
||||
private static final String AUTHENTICATION_URL = "https://www.google.com/accounts/ClientLogin";
|
||||
</pre>The POST request is constructed in <code>makeLoginRequest</code>, and it
|
||||
looks like this:
|
||||
<pre>
|
||||
// POST /accounts/ClientLogin HTTP/1.0
|
||||
// Content-type: application/x-www-form-urlencoded
|
||||
// Email=johndoe@gmail.com&Passwd=north23AZ&service=gbase&source=Insert Example
|
||||
</pre><code>makeLoginRequest</code> sends the request to the Google Accounts
|
||||
server and returns the response as a <code>String</code>. A successful response
|
||||
will have the following structure:
|
||||
<pre>
|
||||
// HTTP/1.0 200 OK
|
||||
// Server: GFE/1.3
|
||||
// Content-Type: text/plain
|
||||
// SID=DQAAAGgA...7Zg8CTN
|
||||
// LSID=DQAAAGsA...lk8BBbG
|
||||
// Auth=DQAAAGgA...dk3fA5N
|
||||
</pre><code>authenticate</code> first obtains the authentication response from
|
||||
<code>makeLoginRequest</code> and stores it in <code>postOutput</code>:
|
||||
<pre>
|
||||
String postOutput = null;
|
||||
try {
|
||||
URL url = new URL(AUTHENTICATION_URL);
|
||||
postOutput = makeLoginRequest(url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Authentication error: " + e.toString());
|
||||
}
|
||||
</pre>It then tokenizes <code>postOutput</code>, and returns the next token
|
||||
after "Auth", or <code>null</code> if the token is not found:
|
||||
<pre>
|
||||
StringTokenizer tokenizer = new StringTokenizer(postOutput, "=\n ");
|
||||
String token = null;
|
||||
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
if (tokenizer.nextToken().equals("Auth")) {
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
token = tokenizer.nextToken();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
</pre><br />
|
||||
<br />
|
||||
|
||||
<p>The items are displayed in <code>displayMyItems</code>, which is very
|
||||
similar to <code>displayItems</code> in QueryExample1, except that it injects
|
||||
the authorization token in the Http header (as in this example):</p>
|
||||
<pre>
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
</pre>
|
||||
|
||||
<h2><a name="insertExample" id="insertExample"></a>Insert Example - Adding
|
||||
your own item to Google Base.</h2>
|
||||
|
||||
<p>The previous examples demonstrated how to query the Google Base data API
|
||||
server, both for snippets (unauthenticated feeds) and for items
|
||||
(authenticated feeds, containing a specific customer's items). Let's
|
||||
demonstrate now how to add to Google Base all the cool stuff you have, so
|
||||
that the world can see it. Again, you will need a Google Account email and
|
||||
password in order to run this example. If you don't have a Google Account,
|
||||
sign up for one <a href=
|
||||
'https://www.google.com/accounts/NewAccount'>here</a>.</p>
|
||||
|
||||
<p>In this example we will connect to your "items" feed, and do an Http POST
|
||||
operation (as opposed to GET, used for querying) to add a new item. The item
|
||||
to be added is encoded in Atom format, and is defined a <code>String</code>
|
||||
constant:</p>
|
||||
<pre>
|
||||
private static final String DATA_ITEM =
|
||||
"<?xml version=\'1.0\'?>\n" +
|
||||
"<entry xmlns=\'http://www.w3.org/2005/Atom\' xmlns:g=\'http://base.google.com/ns/1.0\'>\n" +
|
||||
" <category scheme=\'http://base.google.com/categories/itemtypes\' term=\'Products\'/>\n" +
|
||||
" <g:item_type type=\'text\'>Products</g:item_type>\n" +
|
||||
" <title type=\'text\'>My cool car is for sale</title>" +
|
||||
" <content type=\'xhtml\'>Light pink, yellow seats.</content>" +
|
||||
"</entry>";
|
||||
</pre>It's a very simple item, consisting only of an item type ("products", in
|
||||
our case), a title and a content (description). Feel free to change these
|
||||
fields to contain your personalized items or to add new attributes and labels
|
||||
(use the responses dumped by <code>QueryExample1</code> and
|
||||
<code>QueryExample3</code> as an inspiration for adding new attributes).
|
||||
|
||||
<h3><a name="insertRun" id="insertRun"></a>Running
|
||||
<code>InsertExample</code></h3>
|
||||
|
||||
<ol>
|
||||
<li>Edit InsertExample.java and make the following changes:
|
||||
|
||||
<ul>
|
||||
<li>Enter your Google Accounts email address and your password in the
|
||||
<code>EMAIL</code> and <code>PASSWORD</code> static strings:
|
||||
<pre>
|
||||
private static final String EMAIL = "";
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Compile and run the example using your favorite editor, or the command
|
||||
line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/InsertExample.java
|
||||
java sample.gbase/basic/InsertExample
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>The output will look like:
|
||||
<pre>
|
||||
Obtained authorization token: DQAAAGgA...dk3fA5N
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry>
|
||||
<id>http://base.google.com/base/feeds/items/16024998325761524417</id>
|
||||
<published>2006-08-23T15:18:55.184Z</published>
|
||||
<updated>2006-08-23T15:18:55.184Z</updated>
|
||||
<category scheme="http://base.google.com/categories/itemtypes" term="Products"/>
|
||||
<title type="text">My cool car is for sale</title>
|
||||
<content type="xhtml">Light pink, yellow seats.</content>
|
||||
<link rel="self" type="application/atom+xml" href="http://base.google.com/base/feeds/items/16024998325761524417"/>
|
||||
<link rel="edit" type="application/atom+xml" href="http://base.google.com/base/feeds/items/16024998325761524417"/>
|
||||
<g:item_type type="text">Products</g:item_type>
|
||||
</entry>
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h3><a name="InsertStepThru" id="InsertStepThru"></a>Stepping through the
|
||||
<code>InsertExample</code> code</h3>
|
||||
|
||||
<p>We use the same feed as in QueryExample3.java to insert the item:</p>
|
||||
<pre>
|
||||
private static final String ITEMS_FEED = "http://base.google.com/base/feeds/items";
|
||||
</pre>Authentication is also performed as in <a href=
|
||||
'#QE3stepThru'>QueryExample3</a>, using <code>makeLoginRequest</code> to
|
||||
request an authorization token and <code>authenticate</code> to parse the
|
||||
authentication response. The insertion of the new data item is done in
|
||||
<code>postItem</code>, which connects to the items feed:
|
||||
<pre>
|
||||
HttpURLConnection connection = (HttpURLConnection)(new URL(ITEMS_FEED)).openConnection();
|
||||
</pre>Once the connection is created, we need to set its properties: the Http
|
||||
request method, the content type of the information that is being posted, the
|
||||
authorization header:
|
||||
<pre>
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/atom+xml");
|
||||
connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
|
||||
</pre>We then obtain the output stream of the connection and dump
|
||||
<code>DATA_ITEM</code> into it:
|
||||
<pre>
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(DATA_ITEM.getBytes());
|
||||
outputStream.close();
|
||||
</pre>The rest of the method is already familiar: we obtain the response code
|
||||
and print out to the console the contents of the input stream corresponding to
|
||||
the response code.<br />
|
||||
<br />
|
||||
|
||||
<h2><a name="updateExample" id="updateExample"></a>Update Example - Modifying
|
||||
your Google Base items.</h2>
|
||||
|
||||
<p>The previous examples demonstrated how to query the Google Base data API
|
||||
server both for authenticated and unauthenticated feeds and how to insert a
|
||||
new item. We will combine this knowledge in order to demonstrate how to
|
||||
update an already existing item. Again, you will need a Google Account email
|
||||
and password in order to run this example. If you don't have a Google
|
||||
Account, sign up for one <a href=
|
||||
'https://www.google.com/accounts/NewAccount'>here</a>. This example does not
|
||||
introduce important new concepts, but rather uses all the essentials that
|
||||
have been presented in the previous examples: we will authenticate, insert an
|
||||
item, and then update the inserted item by adding a new label to it.</p>
|
||||
|
||||
<h3><a name="updateRun" id="updateRun"></a>Running
|
||||
<code>UpdateExample</code></h3>
|
||||
|
||||
<ol>
|
||||
<li>Edit UpdateExample.java and make the following changes:
|
||||
|
||||
<ul>
|
||||
<li>Enter your Google Accounts email address and your password in the
|
||||
<code>EMAIL</code> and <code>PASSWORD</code> static strings:
|
||||
<pre>
|
||||
private static final String EMAIL = "";
|
||||
private static final String PASSWORD = "";
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Compile and run the example using your favorite editor, or the command
|
||||
line:
|
||||
<pre>
|
||||
javac sample.gbase/basic/UpdateExample.java
|
||||
java sample.gbase/basic/UpdateExample
|
||||
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>The output will look like:
|
||||
<pre>
|
||||
Obtained authorization token: DQAAAGgA...dk3fA5N
|
||||
Posting item:
|
||||
<?xml version='1.0'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:g='http://base.google.com/ns/1.0'>
|
||||
<category scheme='http://base.google.com/categories/itemtypes' term='Products'/>
|
||||
<g:item_type type='text'>Products</g:item_type>
|
||||
<title type='text'>My cool car is for sale</title>
|
||||
<content type='xhtml'>Light pink, yellow seats.</content>
|
||||
</entry>
|
||||
|
||||
Updating item: http://base.google.com/base/feeds/items/18020038538902937385
|
||||
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry>
|
||||
<id>http://base.google.com/base/feeds/items/18020038538902937385</id>
|
||||
<updated>2006-08-23T16:20:21.601Z</updated>
|
||||
<category scheme="http://base.google.com/categories/itemtypes" term="Products"/>
|
||||
<title type="text">My cool car is for sale</title>
|
||||
<content type="xhtml">Light pink, yellow seats.</content>
|
||||
<link rel="self" type="application/atom+xml" href="http://base.google.com/base/feeds/items/18020038538902937385"/>
|
||||
<link rel="edit" type="application/atom+xml" href="http://base.google.com/base/feeds/items/18020038538902937385"/>
|
||||
<g:item_type type="text">Products</g:item_type>
|
||||
</entry>
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h3><a name="UpdateStepThru" id="UpdateStepThru"></a>Stepping through the
|
||||
<code>UpdateExample</code> code</h3>
|
||||
|
||||
<p>The <code>main</code> method of <code>UpdateExample</code> provides a good
|
||||
outline of the example's structure:</p>
|
||||
<pre>
|
||||
public static void main(String[] args) throws MalformedURLException, IOException {
|
||||
UpdateExample updateExample = new UpdateExample();
|
||||
String token = updateExample.authenticate();
|
||||
System.out.println("Obtained authorization token: " + token);
|
||||
|
||||
System.out.println("Posting item:\n" + DATA_ITEM);
|
||||
String itemUrl = updateExample.extractItemUrlFromResponse(
|
||||
updateExample.postItem(token));
|
||||
|
||||
System.out.println("Updating item: " + itemUrl);
|
||||
String updateResponse = updateExample.updateItem(token, itemUrl);
|
||||
System.out.println(updateResponse);
|
||||
}
|
||||
</pre>Just like in the previous examples, we start by authenticating and
|
||||
obtaining an authorization token using the <code>authenticate</code> method:
|
||||
<pre>
|
||||
String token = updateExample.authenticate();
|
||||
</pre>We then insert <code>DATA_ITEM</code> using <code>postItem</code>:
|
||||
<pre>
|
||||
String itemUrl = updateExample.extractItemUrlFromResponse(
|
||||
updateExample.postItem(token));
|
||||
</pre>In the line above, we pass the output of the post operation
|
||||
to<code>extractItemUrlFromResponse</code> (rather than dumping it out to the
|
||||
console), which extracts the inserted item's id:
|
||||
<pre>
|
||||
<id>http://base.google.com/base/feeds/items/18020038538902937385</id>
|
||||
</pre>We assume that the item's id is surrounded by the first
|
||||
<id></id> tags; this is true for the Google Base data API servers,
|
||||
but it's not enforced by the Atom protocol. See how the title gets parsed in
|
||||
<a href='#QE2stepThru'>Query Example 2</a>, for a superior approach on parsing
|
||||
the item's title.
|
||||
|
||||
<p>Once <code>DATA_ITEM</code> is successfully inserted, we replace it with
|
||||
<code>NEW_DATA_ITEM</code> using <code>updateItem</code>. Updating an item is
|
||||
very similar to inserting a new one - in fact so similar that both operations
|
||||
can be performed by the same method: <code>makeHttpRequest</code>.
|
||||
<code>makeHttpRequest</code> receives as parameters the authorization token,
|
||||
the url to connect to, the item to be inserted or posted, the http method to
|
||||
use (this will be POST for inserting, and PUT for deleting) and the response
|
||||
code to expect in case of a successful operation (HTTP_CREATED in case of
|
||||
insert, HTTP_OK in case of update). Thus, <code>postItem</code> will contain
|
||||
a simple invocation to <code>makeHttpRequest</code>:</p>
|
||||
<pre>
|
||||
public String postItem(String token) throws IOException {
|
||||
return makeHttpRequest(token, ITEMS_FEED, NEW_DATA_ITEM, "POST", HttpURLConnection.HTTP_CREATED);
|
||||
}
|
||||
|
||||
</pre>Similarly, <code>updateItem</code> invokes <code>makeHttpRequest</code>
|
||||
with slightly different parameters:
|
||||
<pre>
|
||||
public String updateItem(String token, String itemUrl) throws MalformedURLException, IOException {
|
||||
return makeHttpRequest(token, itemUrl, NEW_DATA_ITEM, "PUT", HttpURLConnection.HTTP_OK);
|
||||
}
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.gdata.client.Service;
|
||||
|
||||
/**
|
||||
* Execute batch operations.
|
||||
* This command is called from {@link sample.gbase.cmdline.CustomerTool}.
|
||||
*/
|
||||
class BatchCommand extends Command {
|
||||
|
||||
public void execute() throws Exception {
|
||||
|
||||
Service service = createService();
|
||||
Service.GDataRequest request =
|
||||
service.createBatchRequest(
|
||||
fixEditUrl(urlFactory.getItemsBatchFeedURL()));
|
||||
|
||||
inputRawRequest(request);
|
||||
// Send the request (HTTP POST)
|
||||
request.execute();
|
||||
|
||||
// Save the response
|
||||
outputRawResponse(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/* Copyright (c) 2006 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.gbase.cmdline;
|
||||
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.gdata.client.Service;
|
||||
import com.google.gdata.util.AuthenticationException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
|
||||
/**
|
||||
* One command that is part of CustomerTool.
|
||||
* This class contains code that is common to all
|
||||
* commands. It deals, in particular, with the creation
|
||||
* of the GData service object.
|
||||
*/
|
||||
abstract class Command {
|
||||
|
||||
/**
|
||||
* URL of the google authentication server to use for log in.
|
||||
*/
|
||||
private static final String DEFAULT_AUTH_HOSTNAME = "www.google.com";
|
||||
|
||||
/**
|
||||
* Username for google base (e-mail address).
|
||||
*/
|
||||
protected String username;
|
||||
|
||||
/**
|
||||
* The user's password.
|
||||
*/
|
||||
protected String password;
|
||||
|
||||
/**
|
||||
* Base url of the google base server.
|
||||
*/
|
||||
protected FeedURLFactory urlFactory = FeedURLFactory.getDefault();
|
||||
|
||||
/**
|
||||
* Base url of the google authentication server.
|
||||
*/
|
||||
private String authenticationServer = DEFAULT_AUTH_HOSTNAME;
|
||||
|
||||
/**
|
||||
* Protocol (http or https) to use to connect to the authentication server.
|
||||
*/
|
||||
private String authenticationProtocol = "https";
|
||||
|
||||
/**
|
||||
* Developer key used for identification against the Google Base data API
|
||||
* servers.
|
||||
*/
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* Enables dry-run mode for edit operations.
|
||||
*/
|
||||
private boolean dryRun;
|
||||
|
||||
/**
|
||||
* Executes the command.
|
||||
*
|
||||
* Call this method only after setting the username and password.
|
||||
*/
|
||||
public abstract void execute() throws Exception;
|
||||
|
||||
/**
|
||||
* Sets the username, which is required for {@link #execute()} to work.
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password, which is required for {@link #execute()} to work.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Url of the google base server to connect to.
|
||||
*/
|
||||
public void setGoogleBaseServerUrl(String url) throws MalformedURLException {
|
||||
this.urlFactory = new FeedURLFactory(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the google authentication server to connect to.
|
||||
*/
|
||||
public void setAuthenticationServerUrl(String urlString)
|
||||
throws MalformedURLException {
|
||||
URL url = new URL(urlString);
|
||||
this.authenticationProtocol = url.getProtocol();
|
||||
this.authenticationServer = url.getHost();
|
||||
if (url.getPort() != -1) {
|
||||
this.authenticationServer += ":" + url.getPort();
|
||||
}
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure username and password have been set.
|
||||
*/
|
||||
public boolean hasAllIdentificationInformation() {
|
||||
return username != null && password != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the service and sets the username and password for
|
||||
* authentication.
|
||||
*
|
||||
* @return the GData service object to use
|
||||
* @throws com.google.gdata.util.AuthenticationException
|
||||
* if authentication failed
|
||||
*/
|
||||
protected GoogleBaseService createService()
|
||||
throws AuthenticationException {
|
||||
GoogleBaseService service =
|
||||
new GoogleBaseService("Google.-CustomerTool-1.0",
|
||||
key,
|
||||
authenticationProtocol,
|
||||
authenticationServer);
|
||||
service.setUserCredentials(username, password);
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL of the customer feed.
|
||||
*
|
||||
* The feed contains only the items uploaded by this
|
||||
* specific customer. This is also the feed that is
|
||||
* used to upload customer data.
|
||||
*
|
||||
* @return the url to the customer feed
|
||||
*/
|
||||
protected URL getCustomerFeedURL() throws MalformedURLException {
|
||||
return urlFactory.getItemsFeedURL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the response (XML feed) to standard output.
|
||||
*/
|
||||
protected void outputRawResponse(Service.GDataRequest request)
|
||||
throws IOException {
|
||||
InputStream responseStream = request.getResponseStream();
|
||||
try {
|
||||
copyStreamContent(responseStream, System.out);
|
||||
} finally {
|
||||
responseStream.close();
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from in input stream and write it into an
|
||||
* output stream.
|
||||
*/
|
||||
protected void copyStreamContent(InputStream in, OutputStream out)
|
||||
throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
int l;
|
||||
while ( (l=in.read(buffer)) > 0 ) {
|
||||
out.write(buffer, 0, l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from standard input and use it in the request.
|
||||
*
|
||||
* The data must be the XML feed appropriate for the command.
|
||||
* For update, get or insert it should be one Atom XML entry.
|
||||
*/
|
||||
protected void inputRawRequest(Service.GDataRequest request)
|
||||
throws IOException {
|
||||
OutputStream outputStream = request.getRequestStream();
|
||||
try {
|
||||
copyStreamContent(System.in, outputStream);
|
||||
} finally {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the command in dry-run mode, in which nothing will
|
||||
* really happen on the server.
|
||||
*
|
||||
* @param dryRun
|
||||
*/
|
||||
public void setDryRun(boolean dryRun) {
|
||||
this.dryRun = dryRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an edit URL from a string, adding the dry-run parameter
|
||||
* if necessary.
|
||||
*
|
||||
* This method is not applicable to query URLs, for which the dry-run
|
||||
* parameter is not supported.
|
||||
*
|
||||
* @param url the original url
|
||||
* @return the same URL with maybe some parameters
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
protected URL fixEditUrl(URL url) throws MalformedURLException {
|
||||
return fixEditUrl(url.toExternalForm());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an edit URL from a string, adding the dry-run parameter
|
||||
* if necessary.
|
||||
*
|
||||
* This method is not applicable to query URLs, for which the dry-run
|
||||
* parameter is not supported.
|
||||
*
|
||||
* @param url the original url, as a string
|
||||
* @return the same URL with maybe some parameters
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
protected URL fixEditUrl(String url) throws MalformedURLException {
|
||||
if (dryRun) {
|
||||
char separator = url.contains("?") ? '&' : '?';
|
||||
url = url + separator + "dry-run=true";
|
||||
}
|
||||
return new URL(url);
|
||||
}
|
||||
|
||||
}
|
||||