In Warbler, how do I access compiled binaries through Ruby code? - ruby

I have a piece of Ruby code which depends on a binary built from C. I generally call the binary through backticks. But now when I package the Ruby code into a jar using Warbler, I'm not sure on how I'd be able to access the binary.
My code structure looks like this:
root/
|--bin/
|--exec.rb #This is the executable when I call java -jar example.jar
|--lib/
|--Module1.rb #This dir contains all the ruby modules my code requires
|--ext/
|--a.out #A binary compiled with gcc
|--.gemspec #A file to guide warbler into building this structure into a jar
I used warble to build this entire structure into a jar. In Ruby, I can access my a.out through the following statement in exec.rb.
exec = "#{File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'ext'))}/a.out}";
`exec`
But when I try this code packaged as a jar I get the following error:
/bin/sh: file:/path/to/my/jar/example.jar!/root/ext/a.out: not found
So, how do I access the executable packaged in a jar.

Put the jar in the lib folder.
Require it in the code
require 'java'
Dir["#{File.expand_path(File.join(Rails.root, 'lib'))}/\*.jar"].each { |jar| require jar }
# A war is treated as a directory. If that is not successful add the lib folder to the CLASSPATH environment variable
Then it should be available to be used.
Edit:
Maybe this is what you are looking for https://stackoverflow.com/a/600198/643500 you can implement it with JRuby.

Related

How to include class dependency jar in JRuby?

I'm having trouble figuring out how to include/import/require mydependency.jar which MyJavaClass (within a MyJavaClass.class file) depends on. MyJavaClass contains many import statements importing classes from mydependency.jar. Everything is in the same directory.
When I run java -cp '.:mydependency.jar' MyJavaClass on the command line, I get no error and by putting some calls in main I can get it to run how I want, but when I run ruby my_ruby_file.rb with JRuby on the command line I get NoClassDefFoundError for the first class imported (which is being imported from mydependency.jar) within the MyJavaClass.class file. The stack trace for the error points to the java_import line in my_ruby_file.rb so it seems like it's not properly finding the classes imported from mydependency.jar that are included in my MyJavaClass.class file, even though it runs fine in the normal Java environment.
# contents of my_ruby_file.rb
require 'java'
require './mydependency.jar'
java_import 'MyJavaClass'
MyJavaClass.new.myJavaInstanceMethod('argument')
My $CLASSPATH environment variable was not set, which it needs to be in order for JRuby to be able to find my jar. After I ran export CLASSPATH=".:mydependency.jar" on the command line and removed the line require './mydependency.jar', it worked.

Can a Ruby test get the location of the folder where Rake executed it from?

Can a Ruby test get the location of the folder where Rake executed it from? I want to run Test::Unit unit tests using Rake but my defined "test suites" in Rake need to be able to find locations of libraries relative to the root of my project.
With Maven, I can set a system property like so :
<properties>
<main.basedir>${project.basedir}</main.basedir>
</properties>
And then Java can reference it like so:
String baseDir = System.getProperty("main.basedir");
Can Ruby do something similar? If so, how? Do I need to use a Rake namespace-require + include ? Not brewing my own framework: just trying to do the most basic test setup. I do have some lib files I created that my tests want to use.
This doesn't work because it hard codes the base dir into the class file:
base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
You can probably do this by injecting it in a test helper and getting the base location relative to the location of the file the test helper is is, but I would like to ask you what are you actually trying to achive?
normally the tests have access to the lib path and you should be able to just require what you want to use in the tests directly. are you using something like rspec or test::unit? are you brewing your own test framework?
so overall the answer is yes you can do it, but you should not have to do it. can show you how once you clarify what test framework you're using.
Edit
For test unit, this describes almost what you want to do:
https://github.com/test-unit/test-unit/blob/master/doc/text/how-to.md
The run_test.rb helper is placed in test. You see how the base dir is built by using the path of file (as mentioned above) and how the lib dir is placed on the load path.

spring-boot adding a custom command to actuatorshell in java

I am trying to add a java command to spring-actuator's ssh remote shell in a spring-boot applicaton. The spring-boot version is 1.2.3.RELEASE.
My sample command is just named 'kafka' and I tried placing it on the classpath in both /crash/commands as well as just /commands. It is never found - it doesn't show up in the help or actually work.
Is there some way to ask the remote shell to tell me what it's scanning/finding when it starts?
Things I have tried include specfically overriding shell.commandPathPatterns though the default seems like it should cover it.
My command - for testing - is very simple:
package commands;
#Usage("Kafka utility commands")
public class kafka extends BaseCommand {
#Command
public Object main(InvocationContext<ObjectName> context) {
return "it's all good";
}
}
After one hour of debugging I've found that the CRaSH remote shell looks for files with the extensions .groovy or .java within the packages are commands and crash.commands. The found files are compiled to bytecode, compiler errors are ignored.
I presume you use something like Maven. When you put your command into src/main/java then Maven will compile it as .class file and CRaSH will not find it. When you put your command into src/main/resources then Maven will not compile it and keep it as .java file instead.
The solution (which is quite odd for me) is to put your java command file into src/main/resources (package commands or crash.commands) so you have a .java source file in your target directory or JAR.
I tested it with spring-boot 1.2.1.RELEASE (crash.shell: 1.3.0) which should not be much different than 1.2.3.RELEASE (crash.shell: 1.3.1).

unable to execute jar file(consists dependencies), which is build from gradle

i am very new to gradle, i was trying to build a java file which is dependent on other jar file. It is building properly but when i try to execute it, it is giving "NoClassDefinitionFoundError".
my build.gradle file is:
apply plugin : 'java'
jar {
manifest {
attributes 'Main-Class': 'Hey'
}
}
dependencies
{
compile files('lib/BuildBasicJavaProject.jar') ------line A
}
if i remove the above line A then it is not even building the project.
if i keep that line A then it is building properly and producing the jar file, but when i execute it using ,
java -jar jarfilename.jar
then it is giving me a NoClassDefinitionFoundError.
Where do i need to specify the dependents path while running the jar file??
May be its a basic doubt but i wasted 2 days already in it, i tried giving
1) absolute path of the dependency file
2) adding the following line,
runtime files('lib/BuildBasicJavaProject.jar')
But did not succeed.
Thanks in advance
First welcome to Gradle world.
Your Gradle scripts seems to be correct. When you have a dependency, one jar depends on another like in your case at compile time you define compile time dependency like you did. So if you need this jar to run it you need runtime dependency, in your case. But Gradle automatically put all your compile time dependencies to be runtime dependencies. So you do not need to specify them explicitly.
So why then your code does not working?
The classpath (-cp) option is ignored if using the -jar option. So you can not specify dependent jar using -cp when type jar.So you have to write If you are on Windows
java -cp myJar.jar;.\lib\BuildBasicJavaProject.jar Hey
or use (:) and slashes(/) for Linux.
Where Hey is the full-quallified name of your main class, which have to be defind in the Manifest.
So if your class Hey is in the package:com.alabala.dev and it's name is Hey it's full qualified name is com.alabala.dev.Hey. So you have to tell Gradle
mainClassName = "com.alabala.dev.Hey"
So now Gradle put it in the manifest and when you are trying to load this jar in the JVM, she will know that to start it, she have to execute com.alabala.dev.Hey.
What is cp and why you have to specify it? Said with simple word cp is classpath - directories and archives in which JVM searches when want to load something. So here there is nothing linekd with Gradle it is Java.
You'll want to specify dependency jar(s) as a part of classpath, when you are executing your jar.
Something along these these lines:
java -cp myJar.jar:./lib/BuildBasicJavaProject.jar my.package.MyMainClass
Bare in mind that classpath delimiters are different on different platforms (: is for *nix based systems).

Opening JSON file in JRuby throws exception when evoking the Java class files generated

I use jrubyc to compile Ruby into class files. One of the Ruby files contains
dat = File.open "data.json", "r"
And there's a "data.json" file alongside. This program runs well if I directly use the jruby command.
After I compiled the Ruby files and put them into a jar, the following error appears when I run java -jar:
Exception in thread "main" org.jruby.exceptions.RaiseException: (Errno::ENOENT) data.json
at org.jruby.RubyFile.initialize(org/jruby/RubyFile.java:334)
at org.jruby.RubyIO.open(org/jruby/RubyIO.java:1144)
at RUBY.(root)(file:/Users/x5lai/Documents/rqrcode.jar!/read.rb:2)
...
To make sure that I have not put data.json in the wrong place, I have copied data.json all over the jar file, but the same error occurs.
Is there anyway to do this? Is JRuby unable to open JSON files once I have compiled the code?
I don't think that it is going to look inside the JAR by default. I created a small test and was able to reproduce your issue. I then did touch data.json and the code no longer had an error. I'm not sure how to specify that you want to look inside the JAR for your data file.

Resources