blob: 1665c1c7cfae5355d6851404badf09a5f5e7594e [file] [log] [blame]
// Copyright (C) 2010 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.entities;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class PermissionRule implements Comparable<PermissionRule> {
public static final boolean DEF_FORCE = false;
public enum Action {
ALLOW,
DENY,
BLOCK,
INTERACTIVE,
BATCH
}
public abstract Action getAction();
public abstract boolean getForce();
public abstract int getMin();
public abstract int getMax();
public abstract GroupReference getGroup();
public static PermissionRule.Builder builder(GroupReference group) {
return builder().setGroup(group);
}
public static PermissionRule create(GroupReference group) {
return builder().setGroup(group).build();
}
protected static Builder builder() {
return new AutoValue_PermissionRule.Builder()
.setMin(0)
.setMax(0)
.setAction(Action.ALLOW)
.setForce(DEF_FORCE);
}
static PermissionRule merge(PermissionRule src, PermissionRule dest) {
PermissionRule.Builder result = dest.toBuilder();
if (dest.getAction() != src.getAction()) {
if (dest.getAction() == Action.BLOCK || src.getAction() == Action.BLOCK) {
result.setAction(Action.BLOCK);
} else if (dest.getAction() == Action.DENY || src.getAction() == Action.DENY) {
result.setAction(Action.DENY);
} else if (dest.getAction() == Action.BATCH || src.getAction() == Action.BATCH) {
result.setAction(Action.BATCH);
}
}
result.setForce(dest.getForce() || src.getForce());
result.setRange(Math.min(dest.getMin(), src.getMin()), Math.max(dest.getMax(), src.getMax()));
return result.build();
}
public boolean isDeny() {
return getAction() == Action.DENY;
}
public boolean isBlock() {
return getAction() == Action.BLOCK;
}
@Override
public int compareTo(PermissionRule o) {
int cmp = action(this) - action(o);
if (cmp == 0) {
cmp = range(o) - range(this);
}
if (cmp == 0) {
cmp = group(this).compareTo(group(o));
}
return cmp;
}
private static int action(PermissionRule a) {
switch (a.getAction()) {
case DENY:
return 0;
case ALLOW:
case BATCH:
case BLOCK:
case INTERACTIVE:
default:
return 1 + a.getAction().ordinal();
}
}
private static int range(PermissionRule a) {
return Math.abs(a.getMin()) + Math.abs(a.getMax());
}
private static String group(PermissionRule a) {
return a.getGroup().getName() != null ? a.getGroup().getName() : "";
}
@Override
public final String toString() {
return asString(true);
}
public String asString(boolean canUseRange) {
StringBuilder r = new StringBuilder();
switch (getAction()) {
case ALLOW:
break;
case DENY:
r.append("deny ");
break;
case BLOCK:
r.append("block ");
break;
case INTERACTIVE:
r.append("interactive ");
break;
case BATCH:
r.append("batch ");
break;
}
if (getForce()) {
r.append("+force ");
}
if (canUseRange && (getMin() != 0 || getMax() != 0)) {
if (0 <= getMin()) {
r.append('+');
}
r.append(getMin());
r.append("..");
if (0 <= getMax()) {
r.append('+');
}
r.append(getMax());
r.append(' ');
}
r.append(getGroup().toConfigValue());
return r.toString();
}
public static PermissionRule fromString(String src, boolean mightUseRange) {
final String orig = src;
final PermissionRule.Builder rule = PermissionRule.builder();
src = src.trim();
if (src.startsWith("deny ")) {
rule.setAction(Action.DENY);
src = src.substring("deny ".length()).trim();
} else if (src.startsWith("block ")) {
rule.setAction(Action.BLOCK);
src = src.substring("block ".length()).trim();
} else if (src.startsWith("interactive ")) {
rule.setAction(Action.INTERACTIVE);
src = src.substring("interactive ".length()).trim();
} else if (src.startsWith("batch ")) {
rule.setAction(Action.BATCH);
src = src.substring("batch ".length()).trim();
}
if (src.startsWith("+force ")) {
rule.setForce(true);
src = src.substring("+force ".length()).trim();
}
if (mightUseRange && !GroupReference.isGroupReference(src)) {
int sp = src.indexOf(' ');
String range = src.substring(0, sp);
if (range.matches("^([+-]?\\d+)\\.\\.([+-]?\\d+)$")) {
int dotdot = range.indexOf("..");
int min = parseInt(range.substring(0, dotdot));
int max = parseInt(range.substring(dotdot + 2));
if (min > max) {
throw new IllegalArgumentException("Invalid range in rule: " + orig);
}
rule.setRange(min, max);
} else {
throw new IllegalArgumentException("Invalid range in rule: " + orig);
}
src = src.substring(sp + 1).trim();
}
String groupName = GroupReference.extractGroupName(src);
if (groupName != null) {
GroupReference group = GroupReference.create(groupName);
rule.setGroup(group);
} else {
throw new IllegalArgumentException("Rule must include group: " + orig);
}
return rule.build();
}
public boolean hasRange() {
return getMin() != 0 || getMax() != 0;
}
public static int parseInt(String value) {
if (value.startsWith("+")) {
value = value.substring(1);
}
return Integer.parseInt(value);
}
public abstract Builder toBuilder();
@AutoValue.Builder
public abstract static class Builder {
public Builder setDeny() {
return setAction(Action.DENY);
}
public Builder setBlock() {
return setAction(Action.BLOCK);
}
public Builder setRange(int newMin, int newMax) {
if (newMax < newMin) {
setMin(newMax);
setMax(newMin);
} else {
setMin(newMin);
setMax(newMax);
}
return this;
}
public abstract Builder setAction(Action action);
public abstract Builder setGroup(GroupReference groupReference);
public abstract Builder setForce(boolean newForce);
public abstract Builder setMin(int min);
public abstract Builder setMax(int max);
public abstract GroupReference getGroup();
public abstract PermissionRule build();
}
}