Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.almworks.jira.structure.api.permissions.PermissionRule Maven / Gradle / Ivy
package com.almworks.jira.structure.api.permissions;
import com.almworks.jira.structure.api.util.La;
import com.almworks.jira.structure.api.util.StructureUtil;
import com.atlassian.jira.user.ApplicationUser;
import org.codehaus.jackson.annotate.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.annotation.*;
import java.text.ParseException;
import java.util.*;
import static org.apache.commons.lang.StringUtils.removeStart;
/**
* A list of PermissionRule
s is used to define a {@link PermissionLevel}
* for a given user. All possible sub-classes of PermissionRule
are listed here as
* the inner classes.
*
* @see PermissionRule.SetLevel
* @see PermissionRule.ApplyStructure
* @see Structure Permissions (Structure Documentation)
* @author Igor Sereda
*/
@XmlRootElement
@XmlSeeAlso({PermissionRule.ApplyStructure.class, PermissionRule.SetLevel.class})
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = PermissionRule.SetLevel.class, name = "set"),
@JsonSubTypes.Type(value = PermissionRule.ApplyStructure.class, name = "apply")
})
public abstract class PermissionRule implements Cloneable {
private static final Logger logger = LoggerFactory.getLogger(PermissionRule.class);
/**
* @return a string representation of this permission rule
* @see #fromEncodedString
*/
public abstract String toEncodedString();
/**
* Apply permission rule and return the result.
*
* Normally you should not call this method directly - call
* {@link com.almworks.jira.structure.api.structure.Structure#getEffectivePermission} instead.
*
* @param user the user, null means anonymous
* @param pass the default value, which is returned in case this rule does not apply
* @param callStack auxiliary container for objects used to check for recursive rules
* @param resolver auxiliary function that converts structure ID into associated list of permission rules - used by {@link ApplyStructure}. If null, {@link ApplyStructure} will not be able to apply and return pass value.
* @return permission level for the passed user
*/
@NotNull
public abstract PermissionLevel apply(@Nullable ApplicationUser user, @NotNull PermissionLevel pass,
@Nullable List callStack, @Nullable La> resolver);
/**
* Restores permission rule from its encoded String form. In case the string is null or empty,
* returns null.
* Use this method only if user keys were used to encode user permissions.
*
* @param s encoded string
* @return the encoded rule, or null if the string is null or empty
* @throws ParseException if the string is not empty, but cannot be translated back to a rule
* @see #fromEncodedString(String, boolean)
*/
@Nullable
public static PermissionRule fromEncodedString(@Nullable String s) throws ParseException {
return fromEncodedString(s, false);
}
/**
* Restores permission rule from its encoded String form. In case the string is null or empty,
* returns null.
*
* @param s encoded string
* @param usersAsUserNames true if user names were used to encode user permissions (Structure version was less than 2.3),
* false if user keys were used instead.
* @return the encoded rule, or null if the string is null or empty
* @throws ParseException if the string is not empty, but cannot be translated back to a rule
*/
@Nullable
public static PermissionRule fromEncodedString(@Nullable String s, boolean usersAsUserNames) throws ParseException {
try {
if (s == null || s.length() == 0) return null;
String p = removeStart(s, "apply:");
if (!p.equals(s)) {
return new ApplyStructure(Long.parseLong(p));
}
p = removeStart(s, "set:");
if (!p.equals(s)) {
int k = p.indexOf(':');
if (k < 0)
throw new ParseException(s, 0);
// accept both number and name for level
String levelCode = p.substring(0, k);
PermissionLevel level;
try {
int levelInt = Integer.parseInt(levelCode);
level = PermissionLevel.fromSerial(levelInt);
} catch (NumberFormatException e) {
try {
level = PermissionLevel.valueOf(levelCode);
} catch (IllegalArgumentException ee) {
throw e;
}
}
PermissionSubject subject = PermissionSubject.fromEncodedString(p.substring(k + 1), usersAsUserNames);
if (subject == null) {
throw new ParseException(s, 0);
}
return new SetLevel(subject, level);
}
throw new ParseException(s, 0);
} catch (NumberFormatException e) {
throw new ParseException(s, 0);
}
}
/**
* Utility method to encode a list of PermissionRule
s.
*
* @param permissions a list of permissions
* @return a string with encoded permissions, separated by comma
* @see #toEncodedString()
*/
@NotNull
public static String encodePermissions(@Nullable List permissions) {
StringBuilder r = new StringBuilder();
if (permissions != null) {
for (PermissionRule permission : permissions) {
if (permission != null) {
if (r.length() > 0) r.append(',');
r.append(permission.toEncodedString());
}
}
}
return r.toString();
}
/**
* Utility method to decode a list of PermissionRule
s.
*
* @param s encoded list of permissions, delimited by comma
* @return a restored list of rules
* @throws ParseException in case any of the parts used to encode a permission rule failed to decode
* @see #fromEncodedString(String)
*/
@NotNull
public static List decodePermissions(@Nullable String s) throws ParseException {
if (s == null || s.length() == 0) return Collections.emptyList();
String[] elements = s.split(",");
List list = new ArrayList(elements.length);
for (String element : elements) {
PermissionRule rule = PermissionRule.fromEncodedString(element);
if (rule != null) {
list.add(rule);
}
}
return list;
}
/**
* @return a cloned version of this rule
*/
@SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException"})
public PermissionRule clone() {
try {
return (PermissionRule) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(e);
}
}
public String toString() {
return toEncodedString();
}
/**
* This rules applies a list of rules taken from a Structure, identified by the structure ID.
*
* @see com.almworks.jira.structure.api.structure.Structure
*/
@XmlRootElement(name = "apply")
public static class ApplyStructure extends PermissionRule {
private Long myStructureId;
public ApplyStructure() {
}
public ApplyStructure(Long structureId) {
myStructureId = structureId;
}
@XmlAttribute
@JsonProperty("structure")
public Long getStructureId() {
return myStructureId;
}
public void setStructureId(Long structureId) {
myStructureId = structureId;
}
public String toEncodedString() {
return "apply:" + myStructureId;
}
@NotNull
public PermissionLevel apply(ApplicationUser user, @NotNull PermissionLevel pass, List callStack,
La> resolver)
{
Long id = myStructureId;
if (id == null || resolver == null) return pass;
if (callStack != null && callStack.contains(id)) {
logger.error("permissions dependency cycle " + callStack);
return pass;
}
List permissions = resolver.la(id);
if (callStack != null) callStack.add(id);
PermissionLevel r = StructureUtil.applyPermissions(permissions, user, callStack, resolver, pass);
if (callStack != null) callStack.remove(id);
return r;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ApplyStructure that = (ApplyStructure) o;
if (myStructureId != null ? !myStructureId.equals(that.myStructureId) : that.myStructureId != null) return false;
return true;
}
public int hashCode() {
return myStructureId != null ? myStructureId.hashCode() : 0;
}
}
/**
* This rule sets the permission level to a specific value in case the user matches PermissionSubject
.
*
* @see PermissionSubject
*/
@XmlRootElement(name = "set")
public static class SetLevel extends PermissionRule {
private PermissionSubject mySubject;
private PermissionLevel myLevel;
public SetLevel() {
}
public SetLevel(PermissionSubject subject, PermissionLevel level) {
mySubject = subject;
myLevel = level;
}
public SetLevel clone() {
SetLevel r = (SetLevel) super.clone();
if (mySubject != null) r.mySubject = mySubject.clone();
return r;
}
@NotNull
public PermissionLevel apply(ApplicationUser user, @NotNull PermissionLevel pass, List callStack,
La> resolver)
{
PermissionSubject subject = mySubject;
return subject != null && subject.matches(user) ? myLevel : pass;
}
@XmlElementRef
public PermissionSubject getSubject() {
return mySubject;
}
public void setSubject(PermissionSubject subject) {
mySubject = subject;
}
@XmlAttribute
public PermissionLevel getLevel() {
return myLevel;
}
public void setLevel(PermissionLevel level) {
myLevel = level;
}
public String toEncodedString() {
return "set:" + (myLevel == null ? "0" : myLevel.getSerial()) + ":" + (mySubject == null ? "" : mySubject.toEncodedString());
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SetLevel setLevel = (SetLevel) o;
if (myLevel != setLevel.myLevel) return false;
if (mySubject != null ? !mySubject.equals(setLevel.mySubject) : setLevel.mySubject != null) return false;
return true;
}
public int hashCode() {
int result = mySubject != null ? mySubject.hashCode() : 0;
result = 31 * result + (myLevel != null ? myLevel.hashCode() : 0);
return result;
}
}
}