/* * Copyright (C) 2009 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.services.jcr.ext.script.groovy; import org.exoplatform.services.jcr.ext.app.SessionProviderService; import org.exoplatform.services.jcr.ext.common.SessionProvider; import org.exoplatform.services.jcr.ext.registry.RESTRegistryTest.DummyContainerResponseWriter; import org.exoplatform.services.jcr.ext.resource.UnifiedNodeReference; import org.exoplatform.services.jcr.ext.script.groovy.GroovyScript2RestLoader.ScriptMetadata; import org.exoplatform.services.rest.RequestHandler; import org.exoplatform.services.rest.ext.method.filter.MethodAccessFilter; import org.exoplatform.services.rest.impl.ContainerResponse; import org.exoplatform.services.rest.impl.EnvironmentContext; import org.exoplatform.services.rest.impl.MultivaluedMapImpl; import org.exoplatform.services.rest.impl.ProviderBinder; import org.exoplatform.services.rest.impl.ResourceBinder; import org.exoplatform.services.rest.tools.ByteArrayContainerResponseWriter; import org.exoplatform.services.rest.tools.DummySecurityContext; import org.exoplatform.services.rest.tools.ResourceLauncher; import org.exoplatform.services.security.ConversationState; import org.exoplatform.services.security.Identity; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.security.Principal; import java.util.Calendar; import java.util.HashSet; import java.util.Set; import javax.jcr.Node; import javax.jcr.query.Query; import javax.jcr.query.QueryResult; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.SecurityContext; /** * @author <a href="mailto:andrew00x@gmail.com">Andrey Parfonov</a> * @version $Id: $ */ public class GroovyScript2RestLoaderTest extends BaseGroovyTest { private Node testRoot; private ResourceBinder binder; private SessionProviderService sesProv; private Node scriptFile; private Node script; private Node groovyRepo; private int resourceNumber = 0; private ResourceLauncher launcher; private SecurityContext adminSecurityContext; /** * {@inheritDoc} */ public void setUp() throws Exception { super.setUp(); sesProv = (SessionProviderService)container .getComponentInstanceOfType(SessionProviderService.class); sesProv.setSessionProvider(null, new SessionProvider(new ConversationState(new Identity("root")))); binder = (ResourceBinder)container.getComponentInstanceOfType(ResourceBinder.class); resourceNumber = binder.getSize(); RequestHandler handler = (RequestHandler)container.getComponentInstanceOfType(RequestHandler.class); testRoot = root.addNode("testRoot", "nt:unstructured"); scriptFile = testRoot.addNode("script", "nt:file"); script = scriptFile.addNode("jcr:content", "exo:groovyResourceContainer"); script.setProperty("exo:autoload", true); script.setProperty("jcr:mimeType", "script/groovy"); script.setProperty("jcr:lastModified", Calendar.getInstance()); script .setProperty("jcr:data", Thread.currentThread().getContextClassLoader().getResourceAsStream("test1.groovy")); // repository for groovy dependencies groovyRepo = root.addNode("repo", "nt:folder"); launcher = new ResourceLauncher(handler); ProviderBinder.setInstance(new ProviderBinder()); ProviderBinder providers = ProviderBinder.getInstance(); providers.addMethodInvokerFilter(new MethodAccessFilter()); session.save(); Set<String> adminRoles = new HashSet<String>(); adminRoles.add("administrators"); adminSecurityContext = new DummySecurityContext(new Principal() { public String getName() { return "root"; } }, adminRoles); } public void testStartQuery() throws Exception { String xpath = "//element(*, " + "exo:groovyResourceContainer" + ")[@exo:autoload='true']"; Query query = session.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH); QueryResult result = query.execute(); assertEquals(1, result.getNodes().getSize()); script.setProperty("exo:autoload", false); session.save(); result = query.execute(); assertEquals(0, result.getNodes().getSize()); } public void testBindScripts() throws Exception { assertEquals(resourceNumber + 1, binder.getSize()); script.getParent().remove(); session.save(); assertEquals(resourceNumber, binder.getSize()); } public void testGetMetatData() throws Exception { MultivaluedMap<String, String> headers = new MultivaluedMapImpl(); headers.putSingle("Accept", MediaType.APPLICATION_JSON); ContainerResponse response = launcher.service("POST", "/script/groovy/meta/db1/ws/testRoot/script", "", headers, null, null); assertEquals(200, response.getStatus()); ScriptMetadata data = (ScriptMetadata)response.getEntity(); assertEquals("script/groovy", data.getMediaType()); assertTrue(Boolean.valueOf(data.getLoad())); } public void testAutoload() throws Exception { ContainerResponse cres = launcher.service("POST", "/script/groovy/autoload/db1/ws/testRoot/script?state=false", "", null, null, null); assertEquals(204, cres.getStatus()); assertFalse(script.getProperty("exo:autoload").getBoolean()); cres = launcher.service("POST", "/script/groovy/autoload/db1/ws/testRoot/script", "", null, null, null); assertEquals(204, cres.getStatus()); assertTrue(script.getProperty("exo:autoload").getBoolean()); } public void testLoad() throws Exception { EnvironmentContext ctx = new EnvironmentContext(); ctx.put(SecurityContext.class, adminSecurityContext); ContainerResponse cres = launcher.service("POST", "/script/groovy/load/db1/ws/testRoot/script?state=false", "", null, null, ctx); assertEquals(204, cres.getStatus()); assertEquals(resourceNumber, binder.getSize()); launcher.service("POST", "/script/groovy/load/db1/ws/testRoot/script", "", null, null, ctx); assertEquals(204, cres.getStatus()); assertEquals(resourceNumber + 1, binder.getSize()); } public void testLoadNoExtClassPath() throws Exception { String path = createScript(testRoot, "test.load", "Test000.groovy", // "import test.load.User000\n" + // "@javax.ws.rs.Path('test/load') class Test000 {\n" + // "def user = new User000(name:'test')\n" + // "@javax.ws.rs.GET def m() {user}" + // "}\n"); EnvironmentContext ctx = new EnvironmentContext(); ctx.put(SecurityContext.class, adminSecurityContext); int before = binder.getSize(); ContainerResponse cres = launcher.service("POST", "/script/groovy/load/db1/ws" + path, "", null, null, ctx); assertEquals(400, cres.getStatus()); int after = binder.getSize(); assertEquals(before, after); } public void testLoadExtClassPath_File() throws Exception { String scriptPath = createScript(testRoot, "test.load", "Test001.groovy", // "import test.load.User001\n" + // "@javax.ws.rs.Path('test/load_001') class Test001 {\n" + // "def user = new User001(name:'test')\n" + // "@javax.ws.rs.GET def m() {user}" + // "}\n"); String user = createScript(testRoot, "test.load", "User001.groovy",// "package test.load\n" + // "class User001 {def name}"); EnvironmentContext ctx = new EnvironmentContext(); ctx.put(SecurityContext.class, adminSecurityContext); String path = "/script/groovy/load/db1/ws" + scriptPath // + "?file=" // + URLEncoder.encode(new UnifiedNodeReference(repository.getName(), workspace.getName(), user).getURL() .toString(), "UTF-8"); int before = binder.getSize(); ContainerResponse cres = launcher.service("POST", path, "", null, null, ctx); assertEquals(204, cres.getStatus()); int after = binder.getSize(); assertEquals(before + 1, after); } public void testLoadExtClassPath_SourceFolder() throws Exception { String scriptPath = createScript(testRoot, "test.load", "Test002.groovy", // "import test.load.User002\n" + // "@javax.ws.rs.Path('test/load_002') class Test002 {\n" + // "def user = new User002(name:'test')\n" + // "@javax.ws.rs.GET def m() {user}" + // "}\n"); createScript(testRoot, "test.load", "User002.groovy",// "package test.load\n" + // "class User002 {def name}"); EnvironmentContext ctx = new EnvironmentContext(); ctx.put(SecurityContext.class, adminSecurityContext); String path = "/script/groovy/load/db1/ws" + scriptPath // + "?sources=" // + URLEncoder.encode(new UnifiedNodeReference(repository.getName(), workspace.getName(), testRoot.getPath()) .getURL().toString(), "UTF-8"); int before = binder.getSize(); ContainerResponse cres = launcher.service("POST", path, "", null, null, ctx); assertEquals(204, cres.getStatus()); int after = binder.getSize(); assertEquals(before + 1, after); } public void testDelete() throws Exception { ContainerResponse cres = launcher.service("POST", "/script/groovy/delete/db1/ws/testRoot/script", "", null, null, null); assertEquals(204, cres.getStatus()); assertEquals(resourceNumber, binder.getSize()); } public void testGetScript() throws Exception { MultivaluedMap<String, String> headers = new MultivaluedMapImpl(); headers.putSingle("Accept", "script/groovy"); ByteArrayContainerResponseWriter wr = new ByteArrayContainerResponseWriter(); ContainerResponse cres = launcher.service("POST", "/script/groovy/src/db1/ws/testRoot/script", "", headers, null, wr, null); assertEquals(200, cres.getStatus()); compareStream(script.getProperty("jcr:data").getStream(), new ByteArrayInputStream(wr.getBody())); } public void testAddScript() throws Exception { script.getParent().remove(); session.save(); MultivaluedMap<String, String> headers = new MultivaluedMapImpl(); headers.putSingle("Content-type", "script/groovy"); ContainerResponse cres = launcher.service("POST", "/script/groovy/add/db1/ws/testRoot/script", "", headers, getResourceAsBytes("test1.groovy"), null, null); assertEquals(201, cres.getStatus()); } public void testDispatchScript() throws Exception { ContainerResponse cres = launcher.service("GET", "/groovy-test/groovy1/test", "", null, null, null); assertEquals(200, cres.getStatus()); assertEquals("Hello from groovy to test", cres.getEntity()); // change script source code script .setProperty("jcr:data", Thread.currentThread().getContextClassLoader().getResourceAsStream("test2.groovy")); session.save(); // must be rebounded , not created other one assertEquals(resourceNumber + 1, binder.getSize()); cres = new ContainerResponse(new DummyContainerResponseWriter()); cres = launcher.service("GET", "/groovy-test/groovy2/test", "", null, null, null); assertEquals(200, cres.getStatus()); assertEquals("Hello from groovy to >>>>> test", cres.getEntity()); } public void testValidate() throws Exception { MultivaluedMap<String, String> headers = new MultivaluedMapImpl(); headers.putSingle("Content-Type", "script/groovy"); String script = "public class Test { def a = 0\ndef =\n}\n"; ContainerResponse cres = launcher.service("POST", "/script/groovy/validate/%5Bno-name%5D", "", headers, script.getBytes(), null); assertEquals(400, cres.getStatus()); script = "public class Test { def a = 0\ndef b = 1\n }\n"; cres = launcher.service("POST", "/script/groovy/validate/%5Bno-name%5D", "", headers, script.getBytes(), null); assertEquals(200, cres.getStatus()); } public void testValidateNoname() throws Exception { MultivaluedMap<String, String> headers = new MultivaluedMapImpl(); headers.putSingle("Content-Type", "script/groovy"); String script = "public class Test { def a = 0\ndef =\n}\n"; ContainerResponse cres = launcher.service("POST", "/script/groovy/validate/", "", headers, script.getBytes(), null); assertEquals(400, cres.getStatus()); script = "public class Test { def a = 0\ndef b = 1\n }\n"; cres = launcher.service("POST", "/script/groovy/validate/", "", headers, script.getBytes(), null); assertEquals(200, cres.getStatus()); } public void testValidateNoExtClassPath() throws Exception { MultivaluedMap<String, String> headers = new MultivaluedMapImpl(); headers.putSingle("Content-Type", "script/groovy"); String script = "import test.validate.User000\n" + // "@javax.ws.rs.Path('test/validate') class Test {\n" + // "def user = new User000(name:'test')\n" + // "@javax.ws.rs.GET def m() {user}" + // " }\n"; ContainerResponse cres = launcher.service("POST", "/script/groovy/validate/Test", "", headers, script.getBytes(), null); assertEquals(400, cres.getStatus()); } public void testValidateExtClassPath_File() throws Exception { MultivaluedMap<String, String> headers = new MultivaluedMapImpl(); headers.putSingle("Content-Type", "script/groovy"); String script = "import test.validate.User001\n" + // "@javax.ws.rs.Path('test/validate') class Test {\n" + // "def user = new User001(name:'test')\n" + // "@javax.ws.rs.GET def m() {user}" + // " }\n"; String user = createScript(testRoot, "test.validate", "User001.groovy",// "package test.validate\n" + // "class User001 {def name}"); // Specify source file location. String path = "/script/groovy/validate/Test?file=" // + URLEncoder.encode(new UnifiedNodeReference(repository.getName(), workspace.getName(), user).getURL() .toString(), "UTF-8"); ContainerResponse cres = launcher.service("POST", path, "", headers, script.getBytes(), null); assertEquals(200, cres.getStatus()); } public void testValidateExtClassPath_SourceFolder() throws Exception { MultivaluedMap<String, String> headers = new MultivaluedMapImpl(); headers.putSingle("Content-Type", "script/groovy"); String script = "import test.validate.User002\n" + // "@javax.ws.rs.Path('test/validate') class Test {\n" + // "def user = new User002(name:'test')\n" + // "@javax.ws.rs.GET def m() {user}" + // " }\n"; createScript(testRoot, "test.validate", "User002.groovy",// "package test.validate\n" + // "class User002 {def name}"); // Specify source folder location. String path = "/script/groovy/validate/Test?sources=" // + URLEncoder.encode(new UnifiedNodeReference(repository.getName(), workspace.getName(), testRoot.getPath()) .getURL().toString(), "UTF-8"); ContainerResponse cres = launcher.service("POST", path, "", headers, script.getBytes(), null); assertEquals(200, cres.getStatus()); } public void testGroovyDependency() throws Exception { // Add script in dependency repository createScript(groovyRepo, "dependencies", "Dep1.groovy", // "package dependencies\n" + // "class Dep1 { String name = getClass().getName() }"); script.setProperty("jcr:data", Thread.currentThread().getContextClassLoader().getResourceAsStream("TestDependency.groovy")); session.save(); // must be rebounded , not created other one assertEquals(resourceNumber + 1, binder.getSize()); ContainerResponse cres = launcher.service("GET", "/groovy-test-dependency", "", null, null, null); assertEquals(200, cres.getStatus()); assertEquals("dependencies.Dep1", cres.getEntity()); } private byte[] getResourceAsBytes(String resource) throws IOException { byte[] data = null; InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource); if (stream != null) { ByteArrayOutputStream bout = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; int r = -1; while ((r = stream.read(buf)) != -1) bout.write(buf, 0, r); data = bout.toByteArray(); } return data; } }