handle-system 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -0
- data/LICENSE.txt +34 -0
- data/README.md +57 -0
- data/Rakefile +28 -0
- data/lib/handle/command/connection.rb +134 -0
- data/lib/handle/command/persistence.rb +57 -0
- data/lib/handle/command.rb +2 -0
- data/lib/handle/field/admin.rb +79 -0
- data/lib/handle/field.rb +125 -0
- data/lib/handle/java/connection.rb +95 -0
- data/lib/handle/java/persistence.rb +54 -0
- data/lib/handle/java.rb +18 -0
- data/lib/handle/permissions.rb +61 -0
- data/lib/handle/record.rb +82 -0
- data/lib/handle/version.rb +3 -0
- data/lib/handle.rb +19 -0
- data/spec/admin_spec.rb +48 -0
- data/spec/command/connection_spec.rb +145 -0
- data/spec/command/persistence_spec.rb +63 -0
- data/spec/field_spec.rb +40 -0
- data/spec/java/connection_spec.rb +118 -0
- data/spec/java/persistence_spec.rb +67 -0
- data/spec/permissions_spec.rb +39 -0
- data/spec/record_spec.rb +72 -0
- data/spec/spec_helper.rb +20 -0
- metadata +136 -0
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
HANDLE RUBY GEM
|
2
|
+
===============
|
3
|
+
Copyright (c) 2013 Michael Klein
|
4
|
+
|
5
|
+
MIT License
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
a copy of this software and associated documentation files (the
|
9
|
+
"Software"), to deal in the Software without restriction, including
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
|
26
|
+
|
27
|
+
HANDLE SYSTEM AND JAVA LIBRARIES
|
28
|
+
================================
|
29
|
+
HANDLE SYSTEM, HANDLE.NET, HDL, HDL.NET, and GLOBAL HANDLE REGISTRY are trademarks owned by CNRI.
|
30
|
+
|
31
|
+
Copyright © Corporation for National Research Initiatives 2013; All Rights Reserved.
|
32
|
+
|
33
|
+
Made available under the Handle System Public License Agreement v.2
|
34
|
+
< http://hdl.handle.net/4263537/5030 >
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Handle [![Build Status](https://secure.travis-ci.org/mbklein/handle.png)](http://travis-ci.org/mbklein/handle)
|
2
|
+
|
3
|
+
Classes and methods for dealing with [Handle System](http://handle.net/) servers and handles.
|
4
|
+
|
5
|
+
## Platform Notes
|
6
|
+
|
7
|
+
`Handle::Connection` and `Handle::Persistence` have two implementations each – one for JRuby,
|
8
|
+
and one for everything else. Under JRuby, it calls Java HSAdapter methods directly. Under MRI
|
9
|
+
or other non-JVM rubies, it shells out to command line tools (particularly `hdl-qresolver`
|
10
|
+
and `hdl-genericbatch`) behind the scenes to do its work.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
gem 'handle'
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install handle
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require 'handle'
|
30
|
+
|
31
|
+
# Set up an authenticated connection
|
32
|
+
conn = Handle::Connection.new('0.NA/admin.handle', 300,
|
33
|
+
'/path/to/private/key/file', 'privkey-passphrase')
|
34
|
+
|
35
|
+
# Create an empty record
|
36
|
+
record = conn.create_record('handle.prefix/new.handle')
|
37
|
+
|
38
|
+
# Two ways to add fields
|
39
|
+
record.add(:URL, 'http://example.edu/').index = 2
|
40
|
+
record.add(:Email, 'someone@example.edu').index = 6
|
41
|
+
record << Handle::Field::HSAdmin.new('0.NA/admin.handle')
|
42
|
+
|
43
|
+
# Manipulate permissions
|
44
|
+
record.last.perms.public_read = false
|
45
|
+
|
46
|
+
record.save
|
47
|
+
|
48
|
+
record = conn.resolve_handle('handle.prefix/new.handle')
|
49
|
+
```
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
1. Fork it
|
54
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
55
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
56
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
57
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require 'rdoc/task'
|
4
|
+
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'rspec/core/rake_task'
|
15
|
+
RSpec::Core::RakeTask.new do |t|
|
16
|
+
t.pattern = FileList['./spec/**/*_spec.rb']
|
17
|
+
end
|
18
|
+
|
19
|
+
task :default => :spec
|
20
|
+
|
21
|
+
Rake::RDocTask.new do |rdoc|
|
22
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
23
|
+
|
24
|
+
rdoc.rdoc_dir = 'rdoc'
|
25
|
+
rdoc.title = "handle #{version}"
|
26
|
+
rdoc.rdoc_files.include('README*')
|
27
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
28
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Handle
|
4
|
+
module Command
|
5
|
+
HDL_HOME = ENV['HDL_HOME'] || '/usr/local/handle'
|
6
|
+
|
7
|
+
class Batch
|
8
|
+
def initialize(handle, index, auth)
|
9
|
+
@batch_file = Tempfile.new('hdl')
|
10
|
+
auth_type = auth.length == 2 ? "PUBKEY" : "SECKEY"
|
11
|
+
@batch_file.puts "AUTHENTICATE #{auth_type}:#{index}:#{handle}"
|
12
|
+
@batch_file.puts auth.select { |p| not (p.nil? or p.empty?) }.join('|')
|
13
|
+
end
|
14
|
+
|
15
|
+
def cleanup
|
16
|
+
@batch_file.close unless @batch_file.closed?
|
17
|
+
@batch_file.unlink
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute!
|
21
|
+
@batch_file.close
|
22
|
+
cmd = File.join(HDL_HOME, 'bin', 'hdl-genericbatch')
|
23
|
+
output = `#{cmd} #{@batch_file.path} 2>/dev/null`
|
24
|
+
results = output.lines.select { |line| line =~ /^=+>/ }
|
25
|
+
results.each do |rs|
|
26
|
+
(status, message) = rs.scan(/^=+>(.+)\[[0-9]+\]: (.+)/).flatten
|
27
|
+
(action, handle, code, message) = message.split(/:\s*/,4)
|
28
|
+
if status == 'FAILURE'
|
29
|
+
exception = Handle::HandleError.new message
|
30
|
+
exception.set_backtrace(caller[3..-1])
|
31
|
+
raise exception
|
32
|
+
end
|
33
|
+
end
|
34
|
+
return true
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_handle_values(handle, record)
|
38
|
+
@batch_file.puts "\nADD #{handle}"
|
39
|
+
@batch_file.puts record.to_batch
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_handle(handle, record)
|
43
|
+
@batch_file.puts "\nCREATE #{handle}"
|
44
|
+
@batch_file.puts record.to_batch
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete_handle(handle)
|
48
|
+
@batch_file.puts "\nDELETE #{handle}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete_handle_values(handle, record)
|
52
|
+
indexes = record.collect(&:index).join(',')
|
53
|
+
@batch_file.puts "\nREMOVE #{indexes}:#{handle}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def update_handle_values(handle, record)
|
57
|
+
@batch_file.puts "\nMODIFY #{handle}"
|
58
|
+
@batch_file.puts record.to_batch
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Connection
|
63
|
+
def initialize(handle, index, *auth, &block)
|
64
|
+
@handle = handle
|
65
|
+
@index = index
|
66
|
+
@auth_params = auth
|
67
|
+
if block_given?
|
68
|
+
batch &block
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def batch
|
73
|
+
context = Batch.new(@handle, @index, @auth_params)
|
74
|
+
begin
|
75
|
+
yield context
|
76
|
+
result = context.execute!
|
77
|
+
ensure
|
78
|
+
context.cleanup
|
79
|
+
end
|
80
|
+
result
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_handle_values(*args)
|
84
|
+
batch { |b| b.add_handle_values(*args) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def create_handle(*args)
|
88
|
+
batch { |b| b.create_handle(*args) }
|
89
|
+
end
|
90
|
+
|
91
|
+
def delete_handle(*args)
|
92
|
+
batch { |b| b.delete_handle(*args) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def delete_handle_values(*args)
|
96
|
+
batch { |b| b.delete_handle_values(*args) }
|
97
|
+
end
|
98
|
+
|
99
|
+
def update_handle_values(*args)
|
100
|
+
batch { |b| b.update_handle_values(*args) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_record(handle)
|
104
|
+
result = Handle::Record.new
|
105
|
+
result.connection = self
|
106
|
+
result.handle = handle
|
107
|
+
result
|
108
|
+
end
|
109
|
+
|
110
|
+
def resolve_handle(handle, types=[], indexes=[], auth=true)
|
111
|
+
cmd = File.join(HDL_HOME, 'bin', 'hdl-qresolver')
|
112
|
+
response = `#{cmd} #{handle} 2>/dev/null`.strip
|
113
|
+
if response =~ /^Got Response:/
|
114
|
+
response = response.lines.select { |line| line =~ /^\s*index=/ }.join("")
|
115
|
+
result = Handle::Record.from_data(response)
|
116
|
+
result.connection = self
|
117
|
+
result.handle = handle
|
118
|
+
result
|
119
|
+
else
|
120
|
+
(code, message) = response.lines.to_a.last.scan(/Error\(([0-9]+)\): (.+)$/).flatten
|
121
|
+
exception_klass = case code.to_i
|
122
|
+
when 100 then Handle::NotFound
|
123
|
+
else Handle::HandleError
|
124
|
+
end
|
125
|
+
exception = exception_klass.new message
|
126
|
+
exception.set_backtrace(caller)
|
127
|
+
raise exception
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
Connection = Command::Connection
|
134
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Handle
|
2
|
+
module Command
|
3
|
+
module Persistence
|
4
|
+
attr_accessor :handle, :connection
|
5
|
+
|
6
|
+
def to_batch
|
7
|
+
self.collect do |field|
|
8
|
+
perm_params = field.perms.to_s
|
9
|
+
data_type = case field.class.value_type
|
10
|
+
when 'HS_ADMIN' then 'ADMIN'
|
11
|
+
when 'HS_SITE' then 'FILE'
|
12
|
+
when 'HS_PUBKEY' then 'FILE'
|
13
|
+
else 'UTF8'
|
14
|
+
end
|
15
|
+
"#{field.index} #{field.class.value_type} #{field.ttl} #{perm_params} #{data_type} #{field.value_str}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def reload
|
20
|
+
self.initialize_with(connection.resolve_handle(self.handle).fields)
|
21
|
+
end
|
22
|
+
|
23
|
+
def save(new_handle=nil)
|
24
|
+
save_handle = new_handle || self.handle
|
25
|
+
if save_handle.nil?
|
26
|
+
raise Handle::HandleError.new("No handle provided.")
|
27
|
+
end
|
28
|
+
|
29
|
+
if save_handle == self.handle
|
30
|
+
begin
|
31
|
+
original = connection.resolve_handle(save_handle)
|
32
|
+
actions = original | self
|
33
|
+
actions.each_value { |v| v.connection = connection }
|
34
|
+
[:delete,:update,:add].each do |action|
|
35
|
+
unless actions[action].empty?
|
36
|
+
connection.send("#{action}_handle_values".to_sym, save_handle, actions[action])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
rescue Handle::NotFound
|
40
|
+
connection.create_handle(save_handle, self)
|
41
|
+
@handle = save_handle
|
42
|
+
end
|
43
|
+
else
|
44
|
+
connection.create_handle(save_handle, self)
|
45
|
+
@handle = save_handle
|
46
|
+
end
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def destroy
|
51
|
+
connection.delete_handle(self.handle)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
Persistence = Command::Persistence
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Handle
|
2
|
+
module Field
|
3
|
+
class HSAdmin < Base
|
4
|
+
value_type 'HS_ADMIN'
|
5
|
+
default_index 100
|
6
|
+
|
7
|
+
attr_accessor :admin_handle
|
8
|
+
attr :admin_perms, :admin_index
|
9
|
+
|
10
|
+
def initialize(handle=nil)
|
11
|
+
super()
|
12
|
+
@admin_handle = handle
|
13
|
+
@admin_index = 300
|
14
|
+
@admin_perms = Handle::Permissions.new(
|
15
|
+
:add_handle, :delete_handle, :add_na, :delete_na,
|
16
|
+
:modify_values, :remove_values, :add_values, :read_values,
|
17
|
+
:modify_admin, :remove_admin, :add_admin, :list_handles,
|
18
|
+
)
|
19
|
+
@admin_perms.bitmask = 0b111111111111
|
20
|
+
end
|
21
|
+
|
22
|
+
def value
|
23
|
+
values = [self.admin_perms.bitmask, 0, 13, self.admin_handle, 0, self.admin_index]
|
24
|
+
values.pack('nnnZ*cn')
|
25
|
+
end
|
26
|
+
|
27
|
+
def value_str
|
28
|
+
[self.admin_index,self.admin_perms.to_s,self.admin_handle].join(':')
|
29
|
+
#value.bytes.collect { |b| '%2.2X' % b }.join('')
|
30
|
+
end
|
31
|
+
|
32
|
+
def value=(bytes)
|
33
|
+
if bytes =~ /^([0-9]+):([01]+):(.+)$/
|
34
|
+
self.admin_index = $1.to_i
|
35
|
+
self.admin_perms.bitmask = $2.to_i(2)
|
36
|
+
self.admin_handle = $3
|
37
|
+
else
|
38
|
+
if bytes =~ /^[0-9A-Fa-f]+$/
|
39
|
+
bytes = bytes.scan(/../).map(&:hex).pack('C*')
|
40
|
+
end
|
41
|
+
values = bytes.unpack('nnnZ*cn')
|
42
|
+
self.admin_perms.bitmask = values[0]
|
43
|
+
self.admin_handle = values[3]
|
44
|
+
self.admin_index = values[5] unless values[5].nil? or values[5] == 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_h
|
49
|
+
result = super.merge({
|
50
|
+
admin_handle: self.admin_handle,
|
51
|
+
admin_index: self.admin_index,
|
52
|
+
admin_perms: self.admin_perms.bitmask
|
53
|
+
})
|
54
|
+
result.delete(:value)
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_s
|
59
|
+
" index=#{self.index} type=#{self.class.value_type} ttl=#{self.ttl} #{self.perms} #{value_str.inspect}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def admin_index=(value)
|
63
|
+
@admin_index = value.to_i
|
64
|
+
end
|
65
|
+
|
66
|
+
def merge!(hash)
|
67
|
+
hash.each_pair do |key,value|
|
68
|
+
k = key.to_sym
|
69
|
+
self.perms.bitmask = value if k == :perms
|
70
|
+
self.admin_perms.bitmask = value if k == :admin_perms
|
71
|
+
if [:admin_handle, :admin_index, :index, :ttl, :value].include? k
|
72
|
+
self.send(:"#{k.to_s}=", value)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
self
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/handle/field.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
module Handle
|
2
|
+
module Field
|
3
|
+
class Base
|
4
|
+
attr_accessor :value
|
5
|
+
attr :index, :ttl, :perms
|
6
|
+
|
7
|
+
class << self
|
8
|
+
@@value_types = {}
|
9
|
+
def value_type val=nil
|
10
|
+
if val
|
11
|
+
if @value_type
|
12
|
+
@@value_types.delete(@value_type)
|
13
|
+
end
|
14
|
+
@value_type = val
|
15
|
+
@@value_types[val] = self
|
16
|
+
end
|
17
|
+
@value_type
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_index val=nil
|
21
|
+
val ? @default_index = val : @default_index
|
22
|
+
end
|
23
|
+
|
24
|
+
def from_hash(hash)
|
25
|
+
type = hash.values_at(:type,'type').compact.first
|
26
|
+
if @@value_types.has_key? type
|
27
|
+
klass = @@value_types[type]
|
28
|
+
result = klass.new
|
29
|
+
result.merge!(hash)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def from_string(str)
|
34
|
+
attrs, perms, data = str.scan(/^\s*(.+) ([10rw\-]+) "(.+)"$/).flatten
|
35
|
+
attrs = attrs.split(/\s+/).inject({}) { |hash,attr|
|
36
|
+
(k,v) = attr.split(/\=/,2)
|
37
|
+
hash[k.to_sym] = v
|
38
|
+
hash
|
39
|
+
}
|
40
|
+
type = attrs.delete(:type)
|
41
|
+
if @@value_types.has_key? type
|
42
|
+
klass = @@value_types[type]
|
43
|
+
result = klass.new
|
44
|
+
result.merge!(attrs)
|
45
|
+
result.perms.bitmask = perms.gsub(/./) { |m| m =~ /[0\-]/ ? '0' : '1' }.to_i(2)
|
46
|
+
result.value = data
|
47
|
+
result
|
48
|
+
else
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def from_data(data)
|
54
|
+
if data.is_a?(Hash)
|
55
|
+
self.from_hash(data)
|
56
|
+
else
|
57
|
+
self.from_string(data.to_s)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
@index = self.class.default_index
|
64
|
+
@ttl = 86400
|
65
|
+
@perms = Handle::Permissions.new(:admin_read, :admin_write, :public_read, :public_write, 0b1110)
|
66
|
+
end
|
67
|
+
|
68
|
+
def ==(other)
|
69
|
+
self.to_s == other.to_s
|
70
|
+
end
|
71
|
+
|
72
|
+
def index=(value)
|
73
|
+
@index = value.to_i
|
74
|
+
end
|
75
|
+
|
76
|
+
def ttl=(value)
|
77
|
+
@ttl = value.to_i
|
78
|
+
end
|
79
|
+
|
80
|
+
def merge!(hash)
|
81
|
+
hash.each_pair do |key,value|
|
82
|
+
k = key.to_sym
|
83
|
+
value = value.to_i if [:perms,:index].include?(k)
|
84
|
+
self.perms.bitmask = value if k == :perms
|
85
|
+
if [:index, :ttl, :value].include? k
|
86
|
+
self.send(:"#{k.to_s}=", value)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_h
|
93
|
+
{
|
94
|
+
index: self.index,
|
95
|
+
type: self.class.value_type,
|
96
|
+
ttl: self.ttl,
|
97
|
+
perms: self.perms.bitmask,
|
98
|
+
value: self.value
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_json *args
|
103
|
+
self.to_h.to_json *args
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_s
|
107
|
+
" index=#{self.index} type=#{self.class.value_type} ttl=#{self.ttl} #{self.perms} #{self.value.inspect}"
|
108
|
+
end
|
109
|
+
|
110
|
+
def value_str
|
111
|
+
value.to_s
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class URL < Base ; value_type 'URL' ; end
|
116
|
+
class URN < Base ; value_type 'URN' ; end
|
117
|
+
class Email < Base ; value_type 'EMAIL' ; end
|
118
|
+
class HSSite < Base ; value_type 'HS_SITE' ; end
|
119
|
+
class HSServ < Base ; value_type 'HS_SERV' ; end
|
120
|
+
class HSAlias < Base ; value_type 'HS_ALIAS' ; end
|
121
|
+
class HSPubKey < Base ; value_type 'HS_PUB_KEY' ; default_index 300 ; end
|
122
|
+
class HSSecKey < Base ; value_type 'HS_SEC_KEY' ; default_index 301 ; end
|
123
|
+
class HSVList < Base ; value_type 'HS_VLIST' ; default_index 400 ; end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Handle
|
2
|
+
module Java
|
3
|
+
class Connection
|
4
|
+
# A more Ruby-ish HSAdapter
|
5
|
+
|
6
|
+
def initialize(handle, index, *auth)
|
7
|
+
# accept either a key file or the key itself
|
8
|
+
if auth.length == 2 and (not auth[0].bytes.to_a.include?(0)) and File.exists?(auth[0])
|
9
|
+
auth[0] = File.read(auth[0])
|
10
|
+
end
|
11
|
+
auth_params = auth.collect { |p| p.to_java_bytes }
|
12
|
+
protect {
|
13
|
+
@conn = Native::HSAdapterFactory.new_instance(handle, index, *auth_params)
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_handle_values(handle, record)
|
18
|
+
protect {
|
19
|
+
@conn.addHandleValues(handle, record.to_java)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_handle(handle, record)
|
24
|
+
protect {
|
25
|
+
@conn.createHandle(handle, record.to_java)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_record(handle)
|
30
|
+
result = Handle::Record.new
|
31
|
+
result.connection = self
|
32
|
+
result.handle = handle
|
33
|
+
result
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete_handle(handle)
|
37
|
+
protect {
|
38
|
+
@conn.deleteHandle(handle)
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete_handle_values(handle, record)
|
43
|
+
protect {
|
44
|
+
@conn.deleteHandleValues(handle, record.to_java)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def resolve_handle(handle, types=[], indexes=[], auth=true)
|
49
|
+
protect {
|
50
|
+
java_response = @conn.resolveHandle(
|
51
|
+
handle, types.to_java(:string),
|
52
|
+
indexes.to_java(:int), auth
|
53
|
+
)
|
54
|
+
result = Handle::Record.from_data(java_response)
|
55
|
+
result.connection = self
|
56
|
+
result.handle = handle
|
57
|
+
result
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def use_udp=(value)
|
62
|
+
protect {
|
63
|
+
@conn.setUseUDP(value)
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def update_handle_values(handle, record)
|
68
|
+
protect {
|
69
|
+
@conn.updateHandleValues(handle, record.to_java)
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def native
|
74
|
+
@conn
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
def protect
|
79
|
+
begin
|
80
|
+
response = yield
|
81
|
+
rescue Native::HandleException => err
|
82
|
+
exception_klass = case err.getCode()
|
83
|
+
when 9 then Handle::NotFound
|
84
|
+
else Handle::HandleError
|
85
|
+
end
|
86
|
+
exception = exception_klass.new err.message
|
87
|
+
exception.set_backtrace(caller)
|
88
|
+
raise exception
|
89
|
+
end
|
90
|
+
response.nil? ? true : response
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
Connection = Java::Connection
|
95
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Handle
|
2
|
+
module Java
|
3
|
+
module Persistence
|
4
|
+
attr_accessor :handle, :connection
|
5
|
+
|
6
|
+
def to_java
|
7
|
+
result = self.collect do |field|
|
8
|
+
perm_params = field.perms.to_bool
|
9
|
+
Native::HandleValue.new(field.index.to_java(:int), field.class.value_type.to_java_bytes,
|
10
|
+
field.value.to_java_bytes, Native::HandleValue::TTL_TYPE_RELATIVE.to_java(:byte),
|
11
|
+
field.ttl.to_java(:int), 0.to_java(:int), nil, *perm_params)
|
12
|
+
end
|
13
|
+
result.to_java(Native::HandleValue)
|
14
|
+
end
|
15
|
+
|
16
|
+
def reload
|
17
|
+
self.initialize_with(connection.resolve_handle(self.handle).fields)
|
18
|
+
end
|
19
|
+
|
20
|
+
def save(new_handle=nil)
|
21
|
+
save_handle = new_handle || self.handle
|
22
|
+
if save_handle.nil?
|
23
|
+
raise Handle::HandleError.new("No handle provided.")
|
24
|
+
end
|
25
|
+
|
26
|
+
if save_handle == self.handle
|
27
|
+
begin
|
28
|
+
original = connection.resolve_handle(save_handle)
|
29
|
+
actions = original | self
|
30
|
+
actions.each_value { |v| v.connection = connection }
|
31
|
+
[:delete,:update,:add].each do |action|
|
32
|
+
unless actions[action].empty?
|
33
|
+
connection.send("#{action}_handle_values".to_sym, save_handle, actions[action])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
rescue Handle::NotFound
|
37
|
+
connection.create_handle(save_handle, self)
|
38
|
+
@handle = save_handle
|
39
|
+
end
|
40
|
+
else
|
41
|
+
connection.create_handle(save_handle, self)
|
42
|
+
@handle = new_handle
|
43
|
+
end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def destroy
|
48
|
+
connection.delete_handle(self.handle)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
Persistence = Java::Persistence
|
53
|
+
end
|
54
|
+
|
data/lib/handle/java.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'java'
|
2
|
+
# Load all jarfiles in $HDL_HOME/lib
|
3
|
+
hdl_home = ENV['HDL_HOME'] || File.expand_path('../../../vendor/handle',__FILE__)
|
4
|
+
Dir[File.join(hdl_home,'lib','*.jar')].each { |f| require f }
|
5
|
+
|
6
|
+
module Handle
|
7
|
+
module Java
|
8
|
+
module Native
|
9
|
+
java_import 'net.handle.hdllib.HandleException'
|
10
|
+
java_import 'net.handle.hdllib.HandleValue'
|
11
|
+
java_import 'net.handle.api.HSAdapter'
|
12
|
+
java_import 'net.handle.api.HSAdapterFactory'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'handle/java/connection'
|
18
|
+
require 'handle/java/persistence'
|