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