ListBranches: Split filtering and pagination out to a utility class

Split the filtering and pagination functionality out of ListBranches
into a new utility class, RefFilter, that can do the filtering and
pagination on lists of RefInfo.

Change-Id: I9b52612005bafaf0c0a8a03594d0bfcbeb22bf95
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListBranches.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListBranches.java
index f7914e9..370ced2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListBranches.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListBranches.java
@@ -14,8 +14,6 @@
 
 package com.google.gerrit.server.project;
 
-import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
 import com.google.common.collect.ComparisonChain;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Sets;
@@ -35,9 +33,6 @@
 import com.google.inject.Inject;
 import com.google.inject.util.Providers;
 
-import dk.brics.automaton.RegExp;
-import dk.brics.automaton.RunAutomaton;
-
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
@@ -50,7 +45,6 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Locale;
 import java.util.Set;
 import java.util.TreeMap;
 
@@ -96,18 +90,15 @@
   @Override
   public List<BranchInfo> apply(ProjectResource rsrc)
       throws ResourceNotFoundException, IOException, BadRequestException {
-    FluentIterable<BranchInfo> branches = allBranches(rsrc);
-    branches = filterBranches(branches);
-    if (start > 0) {
-      branches = branches.skip(start);
-    }
-    if (limit > 0) {
-      branches = branches.limit(limit);
-    }
-    return branches.toList();
+    return new RefFilter<BranchInfo>(Constants.R_HEADS)
+        .subString(matchSubstring)
+        .regex(matchRegex)
+        .start(start)
+        .limit(limit)
+        .filter(allBranches(rsrc));
   }
 
-  private FluentIterable<BranchInfo> allBranches(ProjectResource rsrc)
+  private List<BranchInfo> allBranches(ProjectResource rsrc)
       throws IOException, ResourceNotFoundException {
     List<Ref> refs;
     try (Repository db = repoManager.openRepository(rsrc.getNameKey())) {
@@ -162,7 +153,7 @@
       }
     }
     Collections.sort(branches, new BranchComparator());
-    return FluentIterable.from(branches);
+    return branches;
   }
 
   private static class BranchComparator implements Comparator<BranchInfo> {
@@ -184,61 +175,6 @@
     }
   }
 
-  private FluentIterable<BranchInfo> filterBranches(
-      FluentIterable<BranchInfo> branches) throws BadRequestException {
-    if (!Strings.isNullOrEmpty(matchSubstring)) {
-      branches = branches.filter(new SubstringPredicate(matchSubstring));
-    } else if (!Strings.isNullOrEmpty(matchRegex)) {
-      branches = branches.filter(new RegexPredicate(matchRegex));
-    }
-    return branches;
-  }
-
-  private static class SubstringPredicate implements Predicate<BranchInfo> {
-    private final String substring;
-
-    private SubstringPredicate(String substring) {
-      this.substring = substring.toLowerCase(Locale.US);
-    }
-
-    @Override
-    public boolean apply(BranchInfo in) {
-      String ref = in.ref;
-      if (ref.startsWith(Constants.R_HEADS)) {
-        ref = ref.substring(Constants.R_HEADS.length());
-      }
-      ref = ref.toLowerCase(Locale.US);
-      return ref.contains(substring);
-    }
-  }
-
-  private static class RegexPredicate implements Predicate<BranchInfo> {
-    private final RunAutomaton a;
-
-    private RegexPredicate(String regex) throws BadRequestException {
-      if (regex.startsWith("^")) {
-        regex = regex.substring(1);
-        if (regex.endsWith("$") && !regex.endsWith("\\$")) {
-          regex = regex.substring(0, regex.length() - 1);
-        }
-      }
-      try {
-        a = new RunAutomaton(new RegExp(regex).toAutomaton());
-      } catch (IllegalArgumentException e) {
-        throw new BadRequestException(e.getMessage());
-      }
-    }
-
-    @Override
-    public boolean apply(BranchInfo in) {
-      if (!in.ref.startsWith(Constants.R_HEADS)){
-        return a.run(in.ref);
-      } else {
-        return a.run(in.ref.substring(Constants.R_HEADS.length()));
-      }
-    }
-  }
-
   private BranchInfo createBranchInfo(Ref ref, RefControl refControl,
       Set<String> targets) {
     BranchInfo info = new BranchInfo();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefFilter.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefFilter.java
new file mode 100644
index 0000000..63fb595
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefFilter.java
@@ -0,0 +1,120 @@
+// Copyright (C) 2015 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.gerrit.server.project;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.FluentIterable;
+import com.google.gerrit.extensions.api.projects.RefInfo;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+
+import dk.brics.automaton.RegExp;
+import dk.brics.automaton.RunAutomaton;
+
+import java.util.List;
+import java.util.Locale;
+
+public class RefFilter<T extends RefInfo> {
+  private final String prefix;
+  private String matchSubstring;
+  private String matchRegex;
+  private int start;
+  private int limit;
+
+  public RefFilter(String prefix) {
+    this.prefix = prefix;
+  }
+
+  public RefFilter<T> subString(String subString) {
+    this.matchSubstring = subString;
+    return this;
+  }
+
+  public RefFilter<T> regex(String regex) {
+    this.matchRegex = regex;
+    return this;
+  }
+
+  public RefFilter<T> start(int start) {
+    this.start = start;
+    return this;
+  }
+
+  public RefFilter<T> limit(int limit) {
+    this.limit = limit;
+    return this;
+  }
+
+  public List<T> filter(List<T> refs) throws BadRequestException {
+    FluentIterable<T> results = FluentIterable.from(refs);
+    if (!Strings.isNullOrEmpty(matchSubstring)) {
+      results = results.filter(new SubstringPredicate(matchSubstring));
+    } else if (!Strings.isNullOrEmpty(matchRegex)) {
+      results = results.filter(new RegexPredicate(matchRegex));
+    }
+    if (start > 0) {
+      results = results.skip(start);
+    }
+    if (limit > 0) {
+      results = results.limit(limit);
+    }
+    return results.toList();
+  }
+
+  private class SubstringPredicate implements Predicate<T> {
+    private final String substring;
+
+    private SubstringPredicate(String substring) {
+      this.substring = substring.toLowerCase(Locale.US);
+    }
+
+    @Override
+    public boolean apply(T in) {
+      String ref = in.ref;
+      if (ref.startsWith(prefix)) {
+        ref = ref.substring(prefix.length());
+      }
+      ref = ref.toLowerCase(Locale.US);
+      return ref.contains(substring);
+    }
+  }
+
+  private class RegexPredicate implements Predicate<T> {
+    private final RunAutomaton a;
+
+    private RegexPredicate(String regex) throws BadRequestException {
+      if (regex.startsWith("^")) {
+        regex = regex.substring(1);
+        if (regex.endsWith("$") && !regex.endsWith("\\$")) {
+          regex = regex.substring(0, regex.length() - 1);
+        }
+      }
+      try {
+        a = new RunAutomaton(new RegExp(regex).toAutomaton());
+      } catch (IllegalArgumentException e) {
+        throw new BadRequestException(e.getMessage());
+      }
+    }
+
+    @Override
+    public boolean apply(T in) {
+      String ref = in.ref;
+      if (ref.startsWith(prefix)) {
+        ref = ref.substring(prefix.length());
+      }
+      return a.run(ref);
+    }
+  }
+}