From b2c53fc04bcec0ca5a1bc948faccc7489c88c78b Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Mon, 28 Sep 2009 09:07:07 +0000
Subject: [PATCH] LMS-1186 standard functions implemented, FilterUtils class
 refactored

SVN: 12724
---
 .../framework/EntityPropertyColDef.java       |  8 +-
 .../application/ui/filter/FilterToolbar.java  | 13 +--
 .../ui/grid/AbstractBrowserGrid.java          |  2 +-
 .../web/client/dto/CustomFilterInfo.java      | 15 ---
 .../client/web/server/calculator/Row.java     | 61 ++++++++++++
 .../web/server/calculator/RowCalculator.java  | 94 +++++++++++++++++++
 .../server/calculator/StandardFunctions.java  | 75 +++++++++++++++
 .../client/web/server/util/FilterUtils.java   | 57 +----------
 8 files changed, 243 insertions(+), 82 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/Row.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/RowCalculator.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/StandardFunctions.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/framework/EntityPropertyColDef.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/framework/EntityPropertyColDef.java
index 3c4a1c8a8cc..3996522528d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/framework/EntityPropertyColDef.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/framework/EntityPropertyColDef.java
@@ -34,6 +34,10 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
 public class EntityPropertyColDef<T extends IEntityPropertiesHolder> extends
         AbstractColumnDefinition<T> implements IsSerializable
 {
+    private static final Double DOUBLE_MIN_VALUE = new Double(-Double.MAX_VALUE);
+
+    private static final Integer INTEGER_MIN_VALUE = new Integer(Integer.MIN_VALUE);
+
     private static final int PROPERTY_COLUMN_WIDTH = 120;
 
     private static final String PROPERTY_PREFIX = "property-";
@@ -114,9 +118,9 @@ public class EntityPropertyColDef<T extends IEntityPropertiesHolder> extends
         switch (dataType)
         {
             case INTEGER:
-                return valueAsString == null ? new Integer(Integer.MIN_VALUE) : new Integer(valueAsString);
+                return valueAsString == null ? INTEGER_MIN_VALUE : new Integer(valueAsString);
             case REAL:
-                return valueAsString == null ? new Double(-Double.MAX_VALUE) : new Double(valueAsString);
+                return valueAsString == null ? DOUBLE_MIN_VALUE : new Double(valueAsString);
             default:
                 return super.getComparableValue(rowModel);
         }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterToolbar.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterToolbar.java
index 5e952fa9d4c..f70ed4577c5 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterToolbar.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterToolbar.java
@@ -1,6 +1,5 @@
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter;
 
-import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -25,13 +24,11 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAs
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.IDatabaseModificationObserver;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IColumnDefinitionProvider;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IDisplayTypeIDProvider;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.PagingColumnFilter;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IDelegatedAction;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.CustomFilterInfo;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ParameterWithValue;
-import ch.systemsx.cisd.openbis.generic.shared.basic.IColumnDefinition;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Filter;
 
@@ -49,20 +46,16 @@ public class FilterToolbar<T> extends ToolBar implements IDatabaseModificationOb
 
     private final FilterSelectionWidget filterSelectionWidget;
 
-    private final IColumnDefinitionProvider<T> columnDefinitionProvider;
-
     private final IDelegatedAction delegatedAction;
 
     private final TextToolItem applyTool;
 
     public FilterToolbar(IViewContext<ICommonClientServiceAsync> viewContext, String gridId,
             IDisplayTypeIDProvider displayTypeIDProvider,
-            final List<PagingColumnFilter<T>> filterWidgets, IDelegatedAction delegatedAction,
-            final IColumnDefinitionProvider<T> columnDefinitionProvider)
+            final List<PagingColumnFilter<T>> filterWidgets, IDelegatedAction delegatedAction)
     {
         this.columnFilters = filterWidgets;
         this.delegatedAction = delegatedAction;
-        this.columnDefinitionProvider = columnDefinitionProvider;
         add(new LabelToolItem(viewContext.getMessage(Dict.FILTER) + ": "));
         filterSelectionWidget =
                 new FilterSelectionWidget(viewContext, gridId, displayTypeIDProvider);
@@ -114,10 +107,6 @@ public class FilterToolbar<T> extends ToolBar implements IDatabaseModificationOb
             } else
             {
                 CustomFilterInfo<T> info = new CustomFilterInfo<T>();
-                List<IColumnDefinition<T>> columnDefinitions =
-                        columnDefinitionProvider.getColumnDefinitions(new ArrayList<String>(
-                                selected.getColumns()));
-                info.setColumns(columnDefinitions);
                 info.setExpression(selected.getExpression());
                 Set<ParameterWithValue> parameters = new HashSet<ParameterWithValue>();
                 for (Component field : filterContainer.getItems())
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java
index 19e841c9205..3eeb4d961fc 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java
@@ -226,7 +226,7 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends BaseEntityMod
         pagingToolbar.bind(pagingLoader);
         this.filterToolbar =
                 new FilterToolbar<T>(viewContext, gridId, this, filterWidgets,
-                        createApplyFiltersDelagator(), this);
+                        createApplyFiltersDelagator());
         final LayoutContainer bottomToolbars = createBottomToolbars(filterToolbar, pagingToolbar);
         this.contentPanel = createEmptyContentPanel();
         contentPanel.add(grid);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/CustomFilterInfo.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/CustomFilterInfo.java
index d46f95ed98f..d52611da5de 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/CustomFilterInfo.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/CustomFilterInfo.java
@@ -16,13 +16,10 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.dto;
 
-import java.util.List;
 import java.util.Set;
 
 import com.google.gwt.user.client.rpc.IsSerializable;
 
-import ch.systemsx.cisd.openbis.generic.shared.basic.IColumnDefinition;
-
 /**
  * Stores information about selected custom filter.
  * 
@@ -35,8 +32,6 @@ public class CustomFilterInfo<T> implements IsSerializable
 
     private Set<ParameterWithValue> parameters;
 
-    private List<IColumnDefinition<T>> columns;
-
     public CustomFilterInfo()
     {
     }
@@ -61,14 +56,4 @@ public class CustomFilterInfo<T> implements IsSerializable
         this.parameters = parameters;
     }
 
-    public List<IColumnDefinition<T>> getColumns()
-    {
-        return columns;
-    }
-
-    public void setColumns(List<IColumnDefinition<T>> columns)
-    {
-        this.columns = columns;
-    }
-
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/Row.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/Row.java
new file mode 100644
index 00000000000..01de1b7e8a2
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/Row.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.client.web.server.calculator;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.IColumnDefinition;
+
+/**
+ * Row object used in jython expressions to access column values. 
+ * <p>
+ * All public methods of this class are part of the Filter/Calculated Column API.
+ *
+ * @author Franz-Josef Elmer
+ */
+public final class Row<T>
+{
+    private final Map<String, IColumnDefinition<T>> map = new HashMap<String, IColumnDefinition<T>>();
+    
+    private T row;
+    
+    public Row(Set<IColumnDefinition<T>> availableColumns)
+    {
+        for (IColumnDefinition<T> columnDefinition : availableColumns)
+        {
+            map.put(columnDefinition.getIdentifier(), columnDefinition);
+        }
+    }
+    
+    void setRowData(T row)
+    {
+        this.row = row;
+    }
+
+    public Object col(String columnID)
+    {
+        IColumnDefinition<T> columnDefinition = map.get(columnID);
+        if (columnDefinition == null)
+        {
+            throw new IllegalArgumentException("Undefined column: " + columnID);
+        }
+        return columnDefinition.getComparableValue(row);
+    }
+    
+}
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/RowCalculator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/RowCalculator.java
new file mode 100644
index 00000000000..be19c31a857
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/RowCalculator.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.client.web.server.calculator;
+
+import java.math.BigInteger;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import ch.systemsx.cisd.common.evaluator.Evaluator;
+import ch.systemsx.cisd.common.evaluator.EvaluatorException;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ParameterWithValue;
+import ch.systemsx.cisd.openbis.generic.shared.basic.IColumnDefinition;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class RowCalculator<T>
+{
+    private static final String INITIAL_SCRIPT =
+            "from " + StandardFunctions.class.getCanonicalName() + " import *";
+
+    private final Evaluator evaluator;
+
+    private final Row<T> row;
+
+    public RowCalculator(Set<IColumnDefinition<T>> availableColumns, String expression,
+            Set<ParameterWithValue> parameters)
+    {
+        evaluator = new Evaluator(substitudeParameters(expression, parameters), Math.class,
+                INITIAL_SCRIPT);
+        row = new Row<T>(availableColumns);
+        evaluator.set("row", row);
+    }
+    
+    public void setRowData(T rowData)
+    {
+        row.setRowData(rowData);
+    }
+    
+    public boolean evalToBoolean() throws EvaluatorException
+    {
+        return evaluator.evalToBoolean();
+    }
+    
+    public int evalToInt() throws EvaluatorException
+    {
+        return evaluator.evalToInt();
+    }
+    
+    public BigInteger evalToBigInt() throws EvaluatorException
+    {
+        return evaluator.evalToBigInt();
+    }
+
+    public double evalToDouble() throws EvaluatorException
+    {
+        return evaluator.evalToDouble();
+    }
+
+    public String evalAsString() throws EvaluatorException
+    {
+        return evaluator.evalAsString();
+    }
+    
+    private String substitudeParameters(String originalExpression, Set<ParameterWithValue> parameters)
+    {
+        String expression = originalExpression;
+        for (ParameterWithValue pw : parameters)
+        {
+            String substParameter = "${" + pw.getParameter() + "}";
+            String quotedParameter = Pattern.quote(substParameter);
+            String quotedReplacement = Matcher.quoteReplacement(pw.getValue());
+            expression = expression.replaceAll(quotedParameter, quotedReplacement);
+        }
+        return expression;
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/StandardFunctions.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/StandardFunctions.java
new file mode 100644
index 00000000000..1866f57fbff
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/StandardFunctions.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.client.web.server.calculator;
+
+/**
+ * Set of standard functions used in jython expressions. 
+ * <p>
+ * All public methods of this class are part of the Filter/Calculated Column API.
+ *
+ * @author Franz-Josef Elmer
+ */
+public final class StandardFunctions
+{
+    private static final Double DOUBLE_DEFAULT_VALUE = new Double(-Double.MAX_VALUE);
+    private static final Integer INTEGER_DEFAULT_VALUE = new Integer(Integer.MIN_VALUE);
+
+    public static Integer toInteger(Object value)
+    {
+        return toInteger(value, INTEGER_DEFAULT_VALUE);
+    }
+    
+    public static Integer toInteger(Object value, Integer defaultValue)
+    {
+        if (value instanceof Number)
+        {
+            Number number = (Number) value;
+            return number.intValue();
+        }
+        return isBlank(value) ? defaultValue : new Integer(value.toString());
+    }
+
+    public static Double toFloat(Object value)
+    {
+        return toFloat(value, DOUBLE_DEFAULT_VALUE);
+    }
+    
+    public static Double toFloat(Object value, Double defaultValue)
+    {
+        if (value instanceof Number)
+        {
+            Number number = (Number) value;
+            return number.doubleValue();
+        }
+        return isBlank(value) ? defaultValue : new Double(value.toString());
+    }
+    
+    public static Object ifThenElse(Boolean condition, Object thenValue, Object elseValue)
+    {
+        return condition != null && condition.booleanValue() ? thenValue : elseValue;
+    }
+    
+    private static boolean isBlank(Object value)
+    {
+        return value == null || value.toString().trim().length() == 0;
+    }
+    
+    private StandardFunctions()
+    {
+    }
+    
+}
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/util/FilterUtils.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/util/FilterUtils.java
index 32f3742a80b..004d30b756b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/util/FilterUtils.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/util/FilterUtils.java
@@ -16,16 +16,12 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.server.util;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
-import ch.systemsx.cisd.common.evaluator.Evaluator;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.CustomFilterInfo;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ParameterWithValue;
+import ch.systemsx.cisd.openbis.generic.client.web.server.calculator.RowCalculator;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IColumnDefinition;
 
 /**
@@ -35,37 +31,6 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.IColumnDefinition;
  */
 public class FilterUtils
 {
-    public static final class Row<T>
-    {
-        private final Map<String, IColumnDefinition<T>> map = new HashMap<String, IColumnDefinition<T>>();
-        
-        private T row;
-        
-        public Row(Set<IColumnDefinition<T>> availableColumns)
-        {
-            for (IColumnDefinition<T> columnDefinition : availableColumns)
-            {
-                map.put(columnDefinition.getIdentifier(), columnDefinition);
-            }
-            System.out.println(map);
-        }
-        
-        void setRowData(T row)
-        {
-            this.row = row;
-        }
-
-        public Object get(String columnID)
-        {
-            IColumnDefinition<T> columnDefinition = map.get(columnID);
-            if (columnDefinition == null)
-            {
-                throw new IllegalArgumentException("Undefined column: " + columnID);
-            }
-            return columnDefinition.getComparableValue(row);
-        }
-    }
-    
     /**
      * Applies the filter described by <code>customFilterInfo</code> to
      * <code>allRows<code> and adds the result to the
@@ -76,28 +41,16 @@ public class FilterUtils
             List<T> filterdRows)
     {
         String expression = customFilterInfo.getExpression();
-        for (ParameterWithValue pw : customFilterInfo.getParameters())
-        {
-            expression = substituteParameter(expression, pw.getParameter(), pw.getValue());
-        }
-        Evaluator e = new Evaluator(expression, Math.class, null);
-        Row<T> row = new Row<T>(availableColumns);
-        e.set("row", row);
+        Set<ParameterWithValue> parameters = customFilterInfo.getParameters();
+        RowCalculator<T> calculator = new RowCalculator<T>(availableColumns, expression, parameters);
         for (T rowData : allRows)
         {
-            row.setRowData(rowData);
-            if (e.evalToBoolean())
+            calculator.setRowData(rowData);
+            if (calculator.evalToBoolean())
             {
                 filterdRows.add(rowData);
             }
         }
     }
 
-    private static String substituteParameter(String expression, String p, String value)
-    {
-        String substParameter = "${" + p + "}";
-        String quotedParameter = Pattern.quote(substParameter);
-        String quotedReplacement = Matcher.quoteReplacement(value);
-        return expression.replaceAll(quotedParameter, quotedReplacement);
-    }
 }
-- 
GitLab