/* * Copyright (c) 2010-2013 Evolveum * * 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 com.evolveum.midpoint.model.common.expression.script; import com.evolveum.midpoint.model.common.expression.ExpressionUtil; import com.evolveum.midpoint.model.common.expression.ExpressionVariables; import com.evolveum.midpoint.model.common.expression.functions.FunctionLibrary; import com.evolveum.midpoint.model.common.expression.script.jsr223.Jsr223ScriptEvaluator; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.crypto.ProtectorImpl; import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.schema.MidPointPrismContextFactory; import com.evolveum.midpoint.schema.constants.MidPointConstants; import com.evolveum.midpoint.schema.internals.InternalMonitor; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectResolver; import com.evolveum.midpoint.test.util.DirectoryFileObjectResolver; import com.evolveum.midpoint.test.util.TestUtil; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.xml.ns._public.common.common_3.ScriptExpressionEvaluatorType; import org.testng.AssertJUnit; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; import org.xml.sax.SAXException; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; import static org.testng.AssertJUnit.*; /** * @author semancik */ public class TestScriptCaching { private static final File TEST_DIR = new File("src/test/resources/expression/groovy"); protected static File OBJECTS_DIR = new File("src/test/resources/objects"); private static final QName PROPERTY_NAME = new QName(MidPointConstants.NS_MIDPOINT_TEST_PREFIX, "whatever"); private static final String NS_WHATEVER = "http://whatever/xml/ns"; protected ScriptExpressionFactory scriptExpressionfactory; protected ScriptEvaluator evaluator; @BeforeSuite public void setup() throws SchemaException, SAXException, IOException { PrettyPrinter.setDefaultNamespacePrefix(MidPointConstants.NS_MIDPOINT_PUBLIC_PREFIX); PrismTestUtil.resetPrismContext(MidPointPrismContextFactory.FACTORY); } @BeforeClass public void setupFactory() { System.out.println("Setting up expression factory and evaluator"); PrismContext prismContext = PrismTestUtil.getPrismContext(); ObjectResolver resolver = new DirectoryFileObjectResolver(OBJECTS_DIR); Protector protector = new ProtectorImpl(); Collection<FunctionLibrary> functions = new ArrayList<FunctionLibrary>(); functions.add(ExpressionUtil.createBasicFunctionLibrary(prismContext, protector)); scriptExpressionfactory = new ScriptExpressionFactory(resolver, prismContext, protector); scriptExpressionfactory.setFunctions(functions); evaluator = new Jsr223ScriptEvaluator("groovy", prismContext, protector); String languageUrl = evaluator.getLanguageUrl(); scriptExpressionfactory.registerEvaluator(languageUrl, evaluator); } @Test public void testGetExtensionPropertyValue() throws Exception { final String TEST_NAME = "testGetExtensionPropertyValue"; TestUtil.displayTestTile(TEST_NAME); // GIVEN InternalMonitor.reset(); assertScriptMonitor(0,0, "init"); // WHEN, THEN long etimeFirst = executeScript("expression-string-variables.xml", "FOOBAR", "first"); assertScriptMonitor(1,1, "first"); long etimeSecond = executeScript("expression-string-variables.xml", "FOOBAR", "second"); assertScriptMonitor(1,2, "second"); assertTrue("Einstein was wrong! "+etimeFirst+" -> "+etimeSecond, etimeSecond <= etimeFirst); long etimeThird = executeScript("expression-string-variables.xml", "FOOBAR", "second"); assertScriptMonitor(1,3, "third"); assertTrue("Einstein was wrong again! "+etimeFirst+" -> "+etimeThird, etimeThird <= etimeFirst); // Different script. Should compile. long horatio1Time = executeScript("expression-func-concatname.xml", "Horatio Torquemada Marley", "horatio"); assertScriptMonitor(2,4, "horatio"); // Same script. No compilation. long etimeFourth = executeScript("expression-string-variables.xml", "FOOBAR", "fourth"); assertScriptMonitor(2,5, "fourth"); assertTrue("Einstein was wrong all the time! "+etimeFirst+" -> "+etimeFourth, etimeFourth <= etimeFirst); // Try this again. No compile. long horatio2Time = executeScript("expression-func-concatname.xml", "Horatio Torquemada Marley", "horatio2"); assertScriptMonitor(2,6, "horatio2"); assertTrue("Even Horatio was wrong! "+horatio1Time+" -> "+horatio2Time, horatio2Time <= horatio1Time); } private void assertScriptMonitor(int expCompilations, int expExecutions, String desc) { assertEquals("Unexpected number of script compilations after "+desc, expCompilations, InternalMonitor.getScriptCompileCount()); assertEquals("Unexpected number of script executions after "+desc, expExecutions, InternalMonitor.getScriptExecutionCount()); } private long executeScript(String filname, String expectedResult, String desc) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException { // GIVEN OperationResult result = new OperationResult(desc); ScriptExpressionEvaluatorType scriptType = parseScriptType(filname); ItemDefinition outputDefinition = new PrismPropertyDefinitionImpl(PROPERTY_NAME, DOMUtil.XSD_STRING, PrismTestUtil.getPrismContext()); ScriptExpression scriptExpression = scriptExpressionfactory.createScriptExpression(scriptType, outputDefinition, desc); ExpressionVariables variables = ExpressionVariables.create( new QName(NS_WHATEVER, "foo"), "FOO", new QName(NS_WHATEVER, "bar"), "BAR" ); // WHEN long startTime = System.currentTimeMillis(); List<PrismPropertyValue<String>> scripResults = scriptExpression.evaluate(variables , null, false, desc, null, result); long endTime = System.currentTimeMillis(); // THEN System.out.println("Script results "+desc+", etime: "+(endTime - startTime)+" ms"); System.out.println(scripResults); String scriptResult = asScalarString(scripResults); assertEquals("Wrong script "+desc+" result", expectedResult, scriptResult); return (endTime - startTime); } private ScriptExpressionEvaluatorType parseScriptType(String fileName) throws SchemaException, IOException, JAXBException { ScriptExpressionEvaluatorType expressionType = PrismTestUtil.parseAtomicValue( new File(TEST_DIR, fileName), ScriptExpressionEvaluatorType.COMPLEX_TYPE); return expressionType; } private String asScalarString(List<PrismPropertyValue<String>> expressionResultList) { if (expressionResultList.size() > 1) { AssertJUnit.fail("Expression produces a list of "+expressionResultList.size()+" while only expected a single value: "+expressionResultList); } if (expressionResultList.isEmpty()) { return null; } return expressionResultList.iterator().next().getValue(); } }