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