jruby-existdb 0.4

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.
Files changed (45) hide show
  1. data/conf.xml +812 -0
  2. data/lib/existdb.rb +74 -0
  3. data/lib/existdb/classwrap.rb +70 -0
  4. data/lib/existdb/collection.rb +98 -0
  5. data/lib/existdb/dom/active_record.rb +82 -0
  6. data/lib/existdb/dom/mapper.rb +285 -0
  7. data/lib/existdb/embedded.rb +84 -0
  8. data/lib/existdb/index_factory.rb +120 -0
  9. data/lib/existdb/meta.rb +41 -0
  10. data/lib/existdb/resource/base.rb +84 -0
  11. data/lib/existdb/resource/binary.rb +21 -0
  12. data/lib/existdb/resource/xml.rb +23 -0
  13. data/lib/existdb/resource_set.rb +34 -0
  14. data/lib/existdb/xql_factory.rb +191 -0
  15. data/lib/existdb/xquery_service.rb +11 -0
  16. data/lib/jars/antlr-2.7.7.jar +0 -0
  17. data/lib/jars/commons-collections-3.2.1.jar +0 -0
  18. data/lib/jars/commons-logging-1.1.1.jar +0 -0
  19. data/lib/jars/commons-pool-1.5.1.jar +0 -0
  20. data/lib/jars/endorsed/resolver-1.2.jar +0 -0
  21. data/lib/jars/endorsed/serializer-2.9.1.jar +0 -0
  22. data/lib/jars/endorsed/xalan-2.7.1.jar +0 -0
  23. data/lib/jars/endorsed/xercesImpl-2.9.1.jar +0 -0
  24. data/lib/jars/endorsed/xml-apis-1.3.04.jar +0 -0
  25. data/lib/jars/exist-lucene-module.jar +0 -0
  26. data/lib/jars/exist-modules.jar +0 -0
  27. data/lib/jars/exist.jar +0 -0
  28. data/lib/jars/extensions/exist-lucene-module.jar +0 -0
  29. data/lib/jars/extensions/exist-ngram-module.jar +0 -0
  30. data/lib/jars/extensions/exist-versioning.jar +0 -0
  31. data/lib/jars/extensions/lucene-core-2.4.1.jar +0 -0
  32. data/lib/jars/extensions/lucene-regex-2.4.1.jar +0 -0
  33. data/lib/jars/jgroups-all-2.2.6.jar +0 -0
  34. data/lib/jars/jta-1.1.jar +0 -0
  35. data/lib/jars/log4j-1.2.15.jar +0 -0
  36. data/lib/jars/lucene-core-2.4.1.jar +0 -0
  37. data/lib/jars/lucene-regex-2.4.1.jar +0 -0
  38. data/lib/jars/quartz-1.6.5.jar +0 -0
  39. data/lib/jars/sunxacml-1.2.jar +0 -0
  40. data/lib/jars/xmldb.jar +0 -0
  41. data/lib/jars/xmlrpc-client-3.1.2.jar +0 -0
  42. data/lib/jars/xmlrpc-common-3.1.2.jar +0 -0
  43. data/lib/jars/xmlrpc-server-3.1.2.jar +0 -0
  44. data/log4j.xml +190 -0
  45. metadata +104 -0
@@ -0,0 +1,84 @@
1
+ module ExistDB
2
+ class Embedded
3
+ include Singleton
4
+
5
+ attr_accessor :username, :password, :url, :properties
6
+
7
+ def initialize
8
+ @username ||= 'admin'
9
+ @password ||= ''
10
+ @properties ||= {'create-database' => 'true'}
11
+ @url ||= "exist:///db"
12
+
13
+ at_exit do
14
+ stop if running?
15
+ end
16
+ end
17
+
18
+ def start
19
+ return false if running?
20
+ @impl = org.exist.xmldb.DatabaseImpl.new
21
+ @properties.each{ |key, value| @impl.setProperty(key.to_s, value.to_s) }
22
+ org.xmldb.api.DatabaseManager.registerDatabase(@impl)
23
+ @base_collection = @impl.getCollection(@url, @username, @password)
24
+ @database_instance_manager = @base_collection.getService('DatabaseInstanceManager', '1.0')
25
+ @collection_manager = @base_collection.getService('CollectionManager', '1.0')
26
+
27
+ @running = true
28
+ end
29
+
30
+ def running?
31
+ @running
32
+ end
33
+
34
+ alias :started? :running?
35
+
36
+ def stop
37
+ return false if stopped?
38
+ @database_instance_manager.shutdown
39
+ @running = false
40
+ true
41
+ end
42
+
43
+ def stopped?
44
+ not running?
45
+ end
46
+
47
+ def db
48
+ raise InstanceNotRunning if stopped?
49
+ ClassWrap[ @base_collection ]
50
+ end
51
+
52
+ def inspect
53
+ "#<#{self.class}:#{self.hash.to_s(16)} #{running? ? 'running' : 'stopped'}>"
54
+ end
55
+
56
+ def xquery_service
57
+ raise InstanceNotRunning if stopped?
58
+ ClassWrap[ @base_collection.getService('XQueryService', '1.0') ]
59
+ end
60
+
61
+ # org.exist.storage.BrokerPool
62
+ def broker_pool
63
+ raise InstanceNotRunning if stopped?
64
+ org.exist.storage.BrokerPool.getInstance(@impl.getName)
65
+ end
66
+
67
+ # org.exist.storage.txn.Txn
68
+ def transaction # :yields: transaction
69
+ raise InstanceNotRunning if stopped?
70
+ mgr = broker_pool.getTransactionManager
71
+ txn = mgr.beginTransaction
72
+ begin
73
+ yield txn
74
+ mgr.commit(txn)
75
+ rescue
76
+ mgr.abort(txn)
77
+ raise
78
+ end
79
+ end
80
+
81
+ class InstanceNotRunning < Exception; end
82
+ end
83
+
84
+ end
@@ -0,0 +1,120 @@
1
+ module ExistDB
2
+ module IndexFactory
3
+ class << self
4
+ def configure(*opts, &block)
5
+ cfg = IndexFactory.new(*opts, &block)
6
+ cfg.configure
7
+ end
8
+ end
9
+
10
+ # Example:
11
+ # ExistDB::IndexFactory.configure do
12
+ # collection '/db/PartList'
13
+ # range 'qtyOnHand' => Fixnum, 'qtyOnOrder' => Fixnum
14
+ # lucene '//part', 'name', 'description'
15
+ # end
16
+
17
+ class IndexFactory
18
+
19
+ include Meta
20
+
21
+ attr_writer :collection
22
+
23
+ def initialize(*options, &block)
24
+ initialize_with_options(options, [:collection])
25
+ self.instance_eval(&block)
26
+ end
27
+
28
+ def to_s
29
+ wrapper do
30
+ ranges.to_s + lucenes.to_s
31
+ end
32
+ end
33
+
34
+ def range(*targets)
35
+ @ranges ||= Array.new
36
+ targets.each do |target|
37
+ if target.is_a?(Hash) then
38
+ target.each do |key, value|
39
+ tgt_name = key.to_s
40
+ tgt_type = tgt_name.index('/') ? 'path' : 'qname'
41
+ index_type = type_convert(value)
42
+ @ranges << %|<create #{tgt_type}="#{tgt_name}" type="#{index_type}"/>|
43
+ end
44
+ elsif target.respond_to?(:to_s) then
45
+ tgt_name = target.to_s
46
+ tgt_type = tgt_name.index('/') ? 'path' : 'qname'
47
+ @ranges << %|<create #{tgt_type}="#{tgt_name}"/>|
48
+ end
49
+ end
50
+ end
51
+
52
+ def lucene(*targets)
53
+ @lucenes ||= Array.new
54
+ targets.each do |target|
55
+ if target.is_a?(Hash) then
56
+ target.each do |key, value|
57
+ tgt_name = key.to_s
58
+ tgt_type = tgt_name.index('/') ? 'path' : 'qname'
59
+ index_type = type_convert(value)
60
+ @lucenes << %|<text #{tgt_type}="#{tgt_name}" type="#{index_type}"/>|
61
+ end
62
+ elsif target.respond_to?(:to_s) then
63
+ tgt_name = target.to_s
64
+ tgt_type = tgt_name.index('/') ? 'path' : 'qname'
65
+ @lucenes << %|<text #{tgt_type}="#{tgt_name}"/>|
66
+ end
67
+ end
68
+ end
69
+
70
+ def collection(col = nil)
71
+ @collection = col if col
72
+ return @collection
73
+ end
74
+
75
+ def configure
76
+ raise "Specify a collection" unless @collection
77
+ col = collection.create_collection(configuration_collection_name)
78
+ res = Resource.new(:parent => col, :name => configuration_file, :xml => to_s)
79
+ end
80
+
81
+ private
82
+
83
+ def ranges
84
+ @ranges && @ranges.join('')
85
+ end
86
+
87
+ def lucenes
88
+ if @lucenes then
89
+ %|<lucene><analyzer class="org.apache.lucene.analysis.standard.StandardAnalyzer"/><analyzer id="ws" class="org.apache.lucene.analysis.WhitespaceAnalyzer"/>#{ @lucenes.join('') }</lucene>|
90
+ end
91
+ end
92
+
93
+ def wrapper
94
+ %|<collection xmlns="http://exist-db.org/collection-config/1.0"><index>| +
95
+ yield +
96
+ %|</index></collection>|
97
+ end
98
+
99
+ def type_convert(data_type)
100
+ data_type = data_type.to_s
101
+ {
102
+ 'String' => 'xs:string',
103
+ 'Fixnum' => 'xs:int',
104
+ 'Bignum' => 'xs:int',
105
+ 'Numeric' => 'xs:int',
106
+ 'Float' => 'xs:float'
107
+ }[data_type]
108
+ end
109
+
110
+ def configuration_file
111
+ 'collection.xconf'
112
+ end
113
+
114
+ def configuration_collection_name
115
+ "/db/system/config#{@collection}" if @collection
116
+ end
117
+
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,41 @@
1
+ module ExistDB
2
+ module Meta
3
+ # Metaprogramming conviences
4
+
5
+ def initialize_with_options(options, ordered_options)
6
+ # Usage:
7
+ # class MyClass
8
+ # include Meta
9
+ # attr_accessor :opt1, :opt2
10
+ # def initialize(*options)
11
+ # initialize_with_options(options, [:opt1, :opt2])
12
+ # end
13
+ # end
14
+ #
15
+ # obj = MyClass.new(:opt1 => 'foo', :opt2 => 'bar')
16
+ # # OR
17
+ # obj = MyClass.new('foo', 'bar')
18
+ # # MyClass.new now accepts named or ordered params!
19
+ named_or_ordered_options(options, ordered_options).each do |key, value|
20
+ if key.is_a?(Symbol) or key.is_a?(String) then
21
+ key = "#{key}=".to_sym
22
+ self.send(key, value) if self.respond_to?(key)
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ def named_or_ordered_options(options, ordered_options)
29
+ hash = Hash.new
30
+ options.each_with_index do |option, i|
31
+ if option.is_a?(Hash) then
32
+ hash.merge!(option)
33
+ else
34
+ key = ordered_options[i]
35
+ hash[key] = option
36
+ end
37
+ end
38
+ return hash
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,84 @@
1
+ module ExistDB
2
+ module Resource
3
+
4
+ class << self
5
+ def new(*options)
6
+ if options.size == 1 and not options.first.is_a?(Hash) then
7
+ obj = options.first
8
+ ClassWrap[obj]
9
+ else
10
+ if options.any?{|opt| opt.is_a?(Hash) && ( opt[:xml] || opt[:type] == 'XMLResource' ) } then
11
+ Xml.new(*options)
12
+ elsif options.any?{|opt| opt.is_a?(Hash) && ( opt[:binary] || opt[:type] == 'BinaryResource' ) } then
13
+ Binary.new(*options)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ class Base
20
+ extend ClassWrappingForwardable
21
+ delegate_to_java(
22
+ :content= => :setContent,
23
+ :content => :getContent,
24
+ :length => :getContentLength,
25
+ :created => :getCreationTime,
26
+ :last_modified => :getLastModificationTime,
27
+ :resource_type => :getResourceType,
28
+ :parent => :getParentCollection,
29
+ :name => :getId
30
+ )
31
+ alias :to_s :content
32
+ alias :size :length
33
+
34
+ def initialize(*opts)
35
+ options = Hash.new
36
+ if opts.size == 1 and not opts.first.is_a?(Hash) then
37
+ @obj = opts.first
38
+ else
39
+ opts.each do |opt|
40
+ if opt.is_a?(Hash) then
41
+ options.merge!(opt)
42
+ end
43
+ end
44
+
45
+ collection = ClassUnwrap[ options[:parent] ]
46
+ data = nil
47
+ if options[:binary]
48
+ type = "BinaryResource"
49
+ data = options[:binary]
50
+ elsif options[:xml]
51
+ type = "XMLResource"
52
+ data = options[:xml]
53
+ else
54
+ type = options[:type]
55
+ data = options[:content]
56
+ end
57
+ type ||= "XMLResource"
58
+
59
+ @obj = collection.createResource(options[:name], type)
60
+ if data then
61
+ self.content = data
62
+ self.save
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ def inspect
69
+ "#<#{self.class}:0x#{self.hash.to_s(16)} name=#{self.name.inspect}>"
70
+ end
71
+
72
+ def save
73
+ collection = @obj.getParentCollection
74
+ collection.storeResource( @obj )
75
+ true
76
+ end
77
+
78
+ def delete
79
+ parent.delete(self)
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,21 @@
1
+ module ExistDB
2
+ module Resource
3
+ class Binary < Base
4
+
5
+ def content=(data)
6
+ bytes = data.to_s.to_java_bytes
7
+ @obj.setContent(bytes)
8
+ end
9
+
10
+ def content
11
+ to_io.read
12
+ end
13
+
14
+ def to_io
15
+ input_stream = @obj.getStreamContent
16
+ return Java.java_to_ruby(org.jruby.RubyIO.new(JRuby.runtime, input_stream).java_object)
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ module ExistDB
2
+ module Resource
3
+ class Xml < Base
4
+
5
+ def xquery(*opts)
6
+ parent.xquery.query(self, *opts)
7
+ end
8
+
9
+ def compile(*opts)
10
+ parent.xquery.compile(*opts)
11
+ end
12
+
13
+ def execute(*opts)
14
+ parent.xquery.execute(self, *opts)
15
+ end
16
+
17
+ def dom
18
+ @obj.getContentAsDOM
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ module ExistDB
2
+ class ResourceSet
3
+
4
+ include Enumerable
5
+ extend ClassWrappingForwardable
6
+ delegate_to_java(
7
+ :size => :getSize,
8
+ :[] => :getResource,
9
+ :join => :getMembersAsResource,
10
+ :add => :addResource
11
+ )
12
+
13
+ def initialize(java_obj)
14
+ @obj = java_obj
15
+ end
16
+
17
+ def each
18
+ for i in (0 .. (size - 1))
19
+ yield self[i]
20
+ end
21
+ end
22
+
23
+ class << self
24
+ def [](*resources)
25
+ set = new( org.exist.xmldb.MapResourceSet.new )
26
+ resources.each do |resource|
27
+ set.add(resource)
28
+ end
29
+ return set
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,191 @@
1
+ module ExistDB
2
+ module XQLFactory
3
+
4
+ class << self
5
+
6
+ # Shorthand for ExistDB::XQLFactory::XQLFactory.new( options ).xquery
7
+
8
+ def Build(*opts, &block)
9
+ XQLFactory.new(*opts, &block).xquery
10
+ end
11
+ end
12
+
13
+ # This is used by the XQLFactory for remapping nodes
14
+ #
15
+ # This could possibly be simplified by using XSLT if there was a Ruby DSL for XSLT
16
+ #
17
+ # The primary goal is to keep the barrier to entry low for rubyists who have limited XML experience
18
+ class Path
19
+
20
+ attr_reader :to_s, :to_a
21
+ def initialize(path)
22
+ if path.is_a?(String) then
23
+ @to_s = path
24
+ @to_a = path.split('/')
25
+ elsif path.is_a?(Array) then
26
+ @to_s = path.join('/')
27
+ @to_a = path
28
+ end
29
+ end
30
+
31
+ def name
32
+ @to_a.last
33
+ end
34
+
35
+ def context
36
+ @to_a[0..-2]
37
+ end
38
+
39
+ def <=>(path)
40
+ to_a <=> path.to_a
41
+ end
42
+
43
+ def common(path)
44
+ a = Array.new
45
+ self.to_a.each_index do |i|
46
+ if self.to_a[i].nil? or
47
+ path.to_a[i].nil? or
48
+ self.to_a[i] != path.to_a[i] then
49
+ break
50
+ else
51
+ a << self.to_a[i]
52
+ end
53
+ end
54
+ a << ''
55
+ return Path.new(a)
56
+ end
57
+
58
+ def switch_context(path)
59
+ output = String.new
60
+ common_path = self.common(path)
61
+ diff = self.context.size - common_path.context.size
62
+ if diff > 0 then
63
+ output << self.context.last(diff).reverse.map{ |node| "</#{node}>"}.join
64
+ end
65
+ diff = path.context.size - common_path.context.size
66
+ if diff > 0 then
67
+ output << path.context.last(diff).map{ |node| "<#{node}>"}.join
68
+ end
69
+ return output
70
+ end
71
+
72
+ end
73
+
74
+ # This is an attempt to create a Ruby DSL for the Most Common XQuery use cases.
75
+ class XQLFactory
76
+
77
+ include Meta
78
+ attr_accessor :start, :max, :doc,
79
+ :node_xpath, :sort, :return_attributes,
80
+ :return_tag, :node_remap, :search, :ftquery
81
+
82
+ # Accepts Ordered or Named Parameters for any of the attr_accessors
83
+ #
84
+ # Ordered Options -- :doc, :start, :max, :sort
85
+ #
86
+ # E.g.
87
+ #
88
+ # <tt>
89
+ # xql = XQLFactory.new("doc('http://example.com')", 5, 10, :node_xpath => '//a').xquery
90
+ # </tt>
91
+ #
92
+ # Would create an XQuery statement to find the fifth through tenth links on example.com
93
+ #
94
+ # See also ExistDB::XQLFactory.Build as a shorthand way of calling this.
95
+
96
+ def initialize(*options)
97
+ initialize_with_options(options, [:doc, :start, :max, :sort])
98
+ yield self if block_given?
99
+ end
100
+
101
+ def limit_statement
102
+ if start or max then
103
+ "let $scope := subsequence($scope, #{start || 1}, #{max || 'count($scope)'})\n"
104
+ else
105
+ ''
106
+ end
107
+ end
108
+
109
+ def sort_statement
110
+ if sort then
111
+ if sort.is_a?(String) then
112
+ "order by $node/#{sort}"
113
+ elsif sort.is_a?(Hash) then
114
+ "order by $node/#{sort.keys.first} #{sort_direction(sort.values.first)}"
115
+ elsif sort.is_a?(Array) then
116
+ "order by " + sort.map{ |h| "$node/#{h.keys.first} #{sort_direction(h.values.first)}" }.join(', ')
117
+ end
118
+ else
119
+ ''
120
+ end
121
+ end
122
+
123
+ def sort_direction(dir)
124
+ dir = dir.to_s.downcase
125
+ if %w|asc ascending|.include?(dir)
126
+ return :ascending
127
+ elsif %|desc descending|.include?(dir)
128
+ return :descending
129
+ else
130
+ return :ascending
131
+ end
132
+ end
133
+
134
+ def search_statement
135
+ "[contains(., #{ search.inspect })]" if search
136
+ "[ft:query(., #{ ftquery.inspect })]" if ftquery
137
+ end
138
+
139
+ def init_statement
140
+ raise "doc attribute required" if doc.nil? or doc.to_s.empty?
141
+ raise "node_xpath attribute required" if node_xpath.nil? or node_xpath.empty?
142
+ "let $scope := for $node in #{doc if doc.is_a?(String)}#{node_xpath}#{search_statement} #{sort_statement} return $node\n"
143
+ end
144
+
145
+ def return_tag
146
+ @return_tag || 'xml'
147
+ end
148
+
149
+ def return_tag=(tag)
150
+ @return_tag = tag
151
+ end
152
+
153
+ def return_statement
154
+ if return_attributes_statement.empty? and @return_tag.nil? then
155
+ "return $scope"
156
+ else
157
+ "return <#{return_tag}#{return_attributes_statement}> { $scope } </#{return_tag}>"
158
+ end
159
+ end
160
+
161
+ def return_attributes_statement
162
+ return '' if return_attributes.nil? or return_attributes.empty?
163
+ ' ' + return_attributes.keys.map{ |key|
164
+ "#{key}=#{return_attributes[key].to_s.inspect}"
165
+ }.join(' ')
166
+ end
167
+
168
+ def node_remap_statement
169
+ return '' if node_remap.nil? or node_remap.empty?
170
+ output = "let $scope := for $node in $scope return\n"
171
+ current_context = Path.new('')
172
+ node_remap.to_a.map{|a|
173
+ a[1] = Path.new(a[1]); a
174
+ }.sort.each do |a|
175
+ (src_path, dest_path) = a
176
+ output << current_context.switch_context(dest_path)
177
+ current_context = dest_path
178
+ output << "<#{dest_path.name}>{ $node#{src_path} }</#{dest_path.name}>"
179
+ end
180
+ output << current_context.switch_context( Path.new('') )
181
+ output << "\n"
182
+ return output
183
+ end
184
+
185
+ def xquery
186
+ init_statement + limit_statement + node_remap_statement + return_statement
187
+ end
188
+
189
+ end
190
+ end
191
+ end