Split ref pattern matching functionality out of SectionMatcher
Refactor SectionMatcher to extract the ref pattern matching part into its own class, RefPatternMatcher, which can be reused in other classes. Change-Id: Id66f636d3af6d0d5d4f51a10848dd8caeaf565d0
This commit is contained in:
committed by
David Pursehouse
parent
eb952c1c80
commit
cb16623109
@@ -77,7 +77,7 @@ public class PermissionCollection {
|
|||||||
|
|
||||||
boolean perUser = false;
|
boolean perUser = false;
|
||||||
Map<AccessSection, Project.NameKey> sectionToProject = Maps.newLinkedHashMap();
|
Map<AccessSection, Project.NameKey> sectionToProject = Maps.newLinkedHashMap();
|
||||||
for (SectionMatcher matcher : matcherList) {
|
for (SectionMatcher sm : matcherList) {
|
||||||
// If the matcher has to expand parameters and its prefix matches the
|
// If the matcher has to expand parameters and its prefix matches the
|
||||||
// reference there is a very good chance the reference is actually user
|
// reference there is a very good chance the reference is actually user
|
||||||
// specific, even if the matcher does not match the reference. Since its
|
// specific, even if the matcher does not match the reference. Since its
|
||||||
@@ -91,12 +91,12 @@ public class PermissionCollection {
|
|||||||
// references are usually less frequent than the non-user references.
|
// references are usually less frequent than the non-user references.
|
||||||
//
|
//
|
||||||
if (username != null && !perUser
|
if (username != null && !perUser
|
||||||
&& matcher instanceof SectionMatcher.ExpandParameters) {
|
&& sm.matcher instanceof RefPatternMatcher.ExpandParameters) {
|
||||||
perUser = ((SectionMatcher.ExpandParameters) matcher).matchPrefix(ref);
|
perUser = ((RefPatternMatcher.ExpandParameters) sm.matcher).matchPrefix(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matcher.match(ref, username)) {
|
if (sm.match(ref, username)) {
|
||||||
sectionToProject.put(matcher.section, matcher.project);
|
sectionToProject.put(sm.section, sm.project);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<AccessSection> sections = Lists.newArrayList(sectionToProject.keySet());
|
List<AccessSection> sections = Lists.newArrayList(sectionToProject.keySet());
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
// Copyright (C) 2013 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 static com.google.gerrit.server.project.RefControl.isRE;
|
||||||
|
import com.google.gerrit.common.data.ParameterizedString;
|
||||||
|
import dk.brics.automaton.Automaton;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
abstract class RefPatternMatcher {
|
||||||
|
public static RefPatternMatcher getMatcher(String pattern) {
|
||||||
|
if (pattern.contains("${")) {
|
||||||
|
return new ExpandParameters(pattern);
|
||||||
|
} else if (isRE(pattern)) {
|
||||||
|
return new Regexp(pattern);
|
||||||
|
} else if (pattern.endsWith("/*")) {
|
||||||
|
return new Prefix(pattern.substring(0, pattern.length() - 1));
|
||||||
|
} else {
|
||||||
|
return new Exact(pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract boolean match(String ref, String username);
|
||||||
|
|
||||||
|
private static class Exact extends RefPatternMatcher {
|
||||||
|
private final String expect;
|
||||||
|
|
||||||
|
Exact(String name) {
|
||||||
|
expect = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean match(String ref, String username) {
|
||||||
|
return expect.equals(ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Prefix extends RefPatternMatcher {
|
||||||
|
private final String prefix;
|
||||||
|
|
||||||
|
Prefix(String pfx) {
|
||||||
|
prefix = pfx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean match(String ref, String username) {
|
||||||
|
return ref.startsWith(prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Regexp extends RefPatternMatcher {
|
||||||
|
private final Pattern pattern;
|
||||||
|
|
||||||
|
Regexp(String re) {
|
||||||
|
pattern = Pattern.compile(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean match(String ref, String username) {
|
||||||
|
return pattern.matcher(ref).matches();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ExpandParameters extends RefPatternMatcher {
|
||||||
|
private final ParameterizedString template;
|
||||||
|
private final String prefix;
|
||||||
|
|
||||||
|
ExpandParameters(String pattern) {
|
||||||
|
template = new ParameterizedString(pattern);
|
||||||
|
|
||||||
|
if (isRE(pattern)) {
|
||||||
|
// Replace ${username} with ":USERNAME:" as : is not legal
|
||||||
|
// in a reference and the string :USERNAME: is not likely to
|
||||||
|
// be a valid part of the regex. This later allows the pattern
|
||||||
|
// prefix to be clipped, saving time on evaluation.
|
||||||
|
Automaton am =
|
||||||
|
RefControl.toRegExp(
|
||||||
|
template.replace(Collections.singletonMap("username",
|
||||||
|
":USERNAME:"))).toAutomaton();
|
||||||
|
String rePrefix = am.getCommonPrefix();
|
||||||
|
prefix = rePrefix.substring(0, rePrefix.indexOf(":USERNAME:"));
|
||||||
|
} else {
|
||||||
|
prefix = pattern.substring(0, pattern.indexOf("${"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean match(String ref, String username) {
|
||||||
|
if (!ref.startsWith(prefix) || username == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String u;
|
||||||
|
if (isRE(template.getPattern())) {
|
||||||
|
u = username.replace(".", "\\.");
|
||||||
|
} else {
|
||||||
|
u = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPatternMatcher next =
|
||||||
|
getMatcher(template.replace(Collections.singletonMap("username", u)));
|
||||||
|
return next != null ? next.match(ref, username) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean matchPrefix(String ref) {
|
||||||
|
return ref.startsWith(prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,147 +14,38 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.project;
|
package com.google.gerrit.server.project;
|
||||||
|
|
||||||
import static com.google.gerrit.server.project.RefControl.isRE;
|
|
||||||
|
|
||||||
import com.google.gerrit.common.data.AccessSection;
|
import com.google.gerrit.common.data.AccessSection;
|
||||||
import com.google.gerrit.common.data.ParameterizedString;
|
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
|
||||||
import dk.brics.automaton.Automaton;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches an AccessSection against a reference name.
|
* Matches an AccessSection against a reference name.
|
||||||
* <p>
|
* <p>
|
||||||
* These matchers are "compiled" versions of the AccessSection name, supporting
|
* These matchers are "compiled" versions of the AccessSection name, supporting
|
||||||
* faster selection of which sections are relevant to any given input reference.
|
* faster selection of which sections are relevant to any given input reference.
|
||||||
*/
|
*/
|
||||||
abstract class SectionMatcher {
|
class SectionMatcher extends RefPatternMatcher {
|
||||||
static SectionMatcher wrap(Project.NameKey project, AccessSection section) {
|
static SectionMatcher wrap(Project.NameKey project, AccessSection section) {
|
||||||
String ref = section.getName();
|
String ref = section.getName();
|
||||||
if (AccessSection.isValid(ref)) {
|
if (AccessSection.isValid(ref)) {
|
||||||
return wrap(project, ref, section);
|
return new SectionMatcher(project, section, getMatcher(ref));
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static SectionMatcher wrap(Project.NameKey project, String pattern,
|
|
||||||
AccessSection section) {
|
|
||||||
if (pattern.contains("${")) {
|
|
||||||
return new ExpandParameters(project, pattern, section);
|
|
||||||
|
|
||||||
} else if (isRE(pattern)) {
|
|
||||||
return new Regexp(project, pattern, section);
|
|
||||||
|
|
||||||
} else if (pattern.endsWith("/*")) {
|
|
||||||
return new Prefix(project, pattern.substring(0, pattern.length() - 1),
|
|
||||||
section);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return new Exact(project, pattern, section);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Project.NameKey project;
|
final Project.NameKey project;
|
||||||
final AccessSection section;
|
final AccessSection section;
|
||||||
|
final RefPatternMatcher matcher;
|
||||||
|
|
||||||
SectionMatcher(Project.NameKey project, AccessSection section) {
|
SectionMatcher(Project.NameKey project, AccessSection section,
|
||||||
|
RefPatternMatcher matcher) {
|
||||||
this.project = project;
|
this.project = project;
|
||||||
this.section = section;
|
this.section = section;
|
||||||
|
this.matcher = matcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract boolean match(String ref, String username);
|
@Override
|
||||||
|
boolean match(String ref, String username) {
|
||||||
private static class Exact extends SectionMatcher {
|
return this.matcher.match(ref, username);
|
||||||
private final String expect;
|
|
||||||
|
|
||||||
Exact(Project.NameKey project, String name, AccessSection section) {
|
|
||||||
super(project, section);
|
|
||||||
expect = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean match(String ref, String username) {
|
|
||||||
return expect.equals(ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Prefix extends SectionMatcher {
|
|
||||||
private final String prefix;
|
|
||||||
|
|
||||||
Prefix(Project.NameKey project, String pfx, AccessSection section) {
|
|
||||||
super(project, section);
|
|
||||||
prefix = pfx;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean match(String ref, String username) {
|
|
||||||
return ref.startsWith(prefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Regexp extends SectionMatcher {
|
|
||||||
private final Pattern pattern;
|
|
||||||
|
|
||||||
Regexp(Project.NameKey project, String re, AccessSection section) {
|
|
||||||
super(project, section);
|
|
||||||
pattern = Pattern.compile(re);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean match(String ref, String username) {
|
|
||||||
return pattern.matcher(ref).matches();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ExpandParameters extends SectionMatcher {
|
|
||||||
private final ParameterizedString template;
|
|
||||||
private final String prefix;
|
|
||||||
|
|
||||||
ExpandParameters(Project.NameKey project, String pattern,
|
|
||||||
AccessSection section) {
|
|
||||||
super(project, section);
|
|
||||||
template = new ParameterizedString(pattern);
|
|
||||||
|
|
||||||
if (isRE(pattern)) {
|
|
||||||
// Replace ${username} with ":USERNAME:" as : is not legal
|
|
||||||
// in a reference and the string :USERNAME: is not likely to
|
|
||||||
// be a valid part of the regex. This later allows the pattern
|
|
||||||
// prefix to be clipped, saving time on evaluation.
|
|
||||||
Automaton am = RefControl.toRegExp(
|
|
||||||
template.replace(Collections.singletonMap("username", ":USERNAME:")))
|
|
||||||
.toAutomaton();
|
|
||||||
String rePrefix = am.getCommonPrefix();
|
|
||||||
prefix = rePrefix.substring(0, rePrefix.indexOf(":USERNAME:"));
|
|
||||||
} else {
|
|
||||||
prefix = pattern.substring(0, pattern.indexOf("${"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean match(String ref, String username) {
|
|
||||||
if (!ref.startsWith(prefix) || username == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String u;
|
|
||||||
if (isRE(template.getPattern())) {
|
|
||||||
u = username.replace(".", "\\.");
|
|
||||||
} else {
|
|
||||||
u = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionMatcher next = wrap(project,
|
|
||||||
template.replace(Collections.singletonMap("username", u)),
|
|
||||||
section);
|
|
||||||
return next != null ? next.match(ref, username) : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean matchPrefix(String ref) {
|
|
||||||
return ref.startsWith(prefix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user