killbill 3.2.2 → 3.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -2
- data/Jarfile +7 -7
- data/README.md +16 -4
- data/VERSION +1 -1
- data/gen_config/api.conf +48 -47
- data/gen_config/plugin_api.conf +17 -16
- data/generators/active_merchant/templates/.gitignore.rb +2 -2
- data/generators/active_merchant/templates/lib/api.rb +8 -0
- data/generators/active_merchant/templates/plugin.gemspec.rb +1 -0
- data/generators/active_merchant/templates/spec/base_plugin_spec.rb +1 -0
- data/generators/active_merchant/templates/spec/integration_spec.rb +5 -1
- data/killbill.gemspec +1 -0
- data/lib/killbill/creator.rb +9 -0
- data/lib/killbill/currency.rb +6 -0
- data/lib/killbill/gen/api/account_audit_logs_for_object_type.rb +9 -7
- data/lib/killbill/gen/api/catalog_user_api.rb +37 -4
- data/lib/killbill/gen/api/payment_api.rb +104 -0
- data/lib/killbill/gen/api/payment_gateway_api.rb +6 -3
- data/lib/killbill/gen/api/plan_phase.rb +1 -8
- data/lib/killbill/gen/api/price_list_set.rb +9 -7
- data/lib/killbill/gen/api/subscription.rb +20 -1
- data/lib/killbill/gen/api/tenant_user_api.rb +3 -3
- data/lib/killbill/gen/plugin-api/currency_plugin_with_events_api.rb +207 -0
- data/lib/killbill/gen/plugin-api/ext_bus_event.rb +7 -1
- data/lib/killbill/gen/plugin-api/invoice_plugin_with_events_api.rb +103 -0
- data/lib/killbill/gen/plugin-api/payment_plugin_with_events_api.rb +782 -0
- data/lib/killbill/gen/plugin-api/require_gen.rb +3 -0
- data/lib/killbill/helpers/active_merchant/configuration.rb +116 -46
- data/lib/killbill/helpers/active_merchant/killbill_spec_helper.rb +49 -32
- data/lib/killbill/helpers/active_merchant/payment_plugin.rb +18 -6
- data/lib/killbill/helpers/active_merchant/private_payment_plugin.rb +3 -3
- data/lib/killbill/helpers/active_merchant/utils.rb +37 -70
- data/lib/killbill/invoice.rb +6 -0
- data/lib/killbill/payment.rb +6 -0
- data/lib/killbill/plugin.rb +1 -1
- data/lib/killbill/rake_task.rb +1 -1
- data/spec/killbill/helpers/configuration_spec.rb +41 -5
- data/spec/killbill/helpers/payment_plugin_spec.rb +4 -1
- data/spec/killbill/helpers/private_payment_plugin_spec.rb +4 -2
- data/spec/killbill/helpers/utils_spec.rb +6 -6
- data/spec/killbill/invoice_plugin_api_spec.rb +1 -1
- data/spec/killbill/notification_plugin_api_spec.rb +1 -1
- data/spec/killbill/payment_plugin_api_spec.rb +1 -1
- metadata +19 -3
- data/lib/killbill/jnotification.rb +0 -31
@@ -28,10 +28,13 @@
|
|
28
28
|
require 'killbill/gen/plugin-api/payment_method_info_plugin'
|
29
29
|
require 'killbill/gen/plugin-api/payment_plugin_api'
|
30
30
|
require 'killbill/gen/plugin-api/payment_plugin_api_exception'
|
31
|
+
require 'killbill/gen/plugin-api/payment_plugin_with_events_api'
|
31
32
|
require 'killbill/gen/plugin-api/ext_bus_event'
|
32
33
|
require 'killbill/gen/plugin-api/notification_plugin_api'
|
33
34
|
require 'killbill/gen/plugin-api/invoice_plugin_api'
|
35
|
+
require 'killbill/gen/plugin-api/invoice_plugin_with_events_api'
|
34
36
|
require 'killbill/gen/plugin-api/currency_plugin_api'
|
37
|
+
require 'killbill/gen/plugin-api/currency_plugin_with_events_api'
|
35
38
|
require 'killbill/gen/plugin-api/gateway_notification'
|
36
39
|
require 'killbill/gen/plugin-api/hosted_payment_page_form_descriptor'
|
37
40
|
require 'killbill/gen/plugin-api/payment_transaction_info_plugin'
|
@@ -1,73 +1,143 @@
|
|
1
1
|
require 'logger'
|
2
|
+
require 'thread_safe'
|
2
3
|
|
3
4
|
module Killbill
|
4
5
|
module Plugin
|
5
6
|
module ActiveMerchant
|
6
|
-
|
7
|
-
mattr_reader :
|
8
|
-
mattr_reader :
|
7
|
+
|
8
|
+
mattr_reader :glob_config
|
9
|
+
mattr_reader :glob_currency_conversions
|
10
|
+
|
9
11
|
mattr_reader :initialized
|
10
12
|
mattr_reader :kb_apis
|
13
|
+
mattr_reader :gateway_name
|
14
|
+
mattr_reader :gateway_builder
|
11
15
|
mattr_reader :logger
|
16
|
+
mattr_reader :config_key_name
|
17
|
+
mattr_reader :per_tenant_config_cache
|
12
18
|
|
13
|
-
def self.initialize!(gateway_builder, gateway_name, logger, config_file, kb_apis)
|
14
|
-
@@config = Properties.new(config_file)
|
15
|
-
@@config.parse!
|
16
19
|
|
17
|
-
|
18
|
-
@@logger.log_level = Logger::DEBUG if (@@config[:logger] || {})[:debug]
|
20
|
+
class << self
|
19
21
|
|
20
|
-
|
21
|
-
@@kb_apis = kb_apis
|
22
|
+
def initialize!(gateway_builder, gateway_name, logger, config_key_name, config_file, kb_apis)
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
@@logger = logger
|
25
|
+
@@kb_apis = kb_apis
|
26
|
+
@@gateway_name = gateway_name
|
27
|
+
@@gateway_builder = gateway_builder
|
28
|
+
@@config_key_name = config_key_name
|
29
|
+
@@per_tenant_config_cache = ThreadSafe::Cache.new
|
30
|
+
|
31
|
+
if defined?(JRUBY_VERSION)
|
32
|
+
begin
|
33
|
+
# See https://github.com/jruby/activerecord-jdbc-adapter/issues/302
|
34
|
+
require 'jdbc/mysql'
|
35
|
+
::Jdbc::MySQL.load_driver(:require) if ::Jdbc::MySQL.respond_to?(:load_driver)
|
36
|
+
rescue => e
|
37
|
+
@@logger.warn "Unable to load the JDBC driver: #{e}"
|
34
38
|
end
|
35
39
|
end
|
36
|
-
|
37
|
-
|
38
|
-
@@gateways[:default] = Gateway.wrap(gateway_builder, logger, gateway_configs)
|
40
|
+
|
41
|
+
initialize_from_global_config!(gateway_builder, gateway_name, logger, config_file)
|
39
42
|
end
|
40
43
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
|
45
|
+
def gateways(kb_tenant_id=nil)
|
46
|
+
tenant_config = get_tenant_config(kb_tenant_id)
|
47
|
+
extract_gateway_config(tenant_config)
|
48
|
+
end
|
49
|
+
|
50
|
+
def currency_conversions(kb_tenant_id=nil)
|
51
|
+
tenant_config = get_tenant_config(kb_tenant_id)
|
52
|
+
if tenant_config
|
53
|
+
tenant_config[:currency_conversions]
|
54
|
+
else
|
55
|
+
@@glob_currency_conversions
|
48
56
|
end
|
49
57
|
end
|
50
58
|
|
51
|
-
|
52
|
-
|
53
|
-
::ActiveRecord::Base.establish_connection(@@config[:database])
|
54
|
-
::ActiveRecord::Base.logger = @@logger
|
55
|
-
rescue => e
|
56
|
-
@@logger.warn "Unable to establish a database connection: #{e}"
|
59
|
+
def config(kb_tenant_id=nil)
|
60
|
+
get_tenant_config(kb_tenant_id)
|
57
61
|
end
|
58
62
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
+
def converted_currency(currency, kb_tenant_id=nil)
|
64
|
+
currency_sym = currency.to_s.upcase.to_sym
|
65
|
+
tmp = currency_conversions(kb_tenant_id)
|
66
|
+
tmp && tmp[currency_sym]
|
63
67
|
end
|
64
68
|
|
65
|
-
|
66
|
-
|
69
|
+
def invalidate_tenant_config!(kb_tenant_id)
|
70
|
+
@@logger.info("Invalidate plugin key #{@@config_key_name}, tenant = #{kb_tenant_id}")
|
71
|
+
@@per_tenant_config_cache[kb_tenant_id] = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def extract_gateway_config(config)
|
77
|
+
gateways_config = {}
|
78
|
+
gateway_configs = config[@@gateway_name.to_sym]
|
79
|
+
if gateway_configs.is_a?(Array)
|
80
|
+
default_gateway = nil
|
81
|
+
gateway_configs.each_with_index do |gateway_config, idx|
|
82
|
+
gateway_account_id = gateway_config[:account_id]
|
83
|
+
if gateway_account_id.nil?
|
84
|
+
@@logger.warn "Skipping config #{gateway_config} -- missing :account_id"
|
85
|
+
else
|
86
|
+
gateways_config[gateway_account_id.to_sym] = Gateway.wrap(gateway_builder, logger, gateway_config)
|
87
|
+
default_gateway = gateways_config[gateway_account_id.to_sym] if idx == 0
|
88
|
+
end
|
89
|
+
end
|
90
|
+
gateways_config[:default] = default_gateway if gateways_config[:default].nil?
|
91
|
+
else
|
92
|
+
gateways_config[:default] = Gateway.wrap(@@gateway_builder, logger, gateway_configs)
|
93
|
+
end
|
94
|
+
gateways_config
|
95
|
+
end
|
67
96
|
|
68
|
-
|
69
|
-
|
70
|
-
|
97
|
+
def get_tenant_config(kb_tenant_id)
|
98
|
+
|
99
|
+
if @@per_tenant_config_cache[kb_tenant_id].nil?
|
100
|
+
# Make the api api to verify if there is a per tenant value
|
101
|
+
context = @@kb_apis.create_context(kb_tenant_id) if kb_tenant_id
|
102
|
+
values = @@kb_apis.tenant_user_api.get_tenant_values_for_key(@@config_key_name, context) if context
|
103
|
+
# If we have a per tenant value, insert it into the cache
|
104
|
+
if values && values[0]
|
105
|
+
parsed_config = YAML.load(values[0])
|
106
|
+
@@per_tenant_config_cache[kb_tenant_id] = parsed_config
|
107
|
+
# Otherwise, add global config so we don't have to make the tenant call on each operation
|
108
|
+
else
|
109
|
+
@@per_tenant_config_cache[kb_tenant_id] = @@glob_config
|
110
|
+
end
|
111
|
+
end
|
112
|
+
# Return value from cache in any case
|
113
|
+
@@per_tenant_config_cache[kb_tenant_id]
|
114
|
+
end
|
115
|
+
|
116
|
+
def initialize_from_global_config!(gateway_builder, gateway_name, logger, config_file)
|
117
|
+
# Look for global config
|
118
|
+
@@glob_config = Properties.new(config_file)
|
119
|
+
@@glob_config.parse!
|
120
|
+
|
121
|
+
@@logger.log_level = Logger::DEBUG if (@@glob_config[:logger] || {})[:debug]
|
122
|
+
|
123
|
+
@@glob_currency_conversions = @@glob_config[:currency_conversions]
|
124
|
+
|
125
|
+
begin
|
126
|
+
require 'active_record'
|
127
|
+
::ActiveRecord::Base.establish_connection(@@glob_config[:database])
|
128
|
+
::ActiveRecord::Base.logger = @@logger
|
129
|
+
rescue => e
|
130
|
+
@@logger.warn "Unable to establish a database connection: #{e}"
|
131
|
+
end
|
132
|
+
|
133
|
+
# Configure the ActiveMerchant HTTP backend
|
134
|
+
connection_type = (@@glob_config[:active_merchant] || {})[:connection_type]
|
135
|
+
if connection_type == :typhoeus
|
136
|
+
require 'killbill/ext/active_merchant/typhoeus_connection'
|
137
|
+
end
|
138
|
+
|
139
|
+
@@initialized = true
|
140
|
+
end
|
71
141
|
end
|
72
142
|
end
|
73
143
|
end
|
@@ -13,18 +13,18 @@ module Killbill
|
|
13
13
|
create_kb_account kb_account_id
|
14
14
|
end
|
15
15
|
|
16
|
-
context
|
17
|
-
account
|
16
|
+
context = @plugin.kb_apis.create_context(kb_tenant_id)
|
17
|
+
account = @plugin.kb_apis.account_user_api.get_account_by_id(kb_account_id, context)
|
18
18
|
|
19
19
|
# The rest is pure Ruby
|
20
|
-
context
|
20
|
+
context = context.to_ruby(context)
|
21
21
|
|
22
22
|
# Generate a token
|
23
23
|
pm_properties = build_pm_properties(account, options)
|
24
24
|
|
25
|
-
info
|
25
|
+
info = Killbill::Plugin::Model::PaymentMethodPlugin.new
|
26
26
|
info.properties = pm_properties
|
27
|
-
payment_method
|
27
|
+
payment_method = @plugin.add_payment_method(kb_account_id, kb_payment_method_id, info, true, properties, context)
|
28
28
|
|
29
29
|
pm = payment_method_model.from_kb_payment_method_id(kb_payment_method_id, context.tenant_id)
|
30
30
|
pm.should == payment_method
|
@@ -35,19 +35,19 @@ module Killbill
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def build_pm_properties(account = nil, overrides = {})
|
38
|
-
cc_number
|
39
|
-
cc_first_name
|
40
|
-
cc_last_name
|
41
|
-
cc_type
|
42
|
-
cc_exp_month
|
43
|
-
cc_exp_year
|
44
|
-
cc_last_4
|
45
|
-
address1
|
46
|
-
address2
|
47
|
-
city
|
48
|
-
state
|
49
|
-
zip
|
50
|
-
country
|
38
|
+
cc_number = (overrides.delete(:cc_number) || '4242424242424242')
|
39
|
+
cc_first_name = (overrides.delete(:cc_first_name) || 'John')
|
40
|
+
cc_last_name = (overrides.delete(:cc_last_name) || 'Doe')
|
41
|
+
cc_type = (overrides.delete(:cc_type) || 'Visa')
|
42
|
+
cc_exp_month = (overrides.delete(:cc_exp_month) || 12)
|
43
|
+
cc_exp_year = (overrides.delete(:cc_exp_year) || 2017)
|
44
|
+
cc_last_4 = (overrides.delete(:cc_last_4) || 4242)
|
45
|
+
address1 = (overrides.delete(:address1) || '5, oakriu road')
|
46
|
+
address2 = (overrides.delete(:address2) || 'apt. 298')
|
47
|
+
city = (overrides.delete(:city) || 'Gdio Foia')
|
48
|
+
state = (overrides.delete(:state) || 'FL')
|
49
|
+
zip = (overrides.delete(:zip) || 49302)
|
50
|
+
country = (overrides.delete(:country) || 'US')
|
51
51
|
cc_verification_value = (overrides.delete(:cc_verification_value) || 1234)
|
52
52
|
|
53
53
|
properties = []
|
@@ -76,14 +76,14 @@ module Killbill
|
|
76
76
|
|
77
77
|
def create_kb_account(kb_account_id)
|
78
78
|
external_key = Time.now.to_i.to_s + '-test'
|
79
|
-
email
|
79
|
+
email = external_key + '@tester.com'
|
80
80
|
|
81
|
-
account
|
82
|
-
account.id
|
81
|
+
account = ::Killbill::Plugin::Model::Account.new
|
82
|
+
account.id = kb_account_id
|
83
83
|
account.external_key = external_key
|
84
|
-
account.email
|
85
|
-
account.name
|
86
|
-
account.currency
|
84
|
+
account.email = email
|
85
|
+
account.name = 'Integration spec'
|
86
|
+
account.currency = :USD
|
87
87
|
|
88
88
|
@account_api.accounts << account
|
89
89
|
|
@@ -91,8 +91,8 @@ module Killbill
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def create_pm_kv_info(key, value)
|
94
|
-
prop
|
95
|
-
prop.key
|
94
|
+
prop = ::Killbill::Plugin::Model::PluginProperty.new
|
95
|
+
prop.key = key
|
96
96
|
prop.value = value
|
97
97
|
prop
|
98
98
|
end
|
@@ -124,17 +124,17 @@ module Killbill
|
|
124
124
|
def add_payment(kb_payment_id=SecureRandom.uuid, kb_payment_transaction_id=SecureRandom.uuid, kb_payment_transaction_external_key=SecureRandom.uuid, transaction_type=:PURCHASE)
|
125
125
|
kb_payment = get_payment kb_payment_id
|
126
126
|
if kb_payment.nil?
|
127
|
-
kb_payment
|
128
|
-
kb_payment.id
|
127
|
+
kb_payment = ::Killbill::Plugin::Model::Payment.new
|
128
|
+
kb_payment.id = kb_payment_id
|
129
129
|
kb_payment.transactions = []
|
130
130
|
@payments << kb_payment
|
131
131
|
end
|
132
132
|
|
133
|
-
kb_payment_transaction
|
134
|
-
kb_payment_transaction.id
|
133
|
+
kb_payment_transaction = ::Killbill::Plugin::Model::PaymentTransaction.new
|
134
|
+
kb_payment_transaction.id = kb_payment_transaction_id
|
135
135
|
kb_payment_transaction.transaction_type = transaction_type
|
136
|
-
kb_payment_transaction.external_key
|
137
|
-
kb_payment_transaction.created_date
|
136
|
+
kb_payment_transaction.external_key = kb_payment_transaction_external_key
|
137
|
+
kb_payment_transaction.created_date = Java::org.joda.time.DateTime.new(Java::org.joda.time.DateTimeZone::UTC)
|
138
138
|
kb_payment.transactions << kb_payment_transaction
|
139
139
|
|
140
140
|
kb_payment
|
@@ -144,6 +144,23 @@ module Killbill
|
|
144
144
|
@payments.find { |payment| payment.id == id.to_s }
|
145
145
|
end
|
146
146
|
end
|
147
|
+
|
148
|
+
class FakeJavaTenantUserApi
|
149
|
+
|
150
|
+
attr_accessor :per_tenant_config
|
151
|
+
|
152
|
+
def initialize(per_tenant_config)
|
153
|
+
@per_tenant_config = per_tenant_config
|
154
|
+
end
|
155
|
+
|
156
|
+
def get_tenant_values_for_key(key, context)
|
157
|
+
result = @per_tenant_config[context.tenant_id.to_s]
|
158
|
+
if result
|
159
|
+
return [result]
|
160
|
+
end
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
end
|
147
164
|
end
|
148
165
|
end
|
149
166
|
end
|
@@ -17,14 +17,18 @@ module Killbill
|
|
17
17
|
@payment_method_model = payment_method_model
|
18
18
|
@transaction_model = transaction_model
|
19
19
|
@response_model = response_model
|
20
|
+
|
20
21
|
end
|
21
22
|
|
22
23
|
def start_plugin
|
24
|
+
|
23
25
|
@logger.progname = "#{@identifier.to_s}-plugin"
|
24
26
|
|
27
|
+
@config_key_name = "PLUGIN_CONFIG_#{@plugin_name}".to_sym
|
25
28
|
::Killbill::Plugin::ActiveMerchant.initialize! @gateway_builder,
|
26
29
|
@identifier.to_sym,
|
27
30
|
@logger,
|
31
|
+
@config_key_name,
|
28
32
|
"#{@conf_dir}/#{@identifier.to_s}.yml",
|
29
33
|
@kb_apis
|
30
34
|
|
@@ -45,6 +49,14 @@ module Killbill
|
|
45
49
|
@logger.debug { "after_request: pool.active_connection? = #{pool.active_connection?}, connection.active? = #{connection.active?}, pool.connections.size = #{pool.connections.size}, connections = #{pool.connections.inspect}" }
|
46
50
|
end
|
47
51
|
|
52
|
+
|
53
|
+
def on_event(event)
|
54
|
+
if (event.event_type == :TENANT_CONFIG_CHANGE || event.event_type == :TENANT_CONFIG_DELETION) &&
|
55
|
+
event.meta_data.to_sym == @config_key_name
|
56
|
+
::Killbill::Plugin::ActiveMerchant.invalidate_tenant_config!(event.tenant_id)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
48
60
|
def authorize_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
49
61
|
gateway_call_proc = Proc.new do |gateway, linked_transaction, payment_source, amount_in_cents, options|
|
50
62
|
gateway.authorize(amount_in_cents, payment_source, options)
|
@@ -161,7 +173,7 @@ module Killbill
|
|
161
173
|
|
162
174
|
# Go to the gateway
|
163
175
|
payment_processor_account_id = options[:payment_processor_account_id] || :default
|
164
|
-
gateway = lookup_gateway(payment_processor_account_id)
|
176
|
+
gateway = lookup_gateway(payment_processor_account_id, context.tenant_id)
|
165
177
|
gw_response = gateway.store(payment_source, options)
|
166
178
|
response, transaction = save_response_and_transaction(gw_response, :add_payment_method, kb_account_id, context.tenant_id, payment_processor_account_id)
|
167
179
|
|
@@ -189,7 +201,7 @@ module Killbill
|
|
189
201
|
|
190
202
|
# Delete the card
|
191
203
|
payment_processor_account_id = options[:payment_processor_account_id] || :default
|
192
|
-
gateway = lookup_gateway(payment_processor_account_id)
|
204
|
+
gateway = lookup_gateway(payment_processor_account_id, context.tenant_id)
|
193
205
|
if options[:customer_id]
|
194
206
|
gw_response = gateway.unstore(options[:customer_id], pm.token, options)
|
195
207
|
else
|
@@ -395,7 +407,7 @@ module Killbill
|
|
395
407
|
payment_processor_account_ids = options[:payment_processor_account_ids].nil? ? [options[:payment_processor_account_id] || :default] : options[:payment_processor_account_ids].split(',')
|
396
408
|
payment_processor_account_ids.each do |payment_processor_account_id|
|
397
409
|
# Find the gateway
|
398
|
-
gateway = lookup_gateway(payment_processor_account_id)
|
410
|
+
gateway = lookup_gateway(payment_processor_account_id, context.tenant_id)
|
399
411
|
|
400
412
|
# Filter before each gateway call
|
401
413
|
before_gateway(gateway, kb_transaction, last_transaction, payment_source, amount_in_cents, currency, options)
|
@@ -523,9 +535,9 @@ module Killbill
|
|
523
535
|
return response, transaction
|
524
536
|
end
|
525
537
|
|
526
|
-
def lookup_gateway(payment_processor_account_id=:default)
|
527
|
-
gateway = ::Killbill::Plugin::ActiveMerchant.gateways[payment_processor_account_id.to_sym]
|
528
|
-
raise "Unable to lookup gateway for payment_processor_account_id #{payment_processor_account_id}, gateways: #{::Killbill::Plugin::ActiveMerchant.gateways}" if gateway.nil?
|
538
|
+
def lookup_gateway(payment_processor_account_id=:default, kb_tenant_id=nil)
|
539
|
+
gateway = ::Killbill::Plugin::ActiveMerchant.gateways(kb_tenant_id)[payment_processor_account_id.to_sym]
|
540
|
+
raise "Unable to lookup gateway for payment_processor_account_id #{payment_processor_account_id}, kb_tenant_id = #{kb_tenant_id}, gateways: #{::Killbill::Plugin::ActiveMerchant.gateways(kb_tenant_id)}" if gateway.nil?
|
529
541
|
gateway
|
530
542
|
end
|
531
543
|
|
@@ -85,9 +85,9 @@ module Killbill
|
|
85
85
|
::Killbill::Plugin::ActiveMerchant.kb_apis
|
86
86
|
end
|
87
87
|
|
88
|
-
def gateway(payment_processor_account_id=:default)
|
89
|
-
gateway = ::Killbill::Plugin::ActiveMerchant.gateways[payment_processor_account_id.to_sym]
|
90
|
-
raise "Unable to lookup gateway for payment_processor_account_id #{payment_processor_account_id}, gateways: #{::Killbill::Plugin::ActiveMerchant.gateways}" if gateway.nil?
|
88
|
+
def gateway(payment_processor_account_id=:default, kb_tenant_id=nil)
|
89
|
+
gateway = ::Killbill::Plugin::ActiveMerchant.gateways(kb_tenant_id)[payment_processor_account_id.to_sym]
|
90
|
+
raise "Unable to lookup gateway for payment_processor_account_id #{payment_processor_account_id}, , kb_tenant_id = #{kb_tenant_id}, gateways: #{::Killbill::Plugin::ActiveMerchant.gateways(kb_tenant_id)}" if gateway.nil?
|
91
91
|
gateway
|
92
92
|
end
|
93
93
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'thread_safe'
|
2
|
+
|
1
3
|
module Killbill
|
2
4
|
module Plugin
|
3
5
|
module ActiveMerchant
|
@@ -46,100 +48,65 @@ module Killbill
|
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
49
|
-
# Relies on the fact that hashes enumerate their values in the order that the corresponding keys were inserted (Ruby 1.9+)
|
50
51
|
class BoundedLRUCache
|
52
|
+
include ThreadSafe::Util::CheapLockable
|
51
53
|
|
52
|
-
def initialize(proc, max_size=10000)
|
53
|
-
@proc = proc
|
54
|
+
def initialize(proc, max_size = 10000)
|
54
55
|
@max_size = max_size
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
lru_cache = Class.new(java.util.LinkedHashMap) do
|
61
|
-
def initialize(max_size)
|
62
|
-
super(max_size, 1.0, true)
|
63
|
-
@max_size = max_size
|
64
|
-
end
|
65
|
-
|
66
|
-
# Note: renaming it to remove_eldest_entry won't work
|
67
|
-
def removeEldestEntry(eldest)
|
68
|
-
size > @max_size
|
69
|
-
end
|
70
|
-
end.new(@max_size)
|
71
|
-
@data = java.util.Collections.synchronizedMap(lru_cache)
|
72
|
-
else
|
73
|
-
@is_jruby = false
|
74
|
-
@semaphore = Mutex.new
|
75
|
-
# TODO Pre-allocate?
|
76
|
-
@data = {}
|
56
|
+
@data = ThreadSafe::Cache.new do |hash, key|
|
57
|
+
# mapping key -> value is constant for our purposes
|
58
|
+
set_value = hash.fetch_or_store key, value = proc.call(key)
|
59
|
+
store_key(key) if value.equal?(set_value) # very same object
|
60
|
+
set_value
|
77
61
|
end
|
62
|
+
@keys = []
|
78
63
|
end
|
79
64
|
|
80
|
-
def [](key)
|
81
|
-
@is_jruby ? jruby_get(key) : ruby_get(key)
|
82
|
-
end
|
65
|
+
def [](key); @data[key] end
|
83
66
|
|
84
67
|
def []=(key, val)
|
85
|
-
|
68
|
+
prev_val = @data.get_and_set(key, val)
|
69
|
+
prev_val.nil? ? store_key(key) : update_key(key)
|
70
|
+
val
|
86
71
|
end
|
87
72
|
|
88
|
-
#
|
73
|
+
# @private for testing
|
74
|
+
def size; @data.size end
|
89
75
|
|
90
|
-
|
91
|
-
|
76
|
+
# @private for testing
|
77
|
+
def keys
|
78
|
+
cheap_synchronize { @keys.dup }
|
92
79
|
end
|
93
80
|
|
94
|
-
|
95
|
-
|
81
|
+
# @private for testing
|
82
|
+
def values
|
83
|
+
cheap_synchronize { @keys.map { |key| self[key] } }
|
96
84
|
end
|
97
85
|
|
98
|
-
|
99
|
-
@is_jruby ? @data.values.to_a : @data.values
|
100
|
-
end
|
86
|
+
protected
|
101
87
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
if value.nil?
|
107
|
-
value = @proc.call(key)
|
108
|
-
# Somebody may have beaten us to it but the mapping key -> value is constant for our purposes
|
109
|
-
jruby_set(key, value)
|
88
|
+
def store_key(key)
|
89
|
+
cheap_synchronize do
|
90
|
+
@keys << key
|
91
|
+
remove_eldest_key_if_full
|
110
92
|
end
|
111
|
-
value
|
112
93
|
end
|
113
94
|
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
def ruby_get(key)
|
119
|
-
@semaphore.synchronize do
|
120
|
-
found = true
|
121
|
-
value = @data.delete(key) { found = false }
|
122
|
-
if found
|
123
|
-
@data[key] = value
|
124
|
-
else
|
125
|
-
value = @proc.call(key)
|
126
|
-
@data[key] = value
|
127
|
-
value
|
128
|
-
end
|
95
|
+
def update_key(key)
|
96
|
+
cheap_synchronize do
|
97
|
+
@keys.delete(key); @keys << key
|
98
|
+
remove_eldest_key_if_full
|
129
99
|
end
|
130
100
|
end
|
131
101
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
if @data.length > @max_size
|
137
|
-
@data.delete(@data.first[0])
|
138
|
-
end
|
139
|
-
val
|
140
|
-
end
|
102
|
+
private
|
103
|
+
|
104
|
+
def remove_eldest_key_if_full
|
105
|
+
@data.delete @keys.shift if @data.size > @max_size
|
141
106
|
end
|
107
|
+
|
142
108
|
end
|
109
|
+
|
143
110
|
end
|
144
111
|
end
|
145
112
|
end
|