handle-system 0.0.3
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/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 [](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'
|