Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package amis.examples.groovy;
- import java.math.BigDecimal;
- import java.util.ArrayList;
- import java.util.BitSet;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Set;
- import oracle.jbo.ExprEval;
- import oracle.jbo.Row;
- import oracle.jbo.RowIterator;
- import oracle.jbo.RowSet;
- import oracle.jbo.RowSetIterator;
- /**
- * GroovySupport delivers basic aggregate functions to RowSets and RowIterators using the
- * built-in-ADF Groovy support. To instantiate a GroovySupport object use the <code>get</code>
- * functions.
- *
- * @see #get(RowIterator) GroovySupport.get(RowIterator)
- * @see #get(RowSet) GroovySupport.get(RowSet)
- */
- public abstract class GroovySupport {
- /*
- * Some simple aggregate functions
- */
- /**
- * Execute the provided <code>groovy</code> expression in the context of each row and return the
- * biggest result (based on the <code>Comparable</code> interface).
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @return the biggest value
- */
- public Comparable max(String groovy) {
- return max(groovy, null);
- }
- /**
- * Execute the provided <code>groovy</code> expression in the context of each row and return the
- * biggest result (based on the <code>Comparable</code> interface). Only rows on which
- * <code>groovyWhere</code> evaluates to <code>true</code> are taken into account.
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @param groovyWhere a (boolean) groovy expression that defines which rows are taken into account
- * @return the biggest value
- */
- public Comparable max(String groovy, String groovyWhere) {
- return aggregate(groovy, groovyWhere, new MaxAggregator()).result;
- }
- private static final class MaxAggregator extends Aggregator<Comparable> {
- Comparable result = null;
- boolean add(Comparable value) {
- if (result == null || (value != null && value.compareTo(result) > 0)) {
- result = value;
- }
- return true;
- }
- }
- /**
- * Execute the provided <code>groovy</code> expression in the context of each row and return the
- * sum of these results.
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @return the sum
- */
- public BigDecimal sum(String groovy) {
- return sum(groovy, null);
- }
- /**
- * Execute the provided <code>groovy</code> expression in the context of each row and return the
- * sum of these results. Only rows on which <code>groovyWhere</code> evaluates to <code>true</code>
- * are taken into account.
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @param groovyWhere a (boolean) groovy expression that defines which rows are taken into account
- * @return the sum
- */
- public BigDecimal sum(String groovy, String groovyWhere) {
- return aggregate(groovy, groovyWhere, new SumAggregator()).result;
- }
- private static final class SumAggregator extends Aggregator<Number> {
- BigDecimal result = null;
- boolean add(Number value) {
- // Convert value to BigDecimal, we don't want to lose precision.
- BigDecimal bd =
- (value == null || value instanceof BigDecimal) ? (BigDecimal)value : new BigDecimal(value.toString());
- if (result == null) {
- result = bd;
- } else if (bd != null) {
- result = result.add(bd);
- }
- return true;
- }
- }
- /**
- * Returns the number of rows for which <code>groovyWhere</code> evaluates to <code>true</code>.
- *
- * @param groovyWhere a groovy expression to be executed in the context of a single row
- * @return the number of rows for which groovyWhere evaluates to true
- */
- public int count(String groovyWhere) {
- return aggregate(null, groovyWhere, new CountAggregator()).result;
- }
- private static final class CountAggregator extends Aggregator<Object> {
- int result = 0;
- boolean add(Object value) {
- ++result;
- return true;
- }
- }
- /**
- * Returns the number of unique values that the provided <code>groovy</code> expression delivers
- * in the context of individual rows.
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @return the number of unique values
- */
- public int distinctCount(String groovy) {
- return distinctCount(groovy, null);
- }
- /**
- * Returns the number of unique values that the provided <code>groovy</code> expression delivers
- * in the context of individual rows. Only rows on which <code>groovyWhere</code> evaluates to
- * <code>true</code> are taken into account.
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @param groovyWhere a (boolean) groovy expression that defines which rows are taken into account
- * @return the number of unique values
- */
- public int distinctCount(String groovy, String groovyWhere) {
- return aggregate(groovy, groovyWhere, new DistinctValuesAggregator()).resultSet.size();
- }
- private static final class DistinctValuesAggregator extends Aggregator<Object> {
- Set<Object> resultSet = new HashSet<Object>();
- boolean add(Object value) {
- resultSet.add(value);
- return true;
- }
- }
- /**
- * Returns a row for which <code>groovyWhere</code> evaluates to <code>true</code>, if found.
- *
- * @param groovyWhere a (boolean) groovy expression that defines when a row qualifies
- * @return a row for which groovyWhere evaluates to true or null
- */
- public Row find(String groovyWhere) {
- return aggregate("adf.object", groovyWhere, new FindAggregator<Row>()).result;
- }
- /**
- * Returns the value of the <code>groovy</code> expression in the context of a row for which
- * <code>groovyWhere</code> evaluates to <code>true</code>, if found.
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @param groovyWhere a (boolean) groovy expression that defines when a row qualifies
- * @return the value of the groovy expression in the context of a row for which groovyWhere
- * evaluates to true
- */
- public Object find(String groovy, String groovyWhere) {
- return aggregate(groovy, groovyWhere, new FindAggregator<Object>()).result;
- }
- private static final class FindAggregator<T> extends Aggregator<T> {
- T result = null;
- boolean add(T value) {
- result = value;
- return false;
- }
- }
- /**
- * Returns all rows for which <code>groovyWhere</code> evaluates to <code>true</code>.
- *
- * @param groovyWhere a (boolean) groovy expression that defines when a row qualifies
- * @return all rows for which groovyWhere evaluates to true
- */
- public List<Row> findAll(String groovyWhere) {
- return aggregate("adf.object", groovyWhere, new FindAllAggregator<Row>()).result;
- }
- /**
- * Returns the value of the <code>groovy</code> expression in the context of all row for which
- * <code>groovyWhere</code> evaluates to <code>true</code>.
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @param groovyWhere a (boolean) groovy expression that defines when a single row qualifies
- * @return the value of the groovy expression in the context of all row for which groovyWhere
- * evaluates to true
- */
- public <T> List<T> findAll(String groovy, String groovyWhere) {
- return aggregate(groovy, groovyWhere, new FindAllAggregator<T>()).result;
- }
- private static final class FindAllAggregator<T> extends Aggregator<T> {
- List<T> result = new ArrayList<T>();
- boolean add(T value) {
- result.add(value);
- return true;
- }
- }
- /**
- * Execute the given <code>groovy</code> statement for each row. For example, to delete all
- * rows, one could call: <code>doForAllRows("adf.object.remove()");</code>
- *
- * @param groovy the groovy statement that should be executed in the context of every single row
- * @return the number of rows for which the statement was executed
- */
- public int doForAllRows(String groovy) {
- return doForAllRows(groovy, null);
- }
- /**
- * Execute the given <code>groovy</code> statement for each row for which
- * <code>groovyWhere</code> evaluates to <code>true</code>. For example, to delete expensive
- * employees, one could call: <code>doForAllRows("adf.object.remove()", "Salary > 1000");</code>
- *
- * @param groovy the groovy statement that should be executed in the context of every single row
- * @param groovyWhere a (boolean) groovy expression that defines when a single row qualifies
- * @return the number of rows for which the statement was executed
- */
- public int doForAllRows(String groovy, String groovyWhere) {
- return aggregate(groovy, groovyWhere, new CountAggregator()).result;
- }
- /**
- * Check whether the <code>groovy</code> expression evaluates to a unique value for every row.
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @return <code>true</code> iff all values are unique
- */
- public boolean unique(String groovy) {
- return unique(groovy, null);
- }
- /**
- * Check whether the <code>groovy</code> expression evaluates to a unique value for every row.
- * Only rows on which <code>groovyWhere</code> evaluates to <code>true</code> are taken into
- * account.
- *
- * @param groovy a groovy expression to be executed in the context of a single row
- * @param groovyWhere a (boolean) groovy expression that defines when a single row qualifies
- * @return <code>true</code> iff all values are unique
- */
- public boolean unique(String groovy, String groovyWhere) {
- return aggregate(groovy, groovyWhere, new UniqueAggregator()).result;
- }
- private static final class UniqueAggregator extends Aggregator<Object> {
- Set<Object> set = new HashSet<Object>();
- boolean result = true;
- boolean add(Object value) {
- result = set.add(value);
- return result;
- }
- }
- /*
- * An example of a more interesting aggregate function
- */
- /**
- * Return the lowest integer in the range <code>startWith..Integer.MAX_VALUE</code> that is
- * available. An integer is "available" if there is no row for which the given
- * <code>groovy</code> expression evaluates to it.
- *
- * @param groovy
- * @param startWith
- * @return
- */
- public int firstFreeInteger(String groovy, int startWith) {
- return firstFreeInteger(groovy, null, startWith);
- }
- /**
- * Return the lowest integer in the range <code>startWith..Integer.MAX_VALUE</code> that is
- * available. An integer is "available" if there is no row for which the given
- * <code>groovy</code> expression evaluates to it.
- *
- * @param groovy
- * @param groovyWhere a (boolean) groovy expression that defines which rows are taken into account
- * @param startWith
- * @return
- */
- public int firstFreeInteger(String groovy, String groovyWhere, int startWith) {
- return aggregate(groovy, groovyWhere,
- new FirstFreeIntegerAggregator(startWith)).firstFree();
- }
- private static final class FirstFreeIntegerAggregator extends Aggregator<Number> {
- int last;
- BitSet free = new BitSet();
- public FirstFreeIntegerAggregator(int startWith) {
- last = startWith;
- }
- boolean add(Number value) {
- if (value == null) {
- return true;
- }
- int i = value.intValue();
- if (i == last) {
- ++last;
- } else if (i > last) {
- free.set(last, i);
- last = i + 1;
- } else {
- free.clear(i);
- }
- return true;
- }
- int firstFree() {
- return free.isEmpty() ? last : free.nextSetBit(0);
- }
- }
- /*
- * The important part... the actual aggregation
- */
- /**
- * The aggregator does the actual aggregation, the <code>{@link #aggregate}</code> function
- * feeds all values (after evaluating the Groovy expression) to the aggregator.
- *
- * @param <T> the expected aggregate type
- */
- private static abstract class Aggregator<T> {
- abstract boolean add(T value);
- }
- /**
- * Execute the <code>groovy</code> expression and feed the calculated values to the aggregator.
- *
- * @param <A> the type of aggregator
- * @param <T> the aggregate type
- * @param groovy the expression that will be evaluated for all qualifying rows
- * @param groovyWhere the expression that indicates which rows qualify
- * @param aggregator the aggregator
- * @return the same aggregator
- */
- private <T, A extends Aggregator<T>> A aggregate(String groovy, String groovyWhere,
- A aggregator) {
- // The ExprEval is the magic class that provides all ADF-BC specific Groovy features, so
- // we can use the same code as we would use in business rules, default values, etc.
- ExprEval eval = null;
- if (groovy != null) {
- eval = new ExprEval(groovy, ExprEval.EXPR_STYLE_GROOVY);
- }
- ExprEval where = null;
- if (groovyWhere != null) {
- where = new ExprEval("(" + groovyWhere + ") as boolean", ExprEval.EXPR_STYLE_GROOVY);
- }
- RowIterator iter = createRowIterator();
- try {
- Row row = iter.first();
- while (row != null) {
- // Evaluate the where clause.
- boolean rowQualifies = true;
- if (where != null) {
- Boolean b = (Boolean)where.evaluateForRow(row);
- rowQualifies = b != null ? b : false;
- }
- // Evaluate the value expression and feed it to the aggregator.
- if (rowQualifies) {
- boolean cont;
- if (eval == null) {
- cont = aggregator.add(null);
- } else {
- cont = aggregator.add((T)eval.evaluateForRow(row));
- }
- if (!cont) {
- break;
- }
- }
- row = iter.next();
- }
- // Finally return the aggregator, for convenience.
- return aggregator;
- } finally {
- closeRowIterator(iter);
- }
- }
- protected abstract RowIterator createRowIterator();
- protected void closeRowIterator(RowIterator iter) {
- }
- /**
- * Get GroovySupport on a RowIterator.
- *
- * @param rowIterator
- * @return a new GroovySupport object
- */
- public static GroovySupport get(final RowIterator rowIterator) {
- return new GroovySupport() {
- protected RowIterator createRowIterator() {
- return rowIterator;
- }
- };
- }
- /**
- * Get GroovySupport on a RowSet (or a ViewObject). This will create a secondary RowSetIterator
- * everytime an aggregate function is called, so you will not lose row currency.
- *
- * @param rowSet
- * @return a new GroovySupport object
- */
- public static GroovySupport get(final RowSet rowSet) {
- return new GroovySupport() {
- protected RowIterator createRowIterator() {
- return rowSet.createRowSetIterator(null);
- }
- @Override
- protected void closeRowIterator(RowIterator iter) {
- ((RowSetIterator)iter).closeRowSetIterator();
- }
- };
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement