Search code examples
javagroovygroovyshellgroovyscriptengine

How to load groovy scripts from within the jar file?


I am using groovy to execute a set of groovy scripts, which works fine when the runtime jar is deployed with the webapp and the runtime executes the groovy scripts present under C:\jboss-eap-7.4\bin (java working directory). Due to portability and other constraints now we need to move these groovy scripts as part of the runtime jar and then load and execute these scripts from the class path.

Can anyone help in running the groovy scripts present inside the runtime jar file (within the webapp)?

enter image description here

The current implementation that executes the groovy scripts from C:\jboss-eap-7.4\bin (java working directory)

** Updated after aswer given by GPT-3**

final String PLUGIN_DESCRIPTOR = "Plugins.groovy"
    final class PluginBootStrapper 
{
    private GroovyScriptEngine scriptEngine = null;
    private GroovyShell shell;
    private GroovyClassLoader classLoader = null;
    private final boolean loadFromClasspath;

    private final List<Plugin> allPlugins = null;
    
    private static final Logger logger = LogManager.getLogger(PluginBootStrapper.class);
    
    public PluginBootStrapper() 
    {
        System.out.println("Inside PluginBootStrapper")
        logger.info("Inside PluginBootStrapper")
        String pluginsDir = System.getProperty(CSMProperties.endorsed_plugins_dir)//".\\plugins"//System.getProperty(CSMProperties.endorsed_plugins_dir)
        loadFromClasspath = true
        shell =  new GroovyShell();
        //scriptEngine = new GroovyScriptEngine(CommonUtils.getAllDirectories(pluginsDir))

        logger.info "Plugins Directory:"+pluginsDir
        println "Plugins Directory:"+pluginsDir
        
        allPlugins = loadDescriptor().invokeMethod("getAllPlugins", null)       
    }
    
    private Object loadDescriptor()
    {
        Object pluginDescriptor = bootStrapScript(CSMProperties.get(CSMProperties.PLUGIN_DESCRIPTOR))                                                                
        pluginDescriptor                         
    }
        
    Object bootStrapScript(String script)
    {
        String pluginsDir = System.getProperty(CSMProperties.endorsed_plugins_dir)
        if (pluginsDir != null) {
            script = pluginsDir + script
        }
        
        printClassPath(this.class.getClassLoader())

        Object pluginScript = null
        //logger.info "script: "+ script
        //String path = this.getClass().getClassLoader().getResource(script).toExternalForm()
        //logger.info "bootStrapScript script "+ script
        logger.info "bootStrapScript script: "+ script + ", path: "+ new File(script).absolutePath
        println "bootStrapScript script: "+ script + ", path: "+ new File(script).absolutePath
        if (this.loadFromClasspath) {
            pluginScript = new GroovyShell(this.class.getClassLoader()).evaluate(new File(script));     //<-- Line no:60
            /* classLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader());
            pluginScript = classLoader.parseClass(new File(script)); */
            return pluginScript
        } else {
            pluginScript = scriptEngine.loadScriptByName(script).newInstance()
            return pluginScript
        }
        
        return pluginScript
    }
    
    public List<Plugin> getAllPlugins()
    {
        return allPlugins
    }

    def printClassPath(classLoader) {
        println "$classLoader"
        classLoader.getURLs().each {url->
            println "- ${url.toString()}"
        }
        if (classLoader.parent) {
            printClassPath(classLoader.parent)
        }
    }
    
}

CommonUtils.getAllDirectories method

public static String[] getAllDirectories(String directory)
{
    logger.info("Inside CommonUtils"+directory)
    def dir = new File(directory)
    def dirListing = []
    if (dir.exists()) {
        logger.info "Looking for plugins in "+dir.absolutePath+" directory."
        
        dir.eachFileRecurse {file->
             if(file.isDirectory()) {
                 dirListing << file.getPath()
                 logger.info "Using "+file.getPath()+" plugin folder."
             } else {
                 logger.info "Using "+file.getPath()+" plugin file."
             }
        }
    } else {
        logger.error directory+" folder does not exist. Please provide the plugin files."
    }
    
    dirListing.toArray() as String []
}

Test Run Command: java -cp runtime-2.0-jar-with-dependencies.jar;.runtime-2.0-jar-with-dependencies.jar; -Dendorsed_plugins_dir=runtime-2.0-jar-with-dependencies.jar\ com.Main %*

Output enter image description here

** Old Update**

At present with the above code, if I place the plugins folder (groovy script) inside the jar, it says it cannot find Plugins.groovy under C:\jboss-eap-7.4\bin folder

Screenshot of jar inside war file C:\Users\ricky\Desktop\siperian-mrm.ear\mysupport.war\WEB-INF\lib\runtime.jar\ enter image description here


Solution

  • The answers provided above are also correct, particularly those provided by @daggett, as they include multiple ways to read/access a resource from within a jar file. I'm sharing my version, which has been tested on this codebase.

    I made the following changes

    1. Placed all the scripts inside "plugins" folder.

    enter image description here

    1. Modified the pom.xml to include the "plugins" folder instead of individual groovy scripts. <include>plugins/</include>

    2. Using getResourceAsStream something like below to read the scripts.

      StringBuilder pluginsDir = new StringBuilder(System.getProperty("plugins_dir").toString()) String script = pluginsDir.append(script) InputStream inputStream = getClass().getResourceAsStream(script) BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)) pluginScript = groovyShell.parse(reader); return pluginScript

    3. Using below command to run

      java -cp mvn-groovy-test-example-1.0-jar-with-dependencies.jar; -Dplugins_dir=/plugins/ com.example.App

    enter image description here