/* * * Copyright 2013 Netflix, Inc. * * 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.netflix.nicobar.example.groovy2; import static com.netflix.nicobar.example.groovy2.ExampleResourceLocator.GROOVY2_COMPILER_PLUGIN_CLASS; import static com.netflix.nicobar.example.groovy2.ExampleResourceLocator.GROOVY2_PLUGIN_ID; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import org.apache.commons.io.IOUtils; import com.netflix.hystrix.Hystrix; import com.netflix.nicobar.core.archive.JarScriptArchive; import com.netflix.nicobar.core.execution.HystrixScriptModuleExecutor; import com.netflix.nicobar.core.execution.ScriptModuleExecutable; import com.netflix.nicobar.core.module.BaseScriptModuleListener; import com.netflix.nicobar.core.module.ScriptModule; import com.netflix.nicobar.core.module.ScriptModuleLoader; import com.netflix.nicobar.core.module.ScriptModuleUtils; import com.netflix.nicobar.core.persistence.ArchiveRepository; import com.netflix.nicobar.core.persistence.ArchiveRepositoryPoller; import com.netflix.nicobar.core.persistence.JarArchiveRepository; import com.netflix.nicobar.core.plugin.ScriptCompilerPluginSpec; /** * Example of how to build a script runtime that polls for Groovy based archives on disk. * At the end of this example, there will be a the following classloaders * *<pre> * Bootstrap Classloader (/jre/lib) - virtual * ExtClassLoader (/jre/lib/exp) * AppClassLoader (nicobar-core, nicobar-example) * Groovy2RuntimeModule (nicobar-groovy2, groovy-all.jar) * HelloWorld (HelloWorld.class) * </pre> * @author James Kojo */ public class GroovyModuleLoaderExample { // test script module info private static final String SCRIPT_MODULE_ID = "HelloWorld"; private static final String ARCHIVE_JAR_NAME = "HelloWorld.jar"; public static void main(String[] args) throws Exception { new GroovyModuleLoaderExample().runExample(); } public void runExample() throws Exception { // create the loader with the groovy plugin ScriptModuleLoader moduleLoader = new ScriptModuleLoader.Builder() .addPluginSpec(new ScriptCompilerPluginSpec.Builder(GROOVY2_PLUGIN_ID) // configure Groovy plugin .addRuntimeResource(ExampleResourceLocator.getGroovyRuntime()) .addRuntimeResource(ExampleResourceLocator.getGroovyPluginLocation()) .withPluginClassName(GROOVY2_COMPILER_PLUGIN_CLASS) .build()) .addListener(new BaseScriptModuleListener() { // add an example listener for module updates public void moduleUpdated(ScriptModule newScriptModule, ScriptModule oldScriptModule) { System.out.printf("Received module update event. newModule: %s, oldModule: %s%n", newScriptModule, oldScriptModule); } }) .build(); // create an archive repository and wrap a poller around it to feed updates to the module loader Path baseArchiveDir = Files.createTempDirectory(GroovyModuleLoaderExample.class.getSimpleName()); JarArchiveRepository repository = new JarArchiveRepository.Builder(baseArchiveDir).build(); deployTestArchive(repository); ArchiveRepositoryPoller poller = new ArchiveRepositoryPoller.Builder(moduleLoader).build(); poller.addRepository(repository, 30, TimeUnit.SECONDS, true); // the test module has now been compiled and is ready for execution. // create a closure which knows how to bind any request time inputs (if any) and execute the module. ScriptModuleExecutable<String> executable = new ScriptModuleExecutable<String>() { @Override public String execute(ScriptModule scriptModule) throws Exception { // the script doesn't necessarily have to implement any specific interfaces, but it does need to // be compilable to a class. Class<?> callable = ScriptModuleUtils.findAssignableClass(scriptModule, Callable.class); @SuppressWarnings("unchecked") Callable<String> instance = (Callable<String>) callable.newInstance(); String result = instance.call(); return result; } }; // Execute it in a Hystrix command. HystrixScriptModuleExecutor<String> executor = new HystrixScriptModuleExecutor<String>("TestModuleExecutor"); List<String> results = executor.executeModules(Collections.singletonList(SCRIPT_MODULE_ID), executable, moduleLoader); System.out.println("Module(s) have been executed. Output: " + results); // release the Hystrix resources Hystrix.reset(); } /* * Copy the example script module files to temporary directory and insert it into the repository */ private static void deployTestArchive(ArchiveRepository repository) throws IOException { InputStream archiveJarIs = GroovyModuleLoaderExample.class.getClassLoader().getResourceAsStream(ARCHIVE_JAR_NAME); Path archiveToDeploy = Files.createTempFile(SCRIPT_MODULE_ID, ".jar"); Files.copy(archiveJarIs, archiveToDeploy, StandardCopyOption.REPLACE_EXISTING); IOUtils.closeQuietly(archiveJarIs); JarScriptArchive jarScriptArchive = new JarScriptArchive.Builder(archiveToDeploy).build(); repository.insertArchive(jarScriptArchive); } }