com.datastax.data.dataset.Parser Maven / Gradle / Ivy
The newest version!
package com.datastax.data.dataset;
import com.datastax.data.dataset.event.DataTableEventAdapter;
import net.sf.jga.fn.*;
import net.sf.jga.fn.adaptor.*;
import net.sf.jga.fn.algorithm.Accumulate;
import net.sf.jga.fn.algorithm.Count;
import net.sf.jga.fn.algorithm.TransformUnary;
import net.sf.jga.fn.arithmetic.Average;
import net.sf.jga.fn.arithmetic.Plus;
import net.sf.jga.fn.arithmetic.ValueOf;
import net.sf.jga.fn.comparison.Max;
import net.sf.jga.fn.comparison.Min;
import net.sf.jga.fn.property.*;
import net.sf.jga.parser.*;
import net.sf.jga.util.FilterIterator;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
class Parser extends JFXGParser {
private DataTable table;
private boolean inTableContext = false;
private boolean inUse = false;
private UnaryFunctor getRowsFn =
new GetProperty(DataTable.class, "Rows");
private UnaryFunctor getRowCountFn =
new InvokeNoArgMethod(List.class, "size").compose(getRowsFn);
private UnaryFunctor iterateTableFn =
new InvokeNoArgMethod(List.class, "iterator")
.compose(getRowsFn);
private UnaryFunctor getValueFn =
new GetProperty(DataValue.class, "Value");
private Class[] filterCtorArgs = new Class[]{Iterator.class,UnaryFunctor.class};
private BinaryFunctor,? extends Iterator>
makeFilterFn = new Construct(filterCtorArgs,FilterIterator.class)
.compose(new ArrayBinary>());
public Parser(DataSet set) {
bindThis(set);
setUndecoratedDecimal(true);
}
synchronized boolean isInUse() { return inUse; }
private Object element;
synchronized UnaryFunctorRef parseComputedColumn(DataTable table, DataColumn column, String expression)
throws ParseException
{
inUse = true;
setCurrentTable(table);
element = column;
try {
ReInit (new java.io.StringBufferInputStream(expression));
return parseUnaryRef(DataRow.class);
}
finally {
setCurrentTable(null);
inUse = false;
element = null;
}
}
synchronized GeneratorRef parseDataValue(String expression, DataValue value) throws ParseException {
inUse = true;
inTableContext = true;
element = value;
try {
ReInit (new java.io.StringBufferInputStream(expression));
return parseGeneratorRef();
}
finally {
inTableContext = false;
inUse = false;
element = null;
setCurrentTable(null);
}
}
static Set register(Visitable exp, Object element, DataTableEventAdapter listener) {
if (exp == null)
return new HashSet();
Registrar registrar = new Registrar(element, listener);
exp.accept(registrar);
return registrar.sources;
}
static void unregister(Visitable exp, DataTableEventAdapter listener, Set dependencies)
{
if (exp != null)
exp.accept(new Unregistrar(listener));
dependencies.clear();
}
static private class Registrar extends AdaptorVisitor
implements ConstantUnary.Visitor, TransformUnary.Visitor
{
private Set sources = new HashSet();
private Object element;
private DataTableEventAdapter listener;
public Registrar(Object element, DataTableEventAdapter listener) {
this.listener = listener;
this.element = element;
}
public void visit(ConstantUnary constant) {
Object value = constant.fn(null);
if (value instanceof DataColumn) {
DataColumn column = (DataColumn) value;
column.getTable().addDataTableListener(listener);
sources.add(column);
}
}
public void visit(TransformUnary xform) {
xform.getFunction().accept(this);
}
public void visit(Bind bind) {
super.visit(bind);
Object value = bind.getConstant();
if (value instanceof DataTable) {
DataTable table = (DataTable) value;
table.addDataTableListener(listener);
}
else if (value instanceof DataValue) {
DataValue data = (DataValue) value;
data.addPropertyChangeListener("value", listener);
data.addPropertyChangeListener("expression", listener);
sources.add(data);
}
}
}
static private class Unregistrar extends AdaptorVisitor
implements ConstantUnary.Visitor, TransformUnary.Visitor
{
private DataTableEventAdapter listener;
public Unregistrar(DataTableEventAdapter listener) {
this.listener = listener;
}
public void visit(ConstantUnary constant) {
Object value = constant.fn(null);
if (value instanceof DataColumn) {
DataTable table = ((DataColumn) value).getTable();
if (table != null)
table.removeDataTableListener(listener);
}
}
public void visit(TransformUnary xform) {
xform.getFunction().accept(this);
}
public void visit(Bind bind) {
super.visit(bind);
Object value = bind.getConstant();
if (value instanceof DataTable) {
DataTable table = (DataTable) value;
table.removeDataTableListener(listener);
}
else if (value instanceof DataValue) {
DataValue data = (DataValue) value;
data.removePropertyChangeListener("value", listener);
data.removePropertyChangeListener("expression", listener);
}
}
}
protected FunctorRef reservedWord(String name) throws ParseException {
if (table == null) {
DataTable maybeTable = ((DataSet) getBoundObject()).getTable(name);
if (maybeTable != null) {
setCurrentTable(maybeTable);
return new GeneratorRef(new Constant(table), DataTable.class);
}
}
if (table != null && name.equals(table.getName()))
return new GeneratorRef(new Constant(table), DataTable.class);
if (table != null) {
DataColumn col = table.getColumn(name);
if (col != null) {
col.getType();
if (col.dependsOn(element))
throw new UncheckedParseException("Circular Reference Exception");
return makeColumnRef(table, col);
}
}
DataValue maybeValue = ((DataSet) getBoundObject()).getValue(name);
if (maybeValue != null) {
if (maybeValue.dependsOn(element))
throw new UncheckedParseException("Circular Reference Exception");
return new GeneratorRef(getValueFn.bind(maybeValue), maybeValue.getType());
}
return null;
}
protected FunctorRef reservedField(FunctorRef prefix, String name) throws ParseException {
if (isTableReference(prefix) && getReferencedTable(prefix).equals(table)) {
DataColumn col = table.getColumn(name);
if (col == null) {
String err = "unknown column {0} in table {1}";
String msg = MessageFormat.format(err, name, table.getName());
throw new ParseException(msg);
}
return makeColumnRef(table, col);
}
return super.reservedField(prefix, name);
}
protected FunctorRef reservedFunction(String name, FunctorRef[] args) throws ParseException{
if (inTableContext) {
assert table != null;
FunctorRef lastArgRef = args[args.length - 1];
boolean hasFilter = (lastArgRef.getReturnType() == Boolean.class);
UnaryFunctor filter = (hasFilter) ?
((UnaryFunctorRef) lastArgRef).getFunctor():
new ConstantUnary(Boolean.TRUE);
if ("count".equals(name)) {
if (hasFilter) {
UnaryFunctor countFn =
new ValueOf(Integer.class)
.compose(new Count(filter))
.compose(iterateTableFn);
return new GeneratorRef(countFn.bind(table), Integer.class);
}
else {
return new GeneratorRef(getRowCountFn.bind(table), Integer.class);
}
}
UnaryFunctor filterTableFn = (hasFilter) ?
makeFilterFn.bind2nd(filter).compose(iterateTableFn): iterateTableFn;
Generator extends Iterator> iterateRows = filterTableFn.bind(table);
Class type = args[0].getReturnType();
if (type.isPrimitive())
type = getBoxedType(type);
TransformUnary xform = new TransformUnary(((UnaryFunctorRef) args[0]).getFunctor());
if ("avg".equals(name)) {
validateArgument(Number.class, type, name);
Average avg = new Average(type);
return new GeneratorRef(avg.generate(xform.generate(iterateRows)), type);
}
BinaryFunctor bf = null;
if ("max".equals(name)) {
validateArgument(Comparable.class, type, name);
bf = new Max(new net.sf.jga.util.ComparableComparator());
}
else if ("min".equals(name)) {
validateArgument(Comparable.class, type, name);
bf = new Min(new net.sf.jga.util.ComparableComparator());
}
else if ("sum".equals(name)) {
validateArgument(Number.class, type, name);
bf = new Plus(type);
}
if (bf != null) {
Generator gen = new Accumulate(bf).generate(xform.generate(iterateRows));
return new GeneratorRef(gen, type);
}
}
return super.reservedFunction(name, args);
}
private void setCurrentTable(DataTable table) throws ParseException {
if (this.table != null && table != null)
throw new ParseException("Parser is currently associated with table " +this.table);
this.table = table;
}
private UnaryFunctorRef makeColumnRef(DataTable table, DataColumn column) {
ApplyUnary args =
new ApplyUnary(new UnaryFunctor[]
{ new Identity(),new ConstantUnary(column) });
InvokeMethod getValue =
new InvokeMethod(DataTable.class,"getValue",
new Class[] {DataRow.class, DataColumn.class});
UnaryFunctor value = getValue.bind1st(table).compose(args);
return new UnaryFunctorRef(value, DataRow.class, ARG_NAME[0], column.getType());
}
private boolean isTableReference(FunctorRef ref) {
return ref != null && ref.getReturnType().equals(DataTable.class) &&
ref.getReferenceType() == FunctorRef.CONSTANT;
}
private DataTable getReferencedTable(FunctorRef ref) {
return (DataTable)((GeneratorRef) ref).getFunctor().gen();
}
private void validateArgument(Class reqType, Class foundType, String fnName)
throws ParseException
{
if (reqType.isAssignableFrom(foundType)) {
return;
}
String msg = "Unable to compute {0} of type {1}";
Object[] msgargs = new Object[] { fnName, foundType.getSimpleName() };
throw new ParseException(MessageFormat.format(msg, msgargs));
}
}