/* (c) 2014, 2015 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.geofence.services.dto;
import org.geoserver.geofence.core.model.Rule;
import java.io.Serializable;
/**
* A Filter for selecting {@link Rule}s.
*
* <P> For every given field, you may choose to select <UL>
* <LI>a given value</LI>
* <LI>any values (no filtering)</LI>
* <LI>only default rules (null value in a field) </LI>
* </UL>
*
* For instances (i.e., classes represented by DB entities) you may specify either the ID or the name.
*
* @author ETj (etj at geo-solutions.it)
*/
public class RuleFilter implements Serializable, Cloneable {
private static final long serialVersionUID = 5629211135629700042L;
public enum FilterType {
NAMEVALUE,
IDVALUE,
ANY,
DEFAULT;
}
public enum SpecialFilterType {
ANY(FilterType.ANY),
DEFAULT(FilterType.DEFAULT);
private FilterType relatedType;
private SpecialFilterType(FilterType relatedType) {
this.relatedType = relatedType;
}
public FilterType getRelatedType() {
return relatedType;
}
}
private final TextFilter user;
private final TextFilter role;
private final IdNameFilter instance;
private final TextFilter sourceAddress;
private final TextFilter service;
private final TextFilter request;
private final TextFilter workspace;
private final TextFilter layer;
public RuleFilter() {
this(SpecialFilterType.DEFAULT);
}
/**
* Creates a RuleFilter by setting all fields filtering either to ANY or DEFAULT. <BR>
* If no other field is set, you will get <UL>
* <LI>with <B>ANY</B>, all Rules will be returned</LI>
* <LI>with <B>DEFAULT</B>, only the default Rule will be returned</LI>
* </UL>
*/
public RuleFilter(SpecialFilterType type) {
FilterType ft = type.getRelatedType();
user = new TextFilter(ft);
role = new TextFilter(ft);
instance = new IdNameFilter(ft);
sourceAddress = new TextFilter(ft);
service = new TextFilter(ft, true);
request = new TextFilter(ft, true);
workspace = new TextFilter(ft);
layer = new TextFilter(ft);
}
public RuleFilter(SpecialFilterType type, boolean includeDefault) {
FilterType ft = type.getRelatedType();
user = new TextFilter(ft);
user.setIncludeDefault(includeDefault);
role = new TextFilter(ft);
role.setIncludeDefault(includeDefault);
instance = new IdNameFilter(ft, includeDefault);
sourceAddress = new TextFilter(ft);
sourceAddress.setIncludeDefault(includeDefault);
service = new TextFilter(ft, true);
service.setIncludeDefault(includeDefault);
request = new TextFilter(ft, true);
request.setIncludeDefault(includeDefault);
workspace = new TextFilter(ft);
workspace.setIncludeDefault(includeDefault);
layer = new TextFilter(ft);
layer.setIncludeDefault(includeDefault);
}
/**
* Creates a RuleFilter by heuristically converting special string values into Fitler behaviour:<UL> <LI>a null value will
* match only with null</LI> <LI>a '*' value will match everything (no filter condition on that given field)</LI> <LI>any
* other string will match literally</LI> </UL>
*
* @deprecated Please use plain setters if you want to handle by hand special values or filter conditions.
*/
public RuleFilter(String userName, String groupName, String instanceName,
String sourceAddress,
String service, String request,
String workspace, String layer) {
this(SpecialFilterType.DEFAULT);
this.user.setHeuristically(userName);
this.role.setHeuristically(groupName);
this.instance.setHeuristically(instanceName);
this.sourceAddress.setHeuristically(sourceAddress);
this.service.setHeuristically(service);
this.request.setHeuristically(request);
this.workspace.setHeuristically(workspace);
this.layer.setHeuristically(layer);
}
public RuleFilter(RuleFilter source) {
try {
user = source.user.clone();
role = source.role.clone();
instance = source.instance.clone();
sourceAddress = source.sourceAddress.clone();
service = source.service.clone();
request = source.request.clone();
workspace = source.workspace.clone();
layer = source.layer.clone();
} catch (CloneNotSupportedException ex) {
// Should not happen
throw new UnknownError("Clone error - should not happen");
}
}
public RuleFilter setUser(String name) {
if(name == null)
throw new NullPointerException();
user.setText(name);
return this;
}
public RuleFilter setUser(SpecialFilterType type) {
user.setType(type);
return this;
}
public RuleFilter setRole(String name) {
if(name == null)
throw new NullPointerException();
role.setText(name);
return this;
}
public RuleFilter setRole(SpecialFilterType type) {
role.setType(type);
return this;
}
public RuleFilter setInstance(Long id) {
instance.setId(id);
return this;
}
public RuleFilter setInstance(String name) {
instance.setName(name);
return this;
}
public RuleFilter setInstance(SpecialFilterType type) {
instance.setType(type);
return this;
}
public RuleFilter setSourceAddress(String dotted) {
sourceAddress.setText(dotted);
return this;
}
public RuleFilter setSourceAddress(SpecialFilterType type) {
sourceAddress.setType(type);
return this;
}
public RuleFilter setService(String name) {
service.setText(name);
return this;
}
public RuleFilter setService(SpecialFilterType type) {
service.setType(type);
return this;
}
public RuleFilter setRequest(String name) {
request.setText(name);
return this;
}
public RuleFilter setRequest(SpecialFilterType type) {
request.setType(type);
return this;
}
public RuleFilter setWorkspace(String name) {
workspace.setText(name);
return this;
}
public RuleFilter setWorkspace(SpecialFilterType type) {
workspace.setType(type);
return this;
}
public RuleFilter setLayer(String name) {
layer.setText(name);
return this;
}
public RuleFilter setLayer(SpecialFilterType type) {
layer.setType(type);
return this;
}
public IdNameFilter getInstance() {
return instance;
}
public TextFilter getSourceAddress() {
return sourceAddress;
}
public TextFilter getLayer() {
return layer;
}
public TextFilter getRole() {
return role;
}
public TextFilter getRequest() {
return request;
}
public TextFilter getService() {
return service;
}
public TextFilter getUser() {
return user;
}
public TextFilter getWorkspace() {
return workspace;
}
// public InetAddress getSourceAddress() {
// return sourceAddress;
// }
//
// public RuleFilter setSourceAddress(InetAddress sourceAddress) {
// this.sourceAddress = sourceAddress;
// return this;
// }
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final RuleFilter other = (RuleFilter) obj;
if (this.user != other.user && (this.user == null || !this.user.equals(other.user))) {
return false;
}
if (this.role != other.role && (this.role == null || !this.role.equals(other.role))) {
return false;
}
if (this.instance != other.instance && (this.instance == null || !this.instance.equals(other.instance))) {
return false;
}
if (this.service != other.service && (this.service == null || !this.service.equals(other.service))) {
return false;
}
if (this.request != other.request && (this.request == null || !this.request.equals(other.request))) {
return false;
}
if (this.workspace != other.workspace && (this.workspace == null || !this.workspace.equals(other.workspace))) {
return false;
}
if (this.layer != other.layer && (this.layer == null || !this.layer.equals(other.layer))) {
return false;
}
//NOTE: ipaddress not in equals() bc it is not used for caching
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 37 * hash + (this.user != null ? this.user.hashCode() : 0);
hash = 37 * hash + (this.role != null ? this.role.hashCode() : 0);
hash = 37 * hash + (this.instance != null ? this.instance.hashCode() : 0);
hash = 37 * hash + (this.sourceAddress != null ? this.sourceAddress.hashCode() : 0);
hash = 37 * hash + (this.service != null ? this.service.hashCode() : 0);
hash = 37 * hash + (this.request != null ? this.request.hashCode() : 0);
hash = 37 * hash + (this.workspace != null ? this.workspace.hashCode() : 0);
hash = 37 * hash + (this.layer != null ? this.layer.hashCode() : 0);
//NOTE: ipaddress not in hashcode bc it is not used for caching
return hash;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
sb.append('[');
sb.append("user:").append(user);
sb.append(" role:").append(role);
sb.append(" inst:").append(instance);
sb.append(" ip:").append(sourceAddress);
sb.append(" serv:").append(service);
sb.append(" req:").append(request);
sb.append(" ws:").append(workspace);
sb.append(" layer:").append(layer);
sb.append(']');
return sb.toString();
}
@Override
public RuleFilter clone() {
return new RuleFilter(this);
}
/**
* A filter that can be either:
* - an id
* - a string
* - a special constraint (DEFAULT, ANY)
*/
public static class IdNameFilter implements Serializable, Cloneable {
private static final long serialVersionUID = -5984311150423659545L;
private Long id;
private String name;
private FilterType type;
/**
* Only used in TYPE_ID and TYPE_NAME, tells if also default Rules should be matched. Old code automatically included
* default rules.
*/
private boolean includeDefault = true;
public IdNameFilter(FilterType type) {
this.type = type;
}
public IdNameFilter(FilterType type, boolean includeDefault) {
this.type = type;
this.includeDefault = includeDefault;
}
public IdNameFilter(long id) {
setId(id);
}
public IdNameFilter(long id, boolean includeDefault) {
setId(id);
this.includeDefault = includeDefault;
}
public IdNameFilter(String name, boolean includeDefault) {
setName(name);
this.includeDefault = includeDefault;
}
public void setHeuristically(String name) {
if ( name == null ) {
this.type = FilterType.DEFAULT;
} else if ( name.equals("*") ) {
this.type = FilterType.ANY;
} else {
this.type = FilterType.NAMEVALUE;
this.name = name;
}
}
public void setHeuristically(Long id) {
if ( id == null ) {
this.type = FilterType.DEFAULT;
} else {
this.type = FilterType.IDVALUE;
this.id = id;
}
}
public void setId(Long id) {
this.id = id;
this.type = FilterType.IDVALUE;
}
public void setName(String name) {
this.name = name;
this.type = FilterType.NAMEVALUE;
}
public void setType(SpecialFilterType type) {
this.type = type.getRelatedType();
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public FilterType getType() {
return type;
}
public boolean isIncludeDefault() {
return includeDefault;
}
public void setIncludeDefault(boolean includeDefault) {
this.includeDefault = includeDefault;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final IdNameFilter other = (IdNameFilter) obj;
if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
return false;
}
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if (this.type != other.type) {
return false;
}
if (this.includeDefault != other.includeDefault) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 83 * hash + (this.id != null ? this.id.hashCode() : 0);
hash = 83 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 83 * hash + (this.type != null ? this.type.hashCode() : 0);
hash = 83 * hash + (this.includeDefault ? 1 : 0);
return hash;
}
@Override
public String toString() {
switch (type) {
case ANY:
case DEFAULT:
return type.toString();
case IDVALUE:
return "id" + (includeDefault?"+:":":") + (id==null?"(null)":id.toString());
case NAMEVALUE:
String tmp;
if(name == null)
tmp = "(null)";
else if (name.isEmpty())
tmp = "(empty)";
else
tmp = name;
return "name" + (includeDefault?"+:":":") + tmp;
default:
throw new AssertionError();
}
}
@Override
public IdNameFilter clone() throws CloneNotSupportedException {
return (IdNameFilter)super.clone();
}
}
/**
* Contains a fixed text OR a special filtering condition (i.e. ANY, DEFAULT).
*/
public static class TextFilter implements Serializable, Cloneable {
private static final long serialVersionUID = 6565336016075974626L;
private String text;
private FilterType type;
private boolean forceUppercase = false;
/**
* Only used in TYPE_NAME, tells if also default Rules should be matched.
*/
private boolean includeDefault = true;
public TextFilter(FilterType type) {
this.type = type;
}
public TextFilter(FilterType type, boolean forceUppercase) {
this.type = type;
this.forceUppercase = forceUppercase;
}
public TextFilter(FilterType type, boolean forceUppercase, boolean includeDefault) {
this.type = type;
this.forceUppercase = forceUppercase;
this.includeDefault = includeDefault;
}
public TextFilter(String text, boolean forceUppercase, boolean includeDefault) {
this(text);
this.forceUppercase = forceUppercase;
this.includeDefault = includeDefault;
}
public TextFilter(String text) {
this.text = text;
this.type = FilterType.NAMEVALUE;
}
public void setHeuristically(String text) {
if ( text == null ) {
this.type = FilterType.DEFAULT;
} else if ( text.equals("*") ) {
this.type = FilterType.ANY;
} else {
this.type = FilterType.NAMEVALUE;
this.text = forceUppercase ? text.toUpperCase() : text;
}
}
public void setText(String name) {
this.text = forceUppercase ? name.toUpperCase() : name;
this.type = FilterType.NAMEVALUE;
}
public void setType(SpecialFilterType type) {
this.type = type.getRelatedType();
}
public String getText() {
return text;
}
public FilterType getType() {
return type;
}
public boolean isIncludeDefault() {
return includeDefault;
}
public void setIncludeDefault(boolean includeDefault) {
this.includeDefault = includeDefault;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TextFilter other = (TextFilter) obj;
if ((this.text == null) ? (other.text != null) : !this.text.equals(other.text)) {
return false;
}
if (this.type != other.type) {
return false;
}
if (this.forceUppercase != other.forceUppercase) {
return false;
}
if (this.includeDefault != other.includeDefault) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 61 * hash + (this.text != null ? this.text.hashCode() : 0);
hash = 61 * hash + (this.type != null ? this.type.hashCode() : 0);
hash = 61 * hash + (this.forceUppercase ? 1 : 0);
hash = 61 * hash + (this.includeDefault ? 1 : 0);
return hash;
}
@Override
public String toString() {
switch (type) {
case ANY:
case DEFAULT:
return type.toString();
case NAMEVALUE:
return (text == null ? "(null)"
: text.isEmpty() ? "(empty)"
: '"'+text+'"')
+ (includeDefault?"+":"") ;
case IDVALUE:
default:
throw new AssertionError();
}
}
@Override
public TextFilter clone() throws CloneNotSupportedException {
return (TextFilter)super.clone();
}
}
}