| // 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(); | |
| } | |
| } |