Loading javascript files from deployment using load()?

Anyone have a pattern for loading a JS file into load() using using Javascript scripting engine?

by default you can use:

load('path/url to JS file');

But you can also do load({script: "my script wrapped in a string", name: "myscript.js"});

I was getting the bytes[] of the js file i deployed along side of the bpmn file. But i cannot seem to get the bytes to convert to a string.

Looking for other patterns that you may have used as well.

I have loaded the file from a URL, but there seems to be a relatively “significant” delay for the file to load from a url.

With from deployment, do you mean deployment in terms of Camunda API or application deployment (e.g. WAR file)?

@thorben: deployment from camunda API

Given that you have the bytes of the deployment resource, here is how you convert it to a String in Nashorn Javascript:

var String = Java.type("java.lang.String");
load({ script: new String("print('hello')".getBytes("UTF-8"), "UTF-8"), name: "myscript.js"});

@thorben

So if i have something like:

var processDefinitionId = execution.getProcessDefinitionId();
var deploymentId = execution.getProcessEngineServices().getRepositoryService().getProcessDefinition(processDefinitionId).getDeploymentId();
var resources = execution.getProcessEngineServices().getRepositoryService().getDeploymentResources(deploymentId);

var file = '';
for each (var resource in resources){
   if (resource.getName() == 'my-script.js'){
      file = resource.getBytes('UTF-8');
   }
}

var String = Java.type("java.lang.String");
load({ script: new String(file, "UTF-8"), name: "my-script.js"});

You expect this to work?

The load() / conversion into a string will not seem to read the bytes returned by getDeploymentResources

Hi Stephen,

I believe Resource#getBytes has no String argument. If you remove that, it might work (although Resource#getBytes is not public API, so if you want to stay with public API, you should go via RepositoryService#getResourceAsStream. What is the error you get when you try this?

Cheers,
Thorben

var processDefinitionId = execution.getProcessDefinitionId();

var deploymentId = execution.getProcessEngineServices().getRepositoryService().getProcessDefinition(processDefinitionId).getDeploymentId();

var resource = execution.getProcessEngineServices().getRepositoryService().getResourceAsStream(deploymentId, 'my-script.js');

var String = Java.type("java.lang.String");
load({ script: new String(resource, "UTF-8"), name: "my-script.js"});

resource returns a java.io.ByteArrayInputStream

But the above code also fails.

Exception while closing command context: java.lang.NoSuchMethodException: None of the fixed arity signatures [(byte[], java.lang.String), (byte[], int)] of method java.lang.String.<init> match the argument types [java.io.ByteArrayInputStream, java.lang.String]
 java.lang.RuntimeException: java.lang.NoSuchMethodException: None of the fixed arity signatures [(byte[], java.lang.String), (byte[], int)] of method java.lang.String.<init> match the argument types [java.io.ByteArrayInputStream, java.lang.String]

I am no Java expert. So I may be missing something here. But based on my understanding, and other java examples I have looked at, this should work?

You are missing code that reads the input stream into a byte array. This is surprisingly painful in plain Java. I think Apache’s IOUtils have convenience methods for that. See for example https://stackoverflow.com/questions/1264709/convert-inputstream-to-byte-array-in-java. Also, for the sake of quick testing, what happens when you use Resource#getBytes?

Ha! yes tried getBytes ;). NoMethodFound

@thorben okay this works to render the file:

var processDefinitionId = execution.getProcessDefinitionId();

var deploymentId = execution.getProcessEngineServices().getRepositoryService().getProcessDefinition(processDefinitionId).getDeploymentId();

var resource = execution.getProcessEngineServices().getRepositoryService().getResourceAsStream(deploymentId, 'my-script.js');

var IOUtils = Java.type('org.apache.commons.io.IOUtils');
var String = Java.type('java.lang.String');

load({ script: new String(IOUtils.toByteArray(resource), 'UTF-8'), name: 'my-script.js'}); 

1 Like

Cool. Perhaps you can extract this logic into a separate Javascript file, put it somewhere on the shared classpath and then load your loader utility via load('classpath:path/to/resourceLoader.js')'. That would keep the logic in one place. See https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions (load section) for all the ways how to load scripts in Nashorn.

1 Like

Good idea. Knew about the feature, but had not thought about that use case!

One problem i have noticed with the load({ script: new String(IOUtils.toByteArray(resource), 'UTF-8'), name: 'my-script.js'}); strategy is that the JS file is loaded differently than with use load('http://...'). Seems to be mainly issues with escaping quotes.

Just a FYI for anyone that comes across this.