package com.plexobject.rbac.domain;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.validator.GenericValidator;
import com.sleepycat.persist.model.DeleteAction;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.Relationship;
import com.sleepycat.persist.model.SecondaryKey;
/**
* This class represents a permission in the system that defines three
* dimensions - subject - operation - target
*
*/
@Entity
@XmlRootElement
public class Permission extends PersistentObject implements Validatable,
Identifiable<Integer> {
@PrimaryKey(sequence = "permission_seq")
private Integer id;
@SecondaryKey(relate = Relationship.MANY_TO_ONE)
private String operation; // can be string or regular expression
@SecondaryKey(relate = Relationship.MANY_TO_ONE)
private String target;
private String expression;
@SecondaryKey(relate = Relationship.MANY_TO_MANY, relatedEntity = Role.class, onRelatedEntityDelete = DeleteAction.NULLIFY)
Set<String> roleIds = new HashSet<String>();
// for JPA
Permission() {
}
public Permission(final String operation, final String target,
final String expression) {
setOperation(operation);
setTarget(target);
setExpression(expression);
}
void setId(Integer id) {
this.id = id;
}
@XmlElement
public Integer getId() {
return id;
}
/**
* The operation is action like read/write/update/delete or regular
* expression
*
* @return
*/
public String getOperation() {
return operation;
}
/**
* This method matches operation by equality or regular expression
*
* @param action
* @return
*/
public boolean implies(final String op, final String tgt) {
if (GenericValidator.isBlankOrNull(op)) {
return false;
}
if (GenericValidator.isBlankOrNull(tgt)) {
return false;
}
return (operation.equalsIgnoreCase(op) || op.toLowerCase().matches(
operation))
&& (target.equalsIgnoreCase(tgt) || tgt.toLowerCase().matches(
target));
}
/**
* The target is object that is being acted upon such as file, row in the
* database
*
* @return
*/
public String getTarget() {
return target;
}
public void setOperation(String operation) {
if (GenericValidator.isBlankOrNull(operation)) {
throw new IllegalArgumentException("operation not specified");
}
if (operation.equals("*")) {
operation = ".*";
}
firePropertyChange("operation", this.operation, operation);
this.operation = operation.toLowerCase();
}
public void setTarget(String target) {
if (GenericValidator.isBlankOrNull(target)) {
throw new IllegalArgumentException("target not specified");
}
firePropertyChange("target", this.target, target);
this.target = target;
}
/**
*
* @return
*/
public String getExpression() {
return expression;
}
public void setExpression(final String expression) {
firePropertyChange("expression", this.expression, expression);
this.expression = expression;
}
@XmlTransient
public Set<String> getRoleIds() {
return new HashSet<String>(roleIds);
}
public void setRoleIds(Set<String> roleIds) {
firePropertyChange("roleIds", this.roleIds, roleIds);
this.roleIds.clear();
this.roleIds.addAll(roleIds);
}
public void addRole(Role role) {
Set<String> old = getRoleIds();
this.roleIds.add(role.getId());
firePropertyChange("roleIds", old, this.roleIds);
}
public void removeRole(Role role) {
Set<String> old = getRoleIds();
this.roleIds.remove(role.getId());
firePropertyChange("roleIds", old, this.roleIds);
}
/**
* @see java.lang.Object#equals(Object)
*/
@Override
public boolean equals(Object object) {
if (!(object instanceof Permission)) {
return false;
}
Permission rhs = (Permission) object;
return new EqualsBuilder().append(this.operation, rhs.operation)
.append(this.target, rhs.target).append(this.expression,
rhs.expression).isEquals();
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return new HashCodeBuilder(786529047, 1924536713)
.append(this.operation).append(this.target).toHashCode();
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return new ToStringBuilder(this).append("id", this.id).append(
"operation", this.operation).append("target", target).append(
"expression", this.expression).append("roleIds", this.roleIds)
.toString();
}
@Override
public void validate() throws ValidationException {
final Map<String, String> errorsByField = new HashMap<String, String>();
if (GenericValidator.isBlankOrNull(operation)) {
errorsByField.put("operation", "operation is not specified");
}
if (GenericValidator.isBlankOrNull(target)) {
errorsByField.put("target", "target is not specified");
}
if (errorsByField.size() > 0) {
throw new ValidationException(errorsByField);
}
}
}