Invoking scripts in Alfresco programatically


I’m working on universal CRON runner, which runs scripts saved somewhere in repository (more on this next time). Running webscripts isn’t so easy, as I thought, there is no scriptService.runScriptWithThisDescription(path) method, so I did some research and got some results, which I’d like to share.

It’s possible to run java backed actions from js-webscripts. Everything you need is just a bean extending ActionExecuterAbstractBase with definition parent=“action-executer“ and it’s possible to access that bean from webscript like actions.create(„that_bean_id“). But not in reverse, at least not so simple.

First think I found was post on forum and advice to look at unit tests of webscripts, but everything I found were invocations through http. So I went deeper and figured out that Alfresco uses Rhino JavaScript implementation for scripts. At Rhino pages are good examples, so I had first working script soon. At following codelist I firstly load content of node (script body) from repository and then invocate script itself.

[code lang=“java“]
NodeRef nodeRef = new NodeRef("workspace://SpacesStore/4a96aaaa-bb80-eeee-aaaa-800a43fcddb8");
ContentReader contentReader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
InputStreamReader isr = new InputStreamReader(contentReader.getContentInputStream());
BufferedReader reader = new BufferedReader(isr);

Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
Object result = cx.evaluateReader(scope, reader, "scriptInvocation", 1, null);
} finally {
Context.exit();
}
[/code]

But I wanted something more – some model in and out and something simplier. So I found ScriptService. Now all those long lines can be ommited, because there is executeScript method!

[code lang=“java“]
Map<String, Object> model = new HashMap<String, Object>();
model.put("foo", "bar");

Object result = scriptService.executeScript(scriptRef, model);
[/code]

Template rendering (I’m using FreeMarker’s ftls) is done the same way, but through TemplateService and processTemplate(nodeRef, model) method, which accepts the same model (altered by script running).

The most beautiful thing is ability of script (and also template) to call java methods, which classes are „injected“ through model, let’s see an example.

[code lang=“java“]
Map<String, Object> model = new HashMap<String, Object>();

model.put("something", new Something());
model.put("bar", "foo");

Object result = scriptService.executeScript(scriptRef, model);
String templateResult = templateService.processTemplate("workspace://SpacesStore/noderef", model);

. . .

public class Something {
public String text = "aaa";

public String getText() {
return "bbb";
}
}
[/code]

Now it’s possible to use script / template:

[code lang=“javascript“]
(** script **)
bar = something.text;

(** template **)
${something.text} ?=? ${bar}
[/code]

What is output? Is in templateResult „aaa ?=? aaa“? Nope! Script accesses class attributes directly, on the other side template accesses methods. So output is „bbb ?=? aaa“!!!

One more important thing: this JavaScript implementation is just a stub, so every alfresco service needs to be „injected“ through model, so for example it’s impossible to run stuff like this without modifications:

[code lang=“javascript“]
var connector = remote.connect("http");
var result = connector.call("http://www.google.com/");
[/code]

Remote object has to be injected (this script is from Share/Surf), more on this in this blogpost. You have to add ScriptRemote to model and create spring-webscripts-config-custom.xml with endpoints defined, see that post. Also another services needs to be injected – to get access to repository, search service… good starting point is Alfresco Wiki.

Edit: Native Java API Access described in wiki is wrong, IT IS POSSIBLE to access maps in JavaScript like this:

[code lang=“javascript“]
var value = javaMap.key;
[/code]


4 komentáře: “Invoking scripts in Alfresco programatically”

  1. There is something related with this post that is driving us crazy:

    How can we execute a Java Class (like you are doing here from within a WebScript) but from within a .JS executed from an standard workflow ?!?!?!?

    Thanks !!!!!!!!

  2. I’m sorry Rodrigo, I’ve never programmed a workflow, so I have no idea :-).

  3. Yes, I meant Debug OFF, not ON. True, there is a min for JS, but not one for CSS.Thanks for replying.However, I am still wndenriog if a decent solution can be found to editing documentlist.get.config.xml and document-actions.get.config.xml. All I can think of is scripting this within Ant/Maven, inside the bigger build process (project-level).What I would like to know if Alfresco has a way of storing multiple such files in separate locations/jars that can be merged together. It would be nice to have something like documentlist-custom.get.config.xml containing only my action which could be appended to the global actions list. But maybe I am pushing for too much right now

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *