Class: SPQR::App

Inherits:
Qmf::AgentHandler
  • Object
show all
Includes:
Util
Defined in:
lib/spqr/app.rb

Defined Under Namespace

Classes: ClassMeta

Constant Summary collapse

VALID_MECHANISMS =
%w{ANONYMOUS PLAIN GSSAPI DIGEST-MD5 CRAM-MD5 OTP}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util

#const_lookup, #encode_argument, #get_xml_constant, #manageable?, #symbolize_dict

Constructor Details

#initialize(options = nil) ⇒ App

Returns a new instance of App.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/spqr/app.rb', line 27

def initialize(options=nil)
  defaults = {:logfile=>STDERR, :loglevel=>Logger::WARN, :notifier=>nil, :server=>"localhost", :port=>5672}
  
  # convenient shorthands for log levels
  loglevels = {:debug => Logger::DEBUG, :info => Logger::INFO, :warn => Logger::WARN, :error => Logger::ERROR, :fatal => Logger::FATAL}
    
  options = defaults unless options

  # set unsupplied options to defaults
  defaults.each do |k,v|
    options[k] = v unless options[k]
  end

  # fix up shorthands
  options[:loglevel] = loglevels[options[:loglevel]] if loglevels[options[:loglevel]]

  logger_opts = ([options[:logfile]] + [options[:logoptions]]).flatten.compact

  @log = Logger.new(*logger_opts)
  @log.level = options[:loglevel]

  @log.info("initializing SPQR app....")

  @event_classes = []
  @classes_by_name = {}
  @classes_by_id = {}
  @pipe = options[:notifier]
  @app_name = (options[:appname] or "SPQR application [#{Process.pid}]")
  @qmf_host = options[:server]
  @qmf_port = options[:port]
  @qmf_sendUserId = options.has_key?(:send_user_id) ? options[:send_user_id] : (options.has_key?(:user) || options.has_key?(:password))

  @qmf_explicit_mechanism = options[:mechanism] && options[:mechanism].upcase
  raise "Invalid authentication mechanism #{@qmf_explicit_mechanism}" unless (!@qmf_explicit_mechanism || VALID_MECHANISMS.include?(@qmf_explicit_mechanism))

  @qmf_user = options[:user]
  @qmf_password = options[:password]
end

Instance Attribute Details

#agentObject (readonly)

Returns the value of attribute agent.



25
26
27
# File 'lib/spqr/app.rb', line 25

def agent
  @agent
end

Instance Method Details

#get_query(context, query, user_id) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/spqr/app.rb', line 161

def get_query(context, query, user_id)
  @log.debug "get_query: user=#{user_id} context=#{context} class=#{query.class_name} object_num=#{query.object_id && query.object_id.object_num_low} details=#{query}"

  cmeta = @classes_by_name[query.class_name]
  objs = []
  
  # XXX:  are these cases mutually exclusive?
  
  # handle queries for a certain class
  if cmeta
    objs = objs + cmeta.object_class.find_all.collect {|obj| qmfify(obj)}
  end

  # handle queries for a specific object
  o = find_object(context, query.object_id.object_num_high, query.object_id.object_num_low) rescue nil
  if o
    objs << qmfify(o)
  end

  objs.each do |obj| 
    @agent.query_response(context, obj) rescue @log.error($!.inspect)
  end
  
  @log.debug("completing query; returned #{objs.size} objects")
  @agent.query_complete(context)
end

#mainObject



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/spqr/app.rb', line 188

def main
  # XXX:  fix and parameterize as necessary
  @log.debug("starting SPQR::App.main...")
  
  settings = Qmf::ConnectionSettings.new
  settings.host = @qmf_host
  settings.port = @qmf_port
  settings.sendUserId = @qmf_sendUserId
  
  settings.username = @qmf_user if @qmf_sendUserId
  settings.password = @qmf_password if @qmf_sendUserId

  implicit_mechanism = @qmf_sendUserId ? "PLAIN" : "ANONYMOUS"
  settings.mechanism = @qmf_explicit_mechanism || implicit_mechanism
  
  @connection = Qmf::Connection.new(settings)
  @log.debug(" +-- @connection created:  #{@connection}")
  @log.debug(" +-- app name is '#{@app_name}'")

  @agent = Qmf::Agent.new(self, @app_name)
  @log.debug(" +-- @agent created:  #{@agent}")
  
  object_class_count = @classes_by_name.size
  event_class_count = @event_classes.size

  @log.info(" +-- registering #{object_class_count} object #{pluralize(object_class_count, "class", "classes")} and #{event_class_count} event #{pluralize(event_class_count, "class", "classes")}....")
  
  all_schemas = @classes_by_name.values + @event_classes
  
  all_schemas.each do |km|
    identifier = ("object #{km.schema_class.package_name}.#{km.schema_class.class_name}" rescue "#{km.class.to_s}")
    
    @log.debug(" +--+-- TRYING to register #{identifier}")
    @agent.register_class(km.schema_class) 
    @log.info(" +--+-- #{identifier} REGISTERED")
  end
  
  @agent.set_connection(@connection)
  @log.debug(" +-- @agent.set_connection called")

  @log.debug("entering orbit....")

  sleep
end

#method_call(context, name, obj_id, args, user_id) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/spqr/app.rb', line 95

def method_call(context, name, obj_id, args, user_id)
  @log.debug("method_call(#{context.inspect}, #{name.inspect}, #{obj_id.inspect}, #{args.inspect}, #{user_id.inspect})")
  begin
    status = 0
    message = "OK"
    failed = false

    class_id = obj_id.object_num_high
    obj_id = obj_id.object_num_low

    Thread.current[:qmf_user_id] = user_id
    Thread.current[:qmf_context] = context

    managed_object = find_object(context, class_id, obj_id)
    @log.debug("managed object is #{managed_object}")
    managed_method = managed_object.class.spqr_meta.mmethods[name.to_sym]

    raise RuntimeError.new("#{managed_object.class} does not have #{name} exposed as a manageable method; has #{managed_object.class.spqr_meta.mmethods.inspect}") unless managed_method

    # Extract actual parameters from the Qmf::Arguments structure into a proper ruby list
    actuals_in = managed_method.formals_in.inject([]) {|acc,nm| acc << args[nm]}
    actual_count = actuals_in.size
    actuals_out = []

    begin
      actuals_out = case actual_count
        when 0 then managed_object.send(name.to_sym)
        when 1 then managed_object.send(name.to_sym, actuals_in[0])
        else managed_object.send(name.to_sym, *actuals_in)
      end
      
      raise RuntimeError.new("#{managed_object.class} did not return the appropriate number of return values; got '#{actuals_out.inspect}', but expected #{managed_method.types_out.inspect}") unless result_valid(actuals_out, managed_method)
      
    rescue ::SPQR::ManageableObjectError => failure
      @log.warn "#{name} called SPQR::Manageable#fail:  #{failure}"
      status = failure.status
      message = failure.message || "ERROR"
      # XXX:  failure.result is currently ignored
      actuals_out = failure.result || managed_method.formals_out.inject([]) {|acc, val| acc << args[val]; acc}
      failed = true
    end
    
    if managed_method.formals_out.size == 0
      actuals_out = [] # ignore return value in this case
    elsif managed_method.formals_out.size == 1
      actuals_out = [actuals_out] # wrap this up in a list
    end

    unless failed
      # Copy any out parameters from return value to the
      # Qmf::Arguments structure; see XXX above
      managed_method.formals_out.zip(actuals_out).each do |k,v|
        @log.debug("fixing up out params:  #{k.inspect} --> #{v.inspect}")
        encoded_val = encode_object(v)
        args[k] = encoded_val
      end
    end

    @agent.method_response(context, status, message, args)
  rescue Exception => ex
    @log.error "Error calling #{name}: #{ex}"
    @log.error "    " + ex.backtrace.join("\n    ")
    @agent.method_response(context, 1, "ERROR: #{ex}", args)
  end
end

#register(*ks) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/spqr/app.rb', line 66

def register(*ks)
  manageable_ks = ks.select {|kl| manageable? kl}
  unmanageable_ks = ks.select {|kl| not manageable? kl}
  manageable_ks.each do |klass|
    @log.info("SPQR will manage registered class #{klass} (#{klass.spqr_meta.classname})...")
    
    schemaclass = schematize(klass)

    klass.log = @log
    
    # XXX
    if klass.included_modules.include?(::SPQR::Manageable)
      @classes_by_id[klass.class_id] = klass        
      @classes_by_name[klass.spqr_meta.classname.to_s] = ClassMeta.new(klass, schemaclass)
    else
      @log.info "NOT registering query/lookup info for #{klass}; is it an event class?"
      @event_classes << klass
    end

    @log.info("SETTING #{klass.spqr_meta.classname}.app to #{self.inspect}")
    klass.app = self        
  end
  
  unmanageable_ks.each do |klass|
    @log.warn("SPQR can't manage #{klass}, which was registered")
  end
end