Why won't Groovy honor my command-line switches? - groovy

I have the following Groovy class:
class MyApp {
public static void main(String[] args) {
String name = System.getProperty("name")
println "My name is ${name}."
}
}
When I package it up as an executable JAR and then run it (java -jar myapp.jar -Dname=Earl), here is the output I get:
My name is null.
Why is name null and not "Earl"?

The java executable considers everything that comes after the main class/Jar as an argument to the main method. Try java -Dname=Earl -jar myapp.jar. (Unless the Jar is a fat Jar or its manifest class path points to the Groovy Jar, you'll have to pass that as well using -cp).

Related

Compile groovy script statically with command line arguments

I am trying to statically compile a groovy script to speed up it's execution, but am not able to get it to work if command line arguments are used. My actual script is much longer, but the one-line script I use for this question perfectly reproduces my error.
Using the following script (test.groovy)
println(args.length)
This can be compiled with the command groovyc test.groovy and ran by the java command java -cp .;%GROOVY_HOME%\lib\* test and will simply print the number of command line arguments used.
Now, if I provide the script (config.groovy)
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
}
and compile with groovyc -configscript config.groovy test.groovy, I get an error
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
testing.groovy: 1: [Static type checking] - The variable [args] is undeclared.
# line 1, column 9.
println(args.length)
^
1 error
This error only occurs when I attempt to compile statically. I can get it to work by wrapping the script in a class and putting my code in a main method (which, of course, is what the compiler does with a script), but not when I try to just use the script (which is what I prefer to do). For some reason, the variable args is unknown when compiled statically. I've tried this.args but still receive the error. If I try to declare a type for args (String[] args), it no longer receives the command line arguments.
Is there a way to still get the command line arguments when a script is compiled statically this way?
I am using Groovy version 2.4.10 on Windows 7 with Java 8.
The Script works via dynamic evaluation of the bindings object. If you want to use static compilation, you need to use the explicit form, changing your test.groovy script into the following:
String[] args = (String[])binding.getVariable('args')
println args.length
Using your already provided configuration script you do get a static compiled Script. I tested running it this way:
groovyc --configscript config.groovy test.groovy
java -cp .;%GROOVY_HOME%\lib\groovy-2.5.3.jar test 1 2 3
This prints 3.
If you want to not modify test.groovy at all, you can create a new base class:
import groovy.transform.CompileStatic
#CompileStatic
abstract class StaticBase extends Script {
StaticBase() {
}
StaticBase(Binding binding) {
super(binding)
}
String[] getArgs() {
(String[]) getBinding().getVariable("args")
}
}
Since the base class has a method getArgs, then when the test.groovy refers to args, the static compiler picks up the call to that method.
groovyc --configscript config.groovy -b StaticBase test.groovy
java -cp .;%GROOVY_HOME%\lib\groovy-2.5.3.jar test 1 2
The code in test.class has a run method whose code represents this.println(this.getArgs().length)
There's difference in executing Groovy class and running simple script. It's not correct that compiler simply wraps your script in main method, the body of the script will be copied into a run method.
Example:
println(args.length)
will be converted to
import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
def run() {
println(args.length)
}
static void main(String[] args) {
InvokerHelper.runScript(Main, args)
}
}
This compiles fine due to dynamic types.
Now, if we add #CompileStatic annotation to that class, we'll get the error of undeclared variable.
So, you have to wrap your code in class in order to use static compiling.
You can read more about Scripts versus classes in documentation.

WSO2 ESB Can't run Groovy script stored in registry

I'm trying to execute a Groovy script that I'm storing in the WSO2 ESB Local registry. When I do that I'm getting the following error:
ERROR {org.apache.synapse.mediators.bsf.ScriptMediator} - The script engine returned a NoSuchMethodException executing the external groovy script : Value {name ='null', keyValue ='file:Scripts/Groovy/test.groovy'} function mediate {org.apache.synapse.mediators.bsf.ScriptMediator}
java.lang.NoSuchMethodException: No signature of method: com.sun.script.groovy.GroovyScriptEngine.mediate() is applicable for argument types: (org.apache.synapse.mediators.bsf.ScriptMessageContext) values: [org.apache.synapse.mediators.bsf.ScriptMessageContext#716f8a10]
Possible solutions: wait()
If I put the code in-line in the script mediator, everything is running ok.
I've tried to wrap the script code like this <x><![CDATA[...code...]]></x>, as shown in the Using Ruby Scripts for Mediation example:
Sample 353: Using Ruby Scripts for Mediation. I add the groovy-all-2.4.7.jar to ESB_HOME\repository\components\lib too.
How can I run the groovy scripts stored in the registry? What am I doing wrong?
Here is the Groovy Script and the proxy, wiht which I'm testing:
Groovy Script
class Example {
static def DisplayName() {
println("This is how methods work in groovy");
println("This is an example of a simple method");
}
static void main(String[] args) {
DisplayName();
}
}
Proxy service
<proxy name="TestScriptProxy" startOnLoad="true" trace="disable"
transports="http https" xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<script language="groovy"><![CDATA[println "This is an in-line script";]]></script>
<script function="DisplayName"
key="file:Scripts/Groovy/test.groovy" language="groovy"/>
</inSequence>
<outSequence/>
<faultSequence/>
</target>
</proxy>
ESB version is 5.0.0 running on Windows 10.
If you have the Groovy script in the registry, the source should be the registry path. For example : gov:scripts/Groovy/test.groovy.
If you are referring a file give path relative to ESB_HOME. For example if scripts folder is in ESB_HOME directory, file:scripts/Groovy/test.groovy
First load the script file as below :
<localEntry key="DisplayNameScript" src="file:scripts/Groovy/test.groovy"/>
Now call the function
<script language="groovy" key="DisplayNameScript" function="DisplayName"/>

Run Groovy application

Now I need development and run simple Groovy TCP server.
Could you please help me make the right choice how I can run my application?
I know follow methods how I can run my Groovy simple application:
1) I can run:
groovy myserver.groovy
2) I can create jar-file and run it. In this case I can write follow code (accordingly documentation):
import org.codehaus.groovy.runtime.InvokerHelper
class MyApp extends Script {
def run() {
// TODO
}
static void main(String[] args) {
InvokerHelper.runScript(MyApp, args)
}
}
Please help me, which way is more effective?
For simple cases you can run your Groovy script in "listening" mode with the -l flag, like this:
groovy -l 9010 SimpleServer.groovy
This starts the SimpleServer script listening on port 9010. I took this example from mrhaki's Groovy Goodness blog here: http://mrhaki.blogspot.com/2009/12/groovy-goodness-serversocket-scripts.html. Check it out for the complete example.

Glassfish 3 + ear + logback.xml

I'm using logback in an EAR-File which contains a JAR (ejb) and a WAR. This should run on a Glassfish v3 Server. Everything works, except the loading of the logback.xml. This can't be found.
I build the Project with Netbeans. The used external libs are in the lib-Directory of the EAR (Which shouldn't make a difference where they are...). I've planed to put the logback.xml-File in the root-Directory or another Subdirectory in the EAR. The Classpath is set in the Manifest-Files of the JAR and WAR. But for some Reasons the logback.xml wasn't found... (The build ear contains the logback.xml ;) )
I've tryied every location of the logback.xml. Even in the WAR or JAR. Nothing worked...
If I use a standalone WAR then everything works fine and the logback.xml was found. (OK. Not everything. Changing the Classpath in the Manifest doesn't work...)
So my Question: Has anybody already get logback.xml to run within an EAR?
Here is my Manifest (I hope, that this ist the correct Syntax):
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.7.0_147-icedtea-b147 (Oracle Corporation)
Class-Path: ./
Hope someone can help me.
Regards
I solved this problem creating a separated simple jar that I deploy exploded inside the EAR (using Maven and a separated module config.jar).
In practice, the logback.xml was inserted in lib/config.jar/logback.xml
I've found out a solution without putting another jar in the classpath.
1) Just put the logback.xml into the classpath of the war application (/src/java/ for instance);
2) Use a ServletContextListener to load the file using getResourceAsStream and, eventually, set some parameters (like the application name) as in the snipped below:
#Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Logback contextInitialized !!!!");
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
JoranConfigurator jc = new JoranConfigurator();
jc.setContext(context); context.reset();
// override default configuration
// inject the name of the current application as "application-name"
// property of the LoggerContext
context.putProperty("application-name", "menu_dinamico");
try {
InputStream is = getClass().getClassLoader().getResourceAsStream("logback.xml");
if(is == null) {
System.out.println("Logback xml file non trovato");
}
else {
jc.doConfigure(is);
}
} catch (JoranException ex) {
System.out.println("Logback contextInitialized error");
StatusPrinter.print(context);
ex.printStackTrace();
}
}
Now the file logback.xml is recognized.

How can I create a pathing jar in Gradle

When running groovyc in a Windows env, I am running into issues due to the length of the classpath, in my situation. I would like to work around this by creating a pathing jar, and then put that jar on the cp. How can I create a pathing jar w/ all of the classpath entries specified automatically in gradle and then add that jar to the cp?
Here is a tested solution:
task pathingJar(type: Jar) {
appendix = "pathing"
doFirst {
manifest {
attributes "Class-Path": configurations.compile.files.join(" ")
}
}
}
compileGroovy {
dependsOn(pathingJar)
classpath = files(pathingJar.archivePath)
}
Depending on your exact requirements, you might have to tweak this a bit. For example, if you have tests written in Groovy, you will also need a pathing Jar for the test compile class path. In this case you'll need to repeat above configuration as follows:
task testPathingJar(type: Jar) {
appendix = "testPathing"
doFirst {
manifest {
attributes "Class-Path": configurations.testCompile.files.join(" ")
}
}
}
compileTestGroovy {
dependsOn(testPathingJar)
classpath = files(testPathingJar.archivePath)
}
I finally got the "pathing jar" idea to work. I consider this to be a permanent workaround. This could be considered a solution if it is made part of gradle itself.
The original pathing jar code was provided by Peter, but it didn't work. The problem: classpath elements referenced in the pathing jar must be relative to the location of the pathing jar. So, this appears to work for me.
task pathingJar(type: Jar , dependsOn: 'cleanPathingJar') {
/**
* If the gradle_user_home env var has been set to
* C:\ on a Win7 machine, we may not have permission to write the jar to
* this directory, so we will write it to the caches subdir instead.
* This assumes a caches subdir containing the jars
* will always exist.
*/
gradleUserHome = new File(gradle.getGradleUserHomeDir(), "caches")
relativeClasspathEntries = configurations.compile.files.collect {
new File(gradleUserHome.getAbsolutePath()).toURI().
relativize(new File(it.getAbsolutePath()).toURI()).getPath()
}
appendix = "pathing"
destinationDir = gradleUserHome
doFirst {
manifest {
attributes "Class-Path": relativeClasspathEntries.join(" ")
}
}
}
compileGroovy {
dependsOn(pathingJar)
classpath = files(pathingJar.archivePath)
}
This is what helped me:
"The filename or extension is too long error" using gradle
In other words: use the com.github.ManifestClasspath plugin.
The other solutions did not work for me because the actual project main class ended up no being included in the classpath at execution time.

Resources