Skip to content
Snippets Groups Projects
Commit 8b40aa7d authored by anttil's avatar anttil
Browse files

BIS-575 / SP-995 : Novartis - dynamic properties do not work anymore in 13.04.5

SVN: 30121
parent 2910e659
No related branches found
No related tags found
No related merge requests found
...@@ -236,6 +236,11 @@ public final class Evaluator ...@@ -236,6 +236,11 @@ public final class Evaluator
interpreter.set(name, value); interpreter.set(name, value);
} }
public Object get(String name)
{
return interpreter.get(name);
}
/** /**
* Deletes the variable <var>name</var> from the evaluator's name space. * Deletes the variable <var>name</var> from the evaluator's name space.
*/ */
......
...@@ -16,9 +16,10 @@ ...@@ -16,9 +16,10 @@
package ch.systemsx.cisd.openbis.generic.server; package ch.systemsx.cisd.openbis.generic.server;
import java.util.Collection; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Stack;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
...@@ -36,9 +37,8 @@ import ch.systemsx.cisd.openbis.generic.shared.managed_property.IEvaluationRunne ...@@ -36,9 +37,8 @@ import ch.systemsx.cisd.openbis.generic.shared.managed_property.IEvaluationRunne
import ch.systemsx.cisd.openbis.generic.shared.managed_property.ManagedPropertyFunctions; import ch.systemsx.cisd.openbis.generic.shared.managed_property.ManagedPropertyFunctions;
/** /**
* Pool of Jython Evaluators for managed properties. When the pool is created, it is filled with new * Pool of Jython Evaluators for managed properties. When the pool is created, it is filled with new Evaluator instances for every managed property
* Evaluator instances for every managed property script. Enables thread-safe execution of calls to * script. Enables thread-safe execution of calls to python functions defined in these scripts.
* python functions defined in these scripts.
* *
* @author anttil * @author anttil
*/ */
...@@ -55,6 +55,8 @@ public class JythonEvaluatorPool ...@@ -55,6 +55,8 @@ public class JythonEvaluatorPool
private Lock cacheLock; private Lock cacheLock;
private static ThreadLocal<Stack<Map<String, Object>>> stack = new ThreadLocal<Stack<Map<String, Object>>>();
public JythonEvaluatorPool(IDAOFactory daoFactory, String poolSize) public JythonEvaluatorPool(IDAOFactory daoFactory, String poolSize)
{ {
this(daoFactory, createCache(poolSize)); this(daoFactory, createCache(poolSize));
...@@ -107,9 +109,8 @@ public class JythonEvaluatorPool ...@@ -107,9 +109,8 @@ public class JythonEvaluatorPool
} }
/** /**
* Evaluate python functions from a script using an Evaluator instance in the pool. If the * Evaluate python functions from a script using an Evaluator instance in the pool. If the Evaluator instance does not exist, create it. Give
* Evaluator instance does not exist, create it. Give access to the instance for only one thread * access to the instance for only one thread at a time.
* at a time.
*/ */
private <T> T evaluate(String expression, Class<?> clazz, String script, private <T> T evaluate(String expression, Class<?> clazz, String script,
IAtomicEvaluation<T> evaluation) IAtomicEvaluation<T> evaluation)
...@@ -134,14 +135,27 @@ public class JythonEvaluatorPool ...@@ -134,14 +135,27 @@ public class JythonEvaluatorPool
} }
} }
Lock lock = state.getLock(); ReentrantLock lock = (ReentrantLock) state.getLock();
if (false == lock.isHeldByCurrentThread())
{
stack.set(new Stack<Map<String, Object>>());
}
lock.lock(); lock.lock();
state.push();
try try
{ {
return evaluation.evaluate(state.getCleanInstance()); return evaluation.evaluate(state.getEvaluator());
} finally } finally
{ {
state.pop();
lock.unlock(); lock.unlock();
if (false == lock.isHeldByCurrentThread())
{
stack.set(null);
}
} }
} }
...@@ -168,37 +182,52 @@ public class JythonEvaluatorPool ...@@ -168,37 +182,52 @@ public class JythonEvaluatorPool
} }
/** /**
* The pooled object. Contains the Evaluator and its initial state to which it is always * The pooled object. Contains the Evaluator and its initial state to which it is always returned to when a new evaluation is started.
* returned to when a new evaluation is started.
*/ */
public static class EvaluatorState public static class EvaluatorState
{ {
private final Evaluator evaluator; private final Evaluator evaluator;
private final Collection<String> globals; private Stack<Map<String, Object>> globalsStack;
private final Lock lock; private final Lock lock;
public EvaluatorState(Evaluator evaluator) public EvaluatorState(Evaluator evaluator)
{ {
this.evaluator = evaluator; this.evaluator = evaluator;
this.globals = evaluator.getGlobalVariables();
this.lock = new ReentrantLock(); this.lock = new ReentrantLock();
this.globalsStack = new Stack<Map<String, Object>>();
} }
/** public void push()
* Returns an evaluator instance in its initial state.
*/
public synchronized Evaluator getCleanInstance()
{ {
for (String value : evaluator.getGlobalVariables()) Map<String, Object> globalsValues = new HashMap<String, Object>();
for (String globalName : evaluator.getGlobalVariables())
{ {
if (globals.contains(value) == false) Object globalValue = evaluator.get(globalName);
{ globalsValues.put(globalName, globalValue);
evaluator.delete(value); }
} globalsStack.push(globalsValues);
}
public void pop()
{
Map<String, Object> globalsValues = globalsStack.pop();
for (String globalName : evaluator.getGlobalVariables())
{
evaluator.delete(globalName);
} }
return this.evaluator;
for (String globalName : globalsValues.keySet())
{
evaluator.set(globalName, globalsValues.get(globalName));
}
}
public Evaluator getEvaluator()
{
return evaluator;
} }
public Lock getLock() public Lock getLock()
......
...@@ -107,7 +107,8 @@ public class JythonDynamicPropertyCalculator implements IDynamicPropertyCalculat ...@@ -107,7 +107,8 @@ public class JythonDynamicPropertyCalculator implements IDynamicPropertyCalculat
try try
{ {
evaluator.set(ENTITY_VARIABLE_NAME, entity); evaluator.set(ENTITY_VARIABLE_NAME, entity);
return evaluator.evalAsStringLegacy2_2(); String x = evaluator.evalAsStringLegacy2_2();
return x;
} finally } finally
{ {
evaluator.releaseResources(); evaluator.releaseResources();
......
...@@ -48,13 +48,16 @@ import org.jmock.Mockery; ...@@ -48,13 +48,16 @@ import org.jmock.Mockery;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import ch.systemsx.cisd.common.filesystem.FileUtilities;
import ch.systemsx.cisd.common.jython.evaluator.Evaluator; import ch.systemsx.cisd.common.jython.evaluator.Evaluator;
import ch.systemsx.cisd.common.utilities.TestResources;
import ch.systemsx.cisd.openbis.generic.server.JythonEvaluatorPool.EvaluatorState; import ch.systemsx.cisd.openbis.generic.server.JythonEvaluatorPool.EvaluatorState;
import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory; import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
import ch.systemsx.cisd.openbis.generic.server.dataaccess.IScriptDAO; import ch.systemsx.cisd.openbis.generic.server.dataaccess.IScriptDAO;
import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ScriptType; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ScriptType;
import ch.systemsx.cisd.openbis.generic.shared.dto.ScriptPE; import ch.systemsx.cisd.openbis.generic.shared.dto.ScriptPE;
import ch.systemsx.cisd.openbis.generic.shared.managed_property.IAtomicEvaluation; import ch.systemsx.cisd.openbis.generic.shared.managed_property.IAtomicEvaluation;
import ch.systemsx.cisd.openbis.generic.shared.managed_property.IEvaluationRunner;
/** /**
* @author anttil * @author anttil
...@@ -78,6 +81,39 @@ public class JythonEvaluatorPoolTest ...@@ -78,6 +81,39 @@ public class JythonEvaluatorPoolTest
} }
} }
@Test
public void globalVariablesAreHandledCorrectlyWhenThereAreNestedCalls() throws Exception
{
TestResources resources = new TestResources(getClass());
String script = FileUtilities.loadToString(resources.getResourceFile("recursive_property.py"));
final IEvaluationRunner runner =
pool.getRunner("calculate()", Math.class, script);
final IAtomicEvaluation<String> action = new IAtomicEvaluation<String>()
{
int counter = 5;
@Override
public String evaluate(Evaluator evaluator)
{
evaluator.set("action", this);
evaluator.set("runner", runner);
evaluator.set("value", counter);
if (counter > 0)
{
counter--;
return evaluator.evalAsStringLegacy2_2();
} else
{
return "";
}
}
};
runner.evaluate(action);
// Assertion in the python script!
}
@Test @Test
public void globalVariablesSetInPreviousRunsAreClearedBeforeNewEvaluation() throws Exception public void globalVariablesSetInPreviousRunsAreClearedBeforeNewEvaluation() throws Exception
{ {
......
def calculate():
temp = value
runner.evaluate(action);
if temp != value:
raise Exception(str(temp)+" vs "+str(value))
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment