Add namespace support

This requires lots of changes because we have to swap to using Principal
everywhere (and namely in MemberIdMapping).
diff --git a/src/com/google/enterprise/adaptor/sharepoint/MemberIdMapping.java b/src/com/google/enterprise/adaptor/sharepoint/MemberIdMapping.java
index 4b6977a..7712a7f 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/MemberIdMapping.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/MemberIdMapping.java
@@ -14,33 +14,38 @@
 
 package com.google.enterprise.adaptor.sharepoint;
 
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
+import com.google.enterprise.adaptor.Principal;
+
 import java.util.*;
 
 /**
  * Immutable lookup from identifier to name for users and groups.
  */
 class MemberIdMapping {
-  private final Map<Integer, String> users;
-  private final Map<Integer, String> groups;
+  private static final Interner<Principal> interner
+      = Interners.newWeakInterner();
 
-  public MemberIdMapping(Map<Integer, String> users,
-      Map<Integer, String> groups) {
-    this.users
-        = Collections.unmodifiableMap(new HashMap<Integer, String>(users));
-    this.groups
-        = Collections.unmodifiableMap(new HashMap<Integer, String>(groups));
+  private final Map<Integer, Principal> principals;
+
+  public MemberIdMapping(Map<Integer, ? extends Principal> principals) {
+    Map<Integer, Principal> tmp = new HashMap<Integer, Principal>(principals);
+    // Most of the purpose for this class is to allow future memory
+    // optimizations without having to tweak all the calling code. Thus, it
+    // makes sense for this class to do intern()ing.
+    for (Map.Entry<Integer, Principal> me : tmp.entrySet()) {
+      me.setValue(interner.intern(me.getValue()));
+    }
+    this.principals = Collections.unmodifiableMap(principals);
   }
 
-  public String getUserName(Integer id) {
-    return users.get(id);
-  }
-
-  public String getGroupName(Integer id) {
-    return groups.get(id);
+  public Principal getPrincipal(Integer id) {
+    return principals.get(id);
   }
 
   @Override
   public String toString() {
-    return "MemberIdMapping(users=" + users + ",groups=" + groups + ")";
+    return "MemberIdMapping(" + principals + ")";
   }
 }
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
index d623b6b..b990f61 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
@@ -27,6 +27,7 @@
 import com.google.enterprise.adaptor.GroupPrincipal;
 import com.google.enterprise.adaptor.IOHelper;
 import com.google.enterprise.adaptor.PollingIncrementalAdaptor;
+import com.google.enterprise.adaptor.Principal;
 import com.google.enterprise.adaptor.Request;
 import com.google.enterprise.adaptor.Response;
 import com.google.enterprise.adaptor.UserPrincipal;
@@ -42,7 +43,6 @@
 import com.microsoft.schemas.sharepoint.soap.Files;
 import com.microsoft.schemas.sharepoint.soap.FolderData;
 import com.microsoft.schemas.sharepoint.soap.Folders;
-import com.microsoft.schemas.sharepoint.soap.GroupDescription;
 import com.microsoft.schemas.sharepoint.soap.GroupMembership;
 import com.microsoft.schemas.sharepoint.soap.Item;
 import com.microsoft.schemas.sharepoint.soap.ItemData;
@@ -240,6 +240,7 @@
   
   private ScheduledThreadPoolExecutor scheduledExecutor 
       = new ScheduledThreadPoolExecutor(1);
+  private String defaultNamespace;
   /** Authenticator instance that authenticates with SP. */
   /**
    * Cached value of whether we are talking to a SP 2010 server or not. This
@@ -294,6 +295,7 @@
     // 2 MB. We need to know how much of the generated HTML the GSA will index,
     // because the GSA won't see links outside of that content.
     config.addKey("sharepoint.maxIndexableSize", "2097152");
+    config.addKey("adaptor.namespace", "Default");
   }
 
   @Override
@@ -308,10 +310,12 @@
         config.getValue("sharepoint.xmlValidation"));
     maxIndexableSize = Integer.parseInt(
         config.getValue("sharepoint.maxIndexableSize"));
+    defaultNamespace = config.getValue("adaptor.namespace");
 
     log.log(Level.CONFIG, "VirtualServer: {0}", virtualServer);
     log.log(Level.CONFIG, "Username: {0}", username);
     log.log(Level.CONFIG, "Password: {0}", password);
+    log.log(Level.CONFIG, "Default Namespace: {0}", defaultNamespace);
 
     ntlmAuthenticator = new NtlmAuthenticator(username, password);
     // Unfortunately, this is a JVM-wide modification.
@@ -733,19 +737,23 @@
       VirtualServer vs = siteDataClient.getContentVirtualServer();
 
       final long necessaryPermissionMask = LIST_ITEM_MASK;
+      List<Principal> permits = new ArrayList<Principal>();
+      List<Principal> denies = new ArrayList<Principal>();
+
       // A PolicyUser is either a user or group, but we aren't provided with
-      // which. Thus, we treat PolicyUsers as both a user and a group in ACLs
-      // and understand that only one of the two entries will have an effect.
-      List<UserPrincipal> permitUsers = new ArrayList<UserPrincipal>();
-      List<GroupPrincipal> permitGroups = new ArrayList<GroupPrincipal>();
-      List<UserPrincipal> denyUsers = new ArrayList<UserPrincipal>();
-      List<GroupPrincipal> denyGroups = new ArrayList<GroupPrincipal>();
-      List<String> policyUsers = new ArrayList<String>();
-      for (PolicyUser policyUser : vs.getPolicies().getPolicyUser()) {
-        policyUsers.add(policyUser.getLoginName());
+      // which. We make a web service call to determine which. When using claims
+      // is enabled, we actually do know the type, but we need additional
+      // information to produce a clear ACL. As such, we blindly get more info
+      // for all the PolicyUsers at once in a single batch.
+      Map<String, PrincipalInfo> resolvedPolicyUsers;
+      {
+        List<String> policyUsers = new ArrayList<String>();
+        for (PolicyUser policyUser : vs.getPolicies().getPolicyUser()) {
+          policyUsers.add(policyUser.getLoginName());
+        }
+        resolvedPolicyUsers = resolvePrincipals(policyUsers);
       }
-      Map<String, PrincipalInfo> resolvedPolicyUsers 
-          = resolvePrincipals(policyUsers);
+
       for (PolicyUser policyUser : vs.getPolicies().getPolicyUser()) {
         String loginName = policyUser.getLoginName();
         PrincipalInfo p = resolvedPolicyUsers.get(loginName);
@@ -755,36 +763,42 @@
           continue;
         }
         // TODO(ejona): special case NT AUTHORITY\LOCAL SERVICE.
+        if (p.getPrincipalType() != SPPrincipalType.SECURITY_GROUP
+            && p.getPrincipalType() != SPPrincipalType.USER) {
+          log.log(Level.WARNING, "Principal {0} is an unexpected type: {1}",
+              new Object[] {p.getAccountName(), p.getPrincipalType()});
+          continue;
+        }
+        boolean isGroup
+            = p.getPrincipalType() == SPPrincipalType.SECURITY_GROUP;
         String accountName = decodeClaim(p.getAccountName(), p.getDisplayName(),
-            p.getPrincipalType() == SPPrincipalType.SECURITY_GROUP);
+            isGroup);
         if (accountName == null) {
           log.log(Level.WARNING, 
               "Unable to decode claim. Skipping policy user {0}", loginName);
+          continue;
         }
         log.log(Level.FINER, "Policy User accountName = {0}", accountName);
+        Principal principal;
+        if (isGroup) {
+          principal = new GroupPrincipal(accountName, defaultNamespace);
+        } else {
+          principal = new UserPrincipal(accountName, defaultNamespace);
+        }
         long grant = policyUser.getGrantMask().longValue();
         if ((necessaryPermissionMask & grant) == necessaryPermissionMask) {
-          if (p.getPrincipalType() == SPPrincipalType.USER) {
-             permitUsers.add(new UserPrincipal(accountName));
-          } else {
-             permitGroups.add(new GroupPrincipal(accountName));
-          }
+          permits.add(principal);
         }
         long deny = policyUser.getDenyMask().longValue();
         // If at least one necessary bit is masked, then deny user.
         if ((necessaryPermissionMask & deny) != 0) {
-          if (p.getPrincipalType() == SPPrincipalType.USER) {
-             denyUsers.add(new UserPrincipal(accountName));
-          } else {
-             denyGroups.add(new GroupPrincipal(accountName));
-          }          
+          denies.add(principal);
         }
       }
       response.setAcl(new Acl.Builder()
           .setEverythingCaseInsensitive()
           .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-          .setPermitUsers(permitUsers).setPermitGroups(permitGroups)
-          .setDenyUsers(denyUsers).setDenyGroups(denyGroups).build());
+          .setPermits(permits).setDenies(denies).build());
 
       HtmlResponseWriter writer = createHtmlResponseWriter(response);
       writer.start(request.getDocId(), ObjectType.VIRTUAL_SERVER,
@@ -1114,8 +1128,7 @@
 
     private Acl.Builder generateAcl(List<Permission> permissions,
         final long necessaryPermissionMask) throws IOException {
-      List<UserPrincipal> permitUsers = new LinkedList<UserPrincipal>();
-      List<GroupPrincipal> permitGroups = new LinkedList<GroupPrincipal>();
+      List<Principal> permits = new LinkedList<Principal>();
       MemberIdMapping mapping = getMemberIdMapping();
       MemberIdMapping newMapping = null;
       for (Permission permission : permissions) {
@@ -1126,25 +1139,21 @@
           continue;
         }
         Integer id = permission.getMemberid();
-        String userName = mapping.getUserName(id);
-        String groupName = mapping.getGroupName(id);
-        if (userName == null && groupName == null) {
+        Principal principal = mapping.getPrincipal(id);
+        if (principal == null) {
           if (newMapping == null) {
             newMapping = refreshMemberIdMapping(mapping);
           }
-          userName = newMapping.getUserName(id);
-          groupName = newMapping.getGroupName(id);
+          principal = newMapping.getPrincipal(id);
         }
-        if (userName != null) {
-          permitUsers.add(new UserPrincipal(userName));
-        } else if (groupName != null) {
-          permitGroups.add(new GroupPrincipal(groupName));
-        } else {
+        if (principal == null) {
           log.log(Level.WARNING, "Could not resolve member id {0}", id);
+          continue;
         }
+        permits.add(principal);
       }
       return new Acl.Builder().setEverythingCaseInsensitive()
-          .setPermitUsers(permitUsers).setPermitGroups(permitGroups);
+          .setPermits(permits);
     }
 
     private void addPermitUserToAcl(int userId, Acl.Builder aclToUpdate)
@@ -1152,16 +1161,24 @@
       if (userId == -1) {
         return;
       }
-      String userName = getUserName(userId);
-      if (userName == null) {
+      Principal principal = getMemberIdMapping().getPrincipal(userId);
+      // MemberIdMapping will have information about users with explicit
+      // permissions on SharePoint or users which are direct members of
+      // SharePoint groups. MemberIdMapping might not have information
+      // about all valid SharePoint Users. To get all valid SharePoint users
+      // under SiteCollection, use SiteUserMapping.
+      if (principal == null) {
+        principal = getSiteUserMapping().getPrincipal(userId);
+      }
+      if (principal == null) {
         log.log(Level.WARNING, "Could not resolve user id {0}", userId);
         return;
       }
 
-      List<UserPrincipal> permitUsers
-          = new LinkedList<UserPrincipal>(aclToUpdate.build().getPermitUsers());
-      permitUsers.add(new UserPrincipal(userName));
-      aclToUpdate.setPermitUsers(permitUsers);
+      List<Principal> permits
+          = new LinkedList<Principal>(aclToUpdate.build().getPermits());
+      permits.add(principal);
+      aclToUpdate.setPermits(permits);
     }
 
     private boolean isPermitted(long permission,
@@ -1200,19 +1217,6 @@
       return vs.policyContainsDeny;
     }
 
-    private String getUserName(int userId) throws IOException {
-      String userName = getMemberIdMapping().getUserName(userId);
-      // MemberIdMapping will have information about users with explicit
-      // permissions on SharePoint or users which are direct members of
-      // SharePoint groups. MemberIdMapping might not have information
-      // about all valid SharePoint Users. To get all valid SharePoint users
-      // under SiteCollection, use SiteUserMapping.
-      if (userName == null) {
-        userName = getSiteUserMapping().getUserName(userId);
-      }
-      return userName;
-    }
-
     private void getAspxDocContent(Request request, Response response)
         throws IOException {
       log.entering("SiteAdaptor", "getAspxDocContent",
@@ -1764,50 +1768,57 @@
     private MemberIdMapping retrieveMemberIdMapping() throws IOException {
       log.entering("SiteAdaptor", "retrieveMemberIdMapping");
       Site site = siteDataClient.getContentSite();
-      Map<Integer, String> groupMap = new HashMap<Integer, String>();
+      Map<Integer, Principal> map = new HashMap<Integer, Principal>();
       for (GroupMembership.Group group : site.getGroups().getGroup()) {
-        GroupDescription gd = group.getGroup();
-        groupMap.put(gd.getID(), gd.getName().intern());
+        map.put(group.getGroup().getID(), new GroupPrincipal(
+            group.getGroup().getName(),
+            defaultNamespace + "_" + site.getMetadata().getURL()));
       }
-      Map<Integer, String> userMap = new HashMap<Integer, String>();
       for (UserDescription user : site.getWeb().getUsers().getUser()) {
-        boolean isDomainGroup = (user.getIsDomainGroup() == TrueFalseType.TRUE);
-        String userName
-            = decodeClaim(user.getLoginName(), user.getName(), isDomainGroup);
-        if (userName == null) {
+        Principal principal = userDescriptionToPrincipal(user);
+        if (principal == null) {
           log.log(Level.WARNING,
               "Unable to determine login name. Skipping user with ID {0}",
               user.getID());
           continue;
         }
-        if (isDomainGroup) {
-          groupMap.put(user.getID(), userName.intern());
-        } else {
-          userMap.put(user.getID(), userName.intern());
-        }
+        map.put(user.getID(), principal);
       }
-      MemberIdMapping mapping = new MemberIdMapping(userMap, groupMap);
+      MemberIdMapping mapping = new MemberIdMapping(map);
       log.exiting("SiteAdaptor", "retrieveMemberIdMapping", mapping);
       return mapping;
     }
 
+    private Principal userDescriptionToPrincipal(UserDescription user) {
+      boolean isDomainGroup = (user.getIsDomainGroup() == TrueFalseType.TRUE);
+      String userName
+          = decodeClaim(user.getLoginName(), user.getName(), isDomainGroup);
+      if (userName == null) {
+        return null;
+      }
+      if (isDomainGroup) {
+        return new GroupPrincipal(userName, defaultNamespace);
+      } else {
+        return new UserPrincipal(userName, defaultNamespace);
+      }
+    }
+
     private MemberIdMapping retrieveSiteUserMapping()
         throws IOException {
       log.entering("SiteAdaptor", "retrieveSiteUserMapping");
       GetUserCollectionFromSiteResponse.GetUserCollectionFromSiteResult result
           = userGroup.getUserCollectionFromSite();
-      Map<Integer, String> userMap = new HashMap<Integer, String>();
-      Map<Integer, String> groupMap = new HashMap<Integer, String>();
+      Map<Integer, Principal> map = new HashMap<Integer, Principal>();
       MemberIdMapping mapping;
       if (result == null) {
-        mapping = new MemberIdMapping(userMap, groupMap);
+        mapping = new MemberIdMapping(map);
         log.exiting("SiteAdaptor", "retrieveSiteUserMapping", mapping);
         return mapping;
       }
       GetUserCollectionFromSiteResult.GetUserCollectionFromSite siteUsers
            = result.getGetUserCollectionFromSite();
       if (siteUsers.getUsers() == null) {
-        mapping = new MemberIdMapping(userMap, groupMap);
+        mapping = new MemberIdMapping(map);
         log.exiting("SiteAdaptor", "retrieveSiteUserMapping", mapping);
         return mapping;
       }
@@ -1823,9 +1834,10 @@
               user.getID());
           continue;
         }
-        userMap.put((int) user.getID(), userName.intern());
+        map.put((int) user.getID(),
+            new UserPrincipal(userName, defaultNamespace));
       }
-      mapping = new MemberIdMapping(userMap, groupMap);
+      mapping = new MemberIdMapping(map);
       log.exiting("SiteAdaptor", "retrieveSiteUserMapping", mapping);
       return mapping;
     }
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java
index ae73523..1bfd1f0 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java
@@ -128,6 +128,7 @@
 
   private String userProfileChangeToken;
   private boolean setAcl = true;
+  private String namespace;
   private UserProfileServiceClient userProfileServiceClient;
   private ScheduledThreadPoolExecutor scheduledExecutor 
       = new ScheduledThreadPoolExecutor(1);
@@ -166,6 +167,7 @@
     config.addKey("sharepoint.username", null);
     config.addKey("sharepoint.password", null);
     config.addKey("profile.setacl", "true");
+    config.addKey("adaptor.namespace", "Default");
   }
 
   @Override
@@ -180,10 +182,12 @@
     String password = context.getSensitiveValueDecoder().decodeValue(
         config.getValue("sharepoint.password"));
     setAcl = Boolean.parseBoolean(config.getValue("profile.setacl"));
+    namespace = config.getValue("adaptor.namespace");
 
     log.log(Level.CONFIG, "virtualServer: {0}", virtualServer);
     log.log(Level.CONFIG, "Username: {0}", username);
     log.log(Level.CONFIG, "setAcl: {0}", setAcl);
+    log.log(Level.CONFIG, "Namespace: {0}", namespace);
 
     ntlmAuthenticator = new NtlmAuthenticator(username, password);
     // Unfortunately, this is a JVM-wide modification.
@@ -506,7 +510,7 @@
       if (setAcl) {
         List<GroupPrincipal> permitGroups = new ArrayList<GroupPrincipal>();
         permitGroups.add(
-            new GroupPrincipal("NT AUTHORITY\\Authenticated Users"));
+            new GroupPrincipal("NT AUTHORITY\\Authenticated Users", namespace));
         response.setAcl(new Acl.Builder().setEverythingCaseInsensitive()
             .setInheritanceType(Acl.InheritanceType.LEAF_NODE)
             .setPermitGroups(permitGroups).build());
diff --git a/test/com/google/enterprise/adaptor/sharepoint/AccumulatingDocIdPusher.java b/test/com/google/enterprise/adaptor/sharepoint/AccumulatingDocIdPusher.java
index 3e7d35c..6e30985 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/AccumulatingDocIdPusher.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/AccumulatingDocIdPusher.java
@@ -17,6 +17,8 @@
 import com.google.enterprise.adaptor.Acl;
 import com.google.enterprise.adaptor.DocId;
 import com.google.enterprise.adaptor.ExceptionHandler;
+import com.google.enterprise.adaptor.GroupPrincipal;
+import com.google.enterprise.adaptor.Principal;
 
 import java.util.*;
 
@@ -24,6 +26,8 @@
   private List<Record> records = new ArrayList<Record>();
   private List<Map<DocId, Acl>> namedResouces
       = new ArrayList<Map<DocId, Acl>>();
+  private Map<GroupPrincipal, Collection<Principal>> groups
+      = new TreeMap<GroupPrincipal, Collection<Principal>>();
 
   @Override
   public DocId pushDocIds(Iterable<DocId> docIds,
@@ -47,6 +51,18 @@
     return null;
   }
 
+  @Override
+  public GroupPrincipal pushGroupDefinitions(
+      Map<GroupPrincipal, ? extends Collection<Principal>> defs,
+      boolean caseSensitive, ExceptionHandler handler)
+      throws InterruptedException {
+    for (GroupPrincipal key : defs.keySet()) {
+      groups.put(key, Collections.unmodifiableList(
+          new ArrayList<Principal>(defs.get(key))));
+    }
+    return null;
+  }
+
   public List<Record> getRecords() {
     return Collections.unmodifiableList(records);
   }
@@ -55,6 +71,10 @@
     return namedResouces;
   }
 
+  public Map<GroupPrincipal, Collection<Principal>> getGroups() {
+    return Collections.unmodifiableMap(groups);
+  }
+
   public void reset() {
     records.clear();
     namedResouces.clear();
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
index 931f731..c20bca8 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
@@ -28,6 +28,7 @@
 import com.google.enterprise.adaptor.GroupPrincipal;
 import com.google.enterprise.adaptor.IOHelper;
 import com.google.enterprise.adaptor.Metadata;
+import com.google.enterprise.adaptor.Principal;
 import com.google.enterprise.adaptor.UserPrincipal;
 import com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.SiteUserIdMappingCallable;
 import com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.SoapFactory;
@@ -177,6 +178,34 @@
           "{6F33949A-B3FF-4B0C-BA99-93CB518AC2C0}", "", "2", true, false,
           null,
           loadTestString("sites-SiteCollection-Lists-CustomList-2-a.xml"));
+  private static final String DEFAULT_NAMESPACE = "Default";
+  private static final String SITES_SITECOLLECTION_NAMESPACE
+      = "Default_http://localhost:1/sites/SiteCollection";
+  private static final UserPrincipal NT_AUTHORITY_LOCAL_SERVICE
+      = new UserPrincipal("NT AUTHORITY\\LOCAL SERVICE", DEFAULT_NAMESPACE);
+  private static final GroupPrincipal NT_AUTHORITY_AUTHENTICATED_USERS
+      = new GroupPrincipal("NT AUTHORITY\\authenticated users",
+          DEFAULT_NAMESPACE);
+  private static final UserPrincipal GDC_PSL_ADMINISTRATOR
+      = new UserPrincipal("GDC-PSL\\administrator", DEFAULT_NAMESPACE);
+  private static final UserPrincipal GDC_PSL_SPUSER1
+      = new UserPrincipal("GDC-PSL\\spuser1", DEFAULT_NAMESPACE);
+  private static final GroupPrincipal SITES_SITECOLLECTION_OWNERS
+      = new GroupPrincipal("chinese1 Owners",
+          SITES_SITECOLLECTION_NAMESPACE);
+  private static final GroupPrincipal SITES_SITECOLLECTION_VISITORS
+      = new GroupPrincipal("chinese1 Visitors",
+          SITES_SITECOLLECTION_NAMESPACE);
+  private static final GroupPrincipal SITES_SITECOLLECTION_MEMBERS
+      = new GroupPrincipal("chinese1 Members",
+          SITES_SITECOLLECTION_NAMESPACE);
+  private static final MemberIdMapping SITES_SITECOLLECTION_MEMBER_MAPPING
+      = new MemberIdMappingBuilder()
+      .put(1, GDC_PSL_ADMINISTRATOR)
+      .put(3, SITES_SITECOLLECTION_OWNERS)
+      .put(4, SITES_SITECOLLECTION_VISITORS)
+      .put(5, SITES_SITECOLLECTION_MEMBERS)
+      .build();
 
   private final Charset charset = Charset.forName("UTF-8");
   private Config config;
@@ -225,22 +254,6 @@
     }
   }
 
-  public List<UserPrincipal> users(String... names) {
-    List<UserPrincipal> users = new ArrayList<UserPrincipal>();
-    for (String name : names) {
-      users.add(new UserPrincipal(name));
-    }
-    return users;
-  }
-
-  public List<GroupPrincipal> groups(String... names) {
-    List<GroupPrincipal> groups = new ArrayList<GroupPrincipal>();
-    for (String name : names) {
-      groups.add(new GroupPrincipal(name));
-    }
-    return groups;
-  }
-  
   public User createUserGroupUser(long id, String loginName, String sid, 
       String name, String email, boolean isDomainGroup, boolean isSiteAdmin) {
     User u = new User();
@@ -398,12 +411,11 @@
         + "SiteCollection</a></li>"
         + "</ul></body></html>";
     assertEquals(golden, responseString);
-    String[] permit = new String[] {"GDC-PSL\\Administrator",
-        "GDC-PSL\\spuser1", "NT AUTHORITY\\LOCAL SERVICE"};
     assertEquals(new Acl.Builder()
         .setEverythingCaseInsensitive()
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-        .setPermitUsers(users(permit)).build(), response.getAcl());
+        .setPermitUsers(Arrays.asList(GDC_PSL_ADMINISTRATOR, GDC_PSL_SPUSER1,
+            NT_AUTHORITY_LOCAL_SERVICE)).build(), response.getAcl());
     assertNull(response.getDisplayUrl());
   }
   
@@ -446,15 +458,15 @@
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     GetContentsResponse response = new GetContentsResponse(baos);
     adaptor.getDocContent(new GetContentsRequest(new DocId("")), response);       
-    String[] permitUsers = new String[] {"GDC-PSL\\Administrator",
-        "GDC-PSL\\spuser1", "NT AUTHORITY\\LOCAL SERVICE",
-        "GSA-CONNECTORS\\Administrator"};
-    String[] permitGroups = new String[] {"GSA-CONNECTORS\\domain users"};
     assertEquals(new Acl.Builder()
         .setEverythingCaseInsensitive()
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-        .setPermitUsers(users(permitUsers))
-        .setPermitGroups(groups(permitGroups)).build(),
+        .setPermitUsers(Arrays.asList(GDC_PSL_ADMINISTRATOR, GDC_PSL_SPUSER1,
+            NT_AUTHORITY_LOCAL_SERVICE, new UserPrincipal(
+                "GSA-CONNECTORS\\Administrator", DEFAULT_NAMESPACE)))
+        .setPermitGroups(Arrays.asList(new GroupPrincipal(
+            "GSA-CONNECTORS\\Domain Users", DEFAULT_NAMESPACE)))
+        .build(),
         response.getAcl());
     assertNull(response.getDisplayUrl());
   }
@@ -505,9 +517,11 @@
         .setEverythingCaseInsensitive()
         .setInheritFrom(new DocId(""))
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-        .setPermitGroups(groups("chinese1 Members", "chinese1 Owners",
-            "chinese1 Visitors"))
-        .setPermitUsers(users("GDC-PSL\\spuser1")).build(),
+        .setPermitGroups(Arrays.asList(
+            SITES_SITECOLLECTION_MEMBERS,
+            SITES_SITECOLLECTION_OWNERS,
+            SITES_SITECOLLECTION_VISITORS))
+        .setPermitUsers(Arrays.asList(GDC_PSL_SPUSER1)).build(),
         response.getAcl());
     assertEquals(URI.create("http://localhost:1/sites/SiteCollection"),
         response.getDisplayUrl());
@@ -545,8 +559,9 @@
         .setEverythingCaseInsensitive()
         .setInheritFrom(new DocId(""))
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-        .setPermitGroups(groups("chinese1 Members", "chinese1 Owners",
-            "chinese1 Visitors", "GDC-PSL\\group")).build(),
+        .setPermitGroups(Arrays.asList(SITES_SITECOLLECTION_MEMBERS,
+            SITES_SITECOLLECTION_OWNERS, SITES_SITECOLLECTION_VISITORS,
+            new GroupPrincipal("GDC-PSL\\group", DEFAULT_NAMESPACE))).build(),
         response.getAcl());
   }
 
@@ -583,12 +598,18 @@
         .setEverythingCaseInsensitive()
         .setInheritFrom(new DocId(""))
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-        .setPermitUsers(users("GDC-PSL\\spuser1", "GSA-CONNECTORS\\User1",
-            "membershipprovider:user2007"))
-        .setPermitGroups(groups("chinese1 Members", "chinese1 Owners",
-            "chinese1 Visitors", "GSA-CONNECTORS\\domain users",
-            "Everyone", "NT AUTHORITY\\authenticated users",
-            "roleprovider:super")).build(),
+        .setPermitUsers(Arrays.asList(GDC_PSL_SPUSER1,
+            new UserPrincipal("GSA-CONNECTORS\\User1", DEFAULT_NAMESPACE),
+            new UserPrincipal("membershipprovider:user2007",
+              DEFAULT_NAMESPACE)))
+        .setPermitGroups(Arrays.asList(SITES_SITECOLLECTION_MEMBERS,
+            SITES_SITECOLLECTION_OWNERS, SITES_SITECOLLECTION_VISITORS,
+            new GroupPrincipal("GSA-CONNECTORS\\domain users",
+              DEFAULT_NAMESPACE),
+            new GroupPrincipal("Everyone", DEFAULT_NAMESPACE),
+            NT_AUTHORITY_AUTHENTICATED_USERS,
+            new GroupPrincipal("roleprovider:super", DEFAULT_NAMESPACE)))
+        .build(),
         response.getAcl());
   }
 
@@ -631,9 +652,9 @@
         .setEverythingCaseInsensitive()
         .setInheritFrom(new DocId(""))
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-        .setPermitGroups(groups("chinese1 Members", "chinese1 Owners",
-            "chinese1 Visitors"))
-        .setPermitUsers(users("GDC-PSL\\spuser1")).build(),
+        .setPermitGroups(Arrays.asList(SITES_SITECOLLECTION_MEMBERS,
+            SITES_SITECOLLECTION_OWNERS, SITES_SITECOLLECTION_VISITORS))
+        .setPermitUsers(Arrays.asList(GDC_PSL_SPUSER1)).build(),
         response.getAcl());
 
     // Were we able to pick up the new user in the ACLs?
@@ -644,9 +665,11 @@
         .setEverythingCaseInsensitive()
         .setInheritFrom(new DocId(""))
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-        .setPermitGroups(groups("chinese1 Members", "chinese1 Owners",
-            "chinese1 Visitors"))
-        .setPermitUsers(users("GDC-PSL\\spuser100")).build(),
+        .setPermitGroups(Arrays.asList(SITES_SITECOLLECTION_MEMBERS,
+            SITES_SITECOLLECTION_OWNERS, SITES_SITECOLLECTION_VISITORS))
+        .setPermitUsers(Arrays.asList(
+            new UserPrincipal("GDC-PSL\\spuser100", DEFAULT_NAMESPACE)))
+        .build(),
         response.getAcl());
   }
 
@@ -677,16 +700,6 @@
         .register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_L_CONTENT_EXCHANGE)
         .register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_F_CONTENT_EXCHANGE)
         .register(SITES_SITECOLLECTION_S_CONTENT_EXCHANGE);
-    final MemberIdMapping memberIdMapping;
-    {
-      Map<Integer, String> users = new HashMap<Integer, String>();
-      Map<Integer, String> groups = new HashMap<Integer, String>();
-      users.put(1, "GDC-PSL\\administrator");
-      groups.put(3, "SiteCollection Owners");
-      groups.put(4, "SiteCollection Visitors");
-      groups.put(5, "SiteCollection Members");
-      memberIdMapping = new MemberIdMapping(users, groups);
-    }
 
     adaptor = new SharePointAdaptor(initableSoapFactory,
         new UnsupportedHttpClient(), executorFactory);
@@ -699,7 +712,7 @@
     adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
           "http://localhost:1/sites/SiteCollection", siteData,
           new UnsupportedUserGroupSoap(), new UnsupportedPeopleSoap(),
-          Callables.returning(memberIdMapping),
+          Callables.returning(SITES_SITECOLLECTION_MEMBER_MAPPING),
           new UnsupportedCallable<MemberIdMapping>())
         .getDocContent(request, response);
     String responseString = new String(baos.toByteArray(), charset);
@@ -717,8 +730,9 @@
         .setEverythingCaseInsensitive()
         .setInheritFrom(new DocId(""))
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-        .setPermitGroups(groups("SiteCollection Members",
-            "SiteCollection Owners", "SiteCollection Visitors")).build(),
+        .setPermitGroups(Arrays.asList(SITES_SITECOLLECTION_MEMBERS,
+            SITES_SITECOLLECTION_OWNERS, SITES_SITECOLLECTION_VISITORS))
+        .build(),
         response.getAcl());
     assertEquals(URI.create("http://localhost:1/sites/SiteCollection/Lists/"
           + "Custom%20List/AllItems.aspx"), response.getDisplayUrl());
@@ -814,16 +828,6 @@
         .register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_1_LI_CONTENT_EXCHANGE)
         .register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_2_LI_CONTENT_EXCHANGE)
         .register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_2_A_CONTENT_EXCHANGE);
-    final MemberIdMapping memberIdMapping;
-    {
-      Map<Integer, String> users = new HashMap<Integer, String>();
-      Map<Integer, String> groups = new HashMap<Integer, String>();
-      users.put(1, "GDC-PSL\\administrator");
-      groups.put(3, "SiteCollection Owners");
-      groups.put(4, "SiteCollection Visitors");
-      groups.put(5, "SiteCollection Members");
-      memberIdMapping = new MemberIdMapping(users, groups);
-    }
 
     adaptor = new SharePointAdaptor(initableSoapFactory,
         new UnsupportedHttpClient(), executorFactory);
@@ -836,7 +840,7 @@
     adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
           "http://localhost:1/sites/SiteCollection", siteData,
           new UnsupportedUserGroupSoap(), new UnsupportedPeopleSoap(),
-          Callables.returning(memberIdMapping),
+          Callables.returning(SITES_SITECOLLECTION_MEMBER_MAPPING),
           new UnsupportedCallable<MemberIdMapping>())
         .getDocContent(request, response);
     String responseString = new String(baos.toByteArray(), charset);
@@ -929,16 +933,6 @@
             .replaceInContent(
                 "ows_ScopeId='2;#{2E29615C-59E7-493B-B08A-3642949CC069}'",
                 "ows_ScopeId='2;#{f9cb02b3-7f29-4cac-804f-ba6e14f1eb39}'"));
-    final MemberIdMapping memberIdMapping;
-    {
-      Map<Integer, String> users = new HashMap<Integer, String>();
-      Map<Integer, String> groups = new HashMap<Integer, String>();
-      users.put(1, "GDC-PSL\\administrator");
-      groups.put(3, "SiteCollection Owners");
-      groups.put(4, "SiteCollection Visitors");
-      groups.put(5, "SiteCollection Members");
-      memberIdMapping = new MemberIdMapping(users, groups);
-    }
 
     adaptor = new SharePointAdaptor(initableSoapFactory,
         new UnsupportedHttpClient(), executorFactory);
@@ -951,7 +945,7 @@
     adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
           "http://localhost:1/sites/SiteCollection", siteData,
           new UnsupportedUserGroupSoap(), new UnsupportedPeopleSoap(),
-          Callables.returning(memberIdMapping),
+          Callables.returning(SITES_SITECOLLECTION_MEMBER_MAPPING),
           new UnsupportedCallable<MemberIdMapping>())
         .getDocContent(request, response);
     assertNull(response.getAcl());
@@ -966,16 +960,6 @@
             .replaceInContent("ReadSecurity=\"1\"", "ReadSecurity=\"2\""))
         .register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_2_LI_CONTENT_EXCHANGE
             .replaceInContent("ows_Attachments='1'", "ows_Attachments='0'"));
-    final MemberIdMapping memberIdMapping;
-    {
-      Map<Integer, String> users = new HashMap<Integer, String>();
-      Map<Integer, String> groups = new HashMap<Integer, String>();
-      users.put(1, "GDC-PSL\\administrator");
-      groups.put(3, "SiteCollection Owners");
-      groups.put(4, "SiteCollection Visitors");
-      groups.put(5, "SiteCollection Members");
-      memberIdMapping = new MemberIdMapping(users, groups);
-    }
 
     Users users = new Users();
     users.getUser().add(createUserGroupUser(1, "GDC-PSL\\administrator",
@@ -1012,7 +996,7 @@
     adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
           "http://localhost:1/sites/SiteCollection", siteData,
           mockUserGroupSoap, new UnsupportedPeopleSoap(),
-          Callables.returning(memberIdMapping),
+          Callables.returning(SITES_SITECOLLECTION_MEMBER_MAPPING),
           adaptor.new SiteUserIdMappingCallable(
               "http://localhost:1/sites/SiteCollection"))
         .getDocContent(request, response);
@@ -1027,9 +1011,9 @@
         .setEverythingCaseInsensitive()
         .setInheritFrom(new DocId("http://localhost:1/sites/SiteCollection"
             + "/Lists/Custom List/Test Folder/2_.000_READ_SECURITY"))
-        .setPermitUsers(users("GDC-PSL\\administrator"))
-        .setPermitGroups(groups("SiteCollection Owners",
-            "SiteCollection Members", "SiteCollection Visitors"))
+        .setPermitUsers(Arrays.asList(GDC_PSL_ADMINISTRATOR))
+        .setPermitGroups(Arrays.asList(SITES_SITECOLLECTION_OWNERS,
+            SITES_SITECOLLECTION_MEMBERS, SITES_SITECOLLECTION_VISITORS))
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES).build(),
         response.getAcl());
     assertEquals(Collections.singletonList(Collections.singletonMap(
@@ -1037,8 +1021,9 @@
             + "Test Folder/2_.000_READ_SECURITY"),
         new Acl.Builder()
             .setEverythingCaseInsensitive()
-            .setPermitUsers(users("GDC-PSL\\administrator", "System.Account"))
-            .setPermitGroups(groups("SiteCollection Owners"))
+            .setPermitUsers(Arrays.asList(GDC_PSL_ADMINISTRATOR,
+                new UserPrincipal("System.Account", DEFAULT_NAMESPACE)))
+            .setPermitGroups(Arrays.asList(SITES_SITECOLLECTION_OWNERS))
             .setInheritanceType(Acl.InheritanceType.AND_BOTH_PERMIT)
             .setInheritFrom(new DocId(""))
             .build())),
@@ -1058,13 +1043,10 @@
               "{6F33949A-B3FF-4B0C-BA99-93CB518AC2C0}", null, null, false,
               false, null,
               loadTestString("tapasnay-Lists-Announcements-l.xml")));
-    final MemberIdMapping memberIdMapping;
-    {
-      Map<Integer, String> users = new HashMap<Integer, String>();
-      Map<Integer, String> groups = new HashMap<Integer, String>();
-      users.put(1, "SOMEHOST\\administrator");
-      memberIdMapping = new MemberIdMapping(users, groups);
-    }
+    final MemberIdMapping memberIdMapping
+        = new MemberIdMappingBuilder()
+        .put(1, new UserPrincipal("SOMEHOST\\administrator", DEFAULT_NAMESPACE))
+        .build();
 
     adaptor = new SharePointAdaptor(initableSoapFactory,
         new UnsupportedHttpClient(), executorFactory);
@@ -1098,16 +1080,6 @@
         .register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_L_CONTENT_EXCHANGE)
         .register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_1_LI_CONTENT_EXCHANGE)
         .register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_1_F_CONTENT_EXCHANGE);
-    final MemberIdMapping memberIdMapping;
-    {
-      Map<Integer, String> users = new HashMap<Integer, String>();
-      Map<Integer, String> groups = new HashMap<Integer, String>();
-      users.put(1, "GDC-PSL\\administrator");
-      groups.put(3, "SiteCollection Owners");
-      groups.put(4, "SiteCollection Visitors");
-      groups.put(5, "SiteCollection Members");
-      memberIdMapping = new MemberIdMapping(users, groups);
-    }
 
     adaptor = new SharePointAdaptor(initableSoapFactory,
         new UnsupportedHttpClient(), executorFactory);
@@ -1120,8 +1092,8 @@
     adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
           "http://localhost:1/sites/SiteCollection",
           siteData, new UnsupportedUserGroupSoap(), new UnsupportedPeopleSoap(),
-        Callables.returning(memberIdMapping),
-        new UnsupportedCallable<MemberIdMapping>())
+          Callables.returning(SITES_SITECOLLECTION_MEMBER_MAPPING),
+          new UnsupportedCallable<MemberIdMapping>())
         .getDocContent(request, response);
     String responseString = new String(baos.toByteArray(), charset);
     final String golden
@@ -1184,9 +1156,9 @@
         .setEverythingCaseInsensitive()
         .setInheritFrom(new DocId(""))
         .setInheritanceType(Acl.InheritanceType.PARENT_OVERRIDES)
-        .setPermitGroups(groups("SiteCollection Members",
-            "SiteCollection Owners", "SiteCollection Visitors"))
-        .setPermitUsers(users("GDC-PSL\\administrator")).build(),
+        .setPermitGroups(Arrays.asList(SITES_SITECOLLECTION_MEMBERS,
+            SITES_SITECOLLECTION_OWNERS, SITES_SITECOLLECTION_VISITORS))
+        .setPermitUsers(Arrays.asList(GDC_PSL_ADMINISTRATOR)).build(),
         response.getAcl());
     assertEquals(URI.create("http://localhost:1/sites/SiteCollection/Lists/"
           + "Custom%20List/AllItems.aspx?RootFolder=/sites/SiteCollection/"
@@ -2284,4 +2256,18 @@
       this.strWeb = strWeb;
     }
   }
+
+  private static class MemberIdMappingBuilder {
+    private final Map<Integer, Principal> map
+        = new HashMap<Integer, Principal>();
+
+    public MemberIdMapping build() {
+      return new MemberIdMapping(map);
+    }
+
+    public MemberIdMappingBuilder put(Integer i, Principal p) {
+      map.put(i, p);
+      return this;
+    }
+  }
 }
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java
index 3ae4b78..513bb06 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java
@@ -184,6 +184,7 @@
 
     serviceFactory.addUserProfileToCollection(1, 2, "user1", profile, colleaguesData);
     adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+    config.overrideKey("adaptor.namespace", "ns1");
 
     AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
     adaptor.init(new MockAdaptorContext(config, pusher));
@@ -244,7 +245,7 @@
 
     //ACL Verification
     List<GroupPrincipal> groups = new ArrayList<GroupPrincipal>();
-    groups.add(new GroupPrincipal("NT AUTHORITY\\Authenticated Users"));
+    groups.add(new GroupPrincipal("NT AUTHORITY\\Authenticated Users", "ns1"));
     assertEquals(new Acl.Builder()
         .setEverythingCaseInsensitive()
         .setInheritanceType(Acl.InheritanceType.LEAF_NODE)