Enables the use of a Ruby script as a delegate.
The delegate script is reloaded whenever the script file changes. Be aware, though, that code that has already been loaded into the JRuby runtime cannot be unloaded. For example, when a class is changed, the new version will replace the old version; but constants within the class cannot be redefined.
JRuby can use most Ruby gems, except those that have been built with native extensions. To import a gem, use a require
statement:
require 'mygem'
require
searches for gems based on the $GEM_PATH
environment variable, falling back to $GEM_HOME
if that is not defined. If JRuby fails to find your gem, check your $GEM_PATH
. If you installed the gem using gem install
, check the output of gem env
(particularly the "gem paths" section) to see where it might have been installed, and ensure that those locations are present in $GEM_PATH
.
This example uses URLConnection, which is part of the JDK, to execute an HTTP request.
require "java"
java_import java.net.HttpURLConnection
java_import java.net.URL
java_import java.io.BufferedReader
java_import java.io.FileNotFoundException
java_import java.io.InputStreamReader
java_import java.util.stream.Collectors
class CustomDelegate
def do_something
url = URL.new "http://example.org/"
conn, is, reader = nil
begin
conn = url.openConnection
conn.setRequestMethod "GET"
conn.setReadTimeout 30 * 1000
conn.connect
is = conn.getInputStream
status = conn.getResponseCode
if status == 200
content_type = conn.getHeaderField "Content-Type"
if content_type.include? "text/plain"
reader = BufferedReader.new(InputStreamReader.new(is))
entity = reader.lines.collect(Collectors.joining("\n"))
puts entity
else
raise IOError, "Unexpected Content-Type: #{content_type}"
end
else
raise IOError, "Unexpected status: #{status}"
end
rescue FileNotFoundException => e
return nil
rescue => e
Java::is.galia.plugin.jruby.Logger.error("#{e}", e)
ensure
reader&.close
is&.close
conn&.disconnect
end
end
end
See also: Calling Java From JRuby
The whole Java Class Library is available, and there's nothing to prevent you from using third-party JARs and accessing their API from JRuby. Be careful, though, as JARs may contain code that conflicts with the application's dependencies—different versions of the same library, for example.
Several delegate methods will be called over the course of a single request, and making them as efficient as possible will improve response times. A couple of ways to improve efficiency are:
Some methods may need to do similar work, which may be expensive. To avoid having to do it twice, a useful technique is to cache the first result. So, rather than doing this:
class CustomDelegate
def method1(options = {})
# perform an expensive query and return the result
end
def method2(options = {})
# perform the same expensive query and return the result
end
end
You could do this:
class CustomDelegate
def method1(options = {})
result = perform_expensive_query
end
def method2(options = {})
result = perform_expensive_query
end
# Performs an expensive query only once, caching the result.
def perform_expensive_query
unless @result
# perform the query
@result = ... # save the result in an instance variable
end
@result
end
end
Many HTTP clients maintain an internal connection pool, but JDBC adapters do not. When accessing a database via JDBC, consider using a connection pool to improve performance. As of now, there is no "official" provision for this, but some options include:
Delegate methods may access a logger that writes to the application log:
require "java"
logger = Java::is.galia.plugin.jruby.Logger
logger.trace "Hello world"
logger.debug "Hello world"
logger.info "Hello world"
logger.warn "Hello world"
logger.error "Hello world"
Error stack traces may also be logged:
require "java"
logger = Java::is.galia.plugin.jruby.Logger
begin
raise "Goodbye world"
rescue => e
logger.error("#{e}", e)
end
Delegate methods can be tested by creating an instance of the CustomDelegate
class, setting its context to be similar to what the application would set it to, and calling a method:
# This file is named `test.rb`, in the same folder as `delegates.rb`
require "./delegates"
# Initialize the delegate
obj = CustomDelegate.new
obj.context = {
"identifier" => "identifier-to-test",
"client_ip" => "127.0.0.1",
"request_headers" => {
"X-SomeHeader" => "peas",
"X-OtherHeader" => "carrots"
}
}
# Perform the test
raise "fail" unless obj.filesystemsource_pathname == "expected value"
This script can then be run on the command line with a command like: ruby test.rb
.
Use the plugin installer:
bin/install_plugin.sh galia-plugin-jruby
Alternatively, download the plugin directly and extract it into Galia's plugins directory.
Copy the delegates.yml.sample
file to config/delegates.rb within the Galia folder, and implement the methods of your choice.
Copy the keys from config.yml.sample
into your application configuration
file and fill them in.
Also, make sure that the delegate.JRubyDelegate.script_pathname
key is set to the path to the script (e.g. config/delegates.rb).