isbm_adaptor 1.0.rc8.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ec831745863947e859edd665925317d42dbf1b7
4
- data.tar.gz: 686b8452491a4b96b490af5f271283e11031f397
3
+ metadata.gz: 25b4c4ff55a4d6c03a3a75fd9f3a1810697b512d
4
+ data.tar.gz: e321d14733e13e32b151b7bebc454f45d3ef9d34
5
5
  SHA512:
6
- metadata.gz: 7a204979a05e7f25d2567de9c38807969900544c2fd9b8f37e9be7acdd57f91ae137f56a3bef269281b4a7a169adbfd57c5446add2c282ea94f9cbac8bd1c7f1
7
- data.tar.gz: 3b9290ce1d6100f169fa6ff9b9dfd5060444063fabc6833f8ab8435dea7c547c43031506e391555a13a137b47d5bb6aab95384580aa2d8d1e7b112ed6aa815be
6
+ metadata.gz: b2616d0904f557ed1838a9278d234ecb88215f18047a0259f0f0e22f3764a22c3966876c7dab35ca88141d4a80a3e94c3bb9400561b72ea09591e350341c0beb
7
+ data.tar.gz: 5556e2d0d28f1bf0a664cb3e33536a1a4c4f03add822b0925e76f8680c3ebc20cecc74ffc4ac16827c2507a831544a72a96c3c022408e28c463faacf6ed6a7a8
@@ -6,11 +6,12 @@ module IsbmAdaptor
6
6
  # Creates a new ISBM ChannelManagement client.
7
7
  #
8
8
  # @param endpoint [String] the SOAP endpoint URI
9
+ # @option options [Array<String>] :wsse_auth username and password, i.e. [username, password]
9
10
  # @option options [Object] :logger (Rails.logger or $stdout) location where log should be output
10
11
  # @option options [Boolean] :log (true) specify whether requests are logged
11
12
  # @option options [Boolean] :pretty_print_xml (false) specify whether request and response XML are formatted
12
13
  def initialize(endpoint, options = {})
13
- super('ISBMChannelManagementService.wsdl', endpoint, options)
14
+ super('ChannelManagementService.wsdl', endpoint, options)
14
15
  end
15
16
 
16
17
  # Creates a new channel.
@@ -18,23 +19,61 @@ module IsbmAdaptor
18
19
  # @param uri [String] the channel URI
19
20
  # @param type [Symbol] the channel type, either publication or request (symbol or titleized string)
20
21
  # @param description [String] the channel description, defaults to nil
22
+ # @param tokens [Hash] username password pairs, e.g. {'u1' => 'p1', 'u2' => 'p2'}
21
23
  # @return [void]
22
24
  # @raise [ArgumentError] if uri or type are blank or type is not a valid Symbol
23
- def create_channel(uri, type, description = nil)
25
+ def create_channel(uri, type, description = nil, tokens = {})
24
26
  validate_presence_of uri, 'Channel URI'
25
27
  validate_presence_of type, 'Channel Type'
26
28
  channel_type = type.to_s.downcase.capitalize
27
- raise ArgumentError, "#{channel_type} is not a valid type. Must be either Publication or Request." unless IsbmAdaptor::Channel::TYPES.include?(channel_type)
29
+ validate_inclusion_in channel_type, IsbmAdaptor::Channel::TYPES, 'Channel Type'
28
30
 
29
31
  message = { 'ChannelURI' => uri,
30
32
  'ChannelType' => channel_type }
31
- message['ChannelDescription'] = description unless description.nil?
33
+ message['ChannelDescription'] = description unless description.nil?
34
+ message['SecurityToken'] = security_token_hash(tokens) if tokens.any?
32
35
 
33
36
  @client.call(:create_channel, message: message)
34
37
 
35
38
  return true
36
39
  end
37
40
 
41
+ # Adds security tokens to a channel.
42
+ #
43
+ # @param uri [String] the channel URI
44
+ # @param tokens [Hash] username password pairs, e.g. {'u1' => 'p1', 'u2' => 'p2'}
45
+ # @return [void]
46
+ # @raise [ArgumentError] if uri is blank or no tokens are provided
47
+ def add_security_tokens(uri, tokens = {})
48
+ validate_presence_of uri, 'Channel URI'
49
+ validate_presence_of tokens, 'Security Tokens'
50
+
51
+ message = { 'ChannelURI' => uri,
52
+ 'SecurityToken' => security_token_hash(tokens) }
53
+
54
+ @client.call(:add_security_tokens, message: message)
55
+
56
+ return true
57
+ end
58
+
59
+ # Removes security tokens from a channel.
60
+ #
61
+ # @param uri [String] the channel URI
62
+ # @param tokens [Hash] username password pairs, e.g. {'u1' => 'p1', 'u2' => 'p2'}
63
+ # @return [void]
64
+ # @raise [ArgumentError] if uri is blank or no tokens are provided
65
+ def remove_security_tokens(uri, tokens = {})
66
+ validate_presence_of uri, 'Channel URI'
67
+ validate_presence_of tokens, 'Security Tokens'
68
+
69
+ message = { 'ChannelURI' => uri,
70
+ 'SecurityToken' => security_token_hash(tokens) }
71
+
72
+ @client.call(:remove_security_tokens, message: message)
73
+
74
+ return true
75
+ end
76
+
38
77
  # Deletes the specified channel.
39
78
  #
40
79
  # @param uri [String] the channel URI
@@ -48,25 +87,27 @@ module IsbmAdaptor
48
87
  return true
49
88
  end
50
89
 
51
- # Gets information about the specified channel
90
+ # Gets information about the specified channel.
52
91
  #
53
92
  # @param uri [String] the channel URI
93
+ # @yield locals local options, including :wsse_auth
54
94
  # @return [Channel] the queried channel
55
95
  # @raise [ArgumentError] if uri is blank
56
- def get_channel(uri)
96
+ def get_channel(uri, &block)
57
97
  validate_presence_of uri, 'Channel URI'
58
98
 
59
- response = @client.call(:get_channel, message: { 'ChannelURI' => uri })
99
+ response = @client.call(:get_channel, message: { 'ChannelURI' => uri }, &block)
60
100
 
61
101
  hash = response.to_hash[:get_channel_response][:channel]
62
102
  IsbmAdaptor::Channel.from_hash(hash)
63
103
  end
64
104
 
65
- # Gets information about all channels
105
+ # Gets information about all channels.
66
106
  #
67
- # @return [Array<Channel>] all channels on the ISBM
68
- def get_channels
69
- response = @client.call(:get_channels)
107
+ # @yield locals local options, including :wsse_auth
108
+ # @return [Array<Channel>] all authorized channels on the ISBM
109
+ def get_channels(&block)
110
+ response = @client.call(:get_channels, {}, &block)
70
111
 
71
112
  channels = response.to_hash[:get_channels_response][:channel]
72
113
  channels = [channels].compact unless channels.is_a?(Array)
@@ -74,5 +115,20 @@ module IsbmAdaptor
74
115
  IsbmAdaptor::Channel.from_hash(hash)
75
116
  end
76
117
  end
118
+
119
+ private
120
+ # Returns tokens mapped to wsse:UsernameToken hash.
121
+ def security_token_hash(tokens)
122
+ wsse = Akami.wsse
123
+ tokens.map do |username, password|
124
+ wsse.credentials(username, password)
125
+ # Extract the UsernameToken element
126
+ username_token = wsse.send(:wsse_username_token)['wsse:Security']
127
+ # Restore the wsse namespace
128
+ ns = {'xmlns:wsse' => Akami::WSSE::WSE_NAMESPACE}
129
+ username_token[:attributes!]['wsse:UsernameToken'].merge!(ns)
130
+ username_token
131
+ end
132
+ end
77
133
  end
78
134
  end
@@ -18,13 +18,34 @@ module IsbmAdaptor
18
18
 
19
19
  # Validates the presence of the passed value.
20
20
  #
21
- # @param value [Object] presence of object to validate
21
+ # @param value [Object] object to validate presence
22
22
  # @param name [String] name of value to include in error message if not present
23
23
  # @return [void]
24
24
  # @raise [ArgumentError] if value is not present
25
25
  def validate_presence_of(value, name)
26
- if value.blank?
27
- raise ArgumentError, "#{name} must be specified"
26
+ if value.respond_to?(:each)
27
+ value.each do |v|
28
+ if v.blank?
29
+ raise ArgumentError, "Values in #{name} must not be blank"
30
+ end
31
+ end
32
+ else
33
+ if value.blank?
34
+ raise ArgumentError, "#{name} must not be blank"
35
+ end
36
+ end
37
+ end
38
+
39
+ # Validates the inclusion of the passed value in a given set.
40
+ #
41
+ # @param value [Object] object to validate inclusion
42
+ # @param set [Array] set to validate inclusion
43
+ # @param name [String] name of value to include in error message if not present
44
+ # @return [void]
45
+ # @raise [ArgumentError] if value is not included
46
+ def validate_inclusion_in(value, set, name)
47
+ unless set.include?(value)
48
+ raise ArgumentError, "#{value} is not a valid #{name}. Must be #{set[0..-2].join(', ')} or #{set.last}."
28
49
  end
29
50
  end
30
51
 
@@ -45,12 +66,12 @@ module IsbmAdaptor
45
66
  def extract_message(response)
46
67
  # Extract the message element
47
68
  # e.g. /Envelope/Body/ReadPublicationResponse/PublicationMessage
48
- message = response.doc.root.element_children.first.element_children.first.element_children.first
69
+ message = response.doc.root.first_element_child.first_element_child.first_element_child
49
70
 
50
71
  return nil unless message
51
72
 
52
73
  id = message.element_children[0].text
53
- content = message.element_children[1].element_children.first
74
+ content = message.element_children[1].first_element_child
54
75
  topics = message.element_children[2..-1].map {|e| e.text}
55
76
 
56
77
  # Retain any ancestor namespaces in case they are applicable for the element
@@ -59,9 +80,9 @@ module IsbmAdaptor
59
80
  # There may be unnecessary namespaces carried across (e.g. ISBM, SOAP), but we
60
81
  # can't tell if the content uses them without parsing the content itself.
61
82
  content.namespaces.each do |key, value|
62
- prefix = key.gsub(/xmlns:?/, '')
63
- prefix = nil if prefix.empty?
64
- content.add_namespace_definition(prefix, value)
83
+ # Don't replace default namespace if it already exists
84
+ next if key == 'xmlns' && content['xmlns']
85
+ content[key] = value
65
86
  end
66
87
 
67
88
  # Wrap content in a separate Nokogiri document. This allows the ability to
@@ -6,23 +6,31 @@ module IsbmAdaptor
6
6
  # Creates a new ISBM ConsumerPublication client.
7
7
  #
8
8
  # @param endpoint [String] the SOAP endpoint URI
9
+ # @option options [Array<String>] :wsse_auth username and password, i.e. [username, password]
9
10
  # @option options [Object] :logger (Rails.logger or $stdout) location where log should be output
10
11
  # @option options [Boolean] :log (true) specify whether requests are logged
11
12
  # @option options [Boolean] :pretty_print_xml (false) specify whether request and response XML are formatted
12
13
  def initialize(endpoint, options = {})
13
- super('ISBMConsumerPublicationService.wsdl', endpoint, options)
14
+ super('ConsumerPublicationService.wsdl', endpoint, options)
14
15
  end
15
16
 
16
17
  # Opens a subscription session for a channel.
17
18
  #
18
19
  # @param uri [String] the channel URI
19
- # @param topics [Array<String>] an array of topics
20
- # @param listener_uri [String] the URI for notification callbacks
20
+ # @param topics [Array<String>, String] a collection of topics or single topic
21
+ # @param listener_url [String] the URL for notification callbacks
22
+ # @param xpath_expression [String] the XPath filter expression
23
+ # @param xpath_namespaces [Array<Hash>] the prefixes and namespaces used by the XPath expression. The hash key
24
+ # represents the namespace prefix while the value represents the namespace name. For example,
25
+ # ["xs" => "http://www.w3.org/2001/XMLSchema", "isbm" => "http://www.openoandm.org/xml/ISBM/"]
21
26
  # @return [String] the session id
22
27
  # @raise [ArgumentError] if uri or topics are blank
23
- def open_session(uri, topics, listener_uri = nil)
28
+ def open_session(uri, topics, listener_url = nil, xpath_expression = nil, xpath_namespaces = [])
24
29
  validate_presence_of uri, 'Channel URI'
25
30
  validate_presence_of topics, 'Topics'
31
+ validate_presence_of xpath_expression, 'XPath Expression' if xpath_namespaces.present?
32
+
33
+ topics = [topics].flatten
26
34
 
27
35
  # Use Builder to generate XML body as we may have multiple Topic elements
28
36
  xml = Builder::XmlMarkup.new
@@ -30,31 +38,46 @@ module IsbmAdaptor
30
38
  topics.each do |topic|
31
39
  xml.isbm :Topic, topic
32
40
  end
33
- xml.isbm :ListenerURI, listener_uri unless listener_uri.nil?
41
+ xml.isbm :ListenerURL, listener_url unless listener_url.nil?
42
+ xml.isbm :XPathExpression, xpath_expression unless xpath_expression.nil?
43
+ xpath_namespaces.each do |prefix, name|
44
+ xml.isbm :XPathNamespace do
45
+ xml.isbm :NamespacePrefix, prefix
46
+ xml.isbm :NamespaceName, name
47
+ end
48
+ end
34
49
 
35
50
  response = @client.call(:open_subscription_session, message: xml.target!)
36
51
 
37
52
  response.to_hash[:open_subscription_session_response][:session_id].to_s
38
53
  end
39
54
 
40
- # Reads the first message after the specified last message in the message
41
- # queue.
55
+ # Reads the first message, if any, in the session queue.
42
56
  #
43
57
  # @param session_id [String] the session id
44
- # @param last_message_id [String] the id of the last message. When set to
45
- # nil, returns the first publication in the message queue
46
- # @return [Message] first message after specified last message. nil if no message.
58
+ # @return [Message] first message in session queue. nil if no message.
47
59
  # @raise [ArgumentError] if session_id is blank
48
- def read_publication(session_id, last_message_id)
60
+ def read_publication(session_id)
49
61
  validate_presence_of session_id, 'Session Id'
50
62
 
51
- message = { 'SessionID' => session_id }
52
- message['LastMessageID'] = last_message_id unless last_message_id.nil?
53
- response = @client.call(:read_publication, message: message)
63
+ response = @client.call(:read_publication, message: { 'SessionID' => session_id })
54
64
 
55
65
  extract_message(response)
56
66
  end
57
67
 
68
+ # Removes the first message, if any, in the session queue.
69
+ #
70
+ # @param session_id [String] the session id
71
+ # @return [void]
72
+ # @raise [ArgumentError] if session_id is blank
73
+ def remove_publication(session_id)
74
+ validate_presence_of session_id, 'Session Id'
75
+
76
+ @client.call(:remove_publication, message: { 'SessionID' => session_id })
77
+
78
+ return true
79
+ end
80
+
58
81
  # Closes a subscription session.
59
82
  #
60
83
  # @param session_id [String] the session id
@@ -6,25 +6,26 @@ module IsbmAdaptor
6
6
  # Creates a new ISBM ConsumerRequest client.
7
7
  #
8
8
  # @param endpoint [String] the SOAP endpoint URI
9
+ # @option options [Array<String>] :wsse_auth username and password, i.e. [username, password]
9
10
  # @option options [Object] :logger (Rails.logger or $stdout) location where log should be output
10
11
  # @option options [Boolean] :log (true) specify whether requests are logged
11
12
  # @option options [Boolean] :pretty_print_xml (false) specify whether request and response XML are formatted
12
13
  def initialize(endpoint, options = {})
13
- super('ISBMConsumerRequestService.wsdl', endpoint, options)
14
+ super('ConsumerRequestService.wsdl', endpoint, options)
14
15
  end
15
16
 
16
17
  # Opens a consumer request session for a channel for posting requests and
17
18
  # reading responses.
18
19
  #
19
20
  # @param uri [String] the channel URI
20
- # @param listener_uri [String] the URI for notification callbacks
21
+ # @param listener_url [String] the URL for notification callbacks
21
22
  # @return [String] the session id
22
23
  # @raise [ArgumentError] if uri is blank
23
- def open_session(uri, listener_uri = nil)
24
+ def open_session(uri, listener_url = nil)
24
25
  validate_presence_of uri, 'Channel URI'
25
26
 
26
27
  message = { 'ChannelURI' => uri }
27
- message['ListenerURI'] = listener_uri if listener_uri
28
+ message['ListenerURL'] = listener_url if listener_url
28
29
 
29
30
  response = @client.call(:open_consumer_request_session, message: message)
30
31
 
@@ -36,10 +37,11 @@ module IsbmAdaptor
36
37
  # @param session_id [String] the session id
37
38
  # @param content [String] a valid XML string as message contents
38
39
  # @param topic [String] the topic
40
+ # @param expiry [Duration] when the message should expire
39
41
  # @return [String] the request message id
40
42
  # @raise [ArgumentError] if session_id, content or topics are blank, or
41
43
  # content is not valid XML
42
- def post_request(session_id, content, topic)
44
+ def post_request(session_id, content, topic, expiry = nil)
43
45
  validate_presence_of session_id, 'Session Id'
44
46
  validate_presence_of content, 'Content'
45
47
  validate_presence_of topic, 'Topic'
@@ -52,12 +54,29 @@ module IsbmAdaptor
52
54
  xml << content
53
55
  end
54
56
  xml.isbm :Topic, topic
57
+ duration = expiry.to_s
58
+ xml.isbm :Expiry, duration unless duration.nil?
55
59
 
56
60
  response = @client.call(:post_request, message: xml.target!)
57
61
 
58
62
  response.to_hash[:post_request_response][:message_id].to_s
59
63
  end
60
64
 
65
+ # Expires a posted request message.
66
+ #
67
+ # @param session_id [String] the session id used to post the request
68
+ # @param message_id [String] the message id received after posting the request
69
+ # @return [void]
70
+ # @raise [ArgumentError] if session_id or message_id are blank
71
+ def expire_request(session_id, message_id)
72
+ validate_presence_of session_id, 'Session Id'
73
+ validate_presence_of message_id, 'Message Id'
74
+
75
+ @client.call(:expire_request, message: { 'SessionID' => session_id, 'MessageID' => message_id })
76
+
77
+ return true
78
+ end
79
+
61
80
  # Returns the first response message, if any, in the message queue
62
81
  # associated with the request.
63
82
  #
@@ -7,11 +7,12 @@ module IsbmAdaptor
7
7
  # Creates a new ISBM ProviderPublication client.
8
8
  #
9
9
  # @param endpoint [String] the SOAP endpoint URI
10
+ # @option options [Array<String>] :wsse_auth username and password, i.e. [username, password]
10
11
  # @option options [Object] :logger (Rails.logger or $stdout) location where log should be output
11
12
  # @option options [Boolean] :log (true) specify whether requests are logged
12
13
  # @option options [Boolean] :pretty_print_xml (false) specify whether request and response XML are formatted
13
14
  def initialize(endpoint, options = {})
14
- super('ISBMProviderPublicationService.wsdl', endpoint, options)
15
+ super('ProviderPublicationService.wsdl', endpoint, options)
15
16
  end
16
17
 
17
18
  # Opens a publication session for a channel.
@@ -6,24 +6,32 @@ module IsbmAdaptor
6
6
  # Creates a new ISBM ProviderRequest client.
7
7
  #
8
8
  # @param endpoint [String] the SOAP endpoint URI
9
+ # @option options [Array<String>] :wsse_auth username and password, i.e. [username, password]
9
10
  # @option options [Object] :logger (Rails.logger or $stdout) location where log should be output
10
11
  # @option options [Boolean] :log (true) specify whether requests are logged
11
12
  # @option options [Boolean] :pretty_print_xml (false) specify whether request and response XML are formatted
12
13
  def initialize(endpoint, options = {})
13
- super('ISBMProviderRequestService.wsdl', endpoint, options)
14
+ super('ProviderRequestService.wsdl', endpoint, options)
14
15
  end
15
16
 
16
17
  # Opens a provider request session for a channel for reading requests and
17
18
  # posting responses.
18
19
  #
19
20
  # @param uri [String] the channel URI
20
- # @param topics [Array<String>] an array of topics
21
- # @param listener_uri [String] the URI for notification callbacks
21
+ # @param topics [Array<String>, String] a collection of topics or single topic
22
+ # @param listener_url [String] the URL for notification callbacks
23
+ # @param xpath_expression [String] the XPath filter expression
24
+ # @param xpath_namespaces [Array<Hash>] the prefixes and namespaces used by the XPath expression. The hash key
25
+ # represents the namespace prefix while the value represents the namespace name. For example,
26
+ # ["xs" => "http://www.w3.org/2001/XMLSchema", "isbm" => "http://www.openoandm.org/xml/ISBM/"]
22
27
  # @return [String] the session id
23
28
  # @raise [ArgumentError] if uri or topics are blank
24
- def open_session(uri, topics, listener_uri = nil)
29
+ def open_session(uri, topics, listener_url = nil, xpath_expression = nil, xpath_namespaces = [])
25
30
  validate_presence_of uri, 'Channel URI'
26
31
  validate_presence_of topics, 'Topics'
32
+ validate_presence_of xpath_expression, 'XPath Expression' if xpath_namespaces.present?
33
+
34
+ topics = [topics].flatten
27
35
 
28
36
  # Use Builder to generate XML body as we may have multiple Topic elements
29
37
  xml = Builder::XmlMarkup.new
@@ -31,7 +39,14 @@ module IsbmAdaptor
31
39
  topics.each do |topic|
32
40
  xml.isbm :Topic, topic
33
41
  end
34
- xml.isbm :ListenerURI, listener_uri unless listener_uri.nil?
42
+ xml.isbm :ListenerURL, listener_url unless listener_url.nil?
43
+ xml.isbm :XPathExpression, xpath_expression unless xpath_expression.nil?
44
+ xpath_namespaces.each do |prefix, name|
45
+ xml.isbm :XPathNamespace do
46
+ xml.isbm :NamespacePrefix, prefix
47
+ xml.isbm :NamespaceName, name
48
+ end
49
+ end
35
50
 
36
51
  response = @client.call(:open_provider_request_session, message: xml.target!)
37
52
 
@@ -1,4 +1,4 @@
1
1
  module IsbmAdaptor
2
2
  # Version should match the ISBM spec version, with a patch level
3
- VERSION = '1.0.rc8.7'
3
+ VERSION = '1.0.0'
4
4
  end