/* 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); } }