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,74 @@
1
+ require 'java'
2
+ require 'uri'
3
+ require 'cgi' # For HTML Escaping
4
+ require 'find'
5
+ require 'fileutils'
6
+ require 'singleton'
7
+ require 'forwardable'
8
+ require 'date'
9
+ require 'time'
10
+
11
+ $LOAD_PATH << File.dirname(__FILE__)
12
+
13
+ module ExistDB
14
+ class SystemProperties
15
+ class << self
16
+ def home_directory
17
+ defined?(EXIST_HOME) && EXIST_HOME || ENV['EXIST_HOME'] || '/var/spool/existdb'
18
+ end
19
+
20
+ def log_directory
21
+ defined?(EXIST_LOG) && EXIST_LOG || ENV['EXIST_LOG'] || '/var/log/existdb'
22
+ end
23
+
24
+ def data_directory
25
+ home_directory + '/data'
26
+ end
27
+
28
+ def init
29
+ java.lang.System.setProperty('exist.home', home_directory)
30
+ java.lang.System.setProperty('exist.logdir', log_directory)
31
+ end
32
+
33
+ def autocreate_config_files
34
+ # Copy the config files to the places where eXist will eXpect them.
35
+ # the log4j.xml file should be on your classpath to ensure proper logging
36
+ [ 'conf.xml', 'log4j.xml' ].each do |config_file|
37
+ src = "#{File.dirname(__FILE__)}/../#{config_file}"
38
+ dest = "#{home_directory}/#{config_file}"
39
+ FileUtils.copy(src, dest) if not File.exists?(dest)
40
+ end
41
+ end
42
+
43
+ def autocreate_data_directory
44
+ FileUtils.mkdir_p data_directory
45
+ end
46
+
47
+ end
48
+ init
49
+ autocreate_data_directory
50
+ autocreate_config_files
51
+ end
52
+ end
53
+
54
+ # Load eXistDB jars
55
+ Find.find( File.dirname(__FILE__) + '/jars' ) do |path|
56
+ next if File.extname(path) != '.jar'
57
+ require path
58
+ end
59
+
60
+ require 'existdb/classwrap.rb'
61
+ require 'existdb/collection.rb'
62
+
63
+ require 'existdb/resource/base.rb'
64
+ require 'existdb/resource/xml.rb'
65
+ require 'existdb/resource/binary.rb'
66
+ require 'existdb/resource_set.rb'
67
+
68
+ require 'existdb/xquery_service.rb'
69
+ require 'existdb/meta.rb'
70
+ require 'existdb/embedded.rb'
71
+ require 'existdb/xql_factory.rb'
72
+ require 'existdb/index_factory.rb'
73
+ require 'existdb/dom/mapper.rb'
74
+ require 'existdb/dom/active_record.rb'
@@ -0,0 +1,70 @@
1
+ module ExistDB
2
+
3
+ class ClassUnwrap
4
+ class << self
5
+ def [](obj)
6
+ if obj.is_a?(Array) then
7
+ return obj.map{ |o| ClassUnwrap[o] }
8
+ else
9
+ obj.instance_variable_get(:@obj) || obj
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ class ClassWrap
16
+ class << self
17
+ def [](java_obj)
18
+ return nil if java_obj.nil?
19
+ if java_obj.is_a?(Fixnum) or java_obj.is_a?(String) then
20
+ return java_obj
21
+ end
22
+ klass = map[java_obj.class]
23
+ if klass then
24
+ if klass.is_a?(Proc) then
25
+ return klass.call(java_obj)
26
+ else
27
+ return klass.new(java_obj)
28
+ end
29
+ else
30
+ raise "I don't know how to wrap [#{java_obj.class}]"
31
+ end
32
+ end
33
+
34
+ def map
35
+ {
36
+ Java::OrgExistXmldb::LocalCollection => Collection,
37
+ Java::OrgExistXmldb::LocalXPathQueryService => XQueryService,
38
+ Java::OrgExistXmldb::LocalResourceSet => ResourceSet,
39
+ Java::OrgExistXmldb::LocalXMLResource => Resource::Xml,
40
+ Java::OrgExistXmldb::LocalBinaryResource => Resource::Binary,
41
+ Java::OrgExistXmldb::FullXmldbURI => Proc.new { |obj| obj.toString },
42
+ Java::JavaUtil::Date => Proc.new { |obj| Time.parse( obj.to_s ) },
43
+ Java::OrgExistXquery::PathExpr => Proc.new { |obj| obj }
44
+ }
45
+ end
46
+ end
47
+ end
48
+
49
+ module ClassWrappingForwardable
50
+ def delegate_to_java(*opts)
51
+ opts.each do |opt|
52
+ if opt.is_a?(Hash) then
53
+ opt.each do |to, from|
54
+ module_eval "
55
+ def #{to}(*opts)
56
+ ClassWrap[ @obj.#{from}( *ClassUnwrap[ opts ] ) ]
57
+ end
58
+ "
59
+ end
60
+ else
61
+ module_eval "
62
+ def #{opt}(*opts)
63
+ ClassWrap[ @obj.#{opt}( *ClassUnwrap[ opts ] ) ]
64
+ end
65
+ "
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,98 @@
1
+ module ExistDB
2
+ class Collection
3
+
4
+ extend ClassWrappingForwardable
5
+ delegate_to_java :name, :path, :uri, :parent => :getParentCollection, :to_s => :name
6
+
7
+ def initialize(java_obj)
8
+ @obj = java_obj
9
+ end
10
+
11
+ def collections
12
+ child_collection_names.map{|name|
13
+ collection(name)
14
+ }
15
+ end
16
+
17
+ def collection(name)
18
+ Collection.new( @obj.getChildCollection(name) ) if child_collection_names.include?(name)
19
+ end
20
+
21
+ def resources
22
+ resource_names.map{ |name|
23
+ resource(name)
24
+ }
25
+ end
26
+
27
+ def resource(name)
28
+ Resource.new( @obj.getResource(name) ) if resource_names.include?(name)
29
+ end
30
+
31
+ # Supports relative paths including slashes
32
+ # e.g. 'foo/bar/baz'
33
+ # Wish I could figure out how to do absolute paths from here...
34
+ def [](path)
35
+ (myconcern, remainder) = path.split('/', 2)
36
+ if myconcern.nil? or myconcern == '' then
37
+ return nil
38
+ elsif myconcern == '..' then
39
+ target = parent
40
+ else
41
+ target = collection(myconcern) || resource(myconcern)
42
+ end
43
+
44
+ if target.nil? then
45
+ return nil
46
+ elsif remainder then
47
+ return target[remainder]
48
+ else
49
+ return target
50
+ end
51
+ end
52
+
53
+ def delete(resource = nil)
54
+ if resource.nil? then
55
+ collection_manager.removeCollection(@obj.uri)
56
+ else
57
+ @obj.removeResource( ClassUnwrap[ resource ] )
58
+ end
59
+ true
60
+ end
61
+
62
+ def xquery
63
+ ClassWrap[ @obj.getService('XQueryService', '1.0') ]
64
+ end
65
+
66
+ def create_collection(path)
67
+ if path =~ /^\// then
68
+ ClassWrap[ collection_manager.createCollection( path ) ]
69
+ else
70
+ ClassWrap[ collection_manager.createCollection( self.path + '/' + path ) ]
71
+ end
72
+ end
73
+
74
+ def store_url(url, name)
75
+ url = url.to_s.gsub(/&(?!amp;)/, '&amp;')
76
+ xquery.query("xmldb:store( '#{self.uri}', '#{name}', doc(#{url.inspect}) )")
77
+ end
78
+
79
+ def inspect
80
+ "#<#{self.class}:0x#{self.hash.to_s(16)} name=#{self.name.inspect}>"
81
+ end
82
+
83
+ def child_collection_names
84
+ @obj.getChildCollections.collect
85
+ end
86
+
87
+ def resource_names
88
+ @obj.getResources.collect
89
+ end
90
+
91
+ private
92
+
93
+ def collection_manager
94
+ @obj.getService('CollectionManager','1.0')
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,82 @@
1
+ module ExistDB
2
+ module Dom
3
+
4
+ # Inspired by Rails ActiveRecord
5
+ # Because we cannot make assumptions about the structure of XML this must inspect the dom when descending into each node.
6
+ # For large well structured documents a mapper pattern where the structure is defined in the class would be more efficient.
7
+
8
+ class ActiveRecord
9
+
10
+ module NodeArray
11
+ def [](*opts)
12
+ raw = super
13
+ if raw.is_a?(Array) then
14
+ return raw.map{|obj| convert(obj) }
15
+ else
16
+ return convert(raw)
17
+ end
18
+ end
19
+
20
+ def each
21
+ super do |obj|
22
+ yield convert(obj)
23
+ end
24
+ end
25
+ end
26
+
27
+ module Convertible
28
+ private
29
+
30
+ def convert(obj)
31
+ @cache ||= Hash.new
32
+ if @cache[obj] then
33
+ return @cache[obj]
34
+ else
35
+ if obj.getFirstChild.getNodeName == '' then
36
+ @cache[obj] = obj.getNodeValue
37
+ else
38
+ @cache[obj] = ActiveRecord.new(obj)
39
+ end
40
+ return @cache[obj]
41
+ end
42
+ end
43
+ end
44
+
45
+
46
+ include org.w3c.dom.Node
47
+ include Convertible
48
+
49
+ def initialize(resource)
50
+ @dom = resource.respond_to?(:dom) ? resource.dom : resource
51
+ @children = Hash.new
52
+ @raw = Hash.new
53
+ @dom.getChildNodes.each do |child|
54
+ name = child.getNodeName.to_s.to_sym
55
+ next if respond_to?(name)
56
+ @raw[name] ||= Array.new
57
+ @raw[name] << child
58
+ end
59
+
60
+ @raw.each_key do |name|
61
+ if @raw[name].size > 1 then
62
+ @raw[name].extend(NodeArray, Convertible)
63
+ self.instance_eval %{
64
+ def #{name}
65
+ @raw[#{name.inspect}]
66
+ end
67
+ }
68
+ else
69
+ @raw[name] = @raw[name].first
70
+ self.instance_eval %{
71
+ def #{name}
72
+ convert( @raw[#{name.inspect}] )
73
+ end
74
+ }
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,285 @@
1
+
2
+ module ExistDB
3
+ module Dom
4
+
5
+ # Inspired by HappyMapper
6
+
7
+ module Mapper
8
+ def self.included(base)
9
+ base.instance_variable_set("@attributes", Hash.new)
10
+ base.instance_variable_set("@elements", Hash.new)
11
+ base.extend ClassMethods
12
+ end
13
+
14
+ def initialize(resource)
15
+ @dom = resource.respond_to?(:dom) ? resource.dom : resource
16
+ @cache = Hash.new
17
+ end
18
+
19
+ private
20
+
21
+ def get_element(tag_name)
22
+ @cache[tag_name] ||= self.class.get_element(tag_name, @dom)
23
+ end
24
+
25
+ def get_elements(tag_name, klass)
26
+ @cache[tag_name] ||= self.class.get_elements(tag_name, klass, @dom)
27
+ end
28
+
29
+ def get_attribute(tag_name)
30
+ @cache[tag_name] ||= self.class.get_attribute(tag_name, @dom)
31
+ end
32
+
33
+ def set_element(tag_name, value)
34
+ @cache.delete(tag_name)
35
+ self.class.set_element(@dom, tag_name, value)
36
+ end
37
+
38
+ def set_attribute(tag_name, value)
39
+ @cache.delete(tag_name)
40
+ self.class.set_attribute(@dom, tag_name, value)
41
+ end
42
+
43
+ module ClassMethods
44
+
45
+ def attribute(name, type = String, options = {})
46
+ a = Attribute.new(name, type, options)
47
+ @attributes ||= Hash.new
48
+ @attributes[a.tag] = a
49
+ self.class_eval %{
50
+ def #{a.method_name}
51
+ get_attribute(#{a.tag.inspect})
52
+ end
53
+
54
+ def #{a.method_name}=(value)
55
+ set_attribute(#{a.tag.inspect}, value)
56
+ end
57
+ }
58
+ end
59
+
60
+ def attributes
61
+ @attributes.values
62
+ end
63
+
64
+ def element(name, type = String, options = {}, &block)
65
+ e = Element.new(name, type, options)
66
+ @elements ||= Hash.new
67
+ @elements[e.tag] = e
68
+
69
+ if (type.respond_to?(:is_dom_mapper?) and type.is_dom_mapper?) or block_given? then # Nested elements
70
+ if block_given? then # Anonymous Mapper Class
71
+ klass = self.class_eval %{
72
+ @@#{e.method_name}_klass = Class.new do
73
+ include ExistDB::Dom::Mapper
74
+ end
75
+ }
76
+ klass.instance_eval &block
77
+ else
78
+ self.class_eval %{
79
+ @@#{e.method_name}_klass = #{type}
80
+ }
81
+ end
82
+ self.class_eval %{
83
+ def #{e.method_name}
84
+ get_elements(#{e.tag.inspect}, @@#{e.method_name}_klass)
85
+ end
86
+ }
87
+ else # No nested elements
88
+ self.class_eval %{
89
+ def #{e.method_name}
90
+ get_element(#{e.tag.inspect})
91
+ end
92
+
93
+ def #{e.method_name}=(value)
94
+ set_element(#{e.tag.inspect}, value)
95
+ end
96
+ }
97
+ end
98
+ end
99
+
100
+ def elements
101
+ @elements.values
102
+ end
103
+
104
+ def get_element(tag_name, dom)
105
+ e = @elements[tag_name]
106
+ child = getFirstChildByTagName(dom, tag_name)
107
+ return e.type_cast( child.getNodeValue ) if child.respond_to?(:getNodeValue)
108
+ return nil
109
+ end
110
+
111
+ def get_elements(tag_name, klass, dom)
112
+ children = dom.getElementsByTagName(tag_name)
113
+ size = children.getLength
114
+ if size == 1 then
115
+ klass.new(children.item(0))
116
+ elsif size > 1 then
117
+ 0..size.map{ |i| klass.new(children.item(i)) }
118
+ end
119
+ end
120
+
121
+ def get_attribute(tag_name, dom)
122
+ a = @attributes[tag_name]
123
+ value = dom.getAttributes.getNamedItem(tag_name).getValue rescue nil
124
+ a.type_cast( value )
125
+ end
126
+
127
+ def set_element(dom, tag_name, value)
128
+ parent = dom
129
+ node = getFirstChildByTagName(dom, tag_name)
130
+
131
+ if node.nil? then
132
+ doc = parent.getOwnerDocument
133
+ node = doc.createElement( tag_name.to_s )
134
+ parent.appendChild(node)
135
+ end
136
+
137
+ child = node.getChildNodes.select{ |child|
138
+ child.getNodeType == org.w3c.dom.Node.TEXT_NODE }.first
139
+ text = org.exist.dom.TextImpl.new( value.to_s.to_java_string )
140
+ if child then
141
+ ExistDB::Embedded.instance.transaction do |transaction|
142
+ text.setOwnerDocument( node.getOwnerDocument )
143
+ node.updateChild(transaction, child, text)
144
+ end
145
+ else
146
+ node.appendChild(text)
147
+ end
148
+ return value
149
+ end
150
+
151
+ def set_attribute(dom, tag_name, value)
152
+ attr = dom.getAttributes.getNamedItem(tag_name)
153
+ new_attr = org.exist.dom.AttrImpl.new(
154
+ org.exist.dom.QName.new( tag_name.to_s.to_java_string ),
155
+ value.to_s.to_java_string )
156
+ ExistDB::Embedded.instance.transaction do |transaction|
157
+ if attr then
158
+ new_attr.setOwnerDocument( dom.getOwnerDocument )
159
+ dom.updateChild(transaction, attr, new_attr)
160
+ else
161
+ dom.appendChild(new_attr)
162
+ end
163
+ end
164
+ return value
165
+ end
166
+
167
+ def tag(new_tag_name)
168
+ @tag_name = new_tag_name.to_s unless new_tag_name.nil? || new_tag_name.to_s.empty?
169
+ end
170
+
171
+ def tag_name
172
+ @tag_name ||= to_s.split('::').last.downcase
173
+ end
174
+
175
+ def parse(resource, options = {})
176
+
177
+ if options[:single] then
178
+ return new(resource)
179
+ else
180
+ xpath = options[:xpath]
181
+ xpath ||= "//#{options[:tag]}" if options[:tag]
182
+ xpath ||= "//#{options[:name]}" if options[:name]
183
+ xpath ||= "//#{tag_name}"
184
+
185
+ resource_set = resource.xquery(xpath)
186
+ return resource_set.map{ |res| new(res) }
187
+ end
188
+
189
+ end
190
+
191
+ def find(*options)
192
+ xql = XQLFactory::XQLFactory.new(*options)
193
+
194
+ if xql.node_xpath.nil? then
195
+ xql.node_xpath = "//#{tag_name}"
196
+ end
197
+
198
+ if xql.doc.is_a?(Resource::Xml) then
199
+ xql.doc.xquery(xql.xquery).map{ |res| new(res) }
200
+ elsif xql.doc.is_a?(ResourceSet) then
201
+ xql.doc.join.xquery(xql.xquery).map{ |res| new(res) }
202
+ elsif xql.doc.is_a?(String) and Embedded.instance.running?
203
+ Embedded.instance.xquery_service.query(xql.xquery).map{ |res| new(res) }
204
+ else
205
+ nil
206
+ end
207
+ end
208
+
209
+ def find_by_xquery(resource, query)
210
+ nodes = resource.xquery(query)
211
+ nodes.map{ |node| new(node) }
212
+ end
213
+
214
+ def is_dom_mapper?
215
+ true
216
+ end
217
+
218
+ private
219
+
220
+ def getFirstChildByTagName(dom, tag_name)
221
+ dom.getChildNodes.each do |child|
222
+ next if not child.respond_to?(:getTagName) or child.getTagName != tag_name
223
+ return child
224
+ break
225
+ end
226
+ return nil
227
+ end
228
+
229
+ end
230
+
231
+ class Boolean; end
232
+
233
+ class Item
234
+ attr_accessor :name, :type, :tag, :options, :method_name
235
+ def initialize(name, type, o={})
236
+ self.name = name.to_s
237
+ self.method_name = self.name.tr('-','_')
238
+ self.type = type
239
+ self.tag = o[:tag] || name.to_s
240
+ self.options = { :single => true }.merge(o.merge(:name => self.name))
241
+
242
+ @xml_type = self.class.to_s.split('::').last.downcase
243
+ end
244
+
245
+ def type_cast(value, type = self.type)
246
+ begin
247
+ if type == String then value.to_s
248
+ elsif type == Float then value.to_f
249
+ elsif type == Time then
250
+ Time.parse(value.to_s) rescue Time.at(value.to_i)
251
+ elsif type == Date then Date.parse(value.to_s)
252
+ elsif type == DateTime then DateTime.parse(value.to_s)
253
+ elsif type == Boolean then
254
+ ['true','t','1','y','yes'].include?(value.to_s.downcase)
255
+ elsif type == Integer then
256
+ # ganked from datamapper, and happymapper
257
+ value_to_i = value.to_i
258
+ if value_to_i == 0 && value != '0'
259
+ value_to_s = value.to_s
260
+ begin
261
+ Integer(value_to_s =~ /^(\d+)/ ? $1 : value_to_s)
262
+ rescue ArgumentError
263
+ nil
264
+ end
265
+ else
266
+ value_to_i
267
+ end
268
+ else
269
+ value
270
+ end
271
+ rescue
272
+ value
273
+ end
274
+ end
275
+
276
+ end
277
+
278
+ class Element < Item; end
279
+
280
+ class Attribute < Item; end
281
+
282
+ end
283
+
284
+ end
285
+ end