conflict 0.1.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.
@@ -0,0 +1,89 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Conflict
19
+
20
+ class Conflict
21
+
22
+ attr_reader :local, :remote
23
+
24
+ def initialize local, remote
25
+ raise ConflictException::new("local event cannot be nil") if nil.eql?(local)
26
+ raise ConflictException::new("remote event cannot be nil") if nil.eql?(remote)
27
+ raise ConflictException::new("local resource '" + local.resource + "' does not match remote resource '" + remote.resource + "'") if ! local.resource.eql?(remote.resource)
28
+ raise ConflictException::new("local and remote cannot have the same identity") if local == remote
29
+ #what about = names, not = resources?
30
+ raise ConflictException::new("local and remote cannot be eql") if local.eql?(remote)
31
+ # using clone because jvYaml does not currently support aliasing
32
+ @local, @remote = local.clone, remote.clone
33
+ end
34
+
35
+ def eql? other
36
+ @local.eql?(other.local) and @remote.eql?(other.remote)
37
+ end
38
+
39
+ yaml_as "tag:java.yaml.org,2002:object:com.thoughtworks.conflict.Conflict"
40
+
41
+ end
42
+
43
+ class Event
44
+
45
+ attr_reader :client, :action, :resource
46
+
47
+ # should at least make constants for event types ?
48
+ def initialize client, action, resource, created=Time.now, ttl=TTL
49
+
50
+ raise ConflictException::new("invalid action '" + action.to_s + "'") if ! ['added', 'changed', 'deleted'].index(action)
51
+ raise ConflictException::new("client must not be empty value") if nil.eql?(client) or client.empty?
52
+ raise ConflictException::new("resource must not be empty value") if nil.eql?(resource) or resource.empty?
53
+ raise ConflictException::new("ttl cannot be negative") if ttl < 0
54
+ @client, @action, @resource = client, action, resource
55
+ # kept around for staleness expiration
56
+ @created_time = created
57
+ # rendered in YAML
58
+ @created = [created.year, created.month, created.day, created.hour, created.min] * "-"
59
+ @ttl = ttl
60
+ end
61
+
62
+ def eql? other
63
+ @client.eql?(other.client) and @action.eql?(other.action) and @resource.eql?(other.resource)
64
+ end
65
+
66
+ def to_s
67
+ self.class.to_s + ":" + @client.to_s + " " + @action.to_s + " " + resource.to_s
68
+ end
69
+
70
+ def to_yaml_properties
71
+ fields = self.instance_variables.clone
72
+ fields.delete "@created_time" # keep data/time out of integration point ( ruby != java != .net )
73
+ fields.delete "@ttl"
74
+ fields
75
+ end
76
+
77
+ yaml_as "tag:java.yaml.org,2002:object:com.thoughtworks.conflict.Event"
78
+
79
+ def to_xml
80
+ '<event client="' + self.client + '" action="' + self.action + '" resource="' + self.resource + '" />'
81
+ end
82
+
83
+ def expires
84
+ @created_time + @ttl
85
+ end
86
+
87
+ end
88
+
89
+ end
@@ -0,0 +1,130 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Conflict
19
+
20
+ class RequestParser
21
+
22
+ def initialize ttl
23
+ raise ConflictException::new("ttl cannot be nil") if nil.eql?(ttl)
24
+ raise ConflictException::new("ttl cannot be negative") if ttl < 0
25
+ @ttl = ttl
26
+ end
27
+
28
+ def parse diff, info, client
29
+
30
+ events = []
31
+
32
+ for i in 0..diff.list.size - 1
33
+
34
+ diff_data = diff.list[i].to_s.strip
35
+ info_data = info.list[i].to_s.strip
36
+
37
+ raise "no value for info @ index " + i.to_s if nil.eql?(info_data) or info_data.empty?
38
+
39
+ lambda {
40
+ infos = InfoParser::new().parse(info_data)
41
+ events = events | DiffParser::new(infos.merge({:ttl=>@ttl})).parse(diff_data, client)
42
+ }.call if ! nil.eql?(diff_data) && ! diff_data.empty?
43
+
44
+ end
45
+
46
+ events
47
+
48
+ end
49
+
50
+ end
51
+
52
+ class InfoParser
53
+
54
+ @@url, @@path = "URL: ", "Path: "
55
+
56
+ def parse info
57
+
58
+ raise ConflictException::new("info cannot be nil or empty") if nil.eql?(info) || info.empty?
59
+
60
+ properties = {}
61
+
62
+ info.split(%r{\n}).each do | line |
63
+ properties[:url] = line.to_s.sub(@@url, "").chomp if line.to_s.index(@@url) == 0
64
+ properties[:path] = line.to_s.sub(@@path, "").chomp if line.to_s.index(@@path) == 0
65
+ end
66
+
67
+ properties
68
+ end
69
+
70
+ end
71
+
72
+ class DiffParser
73
+
74
+ @@key = "Index: "
75
+
76
+ def initialize cfg
77
+ raise ConflictException::new("cfg cannot be nil") if nil.eql?(cfg)
78
+ raise ConflictException::new("url value cannot be nil or empty") if nil.eql?(cfg[:url]) or cfg[:url].empty?
79
+ raise ConflictException::new("path value cannot be nil or empty") if nil.eql?(cfg[:path]) or cfg[:path].empty?
80
+ raise ConflictException::new("ttl value cannot be nil") if nil.eql?(cfg[:ttl])
81
+ raise ConflictException::new("ttl cannot be negative") if cfg[:ttl] < 0
82
+ @cfg = cfg
83
+ end
84
+
85
+ def parse diff, client # would be nice to just get a 3rd party for this
86
+
87
+ raise ConflictException::new("client cannot by empty") if nil.eql?(client) || client.empty?
88
+ raise ConflictException::new("diff cannot by empty") if nil.eql?(diff) || diff.empty?
89
+ events = []
90
+ resource = ""
91
+ lines = diff.split(%r{\n})
92
+ #Conflict.logger.info("received diff w/ " + lines.size.to_s + " line(s)")
93
+ bit = true
94
+ now = Time.now # use one var, so all events for a request get same creation time
95
+ lines.each do |line|
96
+ if bit
97
+ if line.to_s.index(@@key) == 0
98
+ resource = line.to_s.sub(@@key, "")
99
+ bit = ! bit
100
+ end
101
+ else
102
+ if line.to_s.index("@@ ") == 0
103
+ action = infer_action line
104
+ resource_full = infer_resource(@cfg[:url].to_s, @cfg[:path], resource)
105
+ events << Event::new(client, action, resource_full, now, @cfg[:ttl])
106
+ bit = ! bit
107
+ end
108
+ end
109
+ end
110
+
111
+ events
112
+ end
113
+
114
+ private
115
+ def infer_action numbers # we are assuming a lot about unified diff here
116
+ tokens = numbers.split(' ')
117
+ # had to go backwards for the last three in delete, webrick or the clients are
118
+ # dropping the '+' character
119
+ tokens[2][-3,tokens[2].length].eql?("0,0") ? "deleted" : tokens[1].eql?("-0,0") ? "added" : "changed"
120
+ end
121
+
122
+ def infer_resource url, path, resource
123
+ path = path.tr("\\", "/").chomp
124
+ resource = resource.tr("\\", "/").chomp
125
+ url.chomp + ( ".".eql?(path) ? "/" + resource : resource.sub(path, ""))
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,26 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ #!/usr/bin/env ruby
19
+ require 'conflict'
20
+
21
+ port = ARGV.index('-port') ? ARGV[ARGV.index('-port') + 1] : nil
22
+ ttl = ARGV.index('-ttl') ? ARGV[ARGV.index('-ttl') + 1] : nil
23
+
24
+ s = Conflict::Server::new({:port=>port, :ttl=>ttl})
25
+ trap("INT"){ s.stop }
26
+ s.start
@@ -0,0 +1,132 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ require 'test/unit'
19
+ require 'net/http'
20
+ module Conflict
21
+
22
+ class DataBase
23
+ def presence_of item
24
+ @db.index(item)
25
+ end
26
+ def insert item
27
+ @db << item
28
+ end
29
+ end
30
+
31
+ class Client
32
+
33
+ def initialize cfg={}
34
+ @cfg = {}
35
+ @cfg[:command] = cfg[:command] ||= "svn diff"
36
+ @cfg[:id] = cfg[:id] ||= "Conflict Ruby client"
37
+ @cfg[:ip] = cfg[:ip] ||= "127.0.0.1"
38
+ @cfg[:port] = cfg[:port] ||= PORT
39
+ @cfg[:poll] = cfg[:poll] ||= 3
40
+ end
41
+
42
+ def resend
43
+ raise ConflictException::new('do not call resend before calling send') if ! defined?(@last_diff) or ! defined?(@last_info)
44
+ diff @last_diff, @last_info
45
+ end
46
+
47
+ def diff diff, info
48
+
49
+ raise ConflictException::new('info cannot be nil or empty') if nil.eql?(info) || info.empty?
50
+
51
+ response = multi_diff [diff], [info] # a multi diff of one
52
+ @last_diff, @last_info = diff, info
53
+ response
54
+ end
55
+
56
+ def multi_diff diff, info
57
+ body = {"client" => @cfg[:id]}
58
+ diff.each do | d | body = body.merge("diff"=>d, "path"=>".") end
59
+ info.each do | i | body = body.merge("info"=>i) end
60
+ YAML.load send(DIFF_URL, body)
61
+ end
62
+
63
+ def revert info
64
+ diff("", info)
65
+ end
66
+
67
+ #make this static?
68
+ def count
69
+ body = send(STATUS_URL, {})
70
+ document = REXML::Document.new(body)
71
+ document.root.elements['events'].size
72
+ end
73
+
74
+ def poll
75
+
76
+ while true
77
+ diff = `#{@cfg[:command]}`
78
+ info = `svn info`
79
+ puts multi_diff([diff], [info]).to_yaml
80
+ sleep @cfg[:poll]
81
+ end
82
+
83
+ end
84
+
85
+ def to_s
86
+ self.class.to_s + " " + @cfg.to_s
87
+ end
88
+
89
+ private
90
+ def send url, body
91
+ req = Net::HTTP::Post.new(url)
92
+ req.set_form_data(body)
93
+ http = Net::HTTP.new(@cfg[:ip],@cfg[:port])
94
+ res = http.request(req)
95
+ res.body
96
+ end
97
+
98
+ end
99
+
100
+ end
101
+
102
+ module ConflictConstants
103
+
104
+ CLIENT_ONE = "unit test"
105
+ CLIENT_TWO = "unit test 2"
106
+ CLIENT_THREE = "unit test 3"
107
+ NO_CONFLICT = [].to_yaml
108
+ CONTROLLER = "com.thoughtworks.Controller.java"
109
+ VIEW = "com.thoughtworks.View.java"
110
+ MODEL = "com.thoughtworks.Model.java"
111
+ DATA_DIR = './test/data/'
112
+ STOMP_DIR = DATA_DIR + 'stomp/'
113
+ STOMP_1_INFO_PATH = STOMP_DIR + 'stomp.1.info.txt'
114
+ STOMP_2_INFO_PATH = STOMP_DIR + 'stomp.2.info.txt'
115
+ STOMP_1_DIFF_PATH = STOMP_DIR + 'stomp.1.diff.txt'
116
+ STOMP_2_DIFF_PATH = STOMP_DIR + 'stomp.2.diff.txt'
117
+ STOMP_1_URL = 'http://svn.codehaus.org/stomp/ruby/trunk'
118
+ STOMP_2_URL = 'http://svn.codehaus.org/stomp/ruby/trunk/lib'
119
+ STOMP_RESOURCE = STOMP_2_URL + "/stomp.rb"
120
+ CONFLICT_URL = 'https://conflict.svn.sourceforge.net/svnroot/conflict/src/ruby'
121
+
122
+ end
123
+
124
+ class File
125
+ def to_s
126
+ string = ""
127
+ self.each do | line | string += line.to_s end
128
+ self.close
129
+ string
130
+ end
131
+ end
132
+
@@ -0,0 +1,379 @@
1
+ Index: asqs.rb
2
+ ===================================================================
3
+ --- asqs.rb (revision 107)
4
+ +++ asqs.rb (working copy)
5
+ @@ -1,354 +0,0 @@
6
+ -module ActiveMessaging
7
+ - module Adapters
8
+ - module AmazonSQS
9
+ -
10
+ - class Connection
11
+ - include ActiveMessaging::Adapter
12
+ -
13
+ - register :asqs
14
+ -
15
+ - QUEUE_NAME = 1..80
16
+ - MESSAGE_SIZE = 1..(256 * 1024)
17
+ - VISIBILITY_TIMEOUT = 0..(24 * 60 * 60)
18
+ - NUMBER_OF_MESSAGES = 1..255
19
+ -
20
+ - #configurable params
21
+ - attr_accessor :reliable, :reconnectDelay, :access_key_id, :secret_access_key, :aws_version, :content_type, :host, :port, :poll_interval, :cache_queue_list
22
+ -
23
+ - #generic init method needed by a13g
24
+ - def initialize cfg
25
+ - raise "Must specify a access_key_id" if (cfg[:access_key_id].nil? || cfg[:access_key_id].empty?)
26
+ - raise "Must specify a secret_access_key" if (cfg[:secret_access_key].nil? || cfg[:secret_access_key].empty?)
27
+ -
28
+ - @access_key_id=cfg[:access_key_id]
29
+ - @secret_access_key=cfg[:secret_access_key]
30
+ - @aws_version = cfg[:aws_version] || '2006-04-01'
31
+ - @content_type = cfg[:content_type] || 'text/plain'
32
+ - @host = cfg[:host] || 'queue.amazonaws.com'
33
+ - @port = cfg[:port] || 80
34
+ - @poll_interval = cfg[:poll_interval] || 1
35
+ - @cache_queue_list = cfg[:cache_queue_list] || true
36
+ - @reliable = cfg[:reliable] ||= true
37
+ - @reconnectDelay = cfg[:reconnectDelay] ||= 5
38
+ -
39
+ - #initialize the subscriptions and queues
40
+ - @subscriptions = {}
41
+ - @current_subscription = 0
42
+ - queues
43
+ - end
44
+ -
45
+ - def disconnect
46
+ - #it's an http request - there is no disconnect - ha!
47
+ - end
48
+ -
49
+ - # queue_name string, headers hash
50
+ - # for sqs, make sure queue exists, if not create, then add to list of polled queues
51
+ - def subscribe queue_name, message_headers={}
52
+ - # look at the existing queues, create any that are missing
53
+ - queue = get_or_create_queue queue_name
54
+ - if @subscriptions.has_key? queue.name
55
+ - @subscriptions[queue.name] += 1
56
+ - else
57
+ - @subscriptions[queue.name] = 1
58
+ - end
59
+ - end
60
+ -
61
+ - # queue_name string, headers hash
62
+ - # for sqs, attempt delete the queues, won't work if not empty, that's ok
63
+ - def unsubscribe queue_name, message_headers={}
64
+ - @subscriptions[queue_name] -= 1
65
+ - @subscriptions.delete(queue_name) if @subscriptions[queue_name] <= 0
66
+ - end
67
+ -
68
+ - # queue_name string, body string, headers hash
69
+ - # send a single message to a queue
70
+ - def send queue_name, message_body, message_headers
71
+ - queue = get_or_create_queue queue_name
72
+ - send_messsage queue, message_body
73
+ - end
74
+ -
75
+ - # receive a single message from any of the subscribed queues
76
+ - # check each queue once, then sleep for poll_interval
77
+ - def receive
78
+ - raise "No subscriptions to receive messages from." if (@subscriptions.nil? || @subscriptions.empty?)
79
+ - start = @current_subscription
80
+ - while true
81
+ - @current_subscription = ((@current_subscription < @subscriptions.length-1) ? @current_subscription + 1 : 0)
82
+ - sleep poll_interval if (@current_subscription == start)
83
+ - queue_name = @subscriptions.keys.sort[@current_subscription]
84
+ - queue = queues[queue_name]
85
+ - unless queue.nil?
86
+ - messages = retrieve_messsages queue, 1
87
+ - return messages[0] unless (messages.nil? or messages.empty?)
88
+ - end
89
+ - end
90
+ - end
91
+ -
92
+ - def received message
93
+ - delete_message message
94
+ - end
95
+ -
96
+ - protected
97
+ -
98
+ - #belows are the methods from the REST API
99
+ - def create_queue queue_name
100
+ - validate_queue_name queue_name
101
+ - validate_queue queue_name, false
102
+ - response = transmit 'POST', "/?QueueName=#{queue_name}"
103
+ - add_queue response.get_text("//QueueUrl")
104
+ - end
105
+ -
106
+ - def list_queues queue_name_prefix=nil
107
+ - validate_queue_name queue_name_prefix unless queue_name_prefix.nil?
108
+ - response = transmit 'GET', queue_name_prefix.nil? ? '/' : "/?QueueNamePrefix=#{queue_name_prefix}"
109
+ - response.nodes("//QueueUrl").collect{ |n| add_queue(n.text) }
110
+ - end
111
+ -
112
+ - def delete_queue queue
113
+ - validate_queue queue
114
+ - response = transmit 'DELETE', "#{queue.queue_url}", queue.domain
115
+ - end
116
+ -
117
+ - def send_messsage queue, message
118
+ - validate_queue queue
119
+ - validate_message message
120
+ - response = transmit 'PUT', "#{queue.queue_url}/back", queue.domain, message
121
+ - end
122
+ -
123
+ - def set_visibility_timeout queue, timeout
124
+ - validate_queue queue
125
+ - validate_timeout timeout
126
+ - response = transmit 'PUT', "#{queue.queue_url}?VisibilityTimeout=#{timeout}", queue.domain
127
+ - end
128
+ -
129
+ - def retrieve_messsages queue, num_messages=1, timeout=nil
130
+ - validate_queue queue
131
+ - validate_number_of_messages num_messages
132
+ - validate_timeout timeout if timeout
133
+ - timeout_path = timeout ? "VisibilityTimeout=#{timeout}&" : ''
134
+ - response = transmit 'GET', "#{queue.queue_url}/front?#{timeout_path}NumberOfMessages=#{num_messages}", queue.domain
135
+ - response.nodes("//Message").collect{ |n| Message.from_element n, response, queue }
136
+ - end
137
+ -
138
+ - def get_visibility_timeout queue
139
+ - validate_queue queue
140
+ - response = transmit 'GET', "#{queue.queue_url}/", queue.domain
141
+ - response.get_text('//VisibilityTimeout').to_i
142
+ - end
143
+ -
144
+ - def delete_message message
145
+ - delete_message_by_id message.queue, message.id
146
+ - end
147
+ -
148
+ - def delete_message_by_id queue, message_id
149
+ - response = transmit 'DELETE', "#{queue.queue_url}/#{message_id}", queue.domain
150
+ - end
151
+ -
152
+ - def peek_message queue, message_id
153
+ - response = transmit 'GET', "#{queue.queue_url}/#{message_id}", queue.domain
154
+ - Message.from_element( response.node('//Message'), response, queue)
155
+ - end
156
+ -
157
+ - private
158
+ -
159
+ - def queues
160
+ - return @queues if (@queues && cache_queue_list)
161
+ - @queues = {}
162
+ - list_queues.each{|q| @queues[q.name]=q }
163
+ - return @queues
164
+ - end
165
+ -
166
+ - def get_or_create_queue queue_name
167
+ - qs = queues
168
+ - qs.has_key?(queue_name) ? qs[queue_name] : create_queue(queue_name)
169
+ - end
170
+ -
171
+ - def add_queue(url)
172
+ - q = Queue.from_url url
173
+ - queues[q.name] = q if cache_queue_list
174
+ - return q
175
+ - end
176
+ -
177
+ - # method to do the actual send, generic to get, post, delete, etc.
178
+ - # action - possible values: get, post, delete
179
+ - def transmit(command, url, h=host, body=nil, headers={}, p=port)
180
+ - request_headers = create_headers(command, url, headers, body)
181
+ - request = http_request_factory(command, url, request_headers, body)
182
+ - tryit = true
183
+ - begin
184
+ - while tryit
185
+ - response = SQSResponse.new(Net::HTTP.start(h, p){ |http| http.request(request) })
186
+ - tryit = false
187
+ - end
188
+ - rescue
189
+ - raise $! unless reliable
190
+ - puts "transmit failed, will retry in #{@reconnectDelay} seconds"
191
+ - sleep @reconnectDelay
192
+ - end
193
+ - # p response
194
+ - # puts "body: #{response.http_response.body}"
195
+ - check_errors(response)
196
+ - end
197
+ -
198
+ - def create_headers(cmd, url, headers, body)
199
+ - # set then merge the headers
200
+ - hdrs = { 'AWS-Version'=>@aws_version,
201
+ - 'Date'=>Time.now.httpdate,
202
+ - 'Content-type'=>@content_type }
203
+ - hdrs['Content-Length'] = body.length.to_s if (body && (cmd=='POST' or cmd=='PUT'))
204
+ -
205
+ -
206
+ - #merge with the passed in headers to allow overrides
207
+ - hdrs.merge! headers
208
+ -
209
+ - # calculate authorization based on set headers
210
+ - hdrs['Authorization'] = create_authorization_signature(cmd, url, hdrs)
211
+ - return hdrs
212
+ - end
213
+ -
214
+ - def create_authorization_signature(cmd, url, hdrs)
215
+ - base_url = url.index('?') ? url[0..(url.index('?')-1)] : url
216
+ - to_sign = "#{cmd}\n\n#{hdrs['Content-type']}\n#{hdrs['Date']}\n#{base_url}"
217
+ - # puts to_sign
218
+ - signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), secret_access_key, to_sign)).strip
219
+ - return "AWS #{access_key_id}:#{signature}"
220
+ - end
221
+ -
222
+ - def http_request_factory(cmd, url, headers, body)
223
+ - case cmd
224
+ - when 'GET' then Net::HTTP::Get.new(url,headers)
225
+ - when 'DELETE' then Net::HTTP::Delete.new(url,headers)
226
+ - when 'POST'
227
+ - req = Net::HTTP::Post.new(url,headers)
228
+ - req.body=body
229
+ - req
230
+ - when 'PUT'
231
+ - req = Net::HTTP::Put.new(url,headers)
232
+ - req.body=body
233
+ - req
234
+ - else raise 'Unsupported http request type'
235
+ - end
236
+ - end
237
+ -
238
+ - def check_errors(response)
239
+ - raise response.errors if response.errors?
240
+ - response
241
+ - end
242
+ -
243
+ - def validate_queue_name qn
244
+ - raise "Queue name, #{qn}, must be between #{QUEUE_NAME.min} and #{QUEUE_NAME.max} characters." unless QUEUE_NAME.include?(qn.length)
245
+ - raise "Queue name, #{qn}, must be alphanumeric only." if (qn =~ /\W/ )
246
+ - end
247
+ -
248
+ - def validate_queue qn, exists=true
249
+ - if exists
250
+ - raise "Never heard of queue, can't use it: #{qn.name}" unless queues.has_key? qn.name
251
+ - else
252
+ - raise "Queue already exists: #{qn}" if queues.has_key? qn.name
253
+ - end
254
+ - end
255
+ -
256
+ - def validate_message m
257
+ - raise "Message cannot be nil." if m.nil?
258
+ - raise "Message length, #{m.length}, must be between #{MESSAGE_SIZE.min} and #{MESSAGE_SIZE.max}." unless MESSAGE_SIZE.include?(m.length)
259
+ - end
260
+ -
261
+ - def validate_timeout to
262
+ - raise "Timeout, #{to}, must be between #{VISIBILITY_TIMEOUT.min} and #{VISIBILITY_TIMEOUT.max}." unless VISIBILITY_TIMEOUT.include?(to)
263
+ - end
264
+ -
265
+ - def validate_number_of_messages nom
266
+ - raise "Number of messages, #{nom}, must be between #{NUMBER_OF_MESSAGES.min} and #{NUMBER_OF_MESSAGES.max}." unless NUMBER_OF_MESSAGES.include?(nom)
267
+ - end
268
+ -
269
+ - end
270
+ -
271
+ - class SQSResponse
272
+ - attr_accessor :headers, :doc, :http_response
273
+ -
274
+ - def initialize response
275
+ - @http_response = response
276
+ - @headers = response.to_hash()
277
+ - @doc = REXML::Document.new(response.body) if response.kind_of?(Net::HTTPSuccess)
278
+ - end
279
+ -
280
+ - def message_type
281
+ - return doc ? doc.root.name : ''
282
+ - end
283
+ -
284
+ - def errors?
285
+ - (not http_response.kind_of?(Net::HTTPSuccess)) or (message_type == "Response")
286
+ - end
287
+ -
288
+ - def errors
289
+ - msg = ""
290
+ - if http_response.kind_of?(Net::HTTPSuccess)
291
+ - msg = "Errors: "
292
+ - each_node('/Response/Errors/Error') { |n|
293
+ - c = n.elements['Code'].text
294
+ - m = n.elements['Message'].text
295
+ - msg << ", " if msg != "Errors: "
296
+ - msg << "#{c} : #{m}"
297
+ - }
298
+ - else
299
+ - msg = "HTTP Error: #{http_response.code} : #{http_response.message}"
300
+ - end
301
+ - return msg
302
+ - end
303
+ -
304
+ - def get_text(xpath,default='')
305
+ - e = REXML::XPath.first( doc, xpath)
306
+ - e.nil? ? default : e.text
307
+ - end
308
+ -
309
+ - def each_node(xp)
310
+ - REXML::XPath.each(doc.root, xp) {|n| yield n}
311
+ - end
312
+ -
313
+ - def nodes(xp)
314
+ - doc.elements.to_a(xp)
315
+ - end
316
+ - end
317
+ -
318
+ - class Queue
319
+ - attr_accessor :name, :pathinfo, :domain, :visibility_timeout
320
+ -
321
+ - def self.from_url url
322
+ - return Queue.new($3,$2,$1) if url =~ /^http:\/\/(.+)\/(.+)\/(\w+)$/
323
+ - raise "Bad Queue URL: #{url}"
324
+ - end
325
+ -
326
+ - def queue_url
327
+ - "/#{pathinfo}/#{name}"
328
+ - end
329
+ -
330
+ - def initialize name, pathinfo, domain, vt=nil
331
+ - @name, @pathinfo, @domain, @visibility_timeout = name, pathinfo, domain, vt
332
+ - end
333
+ -
334
+ - def to_s
335
+ - "<AmazonSQS::Queue name='#{name}' url='#{queue_url}' domain='#{domain}'>"
336
+ - end
337
+ - end
338
+ -
339
+ - # based on stomp message, has pointer to the SQSResponseObject
340
+ - class Message
341
+ - attr_accessor :headers, :id, :body, :command, :response, :queue
342
+ -
343
+ - def self.from_element e, response, queue
344
+ - Message.new(response.headers, e.elements['MessageId'].text, e.elements['MessageBody'].text, response, queue)
345
+ - end
346
+ -
347
+ - def initialize headers, id, body, response, queue, command='MESSAGE'
348
+ - @headers, @id, @body, @response, @queue, @command = headers, id, body, response, queue, command
349
+ - headers['destination'] = queue.name
350
+ - end
351
+ -
352
+ - def to_s
353
+ - "<AmazonSQS::Message id='#{id}' body='#{body}' headers='#{headers.inspect}' command='#{command}' response='#{response}'>"
354
+ - end
355
+ - end
356
+ -
357
+ - end
358
+ - end
359
+ -end
360
+
361
+ Index: jms.rb
362
+ ===================================================================
363
+ --- jms.rb (revision 107)
364
+ +++ jms.rb (working copy)
365
+ @@ -4,7 +4,7 @@
366
+ include Java
367
+
368
+ import javax.naming.InitialContext
369
+ -import javax.jms.MessageListener
370
+ + import javax.jms.MessageListener
371
+
372
+ module ActiveMessaging
373
+ module Adapters
374
+ Index: new.rb
375
+ ===================================================================
376
+ --- new.rb (revision 0)
377
+ +++ new.rb (revision 0)
378
+ @@ -0,0 +1 @@
379
+ +""