Groovy access script variable from application - groovy

Need to access the variable defined in the groovy script file
Before executing the script using GroovyShell
However, I am getting error:
groovy.lang.MissingPropertyException: No such property: _THREADS for class: Test1
//Test1.groovy
_THREADS=10;
println("Hello from the script test ")
//scriptRunner.groovy
File scriptFile = new File("Test1.groovy");
def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
def script = shell.parse (scriptFile);
def thread = script.getProperty('_THREADS'); // getting ERROR --
// No such property: _THREADS for class: Test1
//-------
//now run the threads
script.run()

you have to run script before getting property/binding
def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
def script = shell.parse (''' _THREADS=10 ''')
script.run()
println script.getProperty('_THREADS')
try to open AST Browser (Ctrl+T) in groovy console for this code:
_THREADS=10
and you'll see approximately following generated class:
public class script1663101205410 extends groovy.lang.Script {
public java.lang.Object run() {
_THREADS = 10
}
}
where _THREADS = 10 assigns property into binding
however it's possible to define _THREADS as a function then it will be accessible without running script.
def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
def script = shell.parse (''' def get_THREADS(){ 11 } ''')
println script.getProperty('_THREADS')

got the solution using #Field modifier value can be accessed after parsing
import groovy.transform.Field
#Field _THREADS=10
File scriptFile = new File("Test1.groovy");
def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
def script = shell.parse (scriptFile);
def thread = script.getProperty('_THREADS'); //value is accessible

Related

How can I use wrapped Groovy shell inside the groovy script?

I have a Java app through which I'm executing a Groovy Script, the problem occurs when my Script again has code to use the groovy shell to execute the Inner script.
something like this
import com.xx.WrappedGroovyShell
import java.lang.*
def scriptString = """
def test(str) {
str.toLowerCase() // This doesn't work as GString can't seem to be treated as a String
}
"""
try {
def script = WrappedGroovyShell.getInstance().getScript("Test1", scriptString)
def script2 = new GroovyShell().parse(scriptString)
def example = 1
def gstring = "OUR VALUE IS ${example}";
println script instanceof GroovyObject // Statement returning false
println script.test(gstring) // This throws an exception groovy.lang.MissingMethodException: No signature of method: org.codehaus.groovy.runtime.GStringImpl.toLowerCase() is applicable for argument types: () values: []
println script2 instanceof GroovyObject // Statement returns true
println script2.test(gstring) //this one works
println "Success"
} catch (ex) {
println ex
}
return 0
The getScript method in WrappedGroovyShell.java is as simple as
public Script getScript(String scriptName, String scriptBody){
return new GroovyShell().parse(scriptBody);
}
I will be thankful if someone let me know why two different behavior.
new GroovyShell() creates a new groovy classloader with parent = GroovyShell.class.getClassLoader()
and if GString.class is unknown for parent classloader - then it will be loaded again.
two GString classes loaded by different classloaders are not equal that's why you could have unexpected exceptions like "method not found for parameter GString" or "can't cast GString to GString"
this code should work because it uses classloader of current groovy class
def scriptText='''
def test(str) {
str.toLowerCase()
}
'''
def gs = new GroovyShell(this.getClass().getClassLoader())
def script = gs.parse(scriptText)
def arg = "GSTRING ${123}"
println script.test(arg)

Error: md5sum: stat '>': No such file or directory

I am trying to write a program that runs the Linux commands using Scala.
I have written a snippet of code to run the functionalities of md5sum command.
Code snippet
object Test extends App {
import sys.process._
case class md5sum_builder private(i: Seq[String]) {
println(i)
protected def this() = this(Seq(""))
def optionCheck() = new md5sum_builder(i :+ "-c")
def files(file: String) = new md5sum_builder(i :+ file)
def hashFile(hashfile: String) = new md5sum_builder(i :+ hashfile)
def assignment(operator: String) = new md5sum_builder(i :+ operator)
def build() = println(("md5sum" + i.mkString(" ")).!!)
}
object md5sum_builder {
def apply() = new md5sum_builder
}
md5sum_builder().files("text.txt").files("text1.txt").assignment(">").hashFile("hashes.md5").build()
}
When I try to run the command md5sum text.txt text1.txt > hashes.md5 using this program, it throws the error:
Error: md5sum: stat '>': No such file or directory
I don't know why. Any way to make it work?
Your interface doesn't appear to be well thought out. Notice that files(), hashFile(), and assignment() all do the same thing. So someone could come along and do something like this ...
md5sum_builder().assignment("text0.txt")
.hashFile("text1.txt")
.files(">") // <--shell redirection won't work
.assignment("hashes.md5")
.build()
... and get the same (non-functional) result as your posted example.
Here's a modification that corrects for that as well as allowing redirected output.
case class md5sum_builder private(i :Seq[String], outfile :String = "/dev/null") {
protected def this() = this(Seq.empty[String])
def optionCheck(file :String) = this.copy(i = i ++ Seq("-c", file))
def file(file: String) = this.copy(i = i :+ file)
def hashFile(file: String) = this.copy(outfile = file)
def build() = println(("md5sum" +: i).#|(Seq("tee", outfile)).!!)
}
Now the methods can be in almost any order and still get the expected results.
md5sum_builder().file("text0.txt")
.hashFile("hashes.md5")
.file("text1.txt")
.build()

java.lang.NullPointerException displayed when run testcase inside Groovy Script step

I am trying to run TestCase from Groovy Script TestStep using Groovy in SoapUI.
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context );
def testCase = testRunner.testCase;
def testStep = testCase.testSteps["CreateMeeting"];
testRunner = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner(testCase, null);
testStepContext = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext(testStep);
testStep.run(testRunner, testStepContext);
Error displayed :
java.lang.NullPointerException
Error occured at line :
testStepContext = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext(testStep);
Project Structure :
When you invoke a Groovy test step you get a number of variables pre-declared such as log, context, and testRunner, so you don't have to declare your own.
This worked for me:
//def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context );
def testCase = testRunner.testCase.testSuite.project.getTestSuiteByName("AddBooking").getTestCaseByName("CreateMeeting")
//def testStep = testCase.testSteps["CreateMeeting"]
//testRunner = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner(testCase, null);
//testStepContext = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext(testStep);
def properties = new com.eviware.soapui.support.types.StringToObjectMap ()
testCase.run(properties, false)

Loop with groovy to execute a TestCase in soapui

i wanto run 5 times a testcase in soapui using groovy.
i found the following code in Stackoverflow and added the loop part but it executes randomly.
Sometimes it executes 2 times and sometimes 4 times.
here is the code:
def a = 5;
while (a>0) {
a--;
def testCase = testRunner.testCase.testSuite.testCases["TestCase"];
def properties = new com.eviware.soapui.support.types.StringToObjectMap();
def async = false;
testCase.run(properties, async);
}
Thank you
def doSomething() {
println 'Foo Bar'
}
5.times {
doSomething()
}
First thing, you do not want to def testCase in your script, as testCase is usually defined for you.
def myTestCase = testSuite.getTestCaseByName("some TestCase")
def myContext = (com.eviware.soapui.support.types.StringToObjectMap)context
5.times {
myTestCase.run(myContext, false)
}
You also did not specify where you are doing this from. The above code will work from test suite Setup Script. If you are doing it elsewhere, you will probably need to adjust def myTestCase.
I have following script in Setup Script of a test Suite and it is running indefinite loop:
def count=context.expand('${#Global#run}')
log.info count
def project1 = runner.testCase.testSuite.project
def properties = new com.eviware.soapui.support.types.StringToObjectMap()
def testcase = project1.getTestSuiteByName("TestSuite 1").getTestCaseByName("Login");
def testcase1 = project1.getTestSuiteByName("TestSuite 1").getTestCaseByName("Logout");
// This will run everything in the selected project
for(int i=1;i<=count;i++){
// testRunner = testcase.run(new com.eviware.soapui.support.types.StringToObjectMap(), false)
def myContext = (com.eviware.soapui.support.types.StringToObjectMap)context
testcase.run(myContext, false)
sleep(70000)
//testRunner = testcase1.run(new com.eviware.soapui.support.types.StringToObjectMap(), false)
testcase1.run(myContext, false)
sleep(5000)
log.info( "Finished running "+i+" cycle" )
if(i==count){
testRunner.cancel('Test Execution is completed')
break;
}
}

Groovy cannot call Classloader (NullpointerException)

I have created the following Groovy Script to transform a JSON Document with a Java Library. But somehow I am not able to load the class from a jar that I need. I always get java.lang.ClassNotFoundException: de.is24.gis.geotools.CoordinateTransformer
The Jar file is in the same directory the groovy script is. I can not edit the way I call the groovy script. It is called automatically by a river.
import groovy.json.JsonSlurper
geo = new GeoTransformer()
geo.transform(ctx.document)
class GeoTransformer {
void transform(doc) {
this.getClass().classLoader.addURL(new File("gis-geotools-1.9.0.jar").toURL())
def CoordinateTransformer = Class.forName("de.is24.gis.geotools.CoordinateTransformer").newInstance();
def x = doc.realEstateCommonData.locationDto.geoCoordinateDto.xCoordinate;
def y = doc.realEstateCommonData.locationDto.geoCoordinateDto.yCoordinate;
def coords = CoordinateTransformer.transformFromLambertEuToWgs84(x,z)
println coords.getLatitude()
println coords.getLongitude()
def jsonObj = new JsonSlurper().parseText( '{"type" : "Point", "coordinates" : [' + coords.getLatitude() + ',' + coords.getLongitude() + ']}' )
doc.location = jsonObj
}
}
Not sure why you can't get to the rooLoader, it must be to do with how this Groovy script is executed.
You could try this (obviously untested)
class GeoTransformer {
void transform( doc ) {
def urlLoader = new GroovyClassLoader()
urlLoader.addURL( new File("gis-geotools-1.9.0.jar").toURL() )
def coordTransformer = Class.forName( "de.is24.gis.geotools.CoordinateTransformer",
true,
urlLoader ).newInstance()
def x = doc.realEstateCommonData.locationDto.geoCoordinateDto.xCoordinate;
def y = doc.realEstateCommonData.locationDto.geoCoordinateDto.yCoordinate;
def coords = coordTransformer.transformFromLambertEuToWgs84( x, z )
println coords.latitude
println coords.longitude
doc.location = [ type:'Point',
coordinates:[ coords.latitude, coords.longitude ] ]
}
}
I got rid of the JsonSlurper bit at the bottom, and just created the map directly (I assume doc.location needs to be a map)?
Edit:
This works in the Groovy Console:
def jar = new File( '/path/to/commons-collections-3.2.1.jar' )
def loader = new GroovyClassLoader()
loader.addURL( jar.toURL() )
def bag = Class.forName( 'org.apache.commons.collections.bag.HashBag',
true,
loader ).newInstance()
bag.add( 'tim' )
println bag
println bag.getClass().name
And prints:
[tim]
org.apache.commons.collections.bag.HashBag
I had the same problem when running groovy from java via GroovyShell.
This solution works for me and solves the dependency-loading problems that MeiSign mentions in tim_yates solution. Explanation follows:
def thisLoader = this.class.classLoader
// try the "proper" way to find the root classloader
def rootLoader = DefaultGroovyMethods.getRootLoader(thisLoader)
if (rootLoader == null) {
// Root classloader is not a groovy RootLoader, but we still need it,
// so walk up the hierarchy and get the top one (whose parent is null)
// When running from Java this is sun.misc.Launcher.ExtClassLoader
rootLoader = thisLoader
ClassLoader parentLoader = rootLoader.getParent()
while (parentLoader != null) {
rootLoader = parentLoader
parentLoader = parentLoader.getParent()
}
}
rootLoader.addURL(new File("gis-geotools-1.9.0.jar").toURL())
def CoordinateTransformer =
Class.forName("de.is24.gis.geotools.CoordinateTransformer",
true,
rootLoader).newInstance();
When running groovy from java using groovy.lang.GroovyShell.main, the this.classLoader is GroovyClassLoader.InnerLoader
When running groovy from command line groovy.bat, the class loader is org.codehaus.groovy.tools.RootLoader
When you call getRootLoader, it walks up the classloader hiearchy - with getParent() - until it finds an instance of a RootLoader. If it doesn't it finds null. (That's the NPE in the title of this question)
The problem is that when running from Java the heirarchy tops out at sun.misc.Launcher.ExtClassLoader which is clearly not a groovy class at all, let alone the groovy RootLoader.
Specifically the hiearchy is:
GroovyClassLoader.InnerLoader
--> GroovyClassLoader
---> sun.misc.Launcher.AppClassLoader
----> sun.misc.Launcher.ExtClassLoader
------> null
How it ends up that way is pretty obscure in GroovyMain (but if you really want to set it yourself there's a GroovyShell constructor that takes a ClassLoader).
Anyway, Tim's solution doesn't work in depth, because the new ClassLoader you are creating on the fly is used only to load that class and not subsequent classes. You really do need to add the classpath entries to the root classpath.
So I simply used the real root when the groovy root fails.
Here's the original code from org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport
/**
* Iterates through the classloader parents until it finds a loader with a class
* named "org.codehaus.groovy.tools.RootLoader". If there is no such class
* <code>null</code> will be returned. The name is used for comparison because
* a direct comparison using == may fail as the class may be loaded through
* different classloaders.
*
* #param self a ClassLoader
* #return the rootLoader for the ClassLoader
* #see org.codehaus.groovy.tools.RootLoader
* #since 1.5.0
*/
public static ClassLoader getRootLoader(ClassLoader self) {
while (true) {
if (self == null) return null;
if (isRootLoaderClassOrSubClass(self)) return self;
self = self.getParent();
}
}
private static boolean isRootLoaderClassOrSubClass(ClassLoader self) {
Class current = self.getClass();
while(!current.getName().equals(Object.class.getName())) {
if(current.getName().equals(RootLoader.class.getName())) return true;
current = current.getSuperclass();
}
return false;
}

Resources