Is it possible to automatically preload user classes into the groovy interpreter? - groovy

Is there any way to automatically load user classes in the groovy interpreter, the way System.out is automatically loaded (so you don't have to import System.out to use println)? I want to be able to write scripts that employ custom classes and run the scripts in the groovy interpreter without having to import all the classes all the time.

Yep, you just need to create a profile/rc file. Just create a file at ~/.groovy/groovysh.profile and put your imports in there. You'll also want to make sure that any additional classes you want to include are part of your CLASSPATH.
ex: ~/.groovy/groovysh.profile:
import org.apache.commons.lang.StringUtils
println "in groovysh.profile"
Then run groovysh and use a method from StringUtils:
% groovysh
in groovysh.profile
Groovy Shell (1.7.3, JVM: 1.6.0_20)
Type 'help' or '\h' for help.
---------------------------------------------------------------------------------------------------------------------------------
groovy:000> StringUtils.isWhitespace(" ")
===> true
groovy:000>
You can see that the import is in place (and that it also printed out the println I had in the profile. This example will only work if you've got the commons-lang jar file is in your classpath.
See the Groovy Shell page for more details.

Groovy adds some methods to Object, including methods like println and printf that you'd expect on printWriters. They implicitly use System.out. This is actually how groovy makes if feel like System.out is globally available.
If you want to import a set of classes by default, so they can be used without specifying the full package name, Ted's comment about groovysh.profile applies.
However, if you want a specific object, like System.out, global available so its methods can be called without referencing the object, then you can add some dynamic methods to Object. For example, to make the logging methods of the default global JDK logger globally available:
Object.metaClass.info = { String message ->
java.util.logging.Logger.global.info(message)
}
Object.metaClass.warning = { String message ->
java.util.logging.Logger.global.warning(message)
}
Object.metaClass.severe = { String message ->
java.util.logging.Logger.global.severe(message)
}
etc...
Once those methods are applied to the base Object metaClass, any object can call info("message") and have it logged, effectively making Logger.global available in the same way System.out is.

Related

How to use GroovyClassLoader to load GroovyCompiled classes or how to set delegate in case of loadClass

I am trying to loadClass which are compiled during build and placed in classpath as .class files. For this I tried
GroovyClassLoader gos = new GroovyClassLoader();
gos.loadClass("className");
This will successfully load the class file in java code but it uses AppClassLoader to load this not GroovyClassLoader.
I understand that GroovyClassLoader internally finds it using AppClassLoader.
But there is a difference :
As gos.parseClass(string) will give us a class parsed from GroovyClassLoader.
While instantiating class file in second case(parseClass) give us delegate to set Delegate but in the first case(loadClass), we don't have any.
How to set delegate after doing loadClass or any way to load class file through GroovyClassLoader.
Load Class
Groovy Compiler compiles the groovy files(HelloWorld.dsl) and put them in class path creating .class file(HelloWorld.class) with same name.
By default compiled class file(open the byte code) have class(HelloWorld) with same name as of class file.
This class will get extended from Script. Now if you try to load this class file using
gos.loadClass("HelloWorld").newInstance() , it will give us a Script object and we won't be able to set a delegate to a Script object. Also it won't get converted into DelegatingScript.
To make your compile class extended from DelegatingScript add this at top of your dsl file #groovy.transform.BaseScript DelegatingScript delegatingScript . Groovy compiler will understand that and make the class files to get extended from DelegatingScript instead of Script as it was earlier.
Now when you try to load class using gos.loadClass("HelloWorld").newInstance(), it will give a DelegatingScript object not a Script object. To this object, we can set the delegate and run the script.
To use a delegate if you are using parseClass, we need to setScriptBaseClass as DelegatingScript to compilerConfiguration. Now if you try gos.parseClass(dslText).newInstance() , it will give directly give a DelegatingScript object and we can set a delegate and run the script.

How to declare a constructor or extends a class of a groovy script?

I am working on a shared library for Jenkins, and I want to access some utilities methods between some classes, but not all of them, thus I have established some statements:
I would like to avoid using static methods, since it does not access pipeline steps directly, and passing the pipeline instance every call would be a pain;
I would like to avoid a singleton as well, or prefixing every method call with the util class' instance;
Since it is not supposed to be shared between all classes I would like to avoid putting every method as a file on vars/ special directory, but I would like a similar behavior;
Despite extending the class would be a anti-pattern, it would be acceptable, though I would like to avoid the verbose Java syntax for declaring the class the same name as the file, once it is implicit in groovy;
This question does solve my problem partially, although there are issues with serialization, I noted that when I use checkpoint and some build is resumed from some stage, the instance loses all extra methods.
This other question would have helped me fix the serialization issue, however the author seems the have solved the root cause of his problem using a way that is not the original question titled for.
Is there a way to extends a implicit script class in groovy without using the class NameOfFile extends SomeOtherClass { put every thing inside this block } syntax? And without working with inner-class?
Or else, is there a way to declare a constructor using the script groovy syntax analogue as the previous question?
Or even, is there a way to change the serialization behavior to install the extra methods again after unserializing?
Appendix
The script syntax works more-or-less like this:
Consider the content of file src/cicd/pipeline/SomePipeline.groovy:
package cicd.pipeline
// there is no need to wrap everything inside class SomePipeline,
// since it is implicit
def method() {
// instance method, here I can access pipeline steps freely
}
def static otherMethod() {
// static method, here it is unable to access pipeline steps
// without a instance
}
#groovy.transform.Field
def field
def call() {
// if the class is used as method it will run
this.method()
SomePipeline.otherMethod() // or simply otherMethod() should work
this.field = 'foo'
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
}
// any code other than methods or variables with #Field
// annotation will be inside a implicit run method that is
// triggered likewise main method but isn't a static one
def localVar = 'foo'
println "It will not execute on constructor since it is on run: $localVar"
println "Method: ${org.codehaus.groovy.runtime.StackTraceUtils.sanitize(new Throwable()).stackTrace[0].methodName}"
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
If I was going to use the Java verbose syntax I would have to wrap almost everything inside a class SomePipeline which is implicit in groovy, this is the script syntax I want to keep.
I realised that this.getClass().superclass.canonicalName when outside Jenkins pipeline is groovy.lang.Script and when inside pipeline is org.jenkinsci.plugins.workflow.cps.CpsScript and based on this resource I was able to elaborate the following solution:
abstract class CustomScript extends org.jenkinsci.plugins.workflow.cps.CpsScript {
public CustomScript() {
// do something here, it will always execute regardless
// serialization, and before everything
}
}
#groovy.transform.BaseScript CustomScript baseScript
That is it, worked as expected! Of course you can elaborate this solution better in order to reduce repeating and avoid inner-classes, but I will leave it for your imagination.

Populating variables in a groovy script from a java program

I know how to call Groovy code from Java code, but can you, while running Groovy script script.groovy, ask a Java program to populate its varabies?
// script.groovy
import static org.mydomain.WiseJavaProgram.*;
pleasePopulateMeWithVariables();
println numberOfLegs // 2
// We didn't declare numberOfLegs in our sript, the Java program set it for us.
I guess maybe for that script.groovy should pass its environment to the pleasePopulateMeWithVariables method, but I haven't found how to do that. Is this even possible?
The case where I want to use such behavior: I have script.groovy, and also an undefined number of groovy scripts of which Java program knows, but of which script.groovy doesn't know, and I want to add what is declared in them to script.groovy. Basically those additional scripts are data, for example descriptions of various products and their features. This is easy if you run a Java program that creates GroovyShell and evaluates in it data-scripts and then script.groovy, but for me it is necessary that we initially call script.groovy, not the Java program.
Just as usual, while asking the question I was one step behind the answer -__-
The "environment" I was searching for is the Script object itself, available from script.groovy simply as this. So:
// script.groovy
import static org.mydomain.WiseJavaProgram.*;
populateWithVariables(this);
println numberOfLegs // 2
// WiseJavaProgram.java
public class WiseJavaProgram {
public static void populateWithVariables(Script script) {
script.evaluate('numberOfLegs = 2');
script.evaluate(new File("another.groovy"));
script.evaluate(new File("yetAnother.groovy"));
}
}

Calling groovy script from other groovy script

I want to call a groovy script from the other groovy script... anybody can help me in this ASAP..
example :
Class A having some code and it should call from B
class A{
static main(args){
println "Hello.. calling A Class"
}
}
I want to create a new class like B.groovy
class B{
static main(args){
// I need code for this to call A.groovy
}
}
Putting the following at the top of your script will load the contents of a groovy file.
evaluate(new File("/path/to/script/MyScript.groovy"))
You could also add this to the groovy classpath if you need to do something like this often. Hope this helps.
additionally if you need to run other scripts from your script you could do the following...
def script = new GroovyShell();
def args = ['Hello World'];
script.run(new File("/path/to/script/MyScript.groovy"), args as String[]);
Too late for the party (any beer for me?) but here I´ll show you 2 more flavors:
1) Remember the concept of Java´s CLASSPATH? That aplies to Groovy (because Groovy is Java!):
"The CLASSPATH variable is one way to tell applications, including the JDK tools, where to look for user classes.”
In order to run the script B.groovy you have to inform the location of the A.groovy (A class):
groovy –cp c:\groovy\yourscripts c:\groovy\scripts\B.groovy
The command above is telling the runtime to look in the c:\groovy\yourscripts folder because there is where we have our classes and we need them to run the B.groovy script successfully.
2) Use the GroovyClassLoader to load your scripts at runtime and using the code!
Both ways solve your needs. Now the next question is when to use each?

Populate List<Callable<String>> in Groovy with Groovy objects

In What JVM-based scripting language support #WebService to create services at runtime? I was suggested to use Groovy to provide web services configured in a script read in at runtime.
To make this work with our existing infrastructure I need essentially to be able to add new entries to a List<Callable<String>> which I then can ask an executor to invokeAny upon.
The basic structure will be something like:
Groovy is embedded using GroovyScriptEngine
Initial list passed in from Java as "l" in the Binding passed in.
Groovy script defines and instantiates N objects, all implementing Callable<String> and add them to the list.
Back in Java the list is then further processed and then passed to the executor.
My initial feeble steps show that I will most likely need to use def c = { ... } as Callable<String> but then I get a ClassCastException. Reading up I see that it appears that this is a bit hard and involves closures.
What is the correct way to define and instantiate an object in Groovy which implements Callable<String>?
In Groovy 1.8 and later, groovy.lang.Closure implements Callable by default so you don't need any "as" magic., simply:
l << { "hello" }
l << { "world" }
For earlier versions of Groovy (1.6 and 1.7 certainly, not sure about "ancient" versions) you need to use as:
import java.util.concurrent.Callable
l << ({ "hello" } as Callable)

Resources