isbm_adaptor 1.0.rc8.7 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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