For a Salesforce.com integration project, I need to create a SOAP server to accept messages from Salesforce. Seeing as there is no way directly import a wsdl into ActionWebService, I instead used wsdl2ruby from the soap4r distribution to generate server stubs. Then, I used ActionWebService to emulate the same service. I had problems with using the default layout, so I changed my structure to use a delegated structure:
class NotificationServiceController < ApplicationController
web_service_dispatching_mode :delegated
web_service_scaffold :invoke
web_service :notifications, NotificationService.new
end
class NotificationServiceApi < ActionWebService::API::Base
inflect_names false
require_soap_action_header false
api_method :notifications,
:expects => [Notifications],
:returns => [:bool]
end
class NotificationService < ActionWebService::Base
web_service_api NotificationServiceApi
def logger
RAILS_DEFAULT_LOGGER
end
def notifications(organization_id, action_id, session_id, enterprise_url, partner_url, notification)
my_object_id = notification.sObject.id
ack = false
begin
ack = so_something(my_object_id)
rescue Exception => e
logger.error("Error processing payment: #{e.message}")
end
ack
end
end
But STILL SOMETHING WAS WRONG. I was getting "No valid method call - missing method name" with the Salesforce outbound message queue reporting "org.xml.sax.SAXParseException: Content is not allowed in prolog." MMmmmmm helpful. The stack trace was showing that rails was trying to process the request as XMLRPC not SOAP, which was all wrong.
The stack trace looked something like this:
RuntimeError (No valid method call - missing method name!):
/usr/lib/ruby/1.8/xmlrpc/parser.rb:476:in `parseMethodCall'
/usr/lib/ruby/1.8/xmlrpc/marshal.rb:63:in `load_call'
/usr/lib/ruby/1.8/xmlrpc/marshal.rb:32:in `load_call'
/vendor/rails/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb:36:in `decode_request'
/vendor/rails/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb:32:in `decode_action_pack_request'
/vendor/rails/actionwebservice/lib/action_web_service/protocol/discovery.rb:20:in `discover_web_service_request'
/vendor/rails/actionwebservice/lib/action_web_service/protocol/discovery.rb:18:in `discover_web_service_request'
/vendor/rails/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb:49:in `dispatch_web_service_request'
(eval):1:in `notifications'
..........
Then, I came across patch 7077 (indirectly via this and then this), so, using my new best friend Piston I checked out Rails 1.2.3 into vendor/rails, and patched with the diff in the change. It was not entirely smooth - the xmlrpc.rb file could not be patched, but I merged the change manually.
All done! Works!
One thing I did discover the hard way though is that you need to have the whole stack of definitions with the same naming scheme for this to work. That is, if you've got a NotificationServiceController, you need to ensure that you have a NotificationService and a NotificationServiceApi defined and in use - no other class names will work. No Reuse of API Definitions, which is a bit of a bugger.