conflict 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ +""