activemessaging 0.6.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.
- data/Rakefile +50 -0
- data/generators/a13g_test_harness/a13g_test_harness_generator.rb +19 -0
- data/generators/a13g_test_harness/templates/active_messaging_test.rhtml +13 -0
- data/generators/a13g_test_harness/templates/active_messaging_test_controller.rb +29 -0
- data/generators/a13g_test_harness/templates/index.rhtml +17 -0
- data/generators/filter/USAGE +0 -0
- data/generators/filter/filter_generator.rb +19 -0
- data/generators/filter/templates/filter.rb +12 -0
- data/generators/filter/templates/filter_test.rb +28 -0
- data/generators/processor/USAGE +8 -0
- data/generators/processor/processor_generator.rb +31 -0
- data/generators/processor/templates/application.rb +18 -0
- data/generators/processor/templates/broker.yml +79 -0
- data/generators/processor/templates/jruby_poller +117 -0
- data/generators/processor/templates/messaging.rb +12 -0
- data/generators/processor/templates/poller +23 -0
- data/generators/processor/templates/poller.rb +23 -0
- data/generators/processor/templates/processor.rb +8 -0
- data/generators/processor/templates/processor_test.rb +20 -0
- data/generators/tracer/USAGE +8 -0
- data/generators/tracer/templates/controller.rb +14 -0
- data/generators/tracer/templates/helper.rb +2 -0
- data/generators/tracer/templates/index.rhtml +4 -0
- data/generators/tracer/templates/layout.rhtml +16 -0
- data/generators/tracer/templates/trace_processor.rb +100 -0
- data/generators/tracer/tracer_generator.rb +25 -0
- data/lib/activemessaging.rb +133 -0
- data/lib/activemessaging/adapter.rb +21 -0
- data/lib/activemessaging/adapters/asqs.rb +412 -0
- data/lib/activemessaging/adapters/base.rb +82 -0
- data/lib/activemessaging/adapters/jms.rb +237 -0
- data/lib/activemessaging/adapters/reliable_msg.rb +190 -0
- data/lib/activemessaging/adapters/stomp.rb +99 -0
- data/lib/activemessaging/adapters/test.rb +155 -0
- data/lib/activemessaging/adapters/wmq.rb +202 -0
- data/lib/activemessaging/filter.rb +29 -0
- data/lib/activemessaging/gateway.rb +422 -0
- data/lib/activemessaging/message_sender.rb +30 -0
- data/lib/activemessaging/named_base.rb +54 -0
- data/lib/activemessaging/processor.rb +45 -0
- data/lib/activemessaging/support.rb +17 -0
- data/lib/activemessaging/test_helper.rb +194 -0
- data/lib/activemessaging/trace_filter.rb +34 -0
- data/messaging.rb.example +5 -0
- data/tasks/start_consumers.rake +8 -0
- metadata +123 -0
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rdoc/rdoc'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
desc 'Default: run unit tests.'
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
desc 'Test the ActiveMessaging plugin.'
|
10
|
+
Rake::TestTask.new(:test) do |t|
|
11
|
+
t.libs << 'lib'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation for the ActiveMessaging plugin.'
|
17
|
+
task :rdoc do
|
18
|
+
rm_rf 'doc'
|
19
|
+
RDoc::RDoc.new.document(%w(--line-numbers --inline-source --title ActiveMessaging README lib))
|
20
|
+
end
|
21
|
+
|
22
|
+
gem_spec = Gem::Specification.new do |s|
|
23
|
+
s.name = %q{activemessaging}
|
24
|
+
s.version = "0.6.0"
|
25
|
+
|
26
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
27
|
+
|
28
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
29
|
+
s.authors = ["jon.tirsen", "kookster", "olle.jonsson", "sylvain.perez", "anti.god.botherer", 'uwe.kubosch']
|
30
|
+
s.date = %q{2008-08-15}
|
31
|
+
s.description = %q{ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java's JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc.}
|
32
|
+
s.email = %q{activemessaging-discuss@googlegroups.com}
|
33
|
+
s.files = FileList['generators/**/*', 'lib/**/*', 'tasks/**/*', 'Rakefile', 'messaging.rb.example'].to_a
|
34
|
+
s.homepage = %q{http://code.google.com/p/activemessaging/}
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.2.0}
|
37
|
+
s.summary = %q{ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java's JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc.}
|
38
|
+
#s.test_files = ["test"]
|
39
|
+
#s.autorequire = 'activemessaging'
|
40
|
+
s.has_rdoc = true
|
41
|
+
|
42
|
+
s.add_dependency(%q<activesupport>, [">= 1.0.0"])
|
43
|
+
s.add_dependency(%q<rubigen>, [">= 1.5.2"])
|
44
|
+
#s.add_dependency(%q<common-pool-cliffmoon>, [">= 0.0.3"])
|
45
|
+
end
|
46
|
+
|
47
|
+
desc 'Generate ActiveMessaging gem.'
|
48
|
+
Rake::GemPackageTask.new(gem_spec) do |pkg|
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class A13gTestHarnessGenerator < RubiGen::Base
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
|
5
|
+
controller_path = 'app/controllers'
|
6
|
+
m.directory controller_path
|
7
|
+
m.file 'active_messaging_test_controller.rb', File.join(controller_path, 'active_messaging_test_controller.rb')
|
8
|
+
|
9
|
+
view_path = 'app/views/active_messaging_test'
|
10
|
+
m.directory view_path
|
11
|
+
m.file 'index.rhtml', File.join(view_path, 'index.rhtml')
|
12
|
+
|
13
|
+
view_path = 'app/views/layouts'
|
14
|
+
m.directory view_path
|
15
|
+
m.file 'active_messaging_test.rhtml', File.join(view_path, 'active_messaging_test.rhtml')
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class ActiveMessagingTestController < ApplicationController
|
2
|
+
|
3
|
+
include ActiveMessaging::MessageSender
|
4
|
+
|
5
|
+
def index
|
6
|
+
@destinations = ActiveMessaging::Gateway.named_destinations.values
|
7
|
+
|
8
|
+
if request.post?
|
9
|
+
@message = params[:message]
|
10
|
+
|
11
|
+
if params[:destination].nil? || params[:destination].empty?
|
12
|
+
flash[:notice] = "Please specify a destination."
|
13
|
+
return
|
14
|
+
else
|
15
|
+
@destination = params[:destination].intern
|
16
|
+
end
|
17
|
+
|
18
|
+
if @message.nil? || @message.empty?
|
19
|
+
flash[:notice] = "Please specify a message."
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "#{@destination} : #{@message}"
|
24
|
+
publish @destination, @message
|
25
|
+
flash[:notice] = "'#{@message}' sent to #{@destination}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h1>ActiveMessaging Test Harness</h1>
|
2
|
+
|
3
|
+
<% form_tag :action => 'index' do |f| %>
|
4
|
+
<p>
|
5
|
+
<label for="destination">Destination:</label><br/>
|
6
|
+
(broker: name => 'destination')<br/>
|
7
|
+
<select name="destination">
|
8
|
+
<option value=""></option>
|
9
|
+
<%= options_from_collection_for_select @destinations, 'name', 'to_s', @destination %>
|
10
|
+
</select>
|
11
|
+
</p>
|
12
|
+
<p>
|
13
|
+
<label for="message">Message:</label><br/>
|
14
|
+
<%= text_area_tag :message, @message, :size=>'50x10' %>
|
15
|
+
</p>
|
16
|
+
<%= submit_tag "submit" %>
|
17
|
+
<% end -%>
|
File without changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class FilterGenerator < RubiGen::Base
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
path = 'app/processors'
|
5
|
+
test_path = 'test/functional'
|
6
|
+
|
7
|
+
# Check for class naming collisions
|
8
|
+
m.class_collisions class_path, "#{class_name}Controller", "#{class_name}ControllerTest", "#{class_name}Helper"
|
9
|
+
|
10
|
+
# filter and test directories
|
11
|
+
m.directory File.join(path, class_path)
|
12
|
+
m.directory File.join(test_path, class_path)
|
13
|
+
|
14
|
+
# filter and test templates
|
15
|
+
m.template 'filter.rb', File.join(path, class_path, "#{file_name}_filter.rb")
|
16
|
+
m.template 'filter_test.rb', File.join(test_path, class_path, "#{file_name}_filter_test.rb")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class <%= class_name %>Filter < ActiveMessaging::Filter
|
2
|
+
|
3
|
+
attr_accessor :options
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def process(message, routing)
|
10
|
+
logger.debug "<%= class_name %>Filter filtering message: #{message.inspect} with routing: #{routing.inspect}"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../../vendor/plugins/activemessaging/lib/activemessaging/test_helper'
|
3
|
+
|
4
|
+
class <%= class_name %>FilterTest < Test::Unit::TestCase
|
5
|
+
include ActiveMessaging::TestHelper
|
6
|
+
|
7
|
+
def setup
|
8
|
+
# if you want to write code to tests against the filter directly
|
9
|
+
load File.dirname(__FILE__) + "/../../app/processors/<%= file_name %>_filter.rb"
|
10
|
+
@options = {:direction=>:incoming, :only=>:<%= file_name %>_test}
|
11
|
+
@filter = <%= class_name %>Filter.new(@options)
|
12
|
+
@destination = ActiveMessaging::Gateway.destination :<%= file_name %>_test, '/queue/<%= file_name %>.test.queue'
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
ActiveMessaging::Gateway.reset
|
17
|
+
@filter = nil
|
18
|
+
@destination = nil
|
19
|
+
@options = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_<%= file_name %>_filter
|
23
|
+
@message = ActiveMessaging::TestMessage.new(@destination.value, {'message-id'=>'test-message-id-header'}, 'message body')
|
24
|
+
@routing = {:direction=>:incoming, :destination=>@destination}
|
25
|
+
@filter.process(@message, @routing)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../lib/activemessaging/named_base'
|
2
|
+
|
3
|
+
class ProcessorGenerator < NamedBase
|
4
|
+
def manifest
|
5
|
+
record do |m|
|
6
|
+
path = 'app/processors'
|
7
|
+
test_path = 'test/functional'
|
8
|
+
|
9
|
+
# Check for class naming collisions.
|
10
|
+
m.class_collisions class_path, "#{class_name}Controller", "#{class_name}ControllerTest", "#{class_name}Helper"
|
11
|
+
|
12
|
+
# processor and test directories
|
13
|
+
m.directory File.join(path, class_path)
|
14
|
+
m.directory File.join(test_path, class_path)
|
15
|
+
|
16
|
+
# processor and test templates
|
17
|
+
m.template 'processor.rb', File.join(path, class_path, "#{file_name}_processor.rb")
|
18
|
+
m.template 'processor_test.rb', File.join(test_path, class_path, "#{file_name}_processor_test.rb")
|
19
|
+
|
20
|
+
m.template 'messaging.rb', File.join('config', "messaging.rb")
|
21
|
+
m.file 'broker.yml', File.join('config', "broker.yml")
|
22
|
+
m.file 'application.rb', File.join(path, "application.rb")
|
23
|
+
m.file 'poller.rb', File.join('lib', "poller.rb")
|
24
|
+
if defined?(JRUBY_VERSION)
|
25
|
+
m.file 'jruby_poller', File.join('script', "jruby_poller"), { :chmod => 0755 }
|
26
|
+
else
|
27
|
+
m.file 'poller', File.join('script', "poller"), { :chmod => 0755 }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class ApplicationProcessor < ActiveMessaging::Processor
|
2
|
+
|
3
|
+
# Default on_error implementation - logs standard errors but keeps processing. Other exceptions are raised.
|
4
|
+
# Have on_error throw ActiveMessaging::AbortMessageException when you want a message to be aborted/rolled back,
|
5
|
+
# meaning that it can and should be retried (idempotency matters here).
|
6
|
+
# Retry logic varies by broker - see individual adapter code and docs for how it will be treated
|
7
|
+
def on_error(err)
|
8
|
+
if (err.kind_of?(StandardError))
|
9
|
+
logger.error "ApplicationProcessor::on_error: #{err.class.name} rescued:\n" + \
|
10
|
+
err.message + "\n" + \
|
11
|
+
"\t" + err.backtrace.join("\n\t")
|
12
|
+
else
|
13
|
+
logger.error "ApplicationProcessor::on_error: #{err.class.name} raised: " + err.message
|
14
|
+
raise err
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#
|
2
|
+
# broker.yml
|
3
|
+
#
|
4
|
+
# Simple yaml file for the env specific configuration of the broker connections.
|
5
|
+
# See the wiki for more information: http://code.google.com/p/activemessaging/wiki/Configuration
|
6
|
+
#
|
7
|
+
development:
|
8
|
+
############################
|
9
|
+
# Stomp Adapter Properties #
|
10
|
+
############################
|
11
|
+
adapter: stomp
|
12
|
+
|
13
|
+
# properties below are all defaults for this adapter
|
14
|
+
# login: ""
|
15
|
+
# passcode: ""
|
16
|
+
# host: localhost
|
17
|
+
# port: 61613
|
18
|
+
# reliable: true
|
19
|
+
# reconnectDelay: 5
|
20
|
+
|
21
|
+
# NEW! enable stomp retry logic
|
22
|
+
# will resend errored out messages to be retried when on_error throws ActiveMessaging::AbortMessageException
|
23
|
+
#
|
24
|
+
# Max number of times to retry an aborted message, for 0, will not retry (default)
|
25
|
+
# retryMax: 0
|
26
|
+
#
|
27
|
+
# If error still occurs after retryMax, send message to specified dead letter queue
|
28
|
+
# deadLetterQueue: '/queue/activemessaging/deadletter'
|
29
|
+
|
30
|
+
|
31
|
+
###################################
|
32
|
+
# Websphere MQ Adapter Properties #
|
33
|
+
###################################
|
34
|
+
# adapter: wmq
|
35
|
+
# q_mgr_name: ""
|
36
|
+
# poll_interval: .1
|
37
|
+
|
38
|
+
|
39
|
+
#################################
|
40
|
+
# Amazon SQS Adapter Properties #
|
41
|
+
#################################
|
42
|
+
# adapter: asqs
|
43
|
+
# access_key_id: XXXXXXXXXXXXXXXXXXXX
|
44
|
+
# secret_access_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
45
|
+
|
46
|
+
## properties below are all defaults for this adapter
|
47
|
+
# host: queue.amazonaws.com
|
48
|
+
# port: 80
|
49
|
+
# reliable: true
|
50
|
+
# reconnectDelay: 5
|
51
|
+
# aws_version: 2006-04-01
|
52
|
+
# content_type: text/plain
|
53
|
+
# poll_interval: 1
|
54
|
+
# cache_queue_list: true
|
55
|
+
|
56
|
+
|
57
|
+
########################################
|
58
|
+
# ReliableMessaging Adapter Properties #
|
59
|
+
########################################
|
60
|
+
# adapter: reliable_msg
|
61
|
+
|
62
|
+
## properties below are all defaults for this adapter
|
63
|
+
# poll_interval: 1
|
64
|
+
# reliable: true
|
65
|
+
|
66
|
+
test:
|
67
|
+
adapter: test
|
68
|
+
reliable: false
|
69
|
+
|
70
|
+
production:
|
71
|
+
adapter: stomp
|
72
|
+
reliable: true
|
73
|
+
# properties below are all defaults for this adapter
|
74
|
+
# login: ""
|
75
|
+
# passcode: ""
|
76
|
+
# host: localhost
|
77
|
+
# port: 61613
|
78
|
+
# reliable: true
|
79
|
+
# reconnectDelay: 5
|
@@ -0,0 +1,117 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
JRUBY_CMD=`which jruby`
|
4
|
+
RAILS_ROOT="$(dirname $0)/.."
|
5
|
+
POLLER_RB="$RAILS_ROOT/vendor/plugins/activemessaging/poller.rb"
|
6
|
+
OUT="$RAILS_ROOT/tmp/poller.output"
|
7
|
+
PID_FILE="$RAILS_ROOT/tmp/poller0.pid"
|
8
|
+
|
9
|
+
if [ -z "$JRUBY_CMD" ] ; then
|
10
|
+
echo "Could not find jruby on your path."
|
11
|
+
exit 1
|
12
|
+
fi
|
13
|
+
|
14
|
+
if [ ! -f $POLLER_RB ] ; then
|
15
|
+
echo "Could not find the poller file at: $POLLER_RB"
|
16
|
+
exit 1
|
17
|
+
fi
|
18
|
+
|
19
|
+
function start() {
|
20
|
+
if [[ -s $PID_FILE && -n "$(ps -A | grep "^[ \t]*$(< $PID_FILE)")" ]] ; then
|
21
|
+
PID=$(< $PID_FILE)
|
22
|
+
echo "Poller already running with pid $PID."
|
23
|
+
exit 1
|
24
|
+
fi
|
25
|
+
$JRUBY_CMD $POLLER_RB "$@" >> $OUT 2>&1 &
|
26
|
+
PID=$!
|
27
|
+
echo $PID > $PID_FILE
|
28
|
+
echo "Poller started with pid=$PID"
|
29
|
+
}
|
30
|
+
|
31
|
+
function stop() {
|
32
|
+
if [[ -z "$(ps -A | grep "^[ \t]*$(< $PID_FILE)")" ]] ; then
|
33
|
+
echo "Poller is not currently running."
|
34
|
+
exit 1
|
35
|
+
fi
|
36
|
+
if [ -z "$FORCE" ] ; then
|
37
|
+
echo "Sending TERM signal to poller."
|
38
|
+
kill -TERM $(< $PID_FILE)
|
39
|
+
else
|
40
|
+
echo "Sending KILL signal to poller."
|
41
|
+
kill -KILL $(< $PID_FILE)
|
42
|
+
fi
|
43
|
+
rm $PID_FILE
|
44
|
+
}
|
45
|
+
|
46
|
+
function restart() {
|
47
|
+
stop
|
48
|
+
start
|
49
|
+
}
|
50
|
+
|
51
|
+
function run() {
|
52
|
+
exec $JRUBY_CMD $POLLER_RB "$@"
|
53
|
+
}
|
54
|
+
|
55
|
+
function zap() {
|
56
|
+
echo "Resetting to stopped state."
|
57
|
+
[ -f $PID_FILE ] && rm $PID_FILE
|
58
|
+
}
|
59
|
+
|
60
|
+
function usage() {
|
61
|
+
cat <<EOF
|
62
|
+
Usage: poller <command> <options> -- <application options>
|
63
|
+
|
64
|
+
* where <command> is one of:
|
65
|
+
start start an instance of the application
|
66
|
+
stop stop all instances of the application
|
67
|
+
restart stop all instances and restart them afterwards
|
68
|
+
run start the application and stay on top
|
69
|
+
zap set the application to a stopped state
|
70
|
+
|
71
|
+
* and where <options> may contain several of the following:
|
72
|
+
|
73
|
+
-t, --ontop Stay on top (does not daemonize)
|
74
|
+
-f, --force Force operation
|
75
|
+
EOF
|
76
|
+
|
77
|
+
}
|
78
|
+
|
79
|
+
CMD=$1
|
80
|
+
shift
|
81
|
+
|
82
|
+
for i in "1" "2" ; do
|
83
|
+
case "$1" in
|
84
|
+
"-f"|"--force")
|
85
|
+
FORCE="true"
|
86
|
+
shift
|
87
|
+
;;
|
88
|
+
"-t"|"--ontop")
|
89
|
+
ONTOP="true"
|
90
|
+
shift
|
91
|
+
;;
|
92
|
+
esac
|
93
|
+
done
|
94
|
+
|
95
|
+
[ "$1" == "--" ] && shift
|
96
|
+
|
97
|
+
case "$CMD" in
|
98
|
+
"start")
|
99
|
+
start
|
100
|
+
;;
|
101
|
+
"stop")
|
102
|
+
stop
|
103
|
+
;;
|
104
|
+
"run")
|
105
|
+
run
|
106
|
+
;;
|
107
|
+
"restart")
|
108
|
+
restart
|
109
|
+
;;
|
110
|
+
"zap")
|
111
|
+
zap
|
112
|
+
;;
|
113
|
+
"usage"|*)
|
114
|
+
usage
|
115
|
+
exit 1
|
116
|
+
;;
|
117
|
+
esac
|