hoth 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +1 -1
- data/{README.rdoc → README.md} +34 -34
- data/Rakefile +15 -0
- data/example/business_objects.rb +60 -0
- data/example/config/module_definition.rb +32 -0
- data/example/config/service_definition.rb +15 -0
- data/example/rack_service_provider.ru +37 -0
- data/example/service_client.rb +32 -0
- data/example/simple/README.md +17 -0
- data/example/simple/config/module_definition.rb +13 -0
- data/example/simple/config/service_definition.rb +5 -0
- data/example/simple/simple_client.rb +27 -0
- data/example/simple/simple_provider.ru +30 -0
- data/hoth.gemspec +34 -0
- data/lib/hoth.rb +3 -1
- data/lib/hoth/transport.rb +0 -6
- data/lib/hoth/transport/beanstalkd.rb +9 -5
- data/lib/hoth/version.rb +3 -0
- data/spec/spec_helper.rb +20 -8
- data/spec/unit/providers/beanstalkd_provider_spec.rb +6 -7
- data/spec/unit/service_module_spec.rb +2 -2
- data/spec/unit/transport/beanstalkd_spec.rb +18 -27
- metadata +132 -314
- data/Gemfile.lock +0 -48
- data/TODO +0 -2
- data/lib/hoth/providers/bertrpc_provider.rb +0 -35
- data/lib/hoth/transport/bert.rb +0 -87
- data/lib/hoth/transport/workling.rb +0 -23
- data/spec/unit/transport/workling_spec.rb +0 -42
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
CHANGED
data/{README.rdoc → README.md}
RENAMED
@@ -1,34 +1,34 @@
|
|
1
|
-
|
1
|
+
# Hoth
|
2
2
|
|
3
3
|
Creating a SOA requires a centralized location to define all services within the SOA. Furthermore you want to know where those services live.
|
4
4
|
|
5
|
-
|
5
|
+
# How to use
|
6
6
|
|
7
|
-
|
7
|
+
## Install
|
8
8
|
|
9
9
|
gem install hoth
|
10
10
|
|
11
|
-
|
11
|
+
## Define services and modules
|
12
12
|
|
13
|
-
|
13
|
+
### Service-Definition
|
14
14
|
|
15
15
|
This is how you define services:
|
16
16
|
|
17
17
|
Hoth::Services.define do
|
18
|
-
|
18
|
+
|
19
19
|
service :service_name do |first_param, second_param|
|
20
20
|
returns :descriptive_name
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
end
|
24
24
|
|
25
25
|
This definition describes a service with a name, some parameters and its return value. The naming of the parameters is just for your understanding and will never be used again, so be descriptive. Same goes for the return value. The only exception is, if you want to assure that a service returns nil you can write
|
26
|
-
|
26
|
+
|
27
27
|
returns :nothing
|
28
|
-
|
28
|
+
|
29
29
|
A service whith this return value will always return nil. You can also specify `:nil`, with the same result.
|
30
30
|
|
31
|
-
|
31
|
+
### Module-Definition
|
32
32
|
|
33
33
|
After defining all you services, you need to specify in which modules they live. Each module can be seen as a set of implemented services. Each module can have one or more endpoints. Here is how you define these modules with its endpoints and services:
|
34
34
|
|
@@ -43,11 +43,6 @@ After defining all you services, you need to specify in which modules they live.
|
|
43
43
|
transport :http
|
44
44
|
end
|
45
45
|
|
46
|
-
endpoint :bert do
|
47
|
-
host 'localhost'
|
48
|
-
port 9999
|
49
|
-
transport :bert
|
50
|
-
end
|
51
46
|
end
|
52
47
|
|
53
48
|
env :production do
|
@@ -57,38 +52,43 @@ After defining all you services, you need to specify in which modules they live.
|
|
57
52
|
transport :http
|
58
53
|
end
|
59
54
|
|
60
|
-
endpoint :
|
55
|
+
endpoint :beanstalk do
|
61
56
|
host '192.168.1.15'
|
62
|
-
port
|
63
|
-
transport :
|
57
|
+
port 11300
|
58
|
+
transport :beanstalkd
|
64
59
|
end
|
65
60
|
end
|
66
|
-
|
61
|
+
|
67
62
|
add_service :first_service
|
68
|
-
add_service :second_service, :via => :
|
63
|
+
add_service :second_service, :via => :beanstalk
|
69
64
|
end
|
70
|
-
|
65
|
+
|
71
66
|
end
|
72
67
|
|
73
68
|
|
74
69
|
As you can see, it is possible to define different endpoints for different environments. Each endpoint has a host, a port and a transport-type. After defining your endpoints you can add your previously defined services to the module and define which endpoint they should use. If you do not specify an endpoint the :default endpoint will be used.
|
75
70
|
|
76
|
-
|
71
|
+
## Integrate in your project
|
77
72
|
|
78
73
|
Just execute current code (in rails you can add this line to an initializer):
|
79
|
-
|
74
|
+
|
80
75
|
Hoth.init!
|
81
|
-
|
76
|
+
|
82
77
|
By default, Hoth looks for the files service_definition and module_definition in the config-Directory (`./config`). If you need to load these files from another place, just set `Hoth.config_path` to your needs.
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
*
|
87
|
-
* Make
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
78
|
+
|
79
|
+
## Todo
|
80
|
+
|
81
|
+
* Make the rack provider independent from one specific transport.
|
82
|
+
* Make the bodies of the `rack_provider` return an object which responds to each in order not break on Ruby 1.9.
|
83
|
+
|
84
|
+
## Note on Patches/Pull Requests
|
85
|
+
|
86
|
+
* Fork the project.
|
87
|
+
* Make your feature addition or bug fix.
|
88
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
89
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
90
|
+
* Send me a pull request. Bonus points for topic branches.
|
91
|
+
|
92
|
+
## Copyright
|
93
93
|
|
94
94
|
Copyright (c) 2009-2010 Dirk Breuer. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
require 'hoth/version'
|
7
|
+
require 'yard'
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
|
11
|
+
task :default => :spec
|
12
|
+
|
13
|
+
YARD::Rake::YardocTask.new do |t|
|
14
|
+
t.options += ['--title', "Hoth #{Hoth::VERSION} Documentation"]
|
15
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
class StatisticsObject
|
4
|
+
attr_accessor :id, :owner_id, :statistic_type, :timestamp, :group_condition
|
5
|
+
|
6
|
+
def initialize(attributes)
|
7
|
+
@id = attributes[:id]
|
8
|
+
@owner_id = attributes[:owner_id]
|
9
|
+
@statistic_type = attributes[:statistic_type]
|
10
|
+
@timestamp = attributes[:timestamp]
|
11
|
+
@group_condition = attributes[:group_condition]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.json_create(hash)
|
15
|
+
new(hash.symbolize_keys)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Event
|
20
|
+
attr_accessor :name, :count
|
21
|
+
|
22
|
+
def initialize(attributes)
|
23
|
+
@name = attributes[:name]
|
24
|
+
@count = attributes[:count]
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.json_create(hash)
|
28
|
+
new(hash.symbolize_keys)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class StatisticData
|
33
|
+
attr_accessor :events, :original_id
|
34
|
+
|
35
|
+
def initialize(attributes)
|
36
|
+
@events = attributes[:events]
|
37
|
+
@original_id = attributes[:original_id]
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.json_create(hash)
|
41
|
+
new(hash.symbolize_keys)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Account
|
46
|
+
attr_accessor :firstname, :lastname, :contract, :company
|
47
|
+
|
48
|
+
def initialize(attributes)
|
49
|
+
@firstname = attributes[:firstname]
|
50
|
+
@lastname = attributes[:lastname]
|
51
|
+
@contract = attributes[:contract]
|
52
|
+
@company = attributes[:company]
|
53
|
+
@contract
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_serialize
|
57
|
+
[:firstname, :lastname, :contract, :company]
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Hoth::Modules.define do
|
2
|
+
service_module :statistics_module do
|
3
|
+
env :development do
|
4
|
+
endpoint :default do
|
5
|
+
host '127.0.0.1'
|
6
|
+
port 443
|
7
|
+
transport :json_via_https
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
add_service :increment_statistics
|
12
|
+
add_service :statistic_of_cars
|
13
|
+
end
|
14
|
+
|
15
|
+
service_module :accounts_module do
|
16
|
+
env :development do
|
17
|
+
endpoint :default do
|
18
|
+
host 'localhost'
|
19
|
+
port 3000
|
20
|
+
transport :http
|
21
|
+
end
|
22
|
+
|
23
|
+
endpoint :beanstalk do
|
24
|
+
host 'localhost'
|
25
|
+
port 11300
|
26
|
+
transport :beanstalkd
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
add_service :create_account, :via => :beanstalk
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Hoth::Services.define do
|
2
|
+
|
3
|
+
service :increment_statistics do |statistic_objects, event|
|
4
|
+
returns :nothing
|
5
|
+
end
|
6
|
+
|
7
|
+
service :statistic_of_cars do |ids|
|
8
|
+
returns :statistic_datas
|
9
|
+
end
|
10
|
+
|
11
|
+
service :create_account do |account|
|
12
|
+
returns :account_ids
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
$:.unshift(File.join("..", "lib"))
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
require 'rack'
|
6
|
+
require 'hoth'
|
7
|
+
require 'hoth/providers/rack_provider'
|
8
|
+
require 'business_objects'
|
9
|
+
|
10
|
+
Hoth.init!
|
11
|
+
|
12
|
+
class IncrementStatisticsImpl
|
13
|
+
def self.execute(statistic_objects, event)
|
14
|
+
puts "** EXECUTING IncrementStatisticsImpl"
|
15
|
+
puts " statistic_objects: #{statistic_objects.inspect}"
|
16
|
+
puts " events: #{event.inspect}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class StatisticOfCarsImpl
|
21
|
+
def self.execute(ids)
|
22
|
+
puts "** EXECUTING StatisticOfCarsImpl"
|
23
|
+
puts " ids: #{ids.inspect}"
|
24
|
+
|
25
|
+
return ids.inject([]) do |data, id|
|
26
|
+
data << StatisticData.new(
|
27
|
+
:events => [Event.new(:name => "viewed", :count => rand(666))],
|
28
|
+
:original_id => id
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
app = lambda {|env| [200, {'Content-Type' => 'application/json'}, ["body"]]}
|
35
|
+
|
36
|
+
rack_thread = Thread.new { run Hoth::Providers::RackProvider.new(app) }
|
37
|
+
rack_thread.join
|
@@ -0,0 +1,32 @@
|
|
1
|
+
$:.unshift(File.join("..", "lib"))
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
require 'hoth'
|
6
|
+
require 'business_objects'
|
7
|
+
|
8
|
+
Hoth.init!
|
9
|
+
|
10
|
+
statistic_object = StatisticsObject.new(
|
11
|
+
:id => 23,
|
12
|
+
:owner_id => 42,
|
13
|
+
:statistic_type => "Car",
|
14
|
+
:timestamp => Time.now,
|
15
|
+
:group_condition => nil
|
16
|
+
)
|
17
|
+
|
18
|
+
event = Event.new(:name => "viewed", :count => 2)
|
19
|
+
|
20
|
+
puts "call increment_statistics"
|
21
|
+
Hoth::Services.increment_statistics([statistic_object], event)
|
22
|
+
|
23
|
+
puts Hoth::Services.statistic_of_cars([23, 42, 303, 101]).inspect
|
24
|
+
|
25
|
+
# account = Account.new(
|
26
|
+
# :firstname => "Dirk",
|
27
|
+
# :lastname => "Breuer",
|
28
|
+
# :contract => "Platinum",
|
29
|
+
# :company => "Galaxy Cats"
|
30
|
+
# )
|
31
|
+
#
|
32
|
+
# puts "Account ID: #{Hoth::Services.create_account(account)}"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Very basic and simple example of using Hoth
|
2
|
+
|
3
|
+
This is a very simple example of using Hoth. It shows you how to define a module (math)
|
4
|
+
and a service (addition) using a very basic RackProvider. It also demonstrates how Hoth
|
5
|
+
choose if it should invoke the service by a remote call or locally (this works by
|
6
|
+
looking for a local implementation of the service, see `simple_client.rb`).
|
7
|
+
|
8
|
+
To run this example you need to start the RackProvider first:
|
9
|
+
|
10
|
+
cd example/simple
|
11
|
+
rackup simple_provider.ru
|
12
|
+
|
13
|
+
Next: Run the client:
|
14
|
+
|
15
|
+
ruby simple_client.rb
|
16
|
+
|
17
|
+
Have fun!
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# the client requires you to have a running provider (see simple_provider.ru)
|
2
|
+
|
3
|
+
$:.unshift(File.join("..", "..", "lib"))
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
|
7
|
+
require 'hoth'
|
8
|
+
|
9
|
+
# first we initialize Hoth (this will load the configuration as well)
|
10
|
+
Hoth.init!
|
11
|
+
|
12
|
+
# let's call the "addition" service and show the result!
|
13
|
+
puts Hoth::Services.addition(40, 2)
|
14
|
+
# => 42
|
15
|
+
|
16
|
+
# Next, we will implement addition locally...
|
17
|
+
class AdditionImpl
|
18
|
+
def self.execute(a, b)
|
19
|
+
puts "I'm local!"
|
20
|
+
return a + b
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# And call the service locally!
|
25
|
+
puts Hoth::Services.addition(1, 2)
|
26
|
+
# => I'm local!
|
27
|
+
# => 3
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# to run this provider, use: rackup simple_provider.ru
|
2
|
+
|
3
|
+
$:.unshift(File.join("..", "..", "lib"))
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
|
7
|
+
require 'rack'
|
8
|
+
require 'hoth'
|
9
|
+
require 'hoth/providers/rack_provider'
|
10
|
+
|
11
|
+
require "logger"
|
12
|
+
|
13
|
+
# Initialize Hoth, load service and module definitions
|
14
|
+
Hoth.init!
|
15
|
+
|
16
|
+
# Example, how you can specify your own log provider
|
17
|
+
Hoth::Logger.log_provider = Logger.new(STDOUT)
|
18
|
+
Hoth::Logger.log_provider.level = Logger::WARN
|
19
|
+
|
20
|
+
# To implement the service "addition", we need to provide AdditionImpl.execute
|
21
|
+
class AdditionImpl
|
22
|
+
def self.execute(a, b)
|
23
|
+
return a + b
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# here we go!
|
28
|
+
app = lambda {|env| [200, {'Content-Type' => 'application/json'}, ["body"]]}
|
29
|
+
run Hoth::Providers::RackProvider.new(app)
|
30
|
+
|