// 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.common.data; public class PermissionRule implements Comparable<PermissionRule> { public static final String FORCE_PUSH = "Force Push"; public static final String FORCE_EDIT = "Force Edit"; public static enum Action { ALLOW, DENY, BLOCK, INTERACTIVE, BATCH } protected Action action = Action.ALLOW; protected boolean force; protected int min; protected int max; protected GroupReference group; public PermissionRule() { } public PermissionRule(GroupReference group) { this.group = group; } public Action getAction() { return action; } public void setAction(Action action) { if (action == null) { throw new NullPointerException("action"); } this.action = action; } public boolean isDeny() { return action == Action.DENY; } public void setDeny() { action = Action.DENY; } public boolean isBlock() { return action == Action.BLOCK; } public void setBlock() { action = Action.BLOCK; } public Boolean getForce() { return force; } public void setForce(Boolean newForce) { force = newForce; } public Integer getMin() { return min; } public void setMin(Integer min) { this.min = min; } public void setMax(Integer max) { this.max = max; } public Integer getMax() { return max; } public void setRange(int newMin, int newMax) { if (newMax < newMin) { min = newMax; max = newMin; } else { min = newMin; max = newMax; } } public GroupReference getGroup() { return group; } public void setGroup(GroupReference newGroup) { group = newGroup; } void mergeFrom(PermissionRule src) { if (getAction() != src.getAction()) { if (getAction() == Action.BLOCK || src.getAction() == Action.BLOCK) { setAction(Action.BLOCK); } else if (getAction() == Action.DENY || src.getAction() == Action.DENY) { setAction(Action.DENY); } else if (getAction() == Action.BATCH || src.getAction() == Action.BATCH) { setAction(Action.BATCH); } } setForce(getForce() || src.getForce()); setRange(Math.min(getMin(), src.getMin()), Math.max(getMax(), src.getMax())); } @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; 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 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("group "); r.append(getGroup().getName()); return r.toString(); } public static PermissionRule fromString(String src, boolean mightUseRange) { final String orig = src; final PermissionRule rule = new PermissionRule(); 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 && !src.startsWith("group ")) { 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)); rule.setRange(min, max); } else { throw new IllegalArgumentException("Invalid range in rule: " + orig); } src = src.substring(sp + 1).trim(); } if (src.startsWith("group ")) { src = src.substring(6).trim(); GroupReference group = new GroupReference(); group.setName(src); rule.setGroup(group); } else { throw new IllegalArgumentException("Rule must include group: " + orig); } return rule; } public static int parseInt(String value) { if (value.startsWith("+")) { value = value.substring(1); } return Integer.parseInt(value); } @Override public boolean equals(final Object obj) { if (!(obj instanceof PermissionRule)) { return false; } final PermissionRule other = (PermissionRule)obj; return action.equals(other.action) && force == other.force && min == other.min && max == other.max && group.equals(other.group); } @Override public int hashCode() { return group.hashCode(); } }