Author: bdelacretaz Date: Mon Jul 29 13:00:49 2013 New Revision: 1508040 URL: http://svn.apache.org/r1508040 Log: SLING-2983 - scripted health check rules, including examples
Added: sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/scriptable/ sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/scriptable/ScriptableRuleBuilder.java sling/trunk/contrib/extensions/healthcheck/hc-rules/src/test/java/org/apache/sling/hc/rules/impl/ScriptableRuleBuilderTest.java sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-ecma.json sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-groovy.json Modified: sling/trunk/contrib/extensions/healthcheck/hc-rules/pom.xml sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/osgi/Activator.java Modified: sling/trunk/contrib/extensions/healthcheck/hc-rules/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-rules/pom.xml?rev=1508040&r1=1508039&r2=1508040&view=diff ============================================================================== --- sling/trunk/contrib/extensions/healthcheck/hc-rules/pom.xml (original) +++ sling/trunk/contrib/extensions/healthcheck/hc-rules/pom.xml Mon Jul 29 13:00:49 2013 @@ -50,6 +50,17 @@ <target>1.6</target> </configuration> </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>animal-sniffer-maven-plugin</artifactId> + <configuration> + <signature> + <groupId>org.codehaus.mojo.signature</groupId> + <artifactId>java16</artifactId> + <version>1.0</version> + </signature> + </configuration> + </plugin> </plugins> </build> @@ -88,5 +99,11 @@ <version>4.8.1</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>1.9.5</version> + <scope>test</scope> + </dependency> </dependencies> </project> Modified: sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/osgi/Activator.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/osgi/Activator.java?rev=1508040&r1=1508039&r2=1508040&view=diff ============================================================================== --- sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/osgi/Activator.java (original) +++ sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/osgi/Activator.java Mon Jul 29 13:00:49 2013 @@ -22,6 +22,7 @@ import java.util.List; import org.apache.sling.hc.api.RuleBuilder; import org.apache.sling.hc.rules.jmx.JmxBeansRuleBuilder; +import org.apache.sling.hc.rules.scriptable.ScriptableRuleBuilder; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; @@ -34,6 +35,7 @@ public class Activator implements Bundle regs = new ArrayList<ServiceRegistration>(); regs.add(ctx.registerService(RuleBuilder.class.getName(), new BundlesRuleBuilder(ctx), null)); regs.add(ctx.registerService(RuleBuilder.class.getName(), new JmxBeansRuleBuilder(), null)); + regs.add(ctx.registerService(RuleBuilder.class.getName(), new ScriptableRuleBuilder(ctx), null)); } public void stop(BundleContext ctx) throws Exception { Added: sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/scriptable/ScriptableRuleBuilder.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/scriptable/ScriptableRuleBuilder.java?rev=1508040&view=auto ============================================================================== --- sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/scriptable/ScriptableRuleBuilder.java (added) +++ sling/trunk/contrib/extensions/healthcheck/hc-rules/src/main/java/org/apache/sling/hc/rules/scriptable/ScriptableRuleBuilder.java Mon Jul 29 13:00:49 2013 @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The SF licenses this file + * to you 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 org.apache.sling.hc.rules.scriptable; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + +import org.apache.sling.hc.api.Evaluator; +import org.apache.sling.hc.api.Rule; +import org.apache.sling.hc.api.RuleBuilder; +import org.apache.sling.hc.api.SystemAttribute; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; + +/** RuleBuilder that builds scriptable rules. The qualifier + * indicates the scripting language extension (defaults to ecma) and + * the expression must evaluate to true. + * The rule name is only used for information, it is not used + * in building the rule. + */ +public class ScriptableRuleBuilder implements RuleBuilder { + + public static final String NAMESPACE = "script"; + private final BundleContext ctx; + + static private class ScriptedAttribute implements SystemAttribute { + + public static final String DEFAULT_LANGUAGE_EXTENSION = "ecma"; + + private final String extension; + private final String expression; + private final String name; + private final ScriptEngine scriptEngine; + private final String scriptEngineMsg; + + ScriptedAttribute(BundleContext ctx, String name, String qualifier, String expression) { + this.extension = qualifier == null || qualifier.length() == 0 ? DEFAULT_LANGUAGE_EXTENSION : qualifier; + this.expression = expression; + this.name = name; + + // Get a ScriptEngine for our language extension + final ServiceReference r = ctx.getServiceReference(ScriptEngineManager.class.getName()); + if(r != null) { + final ScriptEngineManager m = (ScriptEngineManager)ctx.getService(r); + scriptEngine = m.getEngineByExtension(extension); + if(scriptEngine == null) { + scriptEngineMsg = "ScriptEngine not found for extension '" + extension + "'"; + } else { + scriptEngineMsg = null; + } + } else { + scriptEngine = null; + scriptEngineMsg = "No ScriptEngineManager service available"; + } + + } + + @Override + public String toString() { + return NAMESPACE + ":" + extension + ":" + name; + } + + @Override + public Object getValue(Logger logger) { + if(scriptEngineMsg != null) { + logger.error("Cannot evaluate: {}", scriptEngineMsg); + } else { + try { + return scriptEngine.eval(expression); + } catch(ScriptException e) { + logger.error("Script evaluation error (" + expression + ")", e); + } + } + return null; + } + } + + static private class ExpectTrueEvaluator implements Evaluator { + @Override + public void evaluate(SystemAttribute a, String expression, Logger logger) { + final Object value = a.getValue(logger); + if(a instanceof ScriptedAttribute) { + final ScriptedAttribute sa = (ScriptedAttribute)a; + logger.debug("({}) [{}] is [{}]", new Object[] { sa.extension, sa.expression, value }); + } + if(value == null) { + logger.error("Got null value from {}", a); + } else if(!Boolean.TRUE.equals(value) && !"true".equals(value.toString())) { + logger.warn("Expected 'true' value, got '{}' from '{}'", value, a); + } else { + logger.debug("Got value '{}' from '{}'", value, a); + } + } + } + + public ScriptableRuleBuilder(BundleContext ctx) { + this.ctx = ctx; + } + + @Override + public Rule buildRule(String namespace, String ruleName, final String qualifier, String expression) { + if(!NAMESPACE.equals(namespace)) { + return null; + } + + return new Rule(new ScriptedAttribute(ctx, ruleName,qualifier, expression), expression, new ExpectTrueEvaluator()); + } +} \ No newline at end of file Added: sling/trunk/contrib/extensions/healthcheck/hc-rules/src/test/java/org/apache/sling/hc/rules/impl/ScriptableRuleBuilderTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-rules/src/test/java/org/apache/sling/hc/rules/impl/ScriptableRuleBuilderTest.java?rev=1508040&view=auto ============================================================================== --- sling/trunk/contrib/extensions/healthcheck/hc-rules/src/test/java/org/apache/sling/hc/rules/impl/ScriptableRuleBuilderTest.java (added) +++ sling/trunk/contrib/extensions/healthcheck/hc-rules/src/test/java/org/apache/sling/hc/rules/impl/ScriptableRuleBuilderTest.java Mon Jul 29 13:00:49 2013 @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The SF licenses this file + * to you 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 org.apache.sling.hc.rules.impl; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + +import org.apache.sling.hc.api.Rule; +import org.apache.sling.hc.api.RuleBuilder; +import org.apache.sling.hc.rules.scriptable.ScriptableRuleBuilder; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +public class ScriptableRuleBuilderTest { + private RuleBuilder builder; + private ServiceReference serviceReference; + private ScriptEngineManager scriptEngineManager; + private ScriptEngine scriptEngine; + + public static final String EXT = "test_ext"; + public static final String CODE = "this is the test code"; + public static final String NAME = "The rule name"; + + @Before + public void setup() throws ScriptException { + setupScriptEngine(false); + } + + private void setupScriptEngine(boolean active) throws ScriptException { + final BundleContext ctx = Mockito.mock(BundleContext.class); + builder = new ScriptableRuleBuilder(ctx); + + if(!active) { + scriptEngineManager = null; + serviceReference = null; + scriptEngine = null; + } else { + serviceReference = Mockito.mock(ServiceReference.class); + + scriptEngine = Mockito.mock(ScriptEngine.class); + Mockito.when(scriptEngine.eval(Matchers.same(CODE))).thenReturn("true"); + + scriptEngineManager = Mockito.mock(ScriptEngineManager.class); + Mockito.when( + scriptEngineManager.getEngineByExtension(Matchers.same(EXT))) + .thenReturn(scriptEngine); + } + + Mockito.when( + ctx.getServiceReference(Matchers.same(ScriptEngineManager.class.getName()))) + .thenReturn(serviceReference); + Mockito.when( + ctx.getService(Matchers.same(serviceReference))) + .thenReturn(scriptEngineManager); + } + + @Test + public void testNoServiceReference() { + final Rule r = builder.buildRule(ScriptableRuleBuilder.NAMESPACE, NAME, EXT, CODE); + assertTrue(r.evaluate().anythingToReport()); + } + + @Test + public void testNoScriptEngine() throws ScriptException { + setupScriptEngine(true); + final Rule r = builder.buildRule(ScriptableRuleBuilder.NAMESPACE, NAME, "bad_extension", CODE); + assertTrue(r.evaluate().anythingToReport()); + } + + @Test + public void testGoodScript() throws ScriptException { + setupScriptEngine(true); + final Rule r = builder.buildRule(ScriptableRuleBuilder.NAMESPACE, NAME, EXT, CODE); + assertFalse(r.evaluate().anythingToReport()); + } +} \ No newline at end of file Added: sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-ecma.json URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-ecma.json?rev=1508040&view=auto ============================================================================== --- sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-ecma.json (added) +++ sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-ecma.json Mon Jul 29 13:00:49 2013 @@ -0,0 +1,9 @@ +{ + "sling:resourceType" : "sling/healthcheck/rules", + "namespace": "script", + "ruleName": "Test javascript (ecma) rule", + "qualifier": "ecma", + "expression": "Math.round(2.6) == 3", + "tags" : ["script","javascript"], + "jcr:primaryType": "nt:unstructured" +} \ No newline at end of file Added: sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-groovy.json URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-groovy.json?rev=1508040&view=auto ============================================================================== --- sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-groovy.json (added) +++ sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/scripted-groovy.json Mon Jul 29 13:00:49 2013 @@ -0,0 +1,9 @@ +{ + "sling:resourceType" : "sling/healthcheck/rules", + "namespace": "script", + "ruleName": "Test Groovy rule", + "qualifier": "groovy", + "expression": "karre = { it * it } ; [ 1, 2, 3, 4 ].collect(karre)[2] == 9", + "tags" : ["script","groovy"], + "jcr:primaryType": "nt:unstructured" +} \ No newline at end of file