Class: ThreeScale::Backend::Application

Inherits:
Object
  • Object
show all
Extended by:
Memoizer::Decorator
Includes:
Storable
Defined in:
lib/3scale/backend/application.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Memoizer::Decorator

included

Methods included from Storable

included, #initialize, #storage

Methods included from StorageKeyHelpers

#encode_key

Instance Attribute Details

#metric_namesObject



204
205
206
# File 'lib/3scale/backend/application.rb', line 204

def metric_names
  @metric_names ||= {}
end

Class Method Details

.applications_set_key(service_id) ⇒ Object



127
128
129
# File 'lib/3scale/backend/application.rb', line 127

def applications_set_key(service_id)
  encode_key("service_id:#{service_id}/applications")
end

.attribute_namesObject



36
37
38
# File 'lib/3scale/backend/application.rb', line 36

def attribute_names
  (ATTRIBUTES + %i[service_id id metric_names].freeze).freeze
end

.clear_cache(service_id, id) ⇒ Object



118
119
120
121
122
123
124
125
# File 'lib/3scale/backend/application.rb', line 118

def clear_cache(service_id, id)
  params = [service_id, id]
  keys = Memoizer.build_keys_for_class(self,
            load: params,
            load!: params,
            exists?: params)
  Memoizer.clear keys
end

.delete(service_id, id) ⇒ Object



105
106
107
108
109
# File 'lib/3scale/backend/application.rb', line 105

def delete(service_id, id)
  raise ApplicationNotFound, id unless exists?(service_id, id)
  delete_data service_id, id
  clear_cache service_id, id
end

.delete_data(service_id, id) ⇒ Object



111
112
113
114
115
116
# File 'lib/3scale/backend/application.rb', line 111

def delete_data(service_id, id)
  storage.pipelined do
    delete_set(service_id, id)
    delete_attributes(service_id, id)
  end
end

.delete_id_by_key(service_id, key) ⇒ Object



82
83
84
85
86
# File 'lib/3scale/backend/application.rb', line 82

def delete_id_by_key(service_id, key)
  storage.del(id_by_key_storage_key(service_id, key)).tap do
    Memoizer.clear(Memoizer.build_key(self, :load_id_by_key, service_id, key))
  end
end

.exists?(service_id, id) ⇒ Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/3scale/backend/application.rb', line 100

def exists?(service_id, id)
  storage.exists(storage_key(service_id, id, :state))
end

.extract_id!(service_id, app_id, user_key) ⇒ Object



94
95
96
97
98
# File 'lib/3scale/backend/application.rb', line 94

def extract_id!(service_id, app_id, user_key)
  with_app_id_from_params service_id, app_id, user_key do |appid|
    exists? service_id, appid and appid
  end
end

.load(service_id, id) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/3scale/backend/application.rb', line 40

def load(service_id, id)
  return nil unless service_id and id
  values = storage.mget(storage_key(service_id, id, :state),
                        storage_key(service_id, id, :plan_id),
                        storage_key(service_id, id, :plan_name),
                        storage_key(service_id, id, :redirect_url),
                        storage_key(service_id, id, :user_required))
  state, plan_id, plan_name, redirect_url, user_required = values

  # save a network call by just checking state here for existence
  return nil unless state

  ## the default value is false
  user_required = user_required.to_i > 0

  new(service_id: service_id,
      id: id,
      state: state.to_sym,
      plan_id: plan_id,
      plan_name: plan_name,
      user_required: user_required,
      redirect_url: redirect_url)
end

.load!(service_id, app_id) ⇒ Object



65
66
67
# File 'lib/3scale/backend/application.rb', line 65

def load!(service_id, app_id)
  load(service_id, app_id) or raise ApplicationNotFound, app_id
end

.load_by_id_or_user_key!(service_id, app_id, user_key) ⇒ Object



88
89
90
91
92
# File 'lib/3scale/backend/application.rb', line 88

def load_by_id_or_user_key!(service_id, app_id, user_key)
  with_app_id_from_params service_id, app_id, user_key do |appid|
    load service_id, appid
  end
end

.load_id_by_key(service_id, key) ⇒ Object



70
71
72
# File 'lib/3scale/backend/application.rb', line 70

def load_id_by_key(service_id, key)
  storage.get(id_by_key_storage_key(service_id, key))
end

.save(attributes) ⇒ Object



131
132
133
134
135
# File 'lib/3scale/backend/application.rb', line 131

def save(attributes)
  application = new(attributes)
  application.save
  application
end

.save_id_by_key(service_id, key, id) ⇒ Object



75
76
77
78
79
80
# File 'lib/3scale/backend/application.rb', line 75

def save_id_by_key(service_id, key, id)
  raise ApplicationHasInconsistentData.new(id, key) if [service_id, id, key].any?(&:blank?)
  storage.set(id_by_key_storage_key(service_id, key), id).tap do
    Memoizer.memoize(Memoizer.build_key(self, :load_id_by_key, service_id, key), id)
  end
end

.storage_key(service_id, id, attribute) ⇒ Object



137
138
139
# File 'lib/3scale/backend/application.rb', line 137

def storage_key(service_id, id, attribute)
  encode_key("application/service_id:#{service_id}/id:#{id}/#{attribute}")
end

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


242
243
244
# File 'lib/3scale/backend/application.rb', line 242

def active?
  state == :active
end

#applications_set_key(service_id) ⇒ Object



200
201
202
# File 'lib/3scale/backend/application.rb', line 200

def applications_set_key(service_id)
  self.class.applications_set_key(service_id)
end

#create_key(value = nil) ⇒ Object

Create new application key and add it to the list of keys of this app. If value is nil, generates new random key, otherwise uses the given value as the new key.



263
264
265
266
267
268
269
# File 'lib/3scale/backend/application.rb', line 263

def create_key(value = nil)
  db_key = storage_key(:keys)
  invalidate_cache([:smembers, :scard], db_key)
  value ||= SecureRandom.hex(16)
  storage.sadd(db_key, value)
  value
end

#create_referrer_filter(value) ⇒ Object



309
310
311
312
313
314
315
# File 'lib/3scale/backend/application.rb', line 309

def create_referrer_filter(value)
  raise ReferrerFilterInvalid, "referrer filter can't be blank" if value.blank?
  db_key = storage_key(:referrer_filters)
  invalidate_cache([:smembers, :scard], db_key)
  storage.sadd(db_key, value)
  value
end

#delete_key(value) ⇒ Object



271
272
273
274
275
# File 'lib/3scale/backend/application.rb', line 271

def delete_key(value)
  db_key = storage_key(:keys)
  invalidate_cache([:smembers, :scard, :sismember], db_key)
  storage.srem(db_key, value)
end

#delete_referrer_filter(value) ⇒ Object



317
318
319
320
321
# File 'lib/3scale/backend/application.rb', line 317

def delete_referrer_filter(value)
  db_key = storage_key(:referrer_filters)
  invalidate_cache([:smembers, :scard], db_key)
  storage.srem(db_key, value)
end

#has_key?(value) ⇒ Boolean

Returns:

  • (Boolean)


289
290
291
292
293
294
295
# File 'lib/3scale/backend/application.rb', line 289

def has_key?(value)
  db_key = storage_key(:keys)
  key = Memoizer.build_key(self.class, :sismember, db_key, value)
  Memoizer.memoize_block(key) do
    storage.sismember(db_key, value)
  end
end

#has_keys?Boolean

Returns:

  • (Boolean)


277
278
279
280
281
282
283
# File 'lib/3scale/backend/application.rb', line 277

def has_keys?
  db_key = storage_key(:keys)
  key = Memoizer.build_key(self.class, :scard, db_key)
  Memoizer.memoize_block(key) do
    storage.scard(db_key).to_i > 0
  end
end

#has_no_keys?Boolean

Returns:

  • (Boolean)


285
286
287
# File 'lib/3scale/backend/application.rb', line 285

def has_no_keys?
  !has_keys?
end

#has_referrer_filters?Boolean

Returns:

  • (Boolean)


323
324
325
326
327
328
329
# File 'lib/3scale/backend/application.rb', line 323

def has_referrer_filters?
  db_key = storage_key(:referrer_filters)
  key = Memoizer.build_key(self.class, :scard, db_key)
  Memoizer.memoize_block(key) do
    storage.scard(db_key).to_i > 0
  end
end

#invalidate_cache(cmds, cache_key) ⇒ Object



190
191
192
193
194
# File 'lib/3scale/backend/application.rb', line 190

def invalidate_cache(cmds, cache_key)
  # cache key cannot be just cache_key.
  # Command must be added to avoid collisions between different ops over same key
  cmds.each { |cmd| Memoizer.clear(Memoizer.build_key(self.class, cmd, cache_key)) }
end

#keysObject

KEYS



250
251
252
253
254
255
256
257
258
# File 'lib/3scale/backend/application.rb', line 250

def keys
  # We memoize with self.class to avoid caching the result for specific
  # instances as opposed to the combination of service_id and app_id.
  db_key = storage_key(:keys)
  key = Memoizer.build_key(self.class, :smembers, db_key)
  Memoizer.memoize_block(key) do
    storage.smembers(db_key)
  end
end

#load_all_usage_limitsObject



223
224
225
# File 'lib/3scale/backend/application.rb', line 223

def load_all_usage_limits
  @usage_limits = UsageLimit.load_all(service_id, plan_id)
end

#load_metric_namesObject

Sets @metric_names with the names of all the metrics for which there is a usage limit that applies to the app, and returns it.



214
215
216
217
# File 'lib/3scale/backend/application.rb', line 214

def load_metric_names
  metric_ids = usage_limits.map(&:metric_id)
  @metric_names = Metric.load_all_names(service_id, metric_ids)
end

#load_usage_limits_affected_by(metric_names) ⇒ Object

Loads the usage limits affected by the metrics received, that is, the limits that are defined for those metrics plus all their ancestors in the metrics hierarchy. Raises MetricInvalid when a metric does not exist.



231
232
233
234
235
236
237
238
239
240
# File 'lib/3scale/backend/application.rb', line 231

def load_usage_limits_affected_by(metric_names)
  metric_ids = metric_names.flat_map do |name|
    [name] + Metric.ascendants(service_id, name)
  end.uniq.map do |name|
    Metric.load_id(service_id, name) || raise(MetricInvalid.new(name))
  end

  # IDs are sorted to be able to use the memoizer
  @usage_limits = UsageLimit.load_for_affecting_metrics(service_id, plan_id, metric_ids.sort)
end

#metric_name(metric_id) ⇒ Object



208
209
210
# File 'lib/3scale/backend/application.rb', line 208

def metric_name(metric_id)
  metric_names[metric_id] ||= Metric.load_name(service_id, metric_id)
end

#referrer_filtersObject

REFERRER FILTER



301
302
303
304
305
306
307
# File 'lib/3scale/backend/application.rb', line 301

def referrer_filters
  db_key = storage_key(:referrer_filters)
  key = Memoizer.build_key(self.class, :smembers, db_key)
  Memoizer.memoize_block(key) do
    storage.smembers(db_key)
  end
end

#saveObject



177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/3scale/backend/application.rb', line 177

def save
  raise ApplicationHasNoState.new(id) if !state

  storage.pipelined do
    persist_attributes
    persist_set
  end

  self.class.clear_cache(service_id, id)

  Memoizer.memoize(Memoizer.build_key(self.class, :exists?, service_id, id), state)
end

#storage_key(attribute) ⇒ Object



196
197
198
# File 'lib/3scale/backend/application.rb', line 196

def storage_key(attribute)
  self.class.storage_key(service_id, id, attribute)
end

#to_hashObject



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/3scale/backend/application.rb', line 14

def to_hash
  {
    service_id: service_id,
    id: id,
    state: state,
    plan_id: plan_id,
    plan_name: plan_name,
    redirect_url: redirect_url,
    user_required: user_required
  }
end

#update(attributes) ⇒ Object



26
27
28
29
30
31
# File 'lib/3scale/backend/application.rb', line 26

def update(attributes)
  attributes.each do |attr, val|
    public_send("#{attr}=", val)
  end
  self
end

#usage_limitsObject



219
220
221
# File 'lib/3scale/backend/application.rb', line 219

def usage_limits
  @usage_limits ||= UsageLimit.load_all(service_id, plan_id)
end

#user_required?Boolean

Returns:

  • (Boolean)


173
174
175
# File 'lib/3scale/backend/application.rb', line 173

def user_required?
  @user_required
end