From f96531ac1e6e60947abd8e2b9c111de7413d2bab Mon Sep 17 00:00:00 2001
From: buczekp <buczekp>
Date: Tue, 26 Oct 2010 12:03:01 +0000
Subject: [PATCH] [LMS-1845] support multiline expressions with calculate()
 function

SVN: 18444
---
 .../DefaultDynamicPropertyEvaluator.java      | 14 +++----
 .../calculator/DynamicPropertyCalculator.java | 34 +++++++++++++++-
 .../DynamicPropertyCalculatorTest.java        | 40 +++++++++++++++++--
 3 files changed, 75 insertions(+), 13 deletions(-)

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DefaultDynamicPropertyEvaluator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DefaultDynamicPropertyEvaluator.java
index fffd685f2aa..b3a853c6e22 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DefaultDynamicPropertyEvaluator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DefaultDynamicPropertyEvaluator.java
@@ -107,10 +107,10 @@ final class DefaultDynamicPropertyEvaluator implements IDynamicPropertyEvaluator
                     clazz.getSimpleName()));
             final int maxIndex = idsSize - 1;
             // need to increment last id because we use 'lt' condition
-                if (maxIndex > -1)
-        {
-                     ids.set(maxIndex, ids.get(maxIndex) + 1);
-       }
+            if (maxIndex > -1)
+            {
+                ids.set(maxIndex, ids.get(maxIndex) + 1);
+            }
             while (index < maxIndex)
             {
                 final int nextIndex = getNextIndex(index, maxIndex);
@@ -166,8 +166,8 @@ final class DefaultDynamicPropertyEvaluator implements IDynamicPropertyEvaluator
                         listEntitiesWithRestrictedId(hibernateSession, clazz, subList);
                 evaluateProperties(hibernateSession, results, clazz);
                 index = nextIndex;
-                operationLog.info(String.format("%d/%d %ss have been updated...", index + 1, maxIndex + 1,
-                        clazz.getSimpleName()));
+                operationLog.info(String.format("%d/%d %ss have been updated...", index + 1,
+                        maxIndex + 1, clazz.getSimpleName()));
             }
             transaction.commit();
             operationLog.info(String.format(
@@ -263,7 +263,7 @@ final class DefaultDynamicPropertyEvaluator implements IDynamicPropertyEvaluator
                 try
                 {
                     DynamicPropertyCalculator calculator =
-                            new DynamicPropertyCalculator(etpt.getScript().getScript());
+                            DynamicPropertyCalculator.create(etpt.getScript().getScript());
                     final IEntityAdaptor entityAdaptor = EntityAdaptorFactory.create(entity);
                     calculator.setEntity(entityAdaptor);
                     final String dynamicValue = calculator.evalAsString();
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyCalculator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyCalculator.java
index f9c75f3de4a..71868c54439 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyCalculator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyCalculator.java
@@ -20,15 +20,45 @@ import ch.systemsx.cisd.common.evaluator.Evaluator;
 import ch.systemsx.cisd.openbis.generic.shared.calculator.AbstractCalculator;
 
 /**
+ * Calculator for dynamic properties.
+ * <p>
+ * Variables : <code>entity<code> of type {@link IEntityAdaptor}
+ * 
  * @author Piotr Buczek
  */
 public class DynamicPropertyCalculator extends AbstractCalculator
 {
+
     private static final String ENTITY_VARIABLE_NAME = "entity";
 
-    public DynamicPropertyCalculator(String expression)
+    private static final String INVOKE_CALCULATE_EXPR = "calculate()";
+
+    /**
+     * Creates a calculator for given <code>expression</code>.
+     * <p>
+     * Result of the calculation depends on whether the expression is multiline or not. Returned
+     * value will be equal to:
+     * <ul>
+     * <li>result of calculation of a *single line* expression
+     * <li>result of invocation of 'calculate()' function for a *multiline* expression
+     * </ul>
+     */
+    public static DynamicPropertyCalculator create(String expression)
+    {
+        String calculatedExpression = expression;
+        String initialScript = BASIC_INITIAL_SCRIPT;
+        if (Evaluator.isMultiline(expression))
+        {
+            initialScript += "\n" + expression;
+            calculatedExpression = INVOKE_CALCULATE_EXPR;
+        }
+        return new DynamicPropertyCalculator(new Evaluator(calculatedExpression, Math.class,
+                initialScript));
+    }
+
+    private DynamicPropertyCalculator(Evaluator evaluator)
     {
-        super(new Evaluator(expression, Math.class, BASIC_INITIAL_SCRIPT));
+        super(evaluator);
     }
 
     public void setEntity(IEntityAdaptor entity)
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyCalculatorTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyCalculatorTest.java
index 1f1d225f672..b5b554723e3 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyCalculatorTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyCalculatorTest.java
@@ -22,6 +22,7 @@ import java.util.Collection;
 import org.testng.AssertJUnit;
 import org.testng.annotations.Test;
 
+import ch.systemsx.cisd.common.evaluator.EvaluatorException;
 import ch.systemsx.cisd.openbis.generic.shared.util.XmlUtilsTest;
 
 /**
@@ -35,7 +36,8 @@ public class DynamicPropertyCalculatorTest extends AssertJUnit
     {
         final String entityCode1 = "ecode1";
         final String entityCode2 = "ecode2";
-        final DynamicPropertyCalculator calculator = new DynamicPropertyCalculator("entity.code()");
+        final DynamicPropertyCalculator calculator =
+                DynamicPropertyCalculator.create("entity.code()");
 
         calculator.setEntity(createEntity(entityCode1, null));
         assertEquals(entityCode1, calculator.evalAsString());
@@ -48,7 +50,7 @@ public class DynamicPropertyCalculatorTest extends AssertJUnit
     public void testGetEntityPropertyValue()
     {
         final DynamicPropertyCalculator calculator =
-                new DynamicPropertyCalculator("entity.propertyValue('p2')");
+                DynamicPropertyCalculator.create("entity.propertyValue('p2')");
 
         final String entityCode = "ecode";
 
@@ -76,9 +78,9 @@ public class DynamicPropertyCalculatorTest extends AssertJUnit
     public void testGetEntityPropertyRenderedValue()
     {
         final DynamicPropertyCalculator normalPropertyCalculator =
-                new DynamicPropertyCalculator("entity.propertyRendered('normalProperty')");
+                DynamicPropertyCalculator.create("entity.propertyRendered('normalProperty')");
         final DynamicPropertyCalculator xmlPropertyCalculator =
-                new DynamicPropertyCalculator("entity.propertyRendered('xmlProperty')");
+                DynamicPropertyCalculator.create("entity.propertyRendered('xmlProperty')");
 
         final String entityCode = "ecode";
 
@@ -97,6 +99,36 @@ public class DynamicPropertyCalculatorTest extends AssertJUnit
         assertEquals(XmlUtilsTest.SIMPLE_XML_TRANSFORMED, xmlPropertyCalculator.evalAsString());
     }
 
+    @Test
+    public void testEvaluateMultilineExpression()
+    {
+        final String expression = "def calculate():\n" + "\treturn entity.code()";
+        final String entityCode = "ecode";
+        final DynamicPropertyCalculator calculator = DynamicPropertyCalculator.create(expression);
+
+        calculator.setEntity(createEntity(entityCode, null));
+        assertEquals(entityCode, calculator.evalAsString());
+    }
+
+    @Test
+    public void testEvaluateMultilineExpressionFailsWithNoCalculateFunction()
+    {
+        final String expression = "def calc():\n" + "\treturn entity.code()";
+        final String entityCode = "ecode";
+        final DynamicPropertyCalculator calculator = DynamicPropertyCalculator.create(expression);
+
+        calculator.setEntity(createEntity(entityCode, null));
+        try
+        {
+            calculator.evalAsString();
+            fail("expected EvaluatorException");
+        } catch (EvaluatorException e)
+        {
+            final String expectedMsg = "Error evaluating 'calculate()': NameError: calculate";
+            assertEquals("expected exception message: " + expectedMsg, expectedMsg, e.getMessage());
+        }
+    }
+
     private static IEntityAdaptor createEntity(final String code,
             final Collection<IEntityPropertyAdaptor> properties)
     {
-- 
GitLab