killbill 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. data/Jarfile +3 -2
  2. data/README.md +21 -0
  3. data/VERSION +1 -1
  4. data/killbill.gemspec +4 -2
  5. data/lib/killbill.rb +3 -4
  6. data/lib/killbill/http_servlet.rb +99 -0
  7. data/lib/killbill/jpayment.rb +152 -0
  8. data/lib/killbill/jresponse/jconverter.rb +100 -0
  9. data/lib/killbill/jresponse/jpayment_method_response.rb +89 -0
  10. data/lib/killbill/jresponse/jpayment_method_response_internal.rb +54 -0
  11. data/lib/killbill/jresponse/jpayment_response.rb +59 -0
  12. data/lib/killbill/jresponse/jrefund_response.rb +60 -0
  13. data/lib/killbill/logger.rb +44 -0
  14. data/lib/killbill/payment.rb +16 -8
  15. data/lib/killbill/plugin.rb +59 -26
  16. data/lib/killbill/rake_task.rb +27 -8
  17. data/lib/killbill/response/payment_method_response.rb +31 -0
  18. data/lib/killbill/response/payment_method_response_internal.rb +20 -0
  19. data/lib/killbill/response/payment_response.rb +22 -0
  20. data/lib/killbill/response/payment_status.rb +10 -0
  21. data/lib/killbill/response/refund_response.rb +23 -0
  22. data/spec/killbill/base_plugin_spec.rb +7 -0
  23. data/spec/killbill/config_test.ru +7 -0
  24. data/spec/killbill/jpayment_spec.rb +121 -0
  25. data/spec/killbill/jresponse/jconverter_spec.rb +208 -0
  26. data/spec/killbill/jresponse/jpayment_method_response_internal_spec.rb +34 -0
  27. data/spec/killbill/jresponse/jpayment_method_response_spec.rb +53 -0
  28. data/spec/killbill/jresponse/jpayment_response_spec.rb +41 -0
  29. data/spec/killbill/jresponse/jrefund_response_spec.rb +41 -0
  30. data/spec/killbill/killbill_integration_spec.rb +4 -5
  31. data/spec/killbill/payment_plugin_spec.rb +7 -3
  32. data/spec/killbill/payment_test.rb +88 -0
  33. data/spec/killbill/rack_handler_spec.rb +16 -0
  34. data/spec/spec_helper.rb +5 -0
  35. metadata +79 -16
data/Jarfile CHANGED
@@ -1,2 +1,3 @@
1
- jar 'com.ning.billing:killbill-api', '0.1.48'
2
- jar 'com.ning.billing:killbill-util:tests', '0.1.48'
1
+ jar 'com.ning.billing:killbill-api', '0.1.56-SNAPSHOT'
2
+ jar 'com.ning.billing:killbill-util:tests', '0.1.56-SNAPSHOT'
3
+ jar 'javax.servlet:javax.servlet-api', '3.0.1'
data/README.md CHANGED
@@ -1,3 +1,6 @@
1
+ [![Build Status](https://travis-ci.org/killbill/killbill-plugin-framework-ruby.png)](https://travis-ci.org/killbill/killbill-plugin-framework-ruby)
2
+ [![Code Climate](https://codeclimate.com/github/killbill/killbill-plugin-framework-ruby.png)](https://codeclimate.com/github/killbill/killbill-plugin-framework-ruby)
3
+
1
4
  killbill-plugin-framework-ruby
2
5
  ==============================
3
6
 
@@ -8,6 +11,8 @@ There are various types of plugins one can write for Killbill:
8
11
  1. notifications plugins, which listen to external bus events and can react to it
9
12
  2. payment plugins, which are used to issue payments against a payment gateway
10
13
 
14
+ Both types of plugin can interact with Killbill directly via killbill-library APIs and expose HTTP endpoints.
15
+
11
16
  How to write a Notification plugin
12
17
  ----------------------------------
13
18
 
@@ -88,6 +93,22 @@ Make sure to create the corresponding killbill.properties file:
88
93
  mainClass=MyPaymentPlugin
89
94
  pluginType=PAYMENT
90
95
 
96
+ How to expose HTTP endpoints
97
+ ----------------------------
98
+
99
+ Killbill exports a Rack handler that interfaces directly with the container in which killbill-server runs (e.g. Jetty).
100
+
101
+ This basically means that Killbill will understand native Rack config.ru files placed in the root of your plugin, e.g. (using Sinatra):
102
+
103
+ require 'sinatra'
104
+
105
+ get "/plugins/myPlugin/ping" do
106
+ status 200
107
+ "pong"
108
+ end
109
+ run Sinatra::Application
110
+
111
+
91
112
  Rake tasks
92
113
  ----------
93
114
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.0.1
data/killbill.gemspec CHANGED
@@ -23,10 +23,12 @@ Gem::Specification.new do |s|
23
23
  s.rdoc_options << '--exclude' << '.'
24
24
 
25
25
  s.add_development_dependency 'jbundler', '~> 0.4.1'
26
+ s.add_development_dependency 'rack', '>= 1.5.2'
26
27
  s.add_development_dependency 'rake', '>= 0.8.7'
27
28
  s.add_development_dependency 'rspec', '~> 2.12.0'
29
+ s.add_development_dependency 'sinatra', '~> 1.3.4'
28
30
 
29
- s.requirements << "jar 'com.ning.billing:killbill-api', '0.1.48'"
31
+ s.requirements << "jar 'com.ning.billing:killbill-api', '0.1.56-SNAPSHOT'"
30
32
  # For testing only
31
- s.requirements << "jar 'com.ning.billing:killbill-util:tests', '0.1.48'"
33
+ s.requirements << "jar 'com.ning.billing:killbill-util:tests', '0.1.56-SNAPSHOT'"
32
34
  end
data/lib/killbill.rb CHANGED
@@ -17,7 +17,6 @@ KILLBILL_APIS = %w(
17
17
  com.ning.billing.invoice.api.InvoiceMigrationApi
18
18
  com.ning.billing.invoice.api.InvoicePaymentApi
19
19
  com.ning.billing.invoice.api.InvoiceUserApi
20
- com.ning.billing.meter.api.MeterUserApi
21
20
  com.ning.billing.overdue.OverdueUserApi
22
21
  com.ning.billing.payment.api.PaymentApi
23
22
  com.ning.billing.tenant.api.TenantUserApi
@@ -35,12 +34,12 @@ rescue NameError
35
34
  begin
36
35
  require 'jbundler'
37
36
  KILLBILL_APIS.each { |api| java_import api }
38
- warn 'Using JBundler to load killbill-api. This should only happen in development mode!'
39
- warn "Classpath (see .jbundler/classpath.rb):\n\t#{JBUNDLER_CLASSPATH.join("\n\t")}"
37
+ warn 'Using JBundler to load killbill-api (see .jbundler/classpath.rb). This should only happen in development mode!'
40
38
  rescue LoadError => e
41
- warn 'Unable to load killbill-api and couldn\'t find JBundler. For development purposes, make sure to run: `bundle install && jbundle install\' from the killbill gem source tree'
39
+ warn 'Unable to load killbill-api. For development purposes, use JBundler (create the following Jarfile: http://git.io/eobYXA and run: `bundle install && jbundle install\')'
42
40
  end
43
41
  end
44
42
 
43
+ require 'killbill/http_servlet'
45
44
  require 'killbill/notification'
46
45
  require 'killbill/payment'
@@ -0,0 +1,99 @@
1
+ gem 'rack'
2
+ require 'rack'
3
+ require 'rack/rewindable_input'
4
+
5
+ require 'singleton'
6
+
7
+ module Killbill
8
+ module Plugin
9
+ java_package 'com.ning.billing.osgi.api.http'
10
+ class RackHandler < Java::javax.servlet.http.HttpServlet
11
+ include Singleton
12
+
13
+ def configure(logger, config_ru)
14
+ @logger = logger
15
+ @app = Rack::Builder.parse_file(config_ru).first
16
+ end
17
+
18
+ def configured?
19
+ !@app.nil?
20
+ end
21
+
22
+ java_signature 'void service(HttpServletRequest, HttpServletResponse)'
23
+ def service(servlet_request, servlet_response)
24
+ input = Rack::RewindableInput.new(servlet_request.input_stream.to_io)
25
+ scheme = servlet_request.scheme
26
+ method = servlet_request.method
27
+ request_uri = servlet_request.request_uri
28
+ query_string = servlet_request.query_string
29
+ server_name = servlet_request.server_name
30
+ server_port = servlet_request.server_port
31
+ content_type = servlet_request.content_type
32
+ content_length = servlet_request.content_length
33
+
34
+ headers = {}
35
+ servlet_request.header_names.reject { |name| name =~ /^Content-(Type|Length)$/i }.each do |name|
36
+ headers[name] = servlet_request.get_headers(name).to_a
37
+ end
38
+
39
+ response_status, response_headers, response_body = rack_service(request_uri, method, query_string, input, scheme, server_name, server_port, content_type, content_length, headers)
40
+
41
+ # Set status
42
+ servlet_response.status = response_status
43
+
44
+ # Set headers
45
+ response_headers.each do |header_name, header_value|
46
+ case header_name
47
+ when /^Content-Type$/i
48
+ servlet_response.content_type = header_value.to_s
49
+ when /^Content-Length$/i
50
+ servlet_response.content_length = header_value.to_i
51
+ else
52
+ servlet_response.add_header(header_name.to_s, header_value.to_s)
53
+ end
54
+ end
55
+
56
+ # Write output
57
+ response_stream = servlet_response.output_stream
58
+ response_body.each { |part| response_stream.write(part.to_java_bytes) }
59
+ response_stream.flush rescue nil
60
+ ensure
61
+ response_body.close if response_body.respond_to? :close
62
+ end
63
+
64
+ def rack_service(request_uri = '/', method = 'GET', query_string = '', input = '', scheme = 'http', server_name = 'localhost', server_port = 4567, content_type = 'text/plain', content_length = 0, headers = {})
65
+ rack_env = {
66
+ 'rack.version' => Rack::VERSION,
67
+ 'rack.multithread' => true,
68
+ 'rack.multiprocess' => false,
69
+ 'rack.input' => input,
70
+ # TODO
71
+ 'rack.errors' => java::lang::System::err.to_io,
72
+ 'rack.logger' => java::lang::System::out.to_io,
73
+ 'rack.url_scheme' => scheme,
74
+ 'REQUEST_METHOD' => method,
75
+ 'SCRIPT_NAME' => '',
76
+ 'PATH_INFO' => request_uri,
77
+ 'QUERY_STRING' => (query_string || ""),
78
+ 'SERVER_NAME' => server_name,
79
+ 'SERVER_PORT' => server_port.to_s
80
+ }
81
+
82
+ rack_env['CONTENT_TYPE'] = content_type unless content_type.nil?
83
+ rack_env['CONTENT_LENGTH'] = content_length unless content_length.nil?
84
+ headers.each do |name, values|
85
+ rack_env["HTTP_#{name.to_s.upcase.gsub(/-/,'_')}"] = values.join(',')
86
+ end
87
+
88
+ @app.call(rack_env)
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ # Fix bug in JRuby's handling of gems in jars (JRUBY-3986)
95
+ class File
96
+ def self.mtime(path)
97
+ stat(path).mtime
98
+ end
99
+ end
@@ -0,0 +1,152 @@
1
+ require 'singleton'
2
+
3
+ require 'killbill/plugin'
4
+ require 'killbill/jresponse/jpayment_response'
5
+ require 'killbill/jresponse/jrefund_response'
6
+ require 'killbill/jresponse/jpayment_method_response'
7
+ require 'killbill/jresponse/jpayment_method_response_internal'
8
+
9
+
10
+ module Killbill
11
+ module Plugin
12
+
13
+ java_package 'com.ning.billing.payment.plugin.api'
14
+ class JPayment
15
+
16
+ include Java::com.ning.billing.payment.plugin.api.PaymentPluginApi
17
+
18
+ attr_reader :real_payment
19
+
20
+ def initialize(real_class_name, services = {})
21
+ real_payment_class = class_from_string(real_class_name)
22
+ @real_payment = real_payment_class.new(services)
23
+ end
24
+
25
+ # TODO STEPH decide what to do the getName()
26
+ java_signature 'java.lang.String getName()'
27
+ def get_name
28
+ end
29
+
30
+ java_signature 'Java::com.ning.billing.payment.plugin.api.PaymentInfoPlugin processPayment(java.util.UUID, java.util.UUID, java.lang.BigDecimal, Java::com.ning.billing.util.callcontext.CallContext)'
31
+ def charge(*args)
32
+ do_call_handle_exception(__method__, *args) do |res|
33
+ return JPaymentResponse.new(res)
34
+ end
35
+ end
36
+
37
+ java_signature 'Java::com.ning.billing.payment.plugin.api.PaymentInfoPlugin getPaymentInfo(java.util.UUID, Java::com.ning.billing.util.callcontext.TenantContext)'
38
+ def get_payment_info(*args)
39
+ do_call_handle_exception(__method__, *args) do |res|
40
+ return JPaymentResponse.new(res)
41
+ end
42
+ end
43
+
44
+ java_signature 'Java::com.ning.billing.payment.plugin.api.RefundInfoPlugin processRefund(java.util.UUID, java.lang.BigDecimal, Java::com.ning.billing.util.callcontext.CallContext)'
45
+ def refund(*args)
46
+ do_call_handle_exception(__method__, *args) do |res|
47
+ return JRefundResponse.new(res)
48
+ end
49
+ end
50
+
51
+ java_signature 'void addPaymentMethod(java.util.UUID, java.util.UUID, Java::com.ning.billing.payment.api.PaymentMethodPlugin, Java::boolean, Java::com.ning.billing.util.callcontext.CallContext)'
52
+ def add_payment_method(*args)
53
+ do_call_handle_exception(__method__, *args) do |res|
54
+ return nil
55
+ end
56
+ end
57
+
58
+ java_signature 'void deletePaymentMethod(java.util.UUID, Java::com.ning.billing.util.callcontext.CallContext)'
59
+ def delete_payment_method(*args)
60
+ do_call_handle_exception(__method__, *args) do |res|
61
+ return nil
62
+ end
63
+ end
64
+
65
+ java_signature 'Java::com.ning.billing.payment.api.PaymentMethodPlugin getPaymentMethodDetail(java.util.UUID, java.util.UUID, Java::com.ning.billing.util.callcontext.TenantContext)'
66
+ def get_payment_method_detail(*args)
67
+ do_call_handle_exception(__method__, *args) do |res|
68
+ return JPaymentMethodResponse.new(res)
69
+ end
70
+ end
71
+
72
+ java_signature 'void setDefaultPaymentMethod(java.util.UUID kbPaymentMethodId, Java::com.ning.billing.util.callcontext.CallContext)'
73
+ def set_default_payment_method(*args)
74
+ do_call_handle_exception(__method__, *args) do |res|
75
+ return nil
76
+ end
77
+ end
78
+
79
+ java_signature 'java.util.List getPaymentMethods(java.util.UUID, Java::boolean refreshFromGateway, Java::com.ning.billing.util.callcontext.CallContext)'
80
+ def get_payment_methods(*args)
81
+ do_call_handle_exception(__method__, *args) do |res|
82
+ array_res = java.util.ArrayList.new
83
+ res.each do |el|
84
+ array_res.add(JPaymentMethodResponseInternal.new(el))
85
+ end
86
+ return array_res
87
+ end
88
+ end
89
+
90
+ java_signature 'void resetPaymentMethods(java.util.List)'
91
+ def reset_payment_methods(*args)
92
+ do_call_handle_exception(__method__, *args) do |res|
93
+ return nil
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def do_call_handle_exception(method_name, *args)
100
+ begin
101
+ rargs = convert_args(method_name, args)
102
+ res = @real_payment.send(method_name, *rargs)
103
+ yield(res)
104
+ rescue Exception => e
105
+ wrap_and_throw_exception(method_name, e)
106
+ end
107
+ end
108
+
109
+ def wrap_and_throw_exception(api, e)
110
+ raise Java::com.ning.billing.payment.plugin.api.PaymentPluginApiException.new("#{api} failure", e.message)
111
+ end
112
+
113
+ def class_from_string(str)
114
+ str.split('::').inject(Kernel) do |mod, class_name|
115
+ mod.const_get(class_name)
116
+ end
117
+ end
118
+
119
+ def convert_args(api, args)
120
+ args.collect! do |a|
121
+ if a.nil?
122
+ nil
123
+ elsif a.java_kind_of? java.util.UUID
124
+ JConverter.from_uuid(a)
125
+ elsif a.java_kind_of? java.math.BigDecimal
126
+ JConverter.from_big_decimal(a)
127
+ elsif a.java_kind_of? Java::com.ning.billing.payment.api.PaymentMethodPlugin
128
+ JConverter.from_payment_method_plugin(a)
129
+ elsif ((a.java_kind_of? Java::boolean) || (a.java_kind_of? java.lang.Boolean))
130
+ JConverter.from_boolean(a)
131
+ elsif a.java_kind_of? java.util.List
132
+ result = Array.new
133
+ if a.size > 0
134
+ first_element = a.get(0)
135
+ if first_element.java_kind_of? Java::com.ning.billing.payment.plugin.api.PaymentMethodInfoPlugin
136
+ a.each do |el|
137
+ result << JConverter.from_payment_method_info_plugin(el)
138
+ end
139
+ else
140
+ raise Java::com.ning.billing.payment.plugin.api.PaymentPluginApiException.new("#{api} failure", "Unexpected parameter type #{first_element.class} for list")
141
+ end
142
+ end
143
+ result
144
+ else
145
+ raise Java::com.ning.billing.payment.plugin.api.PaymentPluginApiException.new("#{api} failure", "Unexpected parameter type #{a.class}")
146
+ end
147
+ end
148
+ end
149
+
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,100 @@
1
+
2
+ require 'date'
3
+ require 'killbill/response/payment_status'
4
+
5
+ module Killbill
6
+ module Plugin
7
+
8
+ class JConverter
9
+
10
+ class << self
11
+
12
+ #
13
+ # Convert from ruby -> java
14
+ #
15
+ def to_uuid(uuid)
16
+ uuid.nil? ? nil : java.util.UUID.fromString(uuid.to_s)
17
+ end
18
+
19
+ def to_joda_date_time(time)
20
+ time.nil? ? nil : org.joda.time.DateTime.new(time.to_s)
21
+ end
22
+
23
+ def to_string(str)
24
+ str.nil? ? nil : java.lang.String.new(str)
25
+ end
26
+
27
+ def to_payment_plugin_status(status)
28
+ if status == PaymentStatus::SUCCESS
29
+ Java::com.ning.billing.payment.plugin.api.PaymentInfoPlugin::PaymentPluginStatus::PROCESSED
30
+ elsif status == PaymentStatus::ERROR
31
+ Java::com.ning.billing.payment.plugin.api.PaymentInfoPlugin::PaymentPluginStatus::ERROR
32
+ else
33
+ Java::com.ning.billing.payment.plugin.api.PaymentInfoPlugin::PaymentPluginStatus::UNDEFINED
34
+ end
35
+ end
36
+
37
+ def to_big_decimal(amount_in_cents)
38
+ amount_in_cents.nil? ? java.math.BigDecimal::ZERO : java.math.BigDecimal.new('%.2f' % (amount_in_cents.to_i/100.0))
39
+ end
40
+
41
+ def to_boolean(b)
42
+ java.lang.Boolean.new(b)
43
+ end
44
+
45
+
46
+ #
47
+ # Convert from java -> ruby
48
+ #
49
+ def from_uuid(uuid)
50
+ uuid.nil? ? nil : uuid.to_s
51
+ end
52
+
53
+ def from_joda_date_time(joda_time)
54
+ if joda_time.nil?
55
+ return nil
56
+ end
57
+
58
+ fmt = org.joda.time.format.ISODateTimeFormat.date_time
59
+ str = fmt.print(joda_time);
60
+ DateTime.iso8601(str)
61
+ end
62
+
63
+ def from_string(str)
64
+ str.nil? ? nil : str.to_s
65
+ end
66
+
67
+ def from_payment_plugin_status(status)
68
+ if status == Java::com.ning.billing.payment.plugin.api.PaymentInfoPlugin::PaymentPluginStatus::PROCESSED
69
+ PaymentStatus::SUCCESS
70
+ elsif status == Java::com.ning.billing.payment.plugin.api.PaymentInfoPlugin::PaymentPluginStatus::ERROR
71
+ PaymentStatus::ERROR
72
+ else
73
+ PaymentStatus::UNDEFINED
74
+ end
75
+ end
76
+
77
+ def from_big_decimal(big_decimal)
78
+ big_decimal.nil? ? 0 : big_decimal.multiply(java.math.BigDecimal.valueOf(100)).to_s.to_i
79
+ end
80
+
81
+ def from_boolean(b)
82
+ if b.nil?
83
+ return false
84
+ end
85
+
86
+ b_value = (b.java_kind_of? java.lang.Boolean) ? b.boolean_value : b
87
+ return b_value ? true : false
88
+ end
89
+
90
+ def from_payment_method_plugin(payment_method_plugin)
91
+ JPaymentMethodResponse.to_payment_method_response(payment_method_plugin)
92
+ end
93
+
94
+ def from_payment_method_info_plugin(payment_method_info_plugin)
95
+ JPaymentMethodResponseInternal.to_payment_method_response_internal(payment_method_info_plugin)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,89 @@
1
+ require 'killbill/response/payment_method_response'
2
+ require 'killbill/jresponse/jconverter'
3
+
4
+ module Killbill
5
+ module Plugin
6
+
7
+ class JPaymentMethodProperty < Java::com.ning.billing.payment.api.PaymentMethodPlugin::PaymentMethodKVInfo
8
+
9
+ class << self
10
+ def create_from(payment_method_prop)
11
+
12
+ key = JConverter.to_string(payment_method_prop.key)
13
+ value = JConverter.to_string(payment_method_prop.value)
14
+ is_updatable = JConverter.to_boolean(payment_method_prop.is_updatable)
15
+ Java::com.ning.billing.payment.api.PaymentMethodPlugin::PaymentMethodKVInfo.new(key, value, is_updatable)
16
+ end
17
+
18
+ def to_payment_method_property(jpayment_method_prop)
19
+ key = JConverter.from_string(jpayment_method_prop.get_key)
20
+ value = JConverter.from_string(jpayment_method_prop.get_value)
21
+ is_updatable = JConverter.from_boolean(jpayment_method_prop.get_is_updatable)
22
+ PaymentMethodProperty.new(key, value, is_updatable)
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ java_package 'com.ning.billing.payment.api'
30
+ class JPaymentMethodResponse
31
+
32
+ include Java::com.ning.billing.payment.api.PaymentMethodPlugin
33
+
34
+ attr_reader :external_payment_method_id,
35
+ :is_default,
36
+ :properties
37
+
38
+ class << self
39
+ def to_payment_method_response(jpayment_method_response)
40
+ props = Array.new
41
+ jpayment_method_response.get_properties.each do |p|
42
+ props << JPaymentMethodProperty.to_payment_method_property(p)
43
+ end
44
+ pmid = JConverter.from_string(jpayment_method_response.get_external_payment_method_id)
45
+ default = JConverter.from_boolean(jpayment_method_response.is_default_payment_method)
46
+ PaymentMethodResponse.new(pmid, default, props)
47
+ end
48
+
49
+ end
50
+
51
+ def initialize(payment_method_response)
52
+ @external_payment_method_id = JConverter.to_string(payment_method_response.external_payment_method_id)
53
+ @is_default = JConverter.to_boolean(payment_method_response.is_default)
54
+ @properties = java.util.ArrayList.new
55
+ payment_method_response.properties.each do |p|
56
+ jp = JPaymentMethodProperty.create_from(p)
57
+ @properties.add(jp)
58
+ end
59
+ end
60
+
61
+ java_signature 'java.lang.String getExternalPaymentMethodId()'
62
+ def get_external_payment_method_id
63
+ @external_payment_method_id
64
+ end
65
+
66
+ java_signature 'java.lang.Boolean isDefaultPaymentMethod()'
67
+ def is_default_payment_method
68
+ @is_default
69
+ end
70
+
71
+ java_signature 'java.util.List getProperties()'
72
+ def get_properties
73
+ @properties
74
+ end
75
+
76
+ java_signature 'java.lang.String getValueString(java.lang.String)'
77
+ def get_value_string(key)
78
+ @properties.each do |p|
79
+ if p.key == key
80
+ return p
81
+ end
82
+ end
83
+ nil
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+ end