package com.plexobject.rbac.eval.simple;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.Logger;
public enum Operator {
EQUALS("==", new Matchable() {
public boolean doesMatch(final String first, final String second,
final Type type) {
return first.equalsIgnoreCase(second);
}
}), CONTAINS("in", new Matchable() {
public boolean doesMatch(final String first, final String second,
final Type type) {
return first.toLowerCase().contains(second.toLowerCase());
}
}), LESS_THAN("<", new Matchable() {
public boolean doesMatch(final String first, final String second,
final Type type) {
if (Type.isNumber(first) && Type.isNumber(second)) {
return Type.number(second) < Type.number(first);
}
switch (type) {
case TIME:
try {
Date firstDate = TIME_FORMAT.get().parse(first);
Date secondDate = TIME_FORMAT.get().parse(second);
return secondDate.compareTo(firstDate) < 0;
} catch (ParseException e) {
LOGGER.error("failed to parse " + first + " and " + second,
e);
}
break;
case STRING:
return second.compareTo(first) < 0;
}
return false;
}
}), LESS_OR_EQUALS("<=", new Matchable() {
public boolean doesMatch(final String first, final String second,
final Type type) {
if (Type.isNumber(first) && Type.isNumber(second)) {
return Type.number(second) <= Type.number(first);
}
switch (type) {
case TIME:
try {
Date firstDate = TIME_FORMAT.get().parse(first);
Date secondDate = TIME_FORMAT.get().parse(second);
return secondDate.compareTo(firstDate) <= 0;
} catch (ParseException e) {
LOGGER.error("failed to parse " + first + " and " + second,
e);
}
break;
case STRING:
return second.compareTo(first) <= 0;
}
return false;
}
}), GREATER_THAN(">", new Matchable() {
public boolean doesMatch(final String first, final String second,
final Type type) {
if (Type.isNumber(first) && Type.isNumber(second)) {
return Type.number(second) > Type.number(first);
}
switch (type) {
case TIME:
try {
Date firstDate = TIME_FORMAT.get().parse(first);
Date secondDate = TIME_FORMAT.get().parse(second);
return secondDate.compareTo(firstDate) > 0;
} catch (ParseException e) {
LOGGER.error("failed to parse " + first + " and " + second,
e);
}
break;
case STRING:
return second.compareTo(first) > 0;
}
return false;
}
}), GREATER_OR_EQUALS(">=", new Matchable() {
public boolean doesMatch(final String first, final String second,
final Type type) {
if (Type.isNumber(first) && Type.isNumber(second)) {
return Type.number(second) >= Type.number(first);
}
switch (type) {
case TIME:
try {
Date firstDate = TIME_FORMAT.get().parse(first);
Date secondDate = TIME_FORMAT.get().parse(second);
return secondDate.compareTo(firstDate) >= 0;
} catch (ParseException e) {
LOGGER.error("failed to parse " + first + " and " + second,
e);
}
break;
case STRING:
return second.compareTo(first) >= 0;
}
return false;
}
}), NOT_EQUALS("!=", new Matchable() {
public boolean doesMatch(final String first, final String second,
final Type type) {
return !first.equalsIgnoreCase(second);
}
}), IN_RANGE("between", new Matchable() {
public boolean doesMatch(final String first, final String second,
final Type type) {
String[] firstParts = first.split("\\.\\.");
if (firstParts.length != 2) {
throw new IllegalArgumentException(first
+ " does not match range format " + firstParts.length);
}
switch (type) {
case NUMBER:
return Type.number(second) >= Type.number(firstParts[0])
&& Type.number(second) <= Type.number(firstParts[1]);
case TIME:
if (Type.isNumber(second)) {
return Type.number(second) >= Type.number(firstParts[0])
&& Type.number(second) <= Type
.number(firstParts[1]);
} else {
try {
Date firstDate1 = TIME_FORMAT.get()
.parse(firstParts[0]);
Date firstDate2 = TIME_FORMAT.get()
.parse(firstParts[1]);
Date secondDate = TIME_FORMAT.get().parse(second);
return secondDate.compareTo(firstDate1) >= 0
&& secondDate.compareTo(firstDate2) <= 0;
} catch (ParseException e) {
LOGGER.error("failed to parse " + first + " and "
+ second, e);
}
}
break;
case STRING:
return second.compareTo(firstParts[0]) >= 0
&& second.compareTo(firstParts[1]) <= 0;
}
return false;
}
});
private static final Logger LOGGER = Logger.getLogger(Operator.class);
private static final ThreadLocal<SimpleDateFormat> TIME_FORMAT = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("h:mma");
}
};
private final String symbol;
private final Matchable matchable;
Operator(final String symbol, final Matchable matchable) {
this.symbol = symbol;
this.matchable = matchable;
}
public boolean matches(final String first, final String second,
final Type type) {
return matchable.doesMatch(first, second, type);
}
public static Operator bySymbol(final String symbol) {
for (Operator op : Operator.values()) {
if (op.symbol.equals(symbol)) {
return op;
}
}
return null;
}
public String toString() {
return symbol;
}
}