Skip to content

Commit 23e6e3b

Browse files
authored
Merge pull request #356 from robbavey/fix_loading
Fix driver class loading
2 parents 481e0be + f0d5945 commit 23e6e3b

File tree

9 files changed

+87
-53
lines changed

9 files changed

+87
-53
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 4.3.18
2+
- Fix issue with driver loading [#356](https://github.com/logstash-plugins/logstash-input-jdbc/pull/356)
3+
14
## 4.3.17
25
- Added documentation to provide more info about jdbc driver loading [#352](https://github.com/logstash-plugins/logstash-input-jdbc/pull/352)
36

ci/unit/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ FROM docker.elastic.co/logstash/logstash:$ELASTIC_STACK_VERSION
33
COPY --chown=logstash:logstash Gemfile /usr/share/plugins/plugin/Gemfile
44
COPY --chown=logstash:logstash *.gemspec /usr/share/plugins/plugin/
55
RUN cp /usr/share/logstash/logstash-core/versions-gem-copy.yml /usr/share/logstash/versions.yml
6+
RUN curl -o /usr/share/logstash/postgresql.jar https://jdbc.postgresql.org/download/postgresql-42.2.8.jar
67
ENV PATH="${PATH}:/usr/share/logstash/vendor/jruby/bin"
78
ENV LOGSTASH_SOURCE="1"
89
RUN gem install bundler -v '< 2'

ci/unit/docker-compose.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@ services:
1515
LS_JAVA_OPTS: "-Xmx256m -Xms256m"
1616
LOGSTASH_SOURCE: 1
1717
tty: true
18+
19+
postgresql:
20+
image: postgres:latest
21+
volumes:
22+
- ./setup.sql:/docker-entrypoint-initdb.d/init.sql
23+
ports:
24+
- 5432:5432

ci/unit/run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ set -ex
55

66
export USER='logstash'
77

8-
bundle exec rspec -fd 2>/dev/null
8+
bundle exec rspec spec && bundle exec rspec spec/inputs/integ_spec.rb --tag integration -fd 2>/dev/null

ci/unit/setup.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
create DATABASE jdbc_input_db;
2+
3+
\c jdbc_input_db;
4+
5+
CREATE TABLE employee (
6+
emp_no integer NOT NULL,
7+
first_name VARCHAR (50) NOT NULL,
8+
last_name VARCHAR (50) NOT NULL
9+
);
10+
11+
INSERT INTO employee VALUES (1, 'David', 'Blenkinsop');
12+
INSERT INTO employee VALUES (2, 'Mark', 'Guckenheimer');

lib/logstash/plugin_mixins/jdbc/jdbc.rb

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -140,28 +140,18 @@ def jdbc_connect
140140

141141
private
142142

143-
def load_drivers
144-
return if @jdbc_driver_library.nil? || @jdbc_driver_library.empty?
145-
146-
driver_jars = @jdbc_driver_library.split(",")
147-
148-
# Needed for JDK 11 as the DriverManager has a different ClassLoader than Logstash
149-
urls = java.net.URL[driver_jars.length].new
150-
151-
driver_jars.each_with_index do |driver, idx|
152-
urls[idx] = java.io.File.new(driver).toURI().toURL()
153-
end
154-
ucl = java.net.URLClassLoader.new_instance(urls)
155-
begin
156-
klass = java.lang.Class.forName(@jdbc_driver_class.to_java(:string), true, ucl);
157-
rescue Java::JavaLang::ClassNotFoundException => e
158-
raise LogStash::Error, "Unable to find driver class via URLClassLoader in given driver jars: #{@jdbc_driver_class}"
159-
end
160-
begin
161-
driver = klass.getConstructor().newInstance();
162-
java.sql.DriverManager.register_driver(WrappedDriver.new(driver.to_java(java.sql.Driver)).to_java(java.sql.Driver))
163-
rescue Java::JavaSql::SQLException => e
164-
raise LogStash::Error, "Unable to register driver with java.sql.DriverManager using WrappedDriver: #{@jdbc_driver_class}"
143+
def load_driver_jars
144+
unless @jdbc_driver_library.nil? || @jdbc_driver_library.empty?
145+
@jdbc_driver_library.split(",").each do |driver_jar|
146+
begin
147+
@logger.debug("loading #{driver_jar}")
148+
# Use https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby#from-jar-files to make classes from jar
149+
# available
150+
require driver_jar
151+
rescue LoadError => e
152+
raise LogStash::PluginLoadingError, "unable to load #{driver_jar} from :jdbc_driver_library, #{e.message}"
153+
end
154+
end
165155
end
166156
end
167157

@@ -174,7 +164,7 @@ def open_jdbc_connection
174164
Sequel.application_timezone = @plugin_timezone.to_sym
175165
if @drivers_loaded.false?
176166
begin
177-
load_drivers
167+
load_driver_jars
178168
Sequel::JDBC.load_driver(@jdbc_driver_class)
179169
rescue LogStash::Error => e
180170
# raised in load_drivers, e.cause should be the caught Java exceptions

logstash-input-jdbc.gemspec

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Gem::Specification.new do |s|
22
s.name = 'logstash-input-jdbc'
3-
s.version = '4.3.17'
3+
s.version = '4.3.18'
44
s.licenses = ['Apache License (2.0)']
55
s.summary = "Creates events from JDBC data"
66
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -28,5 +28,4 @@ Gem::Specification.new do |s|
2828
s.add_development_dependency 'logstash-devutils'
2929
s.add_development_dependency 'timecop'
3030
s.add_development_dependency 'jdbc-derby'
31-
s.add_development_dependency 'jdbc-postgres'
3231
end

spec/inputs/integ_spec.rb

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
require "logstash/devutils/rspec/spec_helper"
22
require "logstash/inputs/jdbc"
3+
require "sequel"
4+
require "sequel/adapters/jdbc"
35

46
# This test requires: Firebird installed to Mac OSX, it uses the built-in example database `employee`
57

@@ -8,15 +10,23 @@
810
# is picked up. It could be arbitrarily set to any timezone, but then the test
911
# would have to compensate differently. That's why UTC is chosen.
1012
ENV["TZ"] = "Etc/UTC"
11-
let(:mixin_settings) do
12-
{ "jdbc_user" => "SYSDBA", "jdbc_driver_class" => "org.firebirdsql.jdbc.FBDriver", "jdbc_driver_library" => "/elastic/tmp/jaybird-full-3.0.4.jar",
13-
"jdbc_connection_string" => "jdbc:firebirdsql://localhost:3050//Library/Frameworks/Firebird.framework/Versions/A/Resources/examples/empbuild/employee.fdb", "jdbc_password" => "masterkey"}
13+
# For Travis and CI based on docker, we source from ENV
14+
jdbc_connection_string = ENV.fetch("PG_CONNECTION_STRING",
15+
"jdbc:postgresql://postgresql:5432") + "/jdbc_input_db?user=postgres"
16+
17+
let(:settings) do
18+
{ "jdbc_driver_class" => "org.postgresql.Driver",
19+
"jdbc_connection_string" => jdbc_connection_string,
20+
"jdbc_driver_library" => "/usr/share/logstash/postgresql.jar",
21+
"jdbc_user" => "postgres",
22+
"statement" => 'SELECT FIRST_NAME, LAST_NAME FROM "employee" WHERE EMP_NO = 2'
23+
}
1424
end
15-
let(:settings) { {"statement" => "SELECT FIRST_NAME, LAST_NAME FROM EMPLOYEE WHERE EMP_NO > 144"} }
16-
let(:plugin) { LogStash::Inputs::Jdbc.new(mixin_settings.merge(settings)) }
25+
26+
let(:plugin) { LogStash::Inputs::Jdbc.new(settings) }
1727
let(:queue) { Queue.new }
1828

19-
context "when passing no parameters" do
29+
context "when connecting to a postgres instance" do
2030
before do
2131
plugin.register
2232
end
@@ -25,12 +35,44 @@
2535
plugin.stop
2636
end
2737

28-
it "should retrieve params correctly from Event" do
38+
it "should populate the event with database entries" do
2939
plugin.run(queue)
3040
event = queue.pop
3141
expect(event.get('first_name')).to eq("Mark")
3242
expect(event.get('last_name')).to eq("Guckenheimer")
3343
end
3444
end
45+
46+
context "when supplying a non-existent library" do
47+
let(:settings) do
48+
super.merge(
49+
"jdbc_driver_library" => "/no/path/to/postgresql.jar"
50+
)
51+
end
52+
53+
it "should not register correctly" do
54+
plugin.register
55+
q = Queue.new
56+
expect do
57+
plugin.run(q)
58+
end.to raise_error(::LogStash::PluginLoadingError)
59+
end
60+
end
61+
62+
context "when connecting to a non-existent server" do
63+
let(:settings) do
64+
super.merge(
65+
"jdbc_connection_string" => "jdbc:postgresql://localhost:65000/somedb"
66+
)
67+
end
68+
69+
it "should not register correctly" do
70+
plugin.register
71+
q = Queue.new
72+
expect do
73+
plugin.run(q)
74+
end.to raise_error(::Sequel::DatabaseConnectionError)
75+
end
76+
end
3577
end
3678

spec/inputs/jdbc_spec.rb

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
require "logstash/devutils/rspec/spec_helper"
33
require "logstash/inputs/jdbc"
44
require "jdbc/derby"
5-
require 'jdbc/postgres'
6-
Jdbc::Postgres.load_driver
75
require "sequel"
86
require "sequel/adapters/jdbc"
97
require "timecop"
@@ -78,24 +76,6 @@
7876
end
7977
end
8078

81-
context "when connecting to a non-existent server", :no_connection => true do
82-
let(:mixin_settings) do
83-
super.merge(
84-
"jdbc_driver_class" => "org.postgresql.Driver",
85-
"jdbc_connection_string" => "jdbc:postgresql://localhost:65000/somedb"
86-
)
87-
end
88-
let(:settings) { super.merge("statement" => "SELECT 1 as col1 FROM test_table", "jdbc_user" => "foo", "jdbc_password" => "bar") }
89-
90-
it "should not register correctly" do
91-
plugin.register
92-
q = Queue.new
93-
expect do
94-
plugin.run(q)
95-
end.to raise_error(::Sequel::DatabaseConnectionError)
96-
end
97-
end
98-
9979
context "when both jdbc_password and jdbc_password_filepath arguments are passed" do
10080
let(:statement) { "SELECT * from test_table" }
10181
let(:jdbc_password) { "secret" }

0 commit comments

Comments
 (0)