Represent Principals (both user and group)
diff --git a/src/com/google/enterprise/adaptor/GroupPrincipal.java b/src/com/google/enterprise/adaptor/GroupPrincipal.java
new file mode 100644
index 0000000..8f32198
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/GroupPrincipal.java
@@ -0,0 +1,28 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// 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 com.google.enterprise.adaptor;
+
+/**
+ * Represents group.
+ */
+public class GroupPrincipal extends Principal {
+  public GroupPrincipal(String n, String ns) {
+    super(n, ns);
+  }
+
+  public GroupPrincipal(String n) {
+    super(n);
+  }
+}
diff --git a/src/com/google/enterprise/adaptor/Principal.java b/src/com/google/enterprise/adaptor/Principal.java
new file mode 100644
index 0000000..6fd275d
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/Principal.java
@@ -0,0 +1,72 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// 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 com.google.enterprise.adaptor;
+
+import java.util.Arrays;
+
+/**
+ * Represents either a user or a group.
+ */
+public class Principal {
+  private final String name;
+  private final String namespace;
+
+  Principal(String n, String ns) {
+    if (null == n || null == ns) {
+      throw new NullPointerException();
+    }
+    name = n;
+    namespace = ns;
+  }
+
+  Principal(String n) {
+    this(n, "Default");
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String getNamespace() {
+    return namespace;
+  }
+
+  public boolean isUser() {
+    return this instanceof UserPrincipal;
+  }
+
+  public boolean isGroup() {
+    return this instanceof GroupPrincipal;
+  }
+
+  public boolean equals(Object other) {
+    boolean same = other instanceof Principal;
+    if (same) {
+      Principal p = (Principal) other;
+      same = p.isUser() == isUser() && p.name.equals(name)
+          && p.namespace.equals(namespace);
+    }
+    return same;
+  }
+
+  public int hashCode() {
+    return Arrays.hashCode(new Object[]{ isUser(), name, namespace });
+  }
+
+  public String toString() {
+    String type = isUser() ? "User" : "Group";
+    return "Principal(" + type + "," + name + "," + namespace + ")";
+  }
+}
diff --git a/src/com/google/enterprise/adaptor/UserPrincipal.java b/src/com/google/enterprise/adaptor/UserPrincipal.java
new file mode 100644
index 0000000..7d71cca
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/UserPrincipal.java
@@ -0,0 +1,28 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// 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 com.google.enterprise.adaptor;
+
+/**
+ * Represents user.
+ */
+public class UserPrincipal extends Principal {
+  public UserPrincipal(String n, String ns) {
+    super(n, ns);
+  }
+
+  public UserPrincipal(String n) {
+    super(n);
+  }
+}
diff --git a/test/com/google/enterprise/adaptor/PrincipalTest.java b/test/com/google/enterprise/adaptor/PrincipalTest.java
new file mode 100644
index 0000000..23abe20
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/PrincipalTest.java
@@ -0,0 +1,144 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// 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 com.google.enterprise.adaptor;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+
+import java.util.*;
+
+/**
+ * Test cases for {@link Principal}.
+ */
+public class PrincipalTest {
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void testDefaultNamespaceOfUser() {
+    Principal p = new UserPrincipal("id");
+    assertEquals("Default", p.getNamespace());
+  }
+
+  @Test
+  public void testDefaultNamespaceOfGroup() {
+    Principal p = new GroupPrincipal("grooop");
+    assertEquals("Default", p.getNamespace());
+  }
+
+  @Test
+  public void testSimpleUser() {
+    Principal p = new UserPrincipal("user", "ns");
+    assertEquals("user", p.getName());
+    assertEquals("ns", p.getNamespace());
+    assertTrue(p.isUser());
+    assertFalse(p.isGroup());
+  }
+
+  @Test
+  public void testSimpleGroup() {
+    Principal p = new GroupPrincipal("ggg", "ns");
+    assertEquals("ggg", p.getName());
+    assertEquals("ns", p.getNamespace());
+    assertTrue(p.isGroup());
+    assertFalse(p.isUser());
+  }
+
+  @Test
+  public void testNullNameOfUser() {
+    thrown.expect(NullPointerException.class);
+    new UserPrincipal(null);
+  }
+
+  @Test
+  public void testNullNameOfGroup() {
+    thrown.expect(NullPointerException.class);
+    new GroupPrincipal(null);
+  }
+
+  @Test
+  public void testNullNamespaceOfUser() {
+    thrown.expect(NullPointerException.class);
+    new UserPrincipal("yowzer", null);
+  }
+
+  @Test
+  public void testNullNamespaceOfGroup() {
+    thrown.expect(NullPointerException.class);
+    new GroupPrincipal("gooop", null);
+  }
+
+  @Test
+  public void testUserEquals() {
+    Principal p1 = new UserPrincipal("id");
+    assertFalse(p1.equals(null));
+    Principal p2 = new UserPrincipal("id");
+    assertEquals(p1, p2);
+    Principal p3 = new UserPrincipal("id", "N");
+    assertFalse(p1.equals(p3));
+    assertFalse(p2.equals(p3));
+  }
+
+  @Test
+  public void testGroupEquals() {
+    Principal p1 = new GroupPrincipal("id");
+    assertFalse(p1.equals(null));
+    Principal p2 = new GroupPrincipal("id");
+    assertEquals(p1, p2);
+    Principal p3 = new GroupPrincipal("id", "N");
+    assertFalse(p1.equals(p3));
+    assertFalse(p2.equals(p3));
+  }
+
+  @Test
+  public void testUserAndGroupNotEqual() {
+    Principal u = new UserPrincipal("id");
+    Principal g = new GroupPrincipal("id");
+    assertFalse(u.equals(g));
+  }
+
+  @Test
+  public void testUserHashCode() {
+    Principal p1 = new UserPrincipal("id");
+    Principal p2 = new UserPrincipal("id");
+    assertEquals(p1.hashCode(), p2.hashCode());
+    Set<Principal> p = new HashSet<Principal>();
+    p.add(p1);
+    p.add(p2);
+    assertEquals(1, p.size()); 
+  }
+
+  @Test
+  public void testGroupHashCode() {
+    Principal p1 = new GroupPrincipal("id");
+    Principal p2 = new GroupPrincipal("id");
+    assertEquals(p1.hashCode(), p2.hashCode());
+    Set<Principal> p = new HashSet<Principal>();
+    p.add(p1);
+    p.add(p2);
+    assertEquals(1, p.size()); 
+  }
+
+  @Test
+  public void testToString() {
+    Principal u = new UserPrincipal("1d");
+    String s = "" + u;
+    assertTrue(s.contains("User"));
+    assertTrue(s.contains("1d"));
+    assertTrue(s.contains("Default"));
+  }
+}