Skip to content

Commit

Permalink
JENKINS-17910 - groovy.lang.MissingMethodException
Browse files Browse the repository at this point in the history
Updates to how missingMethod is handled
  • Loading branch information
gcummings committed May 22, 2013
1 parent 9aae5d2 commit 9d37d81
Showing 1 changed file with 62 additions and 66 deletions.
Expand Up @@ -5,6 +5,7 @@
import groovy.lang.Binding;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import groovy.text.SimpleTemplateEngine;
import hudson.model.AbstractBuild;
import hudson.model.Hudson;
Expand Down Expand Up @@ -122,68 +123,6 @@ private InputStream getFileInputStream(String fileName)
return inputStream;
}


private class MethodMissingHandler {
private AbstractBuild<?, ?> build;
private TaskListener listener;

public MethodMissingHandler(AbstractBuild<?,?> build, TaskListener listener) {
this.build = build;
this.listener = listener;
}

private void populateArgs(Object args, Map<String, String> map, ListMultimap<String, String> multiMap) {
if(args instanceof Object[]) {
Object[] argArray = (Object[])args;
if(argArray.length > 0) {
Map<String, Object> argMap = (Map<String, Object>)argArray[0];
for(Map.Entry<String, Object> entry : argMap.entrySet()) {
String value = entry.getValue().toString();
if(entry.getValue() instanceof List) {
List valueList = (List)entry.getValue();
for(Object v : valueList) {
multiMap.put(entry.getKey(), v.toString());
}
value = valueList.get(valueList.size() - 1).toString();
} else {
multiMap.put(entry.getKey(), value);
}
map.put(entry.getKey(), value);
}
}
}
}

public Object methodMissing(String name, Object args)
throws MacroEvaluationException, IOException, InterruptedException {
TokenMacro macro = null;
for(TokenMacro m : TokenMacro.all()) {
if(m.acceptsMacroName(name)) {
macro = m;
break;
}
}

if(macro == null) {
for(TokenMacro m : ContentBuilder.getPrivateMacros()) {
if(m.acceptsMacroName(name)) {
macro = m;
break;
}
}
}

if(macro != null) {
Map<String, String> argsMap = new HashMap<String, String>();
ListMultimap<String, String> argsMultimap = ArrayListMultimap.create();
populateArgs(args, argsMap, argsMultimap);

return macro.evaluate(build, listener, name, argsMap, argsMultimap);
}
return String.format("[Could not find content token (check your usage): %s]", name);
}
}

/**
* Renders the template using a SimpleTemplateEngine
*
Expand All @@ -202,11 +141,8 @@ private String renderTemplate(AbstractBuild<?, ?> build, TaskListener listener,
binding.put("rooturl", ExtendedEmailPublisher.DESCRIPTOR.getHudsonUrl());
binding.put("project", build.getParent());

MethodMissingHandler handler = new MethodMissingHandler(build, listener);

// we add the binding to the SimpleTemplateEngine instead of the shell
GroovyShell shell = createEngine(Collections.singletonMap("methodMissing", (Object)InvokerHelper.getMethodPointer(handler, "methodMissing")));
shell.evaluate("Script.metaClass.methodMissing = methodMissing");
GroovyShell shell = createEngine(Collections.EMPTY_MAP);
SimpleTemplateEngine engine = new SimpleTemplateEngine(shell);
return engine.createTemplate(new InputStreamReader(templateStream)).make(binding).toString();
}
Expand Down Expand Up @@ -250,6 +186,7 @@ private GroovyShell createEngine(Map<String, Object> variables)
ClassLoader cl = Jenkins.getInstance().getPluginManager().uberClassLoader;
ScriptSandbox sandbox = null;
CompilerConfiguration cc = new CompilerConfiguration();
cc.setScriptBaseClass(EmailExtScript.class.getCanonicalName());
cc.addCompilationCustomizers(new ImportCustomizer().addStarImports(
"jenkins",
"jenkins.model",
Expand Down Expand Up @@ -277,4 +214,63 @@ private GroovyShell createEngine(Map<String, Object> variables)
public boolean hasNestedContent() {
return false;
}

public static abstract class EmailExtScript extends Script {

private void populateArgs(Object args, Map<String, String> map, ListMultimap<String, String> multiMap) {
if(args instanceof Object[]) {
Object[] argArray = (Object[])args;
if(argArray.length > 0) {
Map<String, Object> argMap = (Map<String, Object>)argArray[0];
for(Map.Entry<String, Object> entry : argMap.entrySet()) {
String value = entry.getValue().toString();
if(entry.getValue() instanceof List) {
List valueList = (List)entry.getValue();
for(Object v : valueList) {
multiMap.put(entry.getKey(), v.toString());
}
value = valueList.get(valueList.size() - 1).toString();
} else {
multiMap.put(entry.getKey(), value);
}
map.put(entry.getKey(), value);
}
}
}
}

public Object methodMissing(String name, Object args)
throws MacroEvaluationException, IOException, InterruptedException {

TokenMacro macro = null;
for(TokenMacro m : TokenMacro.all()) {
if(m.acceptsMacroName(name)) {
macro = m;
break;
}
}

if(macro == null) {
for(TokenMacro m : ContentBuilder.getPrivateMacros()) {
if(m.acceptsMacroName(name)) {
macro = m;
break;
}
}
}

if(macro != null) {
Map<String, String> argsMap = new HashMap<String, String>();
ListMultimap<String, String> argsMultimap = ArrayListMultimap.create();
populateArgs(args, argsMap, argsMultimap);

// Get the build and listener from the binding.
AbstractBuild<?, ?> build = (AbstractBuild<?, ?>)this.getBinding().getVariable("build");
TaskListener listener = (TaskListener)this.getBinding().getVariable("listener");

return macro.evaluate(build, listener, name, argsMap, argsMultimap);
}
return String.format("[Could not find content token (check your usage): %s]", name);
}
}
}

0 comments on commit 9d37d81

Please sign in to comment.