Allow filtering log by committer

Extract an abstract base from AuthorRevFilter.

Change-Id: Ie76898f6a24f78581fe6bad342b72d82b76905c8
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/AuthorRevFilter.java b/gitiles-servlet/src/main/java/com/google/gitiles/AuthorRevFilter.java
deleted file mode 100644
index 52c4cc1..0000000
--- a/gitiles-servlet/src/main/java/com/google/gitiles/AuthorRevFilter.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 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.gitiles;
-
-import com.google.common.annotations.VisibleForTesting;
-
-import org.eclipse.jgit.errors.IncorrectObjectTypeException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.errors.StopWalkException;
-import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.revwalk.filter.RevFilter;
-
-import java.io.IOException;
-
-/**
- * A {@link RevFilter} which only includes {@link RevCommit}s by an author pattern.
- *
- * Mostly equivalent to {@code git log --author}.
- */
-public class AuthorRevFilter extends RevFilter {
-  private final String authorPattern;
-
-  public AuthorRevFilter(String authorPattern) {
-    this.authorPattern = authorPattern;
-  }
-
-  @Override
-  public boolean include(RevWalk walker, RevCommit commit) throws StopWalkException,
-      MissingObjectException, IncorrectObjectTypeException, IOException {
-    return matchesPerson(commit.getAuthorIdent());
-  }
-
-  /** @return whether the given person matches the author filter. */
-  @VisibleForTesting
-  boolean matchesPerson(PersonIdent person) {
-    // Equivalent to --fixed-strings, to avoid pathological performance of Java
-    // regex matching.
-    // TODO(kalman): Find/use a port of re2.
-    return person.getName().contains(authorPattern)
-        || person.getEmailAddress().contains(authorPattern);
-  }
-
-  @Override
-  public RevFilter clone() {
-    return this;
-  }
-}
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/IdentRevFilter.java b/gitiles-servlet/src/main/java/com/google/gitiles/IdentRevFilter.java
new file mode 100644
index 0000000..eb0905b
--- /dev/null
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/IdentRevFilter.java
@@ -0,0 +1,89 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// 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.gitiles;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.StopWalkException;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+
+import java.io.IOException;
+
+/** Filter which only includes commits matching a person identity. */
+public abstract class IdentRevFilter extends RevFilter {
+  public static IdentRevFilter author(String author) {
+    return new Author(author);
+  }
+
+  public static IdentRevFilter committer(String committer) {
+    return new Committer(committer);
+  }
+
+  private final String pattern;
+
+  protected IdentRevFilter(String pattern) {
+    this.pattern = pattern;
+  }
+
+  @Override
+  public boolean include(RevWalk walker, RevCommit commit) throws StopWalkException,
+      MissingObjectException, IncorrectObjectTypeException, IOException {
+    return matchesPerson(getIdent(commit));
+  }
+
+  @Override
+  public RevFilter clone() {
+    return this;
+  }
+
+  /** @return whether the given person matches the author filter. */
+  @VisibleForTesting
+  boolean matchesPerson(PersonIdent person) {
+    // Equivalent to --fixed-strings, to avoid pathological performance of Java
+    // regex matching.
+    // TODO(kalman): Find/use a port of re2.
+    return person.getName().contains(pattern)
+        || person.getEmailAddress().contains(pattern);
+  }
+
+  protected abstract PersonIdent getIdent(RevCommit commit);
+
+  private static class Author extends IdentRevFilter {
+    private Author(String author) {
+      super(author);
+    }
+
+    @Override
+    protected PersonIdent getIdent(RevCommit commit) {
+      return commit.getAuthorIdent();
+    }
+  }
+
+  private static class Committer extends IdentRevFilter {
+    private Committer(String committer) {
+      super(committer);
+    }
+
+    @Override
+    protected PersonIdent getIdent(RevCommit commit) {
+      return commit.getCommitterIdent();
+    }
+  }
+}
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java
index 1593988..fc6db2e 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java
@@ -213,7 +213,11 @@
     }
     String author = Iterables.getFirst(view.getParameters().get("author"), null);
     if (author != null) {
-      walk.setRevFilter(new AuthorRevFilter(author));
+      walk.setRevFilter(IdentRevFilter.author(author));
+    }
+    String committer = Iterables.getFirst(view.getParameters().get("committer"), null);
+    if (committer != null) {
+      walk.setRevFilter(IdentRevFilter.committer(committer));
     }
     return walk;
   }
diff --git a/gitiles-servlet/src/test/java/com/google/gitiles/AuthorRevFilterTest.java b/gitiles-servlet/src/test/java/com/google/gitiles/IdentRevFilterTest.java
similarity index 89%
rename from gitiles-servlet/src/test/java/com/google/gitiles/AuthorRevFilterTest.java
rename to gitiles-servlet/src/test/java/com/google/gitiles/IdentRevFilterTest.java
index 42a4c21..d35bba4 100644
--- a/gitiles-servlet/src/test/java/com/google/gitiles/AuthorRevFilterTest.java
+++ b/gitiles-servlet/src/test/java/com/google/gitiles/IdentRevFilterTest.java
@@ -23,17 +23,17 @@
 import org.junit.Test;
 
 /**
- * Tests for {@link AuthorRevFilter}.
+ * Tests for {@link IdentRevFilter}.
  *
  * Unfortunately it's not easy to test the Filter using real {@link RevCommit}s
  * because {@link TestRepository} hard-codes its author as "J. Author". The next
  * best thing is to test a {@link PersonIdent}, those are easy to construct.
  * TODO(dborowitz): Fix TestRepository to allow this.
  */
-public class AuthorRevFilterTest {
+public class IdentRevFilterTest {
   @Test
   public void matchesName() throws Exception {
-    AuthorRevFilter filter = new AuthorRevFilter("eSt");
+    IdentRevFilter filter = IdentRevFilter.author("eSt");
     assertTrue(filter.matchesPerson(new PersonIdent("eSt", "null@google.com")));
     assertTrue(filter.matchesPerson(new PersonIdent("eStablish", "null@google.com")));
     assertTrue(filter.matchesPerson(new PersonIdent("teSt", "null@google.com")));
@@ -42,7 +42,7 @@
 
   @Test
   public void caseSensitiveName() throws Exception {
-    AuthorRevFilter filter = new AuthorRevFilter("eSt");
+    IdentRevFilter filter = IdentRevFilter.author("eSt");
     assertFalse(filter.matchesPerson(new PersonIdent("est", "null@google.com")));
     assertFalse(filter.matchesPerson(new PersonIdent("Establish", "null@google.com")));
     assertFalse(filter.matchesPerson(new PersonIdent("tESt", "null@google.com")));
@@ -51,7 +51,7 @@
 
   @Test
   public void matchesEmailLocalPart() throws Exception {
-    AuthorRevFilter filter = new AuthorRevFilter("eSt");
+    IdentRevFilter filter = IdentRevFilter.author("eSt");
     assertTrue(filter.matchesPerson(new PersonIdent("null", "eSt@google.com")));
     assertTrue(filter.matchesPerson(new PersonIdent("null", "eStablish@google.com")));
     assertTrue(filter.matchesPerson(new PersonIdent("null", "teSt@google.com")));
@@ -60,7 +60,7 @@
 
   @Test
   public void caseSensitiveEmailLocalPart() throws Exception {
-    AuthorRevFilter filter = new AuthorRevFilter("eSt");
+    IdentRevFilter filter = IdentRevFilter.author("eSt");
     assertFalse(filter.matchesPerson(new PersonIdent("null", "est@google.com")));
     assertFalse(filter.matchesPerson(new PersonIdent("null", "Establish@google.com")));
     assertFalse(filter.matchesPerson(new PersonIdent("null", "tESt@google.com")));
@@ -70,7 +70,7 @@
   @Test
   public void matchesEmailDomain() throws Exception {
     // git log --author matches the email domain as well as the enail name.
-    AuthorRevFilter filter = new AuthorRevFilter("eSt");
+    IdentRevFilter filter = IdentRevFilter.author("eSt");
     assertTrue(filter.matchesPerson(new PersonIdent("null", "null@eSt.com")));
     assertTrue(filter.matchesPerson(new PersonIdent("null", "null@eStablish.com")));
     assertTrue(filter.matchesPerson(new PersonIdent("null", "null@teSt.com")));
@@ -79,7 +79,7 @@
 
   @Test
   public void caseSensitiveEmailDomain() throws Exception {
-    AuthorRevFilter filter = new AuthorRevFilter("eSt");
+    IdentRevFilter filter = IdentRevFilter.author("eSt");
     assertFalse(filter.matchesPerson(new PersonIdent("null", "null@est.com")));
     assertFalse(filter.matchesPerson(new PersonIdent("null", "null@Establish.com")));
     assertFalse(filter.matchesPerson(new PersonIdent("null", "null@tESt.com")));