activerdf_sesame 0.1
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/LICENSE +0 -0
- data/README +0 -0
- data/Rakefile +55 -0
- data/ext/openrdf-sesame-2.0-alpha4-onejar.jar +0 -0
- data/ext/wrapper-sesame2.jar +0 -0
- data/lib/activerdf_sesame/init.rb +11 -0
- data/lib/activerdf_sesame/sesame.rb +312 -0
- data/test/activerdf.log +355 -0
- data/test/eyal-foaf.nt +39 -0
- data/test/eyal-foaf.rdf +65 -0
- data/test/finalize-test.rb +37 -0
- data/test/pathname.rb +3 -0
- data/test/sesame-init-test.rb +31 -0
- data/test/sesame-persistence.s2 +0 -0
- data/test/test_URLClassLoader.rb +60 -0
- data/test/test_sesame_adapter.rb +322 -0
- metadata +73 -0
data/LICENSE
ADDED
File without changes
|
data/README
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require '../tools/rakehelp'
|
7
|
+
require 'fileutils'
|
8
|
+
include FileUtils
|
9
|
+
|
10
|
+
setup_tests
|
11
|
+
setup_rdoc ['README', 'LICENSE', 'lib/**/*.rb', 'doc/**/*.rdoc']
|
12
|
+
|
13
|
+
desc "test and package gem"
|
14
|
+
task :default => [:test, :package]
|
15
|
+
|
16
|
+
# get @VERSION from commandline
|
17
|
+
@VERSION = '0.1'
|
18
|
+
NAME="activerdf_sesame"
|
19
|
+
GEMNAME="#{NAME}-#{@VERSION}.gem"
|
20
|
+
|
21
|
+
# which files should go into the gem?
|
22
|
+
PKG_FILES = FileList[
|
23
|
+
'ext/*.jar',
|
24
|
+
'[A-Z]*',
|
25
|
+
'lib/**/*.rb',
|
26
|
+
'test/**/*',
|
27
|
+
]
|
28
|
+
|
29
|
+
# define package task
|
30
|
+
setup_gem(NAME,@VERSION) do |spec|
|
31
|
+
spec.summary = "an RDF database for usage in ActiveRDF (based on sesame2)"
|
32
|
+
spec.description = spec.summary
|
33
|
+
spec.author="Benjamin Heitmann <benjamin.heitmann@deri.org>"
|
34
|
+
spec.add_dependency('gem_plugin', '>= 0.2.1')
|
35
|
+
spec.add_dependency('activerdf', '>= 1.2')
|
36
|
+
spec.files = PKG_FILES.to_a
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
task :install => [:package] do
|
43
|
+
sh %{sudo gem install pkg/#{NAME}-#{@VERSION}.gem}
|
44
|
+
end
|
45
|
+
|
46
|
+
task :uninstall => [:clean] do
|
47
|
+
sh %{sudo gem uninstall #{NAME}}
|
48
|
+
end
|
49
|
+
|
50
|
+
task :reinstall => [:uninstall, :install]
|
51
|
+
|
52
|
+
task :upload => :package do |task|
|
53
|
+
sh "scp pkg/#{GEMNAME} eyal@activerdf.org:/home/eyal/webs/activerdf/gems/"
|
54
|
+
end
|
55
|
+
|
Binary file
|
Binary file
|
@@ -0,0 +1,312 @@
|
|
1
|
+
# Author:: Eyal Oren
|
2
|
+
# Copyright:: (c) 2005-2006 Eyal Oren
|
3
|
+
# License:: LGPL
|
4
|
+
|
5
|
+
require 'active_rdf'
|
6
|
+
require 'federation/connection_pool'
|
7
|
+
|
8
|
+
$activerdflog.info "loading Sesame adapter"
|
9
|
+
|
10
|
+
|
11
|
+
# ----- java imports and extentsions
|
12
|
+
require 'java'
|
13
|
+
|
14
|
+
StringWriter = java.io.StringWriter
|
15
|
+
FileReader = java.io.FileReader
|
16
|
+
JFile = java.io.File
|
17
|
+
URLClassLoader = java.net.URLClassLoader
|
18
|
+
JURL = java.net.URL
|
19
|
+
JClass = java.lang.Class
|
20
|
+
JObject = java.lang.Object
|
21
|
+
|
22
|
+
# sesame specific classes:
|
23
|
+
WrapperForSesame2 = org.activerdf.wrapper.sesame2.WrapperForSesame2
|
24
|
+
QueryLanguage = org.openrdf.querymodel.QueryLanguage
|
25
|
+
NTriplesWriter = org.openrdf.rio.ntriples.NTriplesWriter
|
26
|
+
RDFFormat = org.openrdf.rio.RDFFormat
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
# TODO: about this adapter
|
31
|
+
class SesameAdapter < ActiveRdfAdapter
|
32
|
+
ConnectionPool.register_adapter(:sesame,self)
|
33
|
+
|
34
|
+
# instantiates Sesame database
|
35
|
+
# available parameters:
|
36
|
+
# * :location => path to a file for persistent storing or :memory for in-memory (defaults to in-memory)
|
37
|
+
# * :inferencing => true or false, if sesame2 rdfs inferencing is uses (defaults to true)
|
38
|
+
def initialize(params = {})
|
39
|
+
$activerdflog.info "initializing Sesame Adapter with params #{params.to_s}"
|
40
|
+
|
41
|
+
@reads = true
|
42
|
+
@writes = true
|
43
|
+
|
44
|
+
# if no directory path given, we use in-memory store
|
45
|
+
if params[:location]
|
46
|
+
if params[:location] == :memory
|
47
|
+
sesameLocation = nil
|
48
|
+
else
|
49
|
+
sesameLocation = JFile.new(params[:location])
|
50
|
+
end
|
51
|
+
else
|
52
|
+
sesameLocation = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# if no inferencing is specified, we use the sesame2 rdfs inferencing
|
56
|
+
sesameInferencing = params[:inferencing] || nil
|
57
|
+
|
58
|
+
# this will not work at the current state of jruby
|
59
|
+
# # fancy JRuby code so that the user does not have to set the java CLASSPATH
|
60
|
+
#
|
61
|
+
# this_dir = File.dirname(File.expand_path(__FILE__))
|
62
|
+
#
|
63
|
+
# jar1 = JFile.new(this_dir + "/../../ext/wrapper-sesame2.jar")
|
64
|
+
# jar2 = JFile.new(this_dir + "/../../ext/openrdf-sesame-2.0-alpha4-onejar.jar")
|
65
|
+
#
|
66
|
+
# # make an array of URL, which contains the URLs corresponding to the files
|
67
|
+
# uris = JURL[].new(2)
|
68
|
+
# uris[0] = jar1.toURL
|
69
|
+
# uris[1] = jar2.toURL
|
70
|
+
#
|
71
|
+
# # this is our custom class loader, yay!
|
72
|
+
# @activerdfClassLoader = URLClassLoader.new(uris)
|
73
|
+
# classWrapper = JClass.forName("org.activerdf.wrapper.sesame2.WrapperForSesame2", true, @activerdfClassLoader)
|
74
|
+
# @myWrapperInstance = classWrapper.new_instance
|
75
|
+
|
76
|
+
@myWrapperInstance = WrapperForSesame2.new
|
77
|
+
|
78
|
+
if sesameLocation == nil
|
79
|
+
if sesameInferencing == nil
|
80
|
+
@db = @myWrapperInstance.callConstructor
|
81
|
+
else
|
82
|
+
@db = @myWrapperInstance.callConstructor(sesameInferencing)
|
83
|
+
end
|
84
|
+
else
|
85
|
+
if sesameInferencing == nil
|
86
|
+
@db = @myWrapperInstance.callConstructor(sesameLocation)
|
87
|
+
else
|
88
|
+
@db = @myWrapperInstance.callConstructor(sesameLocation,sesameInferencing)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
@valueFactory = @db.getRepository.getSail.getValueFactory
|
93
|
+
|
94
|
+
# define the finalizer, which will call close on the sesame triple store
|
95
|
+
# recipie for this, is from: http://wiki.rubygarden.org/Ruby/page/show/GCAndMemoryManagement
|
96
|
+
ObjectSpace.define_finalizer(self, SesameAdapter.create_finalizer(@db))
|
97
|
+
end
|
98
|
+
|
99
|
+
# TODO: this does not work, but it is also not caused by jruby.
|
100
|
+
def SesameAdapter.create_finalizer(db)
|
101
|
+
# we have to call close on the sesame triple store, because otherwise some of the iterators are not closed properly
|
102
|
+
proc { puts "die"; db.close }
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
# returns the number of triples in the datastore (incl. possible duplicates)
|
108
|
+
def size
|
109
|
+
@db.size
|
110
|
+
end
|
111
|
+
|
112
|
+
# deletes all triples from datastore
|
113
|
+
def clear
|
114
|
+
@db.clear
|
115
|
+
end
|
116
|
+
|
117
|
+
# deletes triple(s,p,o,c) from datastore
|
118
|
+
# symbol parameters match anything: delete(:s,:p,:o) will delete all triples
|
119
|
+
# you can specify a context to limit deletion to that context:
|
120
|
+
# delete(:s,:p,:o, 'http://context') will delete all triples with that context
|
121
|
+
def delete(s, p, o, c=nil)
|
122
|
+
if s.class == RDFS::Resource then
|
123
|
+
sesameSubject = @valueFactory.createURI(s.uri)
|
124
|
+
elsif s == :s
|
125
|
+
sesameSubject = nil
|
126
|
+
else
|
127
|
+
raise ActiveRdfError, "the Sesame Adapter tried to delete a subject which was not of type RDFS::Resource, but of type #{s.class}"
|
128
|
+
end
|
129
|
+
if p.class == RDFS::Resource then
|
130
|
+
sesamePredicate = @valueFactory.createURI(p.uri)
|
131
|
+
elsif p == :p
|
132
|
+
sesamePredicate = nil
|
133
|
+
else
|
134
|
+
raise ActiveRdfError, "the Sesame Adapter tried to delete a predicate which was not of type RDFS::Resource, but of type #{p.class}"
|
135
|
+
end
|
136
|
+
if o.class == RDFS::Resource then
|
137
|
+
sesameObject = @valueFactory.createURI(o.uri)
|
138
|
+
elsif o == :o
|
139
|
+
sesameObject = nil
|
140
|
+
else
|
141
|
+
sesameObject = @valueFactory.createLiteral(o.to_s)
|
142
|
+
end
|
143
|
+
|
144
|
+
# TODO contexts
|
145
|
+
candidateStatements = @db.getStatements(sesameSubject, sesamePredicate, sesameObject, false)
|
146
|
+
|
147
|
+
@db.remove(candidateStatements)
|
148
|
+
|
149
|
+
candidateStatements.close
|
150
|
+
return @db
|
151
|
+
end
|
152
|
+
|
153
|
+
# adds triple(s,p,o) to datastore
|
154
|
+
# s,p must be resources, o can be primitive data or resource
|
155
|
+
def add(s,p,o,c=nil)
|
156
|
+
|
157
|
+
if s.class == RDFS::Resource then
|
158
|
+
sesameSubject = @valueFactory.createURI(s.uri)
|
159
|
+
else
|
160
|
+
raise ActiveRdfError, "the Sesame Adapter tried to add a subject which was not of type RDFS::Resource, but of type #{s.class}"
|
161
|
+
end
|
162
|
+
if p.class == RDFS::Resource then
|
163
|
+
sesamePredicate = @valueFactory.createURI(p.uri)
|
164
|
+
else
|
165
|
+
raise ActiveRdfError, "the Sesame Adapter tried to add a predicate which was not of type RDFS::Resource, but of type #{p.class}"
|
166
|
+
end
|
167
|
+
if o.class == RDFS::Resource then
|
168
|
+
sesameObject = @valueFactory.createURI(o.uri)
|
169
|
+
else
|
170
|
+
sesameObject = @valueFactory.createLiteral(o.to_s)
|
171
|
+
end
|
172
|
+
|
173
|
+
# TODO: handle context, especially if it is null
|
174
|
+
|
175
|
+
@db.add(sesameSubject, sesamePredicate, sesameObject)
|
176
|
+
# for contexts, just add 4th parameter
|
177
|
+
|
178
|
+
# TODO: do we need to handle errors from the java side ?
|
179
|
+
|
180
|
+
return @db
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
# flushing is done automatically, because we run sesame2 in autocommit mode
|
186
|
+
def flush
|
187
|
+
true
|
188
|
+
end
|
189
|
+
# saving is done automatically, because we run sesame2 in autocommit mode
|
190
|
+
def save
|
191
|
+
true
|
192
|
+
end
|
193
|
+
|
194
|
+
# close the underlying sesame triple store.
|
195
|
+
# if not called there may be open iterators.
|
196
|
+
def close
|
197
|
+
@db.close
|
198
|
+
end
|
199
|
+
|
200
|
+
# returns all triples in the datastore
|
201
|
+
def dump
|
202
|
+
# the sesame connection has an export method, which writes all explicit statements to
|
203
|
+
# a to a RDFHandler, which we supply, by constructing a NTriplesWriter, which writes to StringWriter,
|
204
|
+
# and we kindly ask that StringWriter to make a string for us. Note, you have to use stringy.to_s,
|
205
|
+
# somehow stringy.toString does not work. yes yes, those wacky jruby guys ;)
|
206
|
+
stringy = StringWriter.new
|
207
|
+
sesameWriter = NTriplesWriter.new(stringy)
|
208
|
+
@db.export(sesameWriter)
|
209
|
+
return stringy.to_s
|
210
|
+
end
|
211
|
+
|
212
|
+
# loads triples from file in ntriples format
|
213
|
+
def load(file)
|
214
|
+
reader = FileReader.new(file)
|
215
|
+
@db.add(reader, "", RDFFormat::NTRIPLES)
|
216
|
+
|
217
|
+
return @db
|
218
|
+
end
|
219
|
+
|
220
|
+
# executes ActiveRDF query on the sesame triple store associated with this adapter
|
221
|
+
def query(query)
|
222
|
+
|
223
|
+
# we want to put the results in here
|
224
|
+
results = []
|
225
|
+
|
226
|
+
# translate the query object into a SPARQL query string
|
227
|
+
qs = Query2SPARQL.translate(query)
|
228
|
+
|
229
|
+
# evaluate the query on the sesame triple store
|
230
|
+
# TODO: if we want to get inferred statements back we have to say so, as third boolean parameter
|
231
|
+
tuplequeryresult = @db.evaluateTupleQuery(QueryLanguage::SPARQL, qs)
|
232
|
+
|
233
|
+
# what are the variables of the query ?
|
234
|
+
variables = tuplequeryresult.getBindingNames
|
235
|
+
sizeOfVariables = variables.size
|
236
|
+
|
237
|
+
# a solution is a binding of a variable to all entities that matched this variable in the sparql query
|
238
|
+
solutionIterator = tuplequeryresult.iterator
|
239
|
+
|
240
|
+
# the following is plainly ugly. the reason is that JRuby currently does not support
|
241
|
+
# using iterators in the ruby way: with "each". it is possible to define "each" for java.util.Iterator
|
242
|
+
# using JavaUtilities.extend_proxy but that fails in strange ways. this is ugly but works.
|
243
|
+
|
244
|
+
# TODO: null handling, if a value is null...
|
245
|
+
|
246
|
+
# if there only was one variable, then the results array should look like this:
|
247
|
+
# results = [ [first Value For The Variable], [second Value], ...]
|
248
|
+
if sizeOfVariables == 1 then
|
249
|
+
# the counter keeps track of the number of values, so we can insert them into the results at the right position
|
250
|
+
counter = 0
|
251
|
+
while solutionIterator.hasNext
|
252
|
+
solution = solutionIterator.next
|
253
|
+
|
254
|
+
temparray = []
|
255
|
+
# get the value associated with a variable in this specific solution
|
256
|
+
temparray[0] = convertSesame2ActiveRDF(solution.getValue(variables[0]))
|
257
|
+
results[counter] = temparray
|
258
|
+
counter = counter + 1
|
259
|
+
end
|
260
|
+
else
|
261
|
+
# if there is more then one variable the results array looks like this:
|
262
|
+
# results = [ [Value From First Solution For First Variable, Value From First Solution For Second Variable, ...],
|
263
|
+
# [Value From Second Solution For First Variable, Value From Second Solution for Second Variable, ...], ...]
|
264
|
+
counter = 0
|
265
|
+
while solutionIterator.hasNext
|
266
|
+
solution = solutionIterator.next
|
267
|
+
|
268
|
+
temparray = []
|
269
|
+
for n in 1..sizeOfVariables
|
270
|
+
value = convertSesame2ActiveRDF(solution.getValue(variables[n-1]))
|
271
|
+
temparray[n-1] = value
|
272
|
+
end
|
273
|
+
results[counter] = temparray
|
274
|
+
counter = counter + 1
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
return results
|
279
|
+
end
|
280
|
+
|
281
|
+
private
|
282
|
+
|
283
|
+
# check if testee is a java subclass of reference
|
284
|
+
def jInstanceOf(testee, reference)
|
285
|
+
# for Java::JavaClass for a <=> b the comparison operator returns: -1 if a is subclass of b,
|
286
|
+
# 0 if a.jclass = b.jclass, +1 in any other case.
|
287
|
+
isSubclass = (testee <=> reference)
|
288
|
+
if isSubclass == -1 or isSubclass == 0
|
289
|
+
return true
|
290
|
+
else
|
291
|
+
return false
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# takes a part of a sesame statement, and converts it to a RDFS::Resource if it is a URI,
|
296
|
+
# or to a String if it is a Literal. The assumption currently, is that we will only get stuff out of sesame,
|
297
|
+
# which we put in there ourselves, and currently we only put URIs or Literals there.
|
298
|
+
# TODO: do we need to think about handling blank nodes ? e.g. if the are part of a graph read from a file ?
|
299
|
+
def convertSesame2ActiveRDF(input)
|
300
|
+
jclassURI = Java::JavaClass.for_name("org.openrdf.model.URI")
|
301
|
+
jclassLiteral = Java::JavaClass.for_name("org.openrdf.model.Literal")
|
302
|
+
|
303
|
+
if jInstanceOf(input.java_class, jclassURI)
|
304
|
+
return RDFS::Resource.new(input.toString)
|
305
|
+
elsif jInstanceOf(input.java_class, jclassLiteral)
|
306
|
+
return input.toString
|
307
|
+
else
|
308
|
+
raise ActiveRdfError, "the Sesame Adapter tried to return something which is neither a URI nor a Literal, but is instead a #{input.java_class.name}"
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|