Your browser was unable to load all of the resources. They may have been blocked by your firewall, proxy or browser configuration.
Press Ctrl+F5 or Ctrl+Shift+R to have your browser try again.

Shared groovy libraries #2985

supererki ·
Is there a way to share custom groovy code among different places in quickbuild? I am writing maintenance code for our QB server (as QB configs that execute script on server) and I have found that I need to reuse some of the code in many scripts.
I was going thru the QB setup on the server and found out that "wrapper.conf" you can add jar-s to classpath, but I have been told (and it makes sense) that this is only loaded when the server (re)starts and that we haven't planned for this year.
Is there any other way to share code among steps?
  • replies 9
  • views 2134
  • stars 1
supererki ·
Well I can create different classes as different steps but how do I pass variables between them?
supererki ·
Ok, I think scripting API is not meant for this, moving to rest API.

Anyway, getting HTTP.500 while doing POST, no problem with GET.

    public void sendPost(ConfigurationDTO config) throws Exception {
// client target is: http://localhost:8810/rest
ResteasyWebTarget target = getTarget();
target.path("configurations");
JAXBContext context = JAXBContext.newInstance(ConfigurationDTO.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
// this here produces exactly what I need
marshaller.marshal(config, new File("test.xml"));
StringWriter stringWriter = new StringWriter();
marshaller.marshal(config, stringWriter);
MultipartFormDataOutput dataOutput = new MultipartFormDataOutput();
dataOutput.addFormData("file", new FileInputStream(new File("test.xml")), MediaType.APPLICATION_OCTET_STREAM_TYPE);
GenericEntity<MultipartFormDataOutput> entity = new GenericEntity<MultipartFormDataOutput>(dataOutput) {};
Response response = target.request().post( Entity.entity(entity, MediaType.MULTIPART_FORM_DATA_TYPE));
response.close();
}


No problem with auth because client is set up the same way as for GET methods, and it works with this.
Config is probably correct:

<com.pmease.quickbuild.model.Configuration>
<disabled>false</disabled>
<parent>8844</parent>
<name>Test-COPY</name>
<versionManagerDOM>
<com.pmease.quickbuild.setting.configuration.version.UseSpecifiedVersion revision="0.0.0">
<version>1.0.1</version>
</com.pmease.quickbuild.setting.configuration.version.UseSpecifiedVersion>
</versionManagerDOM>
<statusDate>2014-09-30T12:35:35.000Z</statusDate>
<pluginSettingDOMs/>
<data/>
<stepDOMs>
<entry>
<string>master</string>
<com.pmease.quickbuild.stepsupport.SequentialStep revision="0.12.2.2">
<name>master</name>
<enabled>true</enabled>
<executeCondition class="com.pmease.quickbuild.setting.step.executecondition.AllPreviousSiblingStepsSuccessful"/>
<nodeMatcher class="com.pmease.quickbuild.setting.step.nodematcher.ServerNodeMatcher"/>
<nodePreference class="com.pmease.quickbuild.setting.step.nodepreference.PreferLeastLoadedNode"/>
<timeout>0</timeout>
<preExecuteAction class="com.pmease.quickbuild.setting.step.executeaction.NoAction"/>
<postExecuteAction class="com.pmease.quickbuild.setting.step.executeaction.NoAction"/>
<repetitions/>
<childStepNames>
<string>get groups</string>
<string>Publish report</string>
</childStepNames>
<successCondition class="com.pmease.quickbuild.setting.step.successcondition.AllChildStepsSuccessful"/>
<environments/>
</com.pmease.quickbuild.stepsupport.SequentialStep>
</entry>
<entry>
<string>Publish report</string>
<com.pmease.quickbuild.plugin.htmlreport.HtmlReportPublishStep revision="0.12.3">
<name>Publish report</name>
<enabled>true</enabled>
<executeCondition class="com.pmease.quickbuild.setting.step.executecondition.AllPreviousSiblingStepsSuccessful"/>
<nodeMatcher class="com.pmease.quickbuild.setting.step.nodematcher.ParentNodeMatcher"/>
<nodePreference class="com.pmease.quickbuild.setting.step.nodepreference.PreferLeastLoadedNode"/>
<timeout>0</timeout>
<preExecuteAction class="com.pmease.quickbuild.setting.step.executeaction.NoAction"/>
<postExecuteAction class="com.pmease.quickbuild.setting.step.executeaction.NoAction"/>
<repetitions/>
<reportName>Report</reportName>
<fromPath>.</fromPath>
<filePatterns>index.html</filePatterns>
<startPage>index.html</startPage>
<order>1</order>
</com.pmease.quickbuild.plugin.htmlreport.HtmlReportPublishStep>
</entry>
<entry>
<string>get groups</string>
<com.pmease.quickbuild.plugin.basis.ScriptStep revision="0.12.1">
<name>get groups</name>
<enabled>true</enabled>
<executeCondition class="com.pmease.quickbuild.setting.step.executecondition.AllPreviousSiblingStepsSuccessful"/>
<nodeMatcher class="com.pmease.quickbuild.setting.step.nodematcher.ParentNodeMatcher"/>
<nodePreference class="com.pmease.quickbuild.setting.step.nodepreference.PreferLeastLoadedNode"/>
<timeout>0</timeout>
<preExecuteAction class="com.pmease.quickbuild.setting.step.executeaction.NoAction"/>
<postExecuteAction class="com.pmease.quickbuild.setting.step.executeaction.NoAction"/>
<repetitions/>
<script>
groovy:
import com.pmease.quickbuild.CacheManager
</script>
</com.pmease.quickbuild.plugin.basis.ScriptStep>
</entry>
</stepDOMs>
<repositoryDOMs/>
<aggregationDOMs/>
<variables/>
<notifications/>
<promotions/>
</com.pmease.quickbuild.model.Configuration>



ERROR com.pmease.quickbuild.rest.providers.GenericExceptionMapper - Error serving restful request.
com.sun.jersey.api.NotFoundException
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:991)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:941)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:932)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:384)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:451)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:632)
at com.pmease.quickbuild.rest.RestServlet.service(RestServlet.java:48)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1336)
at com.pmease.quickbuild.Quickbuild$DisableTraceFilter.doFilter(Quickbuild.java:1035)
robinshen ADMIN ·
I am not familiar with RESTeasy, can you please test with curl (as demonstrated in our wiki) with pre-generated test.xml to see if it works?
Thundera ·
Dear Robin,

I'm very new to java and Quickbuild so please, forgive my basic conceptual mistakes.

I have a goal similar to supererki's title question, I need to pack a jar file for "utils" related to my organization that can be reused in several step scripting (a lib, not exactly a plugin). So far I was manage to successfully test the following groovy class code:

=====================================================================
package foo.bar
class Util {

def String message = "Some text here";

public String helloWorld() {
return message;
}
}
=====================================================================

From this I generated a jar file foo.bar_0.0.1.jar and uploaded it on my $QB_INSTALL_DIR/plugins/com.pmease.quickbuild.libs/ dir.

Since its a groovy class, it also relies on groovy-all-*.jar, so I also include the follow line at wrapper.conf file at $QB_INSTALL_DIR/conf dir:

wrapper.java.classpath.14=../framework/configuration/org.eclipse.osgi/lib/groovy-all-1.8.9.jar

at the step code, the following worked very well after rebooting qb server:

step code:
------------------------------------------------------------------------------------------------
groovy:

import foo.bar.Util;

Util hw = new Util();

def text = hw.helloWorld();

logger.warn('Inner Jar text = ' + text);
------------------------------------------------------------------------------------------------


My problem arises when I am trying to modify this simple helloWorld to recieve the QB logger obj and directly info the message through its method. The following modified code of the same class compiles ok (since all QB jars dependency are mapped in the eclipse project), but doesn't work at runtime
===================================================================
package foo.bar

import com.pmease.quickbuild.log.BuildLogger


class Util {

def String message = "Some Text";

public String helloWorld() {
return message;
}

public void innerLogger( BuildLogger innerLog) {

innerLog.info(message);

}
}
===================================================================

Even without modify the step code, when I execute it (play), it throws java.lang.NoClassDefFoundError: com/pmease/quickbuild/log/BuildLogger

Also, if I try to add the quickbuild jar itself to the wrapper.conf classpath the same way I did to groovy-all-*.jar, QB server fails to start.
wrapper.java.classpath.15=../plugins/com.pmease.quickbuild_5.0.130.jar

(...)
2016-03-08 17:02:10,902 INFO - Caching plugin libraries...
jvm 1 | WrapperStartStopApp:
jvm 1 | WrapperStartStopApp Error: Encountered an error running start main: java.lang.reflect.InvocationTargetException
jvm 1 | WrapperStartStopApp Error: java.lang.reflect.InvocationTargetException
jvm 1 | WrapperStartStopApp Error: at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
jvm 1 | WrapperStartStopApp Error: at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
jvm 1 | WrapperStartStopApp Error: at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
jvm 1 | WrapperStartStopApp Error: at java.lang.reflect.Method.invoke(Method.java:606)
jvm 1 | WrapperStartStopApp Error: at com.pmease.quickbuild.bootstrap.Bootstrap.boot(Bootstrap.java:576)
jvm 1 | WrapperStartStopApp Error: at com.pmease.quickbuild.bootstrap.Bootstrap.main(Bootstrap.java:126)
jvm 1 | WrapperStartStopApp Error: at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
jvm 1 | WrapperStartStopApp Error: at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
jvm 1 | WrapperStartStopApp Error: at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
jvm 1 | WrapperStartStopApp Error: at java.lang.reflect.Method.invoke(Method.java:606)
jvm 1 | WrapperStartStopApp Error: at org.tanukisoftware.wrapper.WrapperStartStopApp.run(WrapperStartStopApp.java:264)
jvm 1 | WrapperStartStopApp Error: at java.lang.Thread.run(Thread.java:745)
jvm 1 | WrapperStartStopApp Error: Caused by: java.lang.NoClassDefFoundError: org/eclipse/jetty/servlet/ServletContextHandler
jvm 1 | WrapperStartStopApp Error: at java.lang.Class.getDeclaredMethods0(Native Method)
jvm 1 | WrapperStartStopApp Error: at java.lang.Class.privateGetDeclaredMethods(Class.java:2625)
jvm 1 | WrapperStartStopApp Error: at java.lang.Class.getMethod0(Class.java:2866)
jvm 1 | WrapperStartStopApp Error: at java.lang.Class.getMethod(Class.java:1676)
jvm 1 | WrapperStartStopApp Error: at com.pmease.quickbuild.equinoxadapter.EquinoxAdapter.startup(EquinoxAdapter.java:58)
jvm 1 | WrapperStartStopApp Error: ... 12 more
jvm 1 | WrapperStartStopApp Error: Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.servlet.ServletContextHandler
jvm 1 | WrapperStartStopApp Error: at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
jvm 1 | WrapperStartStopApp Error: at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
jvm 1 | WrapperStartStopApp Error: at java.security.AccessController.doPrivileged(Native Method)
jvm 1 | WrapperStartStopApp Error: at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
jvm 1 | WrapperStartStopApp Error: at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
jvm 1 | WrapperStartStopApp Error: at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
jvm 1 | WrapperStartStopApp Error: at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
jvm 1 | WrapperStartStopApp Error: ... 17 more

I didnt use any Class-Path: variable under my Manifest.MF file inside the jar I am trying to embbed.

How can I develop a inner Jar method that will expect a qb object such logger to be passed on ? (Assuming that this is actually possible...)

Thanks and Best Regards,
Mauro Ribeiro
robinshen ADMIN ·
jars under "plugins/com.pmease.quickbuild.lib" are loaded with a different class loader than other parts of QB. I'd suggest to write a QB plugin to include your utility classes (and you can call groovy in your utilty without including groovy in your own plugin). Also make sure to remove the groovy-1.8.9 jar reference from "conf/wrapper.conf".
SameOldSong ·

Hello Robin. Since your last comment is 4 years old, I was wondering, if there might be another solution to this "shared groovy" problem in the newest QB versions.
So far, we've been using your suggestion (custom plugin with utility classes) to share common functions in groovy scripts.

Is there any other way we could do it in QuickBuild 9?

robinshen ADMIN ·

You may also store script in variables, and evaluate content of the variable as groovy scripts. This applies to all versions of QB

SameOldSong ·

Do you mean evaluating with GroovyShell? Something like this:

groovy:

def shell = new GroovyShell();
shell.evaluate(vars.getValue("script"))
robinshen ADMIN ·

Yes that is true