/*
* RHQ Management Platform
* Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.scripting.javascript;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.io.FilePermission;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Method;
import java.net.URI;
import java.security.Permissions;
import java.util.Collections;
import java.util.HashSet;
import java.util.PropertyPermission;
import java.util.Set;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import org.testng.annotations.Test;
import org.rhq.scripting.ScriptEngineInitializer;
import org.rhq.scripting.ScriptSourceProvider;
/**
*
*
* @author Lukas Krejci
*/
@Test
public class InitializerTest {
//for Rhino to see this class, it must be public
public static class TestClass {
public boolean[] functionsCalled;
public TestClass() {
functionsCalled = new boolean[6];
}
public void func1() {
functionsCalled[0] = true;
}
public void func2() {
functionsCalled[1] = true;
}
public void func3() {
functionsCalled[2] = true;
}
public void func3(int a, int b) {
functionsCalled[3] = true;
}
public void func3(String a, String b) {
functionsCalled[4] = true;
}
public void func3(int a, int b, int c) {
functionsCalled[5] = true;
}
}
public void engineSecured() throws Exception {
Permissions perms = new Permissions();
//we need to be able to read files and props so that the default module source provider can work
perms.add(new FilePermission("<<ALL FILES>>", "read"));
perms.add(new PropertyPermission("*", "read"));
ScriptEngine eng = new JsEngineInitializer().instantiate(Collections.<String>emptySet(), perms);
try {
eng.eval("java.lang.System.exit(1)");
} catch (Exception e) {
assertSecurityExceptionPresent(e);
}
}
public void scriptSourceProviderApplied() throws Exception {
String script = "var m = require('rhq:/test-module1'); m.func1();";
//first let's try to find the scripts with the default source provider...
ScriptEngine eng = new JsEngineInitializer().instantiate(Collections.<String>emptySet(), null);
try {
eng.eval(script);
fail("The module should not have been loaded using the default source provider.");
} catch (ScriptException e) {
//expected
}
eng = new JsEngineInitializer().instantiate(Collections.<String>emptySet(), null);
new JsEngineInitializer().installScriptSourceProvider(eng, new ScriptSourceProvider() {
@Override
public Reader getScriptSource(URI location) {
if (!"rhq".equals(location.getScheme())) {
return null;
}
String scriptName = location.getPath().substring(1); //remove the '/'
InputStream src = getClass().getClassLoader().getResourceAsStream(scriptName);
return new InputStreamReader(src);
}
});
try {
eng.eval(script);
} catch (ScriptException e) {
fail("The module should have been loaded using the custom source provider. Error message: " + e.getMessage(), e);
}
}
public void indirectionMethodsValid() throws Exception {
JsEngineInitializer initializer = new JsEngineInitializer();
ScriptEngine eng = initializer.instantiate(Collections.<String>emptySet(), null);
TestClass myObject = new TestClass();
eng.put("myObject", myObject);
generateIndirectionMethods(initializer, eng, myObject, "myObject", "func1");
generateIndirectionMethods(initializer, eng, myObject, "myObject", "func2");
generateIndirectionMethods(initializer, eng, myObject, "myObject", "func3");
eng.eval("func1(); func2(); func3(); func3(1, 1); func3('a', 'b'); func3(1, 1, 1);");
assertTrue(myObject.functionsCalled[0], "Function func1() should have been called.");
assertTrue(myObject.functionsCalled[1], "Function func2() should have been called.");
assertTrue(myObject.functionsCalled[2], "Function func3() should have been called.");
assertTrue(myObject.functionsCalled[3], "Function func3(int, int) should have been called.");
assertTrue(myObject.functionsCalled[4], "Function func3(String, String) should have been called.");
assertTrue(myObject.functionsCalled[5], "Function func3(int, int, int) should have been called.");
}
private void assertSecurityExceptionPresent(Throwable t) {
boolean ok = false;
while (t != null) {
if (t instanceof SecurityException) {
ok = true;
break;
} else if ((t instanceof ScriptException) &&
(t.getMessage().contains("java.security.AccessControlException")
|| t.getMessage().contains("java.lang.SecurityException"))) {
ok = true;
break;
}
t = t.getCause();
}
assertTrue(ok, "Didn't find a SecurityException, which should have occured.");
}
private void generateIndirectionMethods(ScriptEngineInitializer initializer, ScriptEngine eng, Object object, String objectName, String methodName) throws ScriptException {
Set<Method> methods = new HashSet<Method>();
for(Method m : object.getClass().getDeclaredMethods()) {
if (methodName.equals(m.getName())) {
methods.add(m);
}
}
eng.put(objectName, object);
for(String m : initializer.generateIndirectionMethods(objectName, methods)) {
eng.eval(m);
}
}
}