iqvoc 4.0.3 → 4.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.
- data/CHANGELOG.md +5 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +13 -2
- data/app/controllers/concepts/versions_controller.rb +9 -2
- data/app/controllers/rdf_controller.rb +21 -0
- data/app/controllers/triplestore_sync_controller.rb +61 -0
- data/app/views/dashboard/_sidebar.html.erb +2 -0
- data/app/views/triplestore_sync/index.html.erb +24 -0
- data/config/application.rb +0 -22
- data/config/locales/de.yml +12 -3
- data/config/locales/en.yml +12 -3
- data/config/routes.rb +4 -3
- data/lib/iqvoc.rb +5 -0
- data/lib/iqvoc/configuration/sync.rb +28 -0
- data/lib/iqvoc/environments/development.rb +0 -20
- data/lib/iqvoc/environments/production.rb +0 -20
- data/lib/iqvoc/rdf_sync.rb +111 -0
- data/lib/iqvoc/version.rb +1 -1
- data/test/test_helper.rb +2 -0
- data/test/unit/rdf_sync_test.rb +123 -0
- metadata +30 -27
- data/app/controllers/triple_store_syncs_controller.rb +0 -45
- data/app/models/rdf_store.rb +0 -96
- data/app/views/triple_store_syncs/new.html.erb +0 -7
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -30,7 +30,8 @@ end
|
|
30
30
|
gem 'kaminari'
|
31
31
|
gem 'authlogic'
|
32
32
|
gem 'cancan'
|
33
|
-
gem 'iq_rdf'
|
33
|
+
gem 'iq_rdf'
|
34
|
+
gem 'iq_triplestorage'
|
34
35
|
gem 'json'
|
35
36
|
gem 'rails_autolink'
|
36
37
|
gem 'jruby-openssl', :platforms => :jruby
|
@@ -67,6 +68,7 @@ group :test do
|
|
67
68
|
gem 'spork-testunit'
|
68
69
|
gem 'turn'
|
69
70
|
gem 'minitest'
|
71
|
+
gem 'webmock'
|
70
72
|
end
|
71
73
|
|
72
74
|
group :production do
|
data/Gemfile.lock
CHANGED
@@ -60,6 +60,7 @@ GEM
|
|
60
60
|
json
|
61
61
|
childprocess (0.3.5)
|
62
62
|
ffi (~> 1.0, >= 1.0.6)
|
63
|
+
crack (0.3.1)
|
63
64
|
database_cleaner (0.8.0)
|
64
65
|
erubis (2.7.0)
|
65
66
|
excon (0.16.2)
|
@@ -83,9 +84,11 @@ GEM
|
|
83
84
|
excon (~> 0.16.1)
|
84
85
|
hike (1.2.1)
|
85
86
|
i18n (0.6.1)
|
86
|
-
iq_rdf (0.1.
|
87
|
+
iq_rdf (0.1.8)
|
87
88
|
builder
|
88
89
|
bundler
|
90
|
+
iq_triplestorage (0.1.2)
|
91
|
+
typhoeus
|
89
92
|
jdbc-mysql (5.1.13)
|
90
93
|
jdbc-sqlite3 (3.7.2)
|
91
94
|
journey (1.0.4)
|
@@ -179,12 +182,18 @@ GEM
|
|
179
182
|
polyglot (>= 0.3.1)
|
180
183
|
turn (0.9.6)
|
181
184
|
ansi
|
185
|
+
typhoeus (0.4.2)
|
186
|
+
ffi (~> 1.0)
|
187
|
+
mime-types (~> 1.18)
|
182
188
|
tzinfo (0.3.33)
|
183
189
|
uglifier (1.3.0)
|
184
190
|
execjs (>= 0.3.0)
|
185
191
|
multi_json (~> 1.0, >= 1.0.2)
|
186
192
|
view_marker (1.0.0)
|
187
193
|
rails
|
194
|
+
webmock (1.8.11)
|
195
|
+
addressable (>= 2.2.7)
|
196
|
+
crack (>= 0.1.7)
|
188
197
|
xpath (0.1.4)
|
189
198
|
nokogiri (~> 1.3)
|
190
199
|
|
@@ -206,7 +215,8 @@ DEPENDENCIES
|
|
206
215
|
factory_girl_rails
|
207
216
|
fastercsv
|
208
217
|
heroku
|
209
|
-
iq_rdf
|
218
|
+
iq_rdf
|
219
|
+
iq_triplestorage
|
210
220
|
jruby-openssl
|
211
221
|
json
|
212
222
|
kaminari
|
@@ -225,3 +235,4 @@ DEPENDENCIES
|
|
225
235
|
turn
|
226
236
|
uglifier (>= 1.0.3)
|
227
237
|
view_marker
|
238
|
+
webmock
|
@@ -14,7 +14,10 @@
|
|
14
14
|
# See the License for the specific language governing permissions and
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
|
+
require 'iqvoc/rdf_sync'
|
18
|
+
|
17
19
|
class Concepts::VersionsController < ApplicationController
|
20
|
+
include Iqvoc::RDFSync::Helper
|
18
21
|
|
19
22
|
def merge
|
20
23
|
current_concept = Iqvoc::Concept.base_class.by_origin(params[:origin]).published.last
|
@@ -25,13 +28,17 @@ class Concepts::VersionsController < ApplicationController
|
|
25
28
|
|
26
29
|
ActiveRecord::Base.transaction do
|
27
30
|
if current_concept.blank? || current_concept.destroy
|
31
|
+
new_version.rdf_updated_at = nil
|
28
32
|
new_version.publish
|
29
33
|
new_version.unlock
|
30
34
|
if new_version.valid_with_full_validation?
|
31
35
|
new_version.save
|
32
|
-
|
33
|
-
|
36
|
+
|
37
|
+
if Iqvoc.config["triplestore.autosync"]
|
38
|
+
synced = triplestore_syncer.sync([new_version]) # XXX: blocking
|
39
|
+
flash[:warning] = "triplestore synchronization failed" unless synced # TODO: i18n
|
34
40
|
end
|
41
|
+
|
35
42
|
flash[:success] = t("txt.controllers.versioning.published")
|
36
43
|
redirect_to concept_path(:id => new_version)
|
37
44
|
else
|
@@ -27,4 +27,25 @@ class RdfController < ApplicationController
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def show
|
31
|
+
scope = if params[:published] == "0"
|
32
|
+
Iqvoc::Concept.base_class.unpublished
|
33
|
+
else
|
34
|
+
Iqvoc::Concept.base_class.published
|
35
|
+
end
|
36
|
+
if @concept = scope.by_origin(params[:id]).with_associations.last
|
37
|
+
respond_to do |format|
|
38
|
+
format.html do
|
39
|
+
redirect_to concept_url(:id => @concept.origin, :published => params[:published])
|
40
|
+
end
|
41
|
+
format.any do
|
42
|
+
authorize! :read, @concept
|
43
|
+
render "concepts/show"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
else
|
47
|
+
raise ActiveRecord::RecordNotFound.new("Concept '#{params[:id]}' not found.")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
30
51
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Copyright 2011 innoQ Deutschland GmbH
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'iqvoc/rdf_sync'
|
18
|
+
|
19
|
+
class TriplestoreSyncController < ApplicationController
|
20
|
+
include Iqvoc::RDFSync::Helper
|
21
|
+
|
22
|
+
def index
|
23
|
+
authorize! :use, :dashboard
|
24
|
+
|
25
|
+
if Iqvoc.config["triplestore.url"] == Iqvoc.config.defaults["triplestore.url"]
|
26
|
+
flash.now[:warning] = I18n.t("txt.controllers.triplestore_sync.config_warning")
|
27
|
+
else
|
28
|
+
host = Iqvoc.config["triplestore.url"]
|
29
|
+
username = Iqvoc.config["triplestore.username"].presence
|
30
|
+
password = Iqvoc.config["triplestore.password"].presence
|
31
|
+
target_info = host
|
32
|
+
if username && password
|
33
|
+
target_info = "#{target_info} (as #{username} with password)" # XXX: i18n
|
34
|
+
elsif username
|
35
|
+
target_info = "#{target_info} (as #{username})" # XXX: i18n
|
36
|
+
end
|
37
|
+
flash.now[:info] = I18n.t("txt.controllers.triplestore_sync.config_info",
|
38
|
+
:target_info => target_info)
|
39
|
+
end
|
40
|
+
|
41
|
+
# per-class pagination
|
42
|
+
@candidates = Iqvoc::RDFSync.candidates.map do |records|
|
43
|
+
records.page(params[:page])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def sync
|
48
|
+
authorize! :use, :dashboard
|
49
|
+
|
50
|
+
success = triplestore_syncer.all # XXX: long-running
|
51
|
+
|
52
|
+
if success
|
53
|
+
flash[:success] = I18n.t("txt.controllers.triplestore_sync.success")
|
54
|
+
else
|
55
|
+
flash[:error] = I18n.t("txt.controllers.triplestore_sync.error")
|
56
|
+
end
|
57
|
+
|
58
|
+
redirect_to :action => "index"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -11,4 +11,6 @@
|
|
11
11
|
<%= sidebar_header 'Extras' %>
|
12
12
|
<%= sidebar_item(:icon => :upload, :text => t('txt.views.dashboard.import'),
|
13
13
|
:path => import_url, :active => params[:controller] == 'import', :perms => [:import, Concept::Base]) %>
|
14
|
+
<%= sidebar_item(:icon => :repeat, :text => t('txt.views.triplestore_sync.caption'),
|
15
|
+
:path => triplestore_sync_path, :active => params[:controller] == "triplestore_sync") %>
|
14
16
|
<% end %>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<%= page_header :title => t("txt.views.triplestore_sync.caption") %>
|
2
|
+
<%= render "dashboard/sidebar" %>
|
3
|
+
|
4
|
+
<%= form_tag triplestore_sync_path(:format => nil, :lang => nil), :method => :post do %>
|
5
|
+
<%= submit_tag t("txt.views.triplestore_sync.start"), :class => "btn btn-primary" %>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<% @candidates.each do |records| %>
|
9
|
+
<% klass = records.table.engine %>
|
10
|
+
<h3><%= klass.model_name.human(:count => 2) %></h3>
|
11
|
+
<ul>
|
12
|
+
<% records.each do |record| %>
|
13
|
+
<% # XXX: does not belong here -- also heavily over-engineered
|
14
|
+
doc = IqRdf::Document.new(root_url(:lang => nil))
|
15
|
+
Iqvoc.default_rdf_namespace_helper_methods.each do |meth|
|
16
|
+
doc.namespaces(self.send(meth))
|
17
|
+
end
|
18
|
+
uri = record.build_rdf_subject(doc, controller).full_uri # XXX: we actually just want path, plus HTML format
|
19
|
+
%>
|
20
|
+
<li><%= link_to record.to_s, uri %></li>
|
21
|
+
<% end %>
|
22
|
+
</ul>
|
23
|
+
<%= paginate records %>
|
24
|
+
<% end %>
|
data/config/application.rb
CHANGED
@@ -68,27 +68,5 @@ module Iqvoc
|
|
68
68
|
|
69
69
|
# Version of your assets, change this if you want to expire all your assets
|
70
70
|
config.assets.version = '1.0'
|
71
|
-
|
72
|
-
# TODO This must be refactored!
|
73
|
-
|
74
|
-
# The JDBC driver url for the coinnection to the virtuoso triple store.
|
75
|
-
# Login crdentials have to be stored here too. See
|
76
|
-
# http://docs.openlinksw.com/virtuoso/VirtuosoDriverJDBC.html#jdbcurl4mat for
|
77
|
-
# more details.
|
78
|
-
# Example: "jdbc:virtuoso://localhost:1111/UID=dba/PWD=dba"
|
79
|
-
# Use nil to disable virtuoso triple synchronization
|
80
|
-
config.virtuoso_jdbc_driver_url = nil
|
81
|
-
|
82
|
-
# Set up the virtuoso synchronization (which is a triggered pull from the
|
83
|
-
# virtuoso server) to be run in a new thread.
|
84
|
-
# This is needed in environments where the webserver only runs in a single
|
85
|
-
# process/thread (mostly in development environments).
|
86
|
-
# When a synchronizaion would be triggered e.g. from a running
|
87
|
-
# update action in the UPB, the update would trigger virtuoso to do a HTTP GET
|
88
|
-
# back to the UPB to fetch the RDF data. But the only process in the UPB would be
|
89
|
-
# blocked by the update... => Deadlock. You can avoid this by using the threaded
|
90
|
-
# mode.
|
91
|
-
config.virtuoso_sync_threaded = false
|
92
|
-
|
93
71
|
end
|
94
72
|
end
|
data/config/locales/de.yml
CHANGED
@@ -92,6 +92,10 @@ de:
|
|
92
92
|
available_languages: verfügbare Sprachen
|
93
93
|
languages_pref_labeling: Sprachen für bevorzugte Labels
|
94
94
|
languages_further_labelings_Labeling::SKOS::AltLabel: Sprachen für alternative Labels
|
95
|
+
triplestore_url: Triplestore-URL
|
96
|
+
triplestore_username: Benutzername für Triplestore
|
97
|
+
triplestore_password: Passwort für Triplestore
|
98
|
+
triplestore_autosync: automatische Synchronisation mit Triplestore
|
95
99
|
alphabetical_concepts:
|
96
100
|
untranslated_concepts:
|
97
101
|
caption: "Fehlende Übersetzungen"
|
@@ -242,6 +246,9 @@ de:
|
|
242
246
|
import: Import
|
243
247
|
collections:
|
244
248
|
new: "Neue Kollektion"
|
249
|
+
triplestore_sync:
|
250
|
+
caption: "Sync mit Triplestore"
|
251
|
+
start: "Synchronisierung starten"
|
245
252
|
|
246
253
|
partials:
|
247
254
|
note:
|
@@ -289,7 +296,6 @@ de:
|
|
289
296
|
consistency_check_error: "Instanz ist inkonsistent!"
|
290
297
|
to_review_success: "Wurde in den Freigabeprozess aufgenommen"
|
291
298
|
to_review_error: "Konnte nicht in den Freigabeprozess aufgenommen werden"
|
292
|
-
virtuoso_exception: "Das Objekt wurde veröffentlicht, konnte aber nicht mit Virtuoso synchronisiert werden. Fehler: "
|
293
299
|
labelings:
|
294
300
|
save:
|
295
301
|
success: "Das Labeling wurde erfolgreich gespeichert."
|
@@ -318,8 +324,6 @@ de:
|
|
318
324
|
label_error: "Ungültige Label-Zuordnungen:\n%s"
|
319
325
|
narrowers:
|
320
326
|
error: "Die Assoziation wurde nicht gefunden. Evtl. wurde diese von der anderen Seite bearbeitet. Bitte das Fenster neu laden!"
|
321
|
-
triple_store_syncs:
|
322
|
-
success: "Es wurden %{concept_count} freigegebene Concepts und %{label_count} freigegebene Labels synchronisiert."
|
323
327
|
collections:
|
324
328
|
save:
|
325
329
|
success: "Die Kollektion wurde erfolgreich gespeichert."
|
@@ -328,6 +332,11 @@ de:
|
|
328
332
|
success: "Die Kollektion wurde erfolgreich gelöscht."
|
329
333
|
error: "Die Kollektion konnte nicht gelöscht werden."
|
330
334
|
circular_error: "Ungültige Subkollektions-Zuordnungen aufgrund von Zirkelbezügen:\n%s"
|
335
|
+
triplestore_sync:
|
336
|
+
success: "Synchronisierung erfolgreich."
|
337
|
+
error: "Bei der Synchronisierung traten Fehler auf - einige Einträge wurden nicht synchronisiert."
|
338
|
+
config_info: "Synchronisierung mit Triplestore: %{target_info}"
|
339
|
+
config_warning: "Bisher wurde kein Triplestore konfiguriert."
|
331
340
|
|
332
341
|
models:
|
333
342
|
label:
|
data/config/locales/en.yml
CHANGED
@@ -92,6 +92,10 @@ en:
|
|
92
92
|
available_languages: available languages
|
93
93
|
languages_pref_labeling: languages for preferred labels
|
94
94
|
languages_further_labelings_Labeling::SKOS::AltLabel: languages for alternative labels
|
95
|
+
triplestore_url: triplestore URL
|
96
|
+
triplestore_username: username for triplestore
|
97
|
+
triplestore_password: password for triplestore
|
98
|
+
triplestore_autosync: automatic triplestore synchronization
|
95
99
|
alphabetical_concepts:
|
96
100
|
untranslated_concepts:
|
97
101
|
caption: "Missing Translations"
|
@@ -249,6 +253,9 @@ en:
|
|
249
253
|
import: Import
|
250
254
|
collections:
|
251
255
|
new: "New collection"
|
256
|
+
triplestore_sync:
|
257
|
+
caption: "Sync with Triplestore"
|
258
|
+
start: "Start synchronization"
|
252
259
|
|
253
260
|
partials:
|
254
261
|
note:
|
@@ -296,7 +303,6 @@ en:
|
|
296
303
|
consistency_check_success: "Instance is consistent."
|
297
304
|
consistency_check_success_with_warning: "Instance is consistent but has no relations."
|
298
305
|
consistency_check_error: "Instance is inconsistent."
|
299
|
-
virtuoso_exception: "The object has been published, but could not by synced with Virtuoso. Error: "
|
300
306
|
labelings:
|
301
307
|
save:
|
302
308
|
success: "The labeling has been saved."
|
@@ -325,8 +331,6 @@ en:
|
|
325
331
|
label_error: "Invalid label assignments:\n%s"
|
326
332
|
narrowers:
|
327
333
|
error: "Relation not found. Probably removed from the target side. Please refresh your browser window."
|
328
|
-
triple_store_syncs:
|
329
|
-
success: "%{concept_count} published concepts and %{label_count} published labels have been synced."
|
330
334
|
collections:
|
331
335
|
save:
|
332
336
|
success: "The collection has been successfully created."
|
@@ -335,6 +339,11 @@ en:
|
|
335
339
|
success: "The collection has been successfully deleted."
|
336
340
|
error: "The collection could not be deleted."
|
337
341
|
circular_error: "Invalid sub-collection assignments due to circular references:\n%s"
|
342
|
+
triplestore_sync:
|
343
|
+
success: "Synchronization successful."
|
344
|
+
error: "An error occurred during the synchronization process - some entities have not been synchronized."
|
345
|
+
config_info: "Synchronizing with triplestore: %{target_info}"
|
346
|
+
config_warning: "Triplestore has not been configured yet."
|
338
347
|
|
339
348
|
models:
|
340
349
|
label:
|
data/config/routes.rb
CHANGED
@@ -28,8 +28,6 @@ Rails.application.routes.draw do
|
|
28
28
|
resources :concepts
|
29
29
|
resources :collections
|
30
30
|
|
31
|
-
resources :triple_store_syncs, :only => [:new, :create]
|
32
|
-
|
33
31
|
match "/" => "frontpage#index"
|
34
32
|
|
35
33
|
match "concepts/:origin/branch(.:format)" => "concepts/versions#branch", :as => "concept_versions_branch"
|
@@ -58,8 +56,11 @@ Rails.application.routes.draw do
|
|
58
56
|
get "help" => "pages#help", :as => "help"
|
59
57
|
|
60
58
|
root :to => 'frontpage#index', :format => nil
|
59
|
+
|
60
|
+
get "triplestore_sync" => "triplestore_sync#index"
|
61
|
+
post "triplestore_sync" => "triplestore_sync#sync"
|
61
62
|
end
|
62
63
|
|
63
64
|
match '/scheme(.:format)' => 'rdf#scheme', :as => 'scheme'
|
64
|
-
match '/:id(.:format)' => '
|
65
|
+
match '/:id(.:format)' => 'rdf#show', :as => 'rdf'
|
65
66
|
end
|
data/lib/iqvoc.rb
CHANGED
@@ -20,6 +20,7 @@ require 'iqvoc/configuration/core'
|
|
20
20
|
require 'iqvoc/configuration/concept'
|
21
21
|
require 'iqvoc/configuration/collection'
|
22
22
|
require 'iqvoc/configuration/label'
|
23
|
+
require 'iqvoc/configuration/sync'
|
23
24
|
|
24
25
|
module Iqvoc
|
25
26
|
unless Iqvoc.const_defined?(:Application)
|
@@ -40,6 +41,10 @@ module Iqvoc
|
|
40
41
|
include Iqvoc::Configuration::Label
|
41
42
|
end
|
42
43
|
|
44
|
+
module Sync
|
45
|
+
include Iqvoc::Configuration::Sync
|
46
|
+
end
|
47
|
+
|
43
48
|
end
|
44
49
|
|
45
50
|
# FIXME: For reasons yet unknown, the load hook is executed twice
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Iqvoc
|
4
|
+
module Configuration
|
5
|
+
module Sync
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
mattr_accessor :syncable_class_names
|
10
|
+
self.syncable_class_names = [Iqvoc::Concept.base_class_name]
|
11
|
+
|
12
|
+
Iqvoc.config.register_settings({
|
13
|
+
"triplestore.url" => "http://example.org:8080",
|
14
|
+
"triplestore.username" => "",
|
15
|
+
"triplestore.password" => "",
|
16
|
+
"triplestore.autosync" => false
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def syncable_classes
|
22
|
+
self.syncable_class_names.map { |name| name.constantize }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -82,26 +82,6 @@ module Iqvoc::Environments
|
|
82
82
|
|
83
83
|
# The default URI prefix for RDF data. This will be followed by a document
|
84
84
|
# specific shnippet like (specimenType) and the id.
|
85
|
-
|
86
|
-
# The JDBC driver URL for the connection to the virtuoso triple store.
|
87
|
-
# Login credentials have to be stored here too. See
|
88
|
-
# http://docs.openlinksw.com/virtuoso/VirtuosoDriverJDBC.html#jdbcurl4mat for
|
89
|
-
# more details.
|
90
|
-
# Example: "jdbc:virtuoso://localhost:1111/UID=dba/PWD=dba"
|
91
|
-
# Use nil to disable virtuoso triple synchronization
|
92
|
-
# Rails.application.config.virtuoso_jdbc_driver_url = "jdbc:virtuoso://virtuoso.dyndns.org:1111/UID=iqvoc/PWD=vocpass!/charset=UTF-8"
|
93
|
-
config.virtuoso_jdbc_driver_url = nil
|
94
|
-
|
95
|
-
# Set up the virtuoso synchronization (which is a triggered pull from the
|
96
|
-
# virtuoso server) to be run in a new thread.
|
97
|
-
# This is needed in environments where the web server only runs in a single
|
98
|
-
# process/thread (mostly in development environments).
|
99
|
-
# When a synchronization would be triggered e.g. from a running
|
100
|
-
# update action in the UPB, the update would trigger virtuoso to do a HTTP GET
|
101
|
-
# back to the UPB to fetch the RDF data. But the only process in the UPB would be
|
102
|
-
# blocked by the update... => Deadlock. You can avoid this by using the threaded
|
103
|
-
# mode.
|
104
|
-
config.virtuoso_sync_threaded = false
|
105
85
|
end
|
106
86
|
|
107
87
|
end
|
@@ -67,26 +67,6 @@ module Iqvoc::Environments
|
|
67
67
|
# in your app. As such, your models will need to explicitly whitelist or blacklist accessible
|
68
68
|
# parameters by using an attr_accessible or attr_protected declaration.
|
69
69
|
config.active_record.whitelist_attributes = false
|
70
|
-
|
71
|
-
# The JDBC driver URL for the connection to the virtuoso triple store.
|
72
|
-
# Login credentials have to be stored here too. See
|
73
|
-
# http://docs.openlinksw.com/virtuoso/VirtuosoDriverJDBC.html#jdbcurl4mat for
|
74
|
-
# more details.
|
75
|
-
# Example: "jdbc:virtuoso://localhost:1111/UID=dba/PWD=dba"
|
76
|
-
# Use nil to disable virtuoso triple synchronization
|
77
|
-
# Rails.application.config.virtuoso_jdbc_driver_url = "jdbc:virtuoso://virtuoso.dyndns.org:1111/UID=iqvoc/PWD=vocpass!/charset=UTF-8"
|
78
|
-
config.virtuoso_jdbc_driver_url = nil
|
79
|
-
|
80
|
-
# Set up the virtuoso synchronization (which is a triggered pull from the
|
81
|
-
# virtuoso server) to be run in a new thread.
|
82
|
-
# This is needed in environments where the web server only runs in a single
|
83
|
-
# process/thread (mostly in development environments).
|
84
|
-
# When a synchronization would be triggered e.g. from a running
|
85
|
-
# update action in the UPB, the update would trigger virtuoso to do a HTTP GET
|
86
|
-
# back to the UPB to fetch the RDF data. But the only process in the UPB would be
|
87
|
-
# blocked by the update... => Deadlock. You can avoid this by using the threaded
|
88
|
-
# mode.
|
89
|
-
config.virtuoso_sync_threaded = false
|
90
70
|
end
|
91
71
|
|
92
72
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'iq_triplestorage/virtuoso_adaptor'
|
4
|
+
|
5
|
+
class Iqvoc::RDFSync
|
6
|
+
delegate :url_helpers, :to => "Rails.application.routes"
|
7
|
+
|
8
|
+
def initialize(base_url, target_host, *args)
|
9
|
+
@base_url = base_url
|
10
|
+
@target_host = target_host
|
11
|
+
options = args.extract_options!
|
12
|
+
@target_port = options[:port]
|
13
|
+
@username = options[:username]
|
14
|
+
@password = options[:password]
|
15
|
+
@batch_size = options[:batch_size]
|
16
|
+
@view_context = options[:view_context] # XXX: not actually optional
|
17
|
+
raise(ArgumentError, "missing view context") unless @view_context # XXX: smell (see above)
|
18
|
+
end
|
19
|
+
|
20
|
+
def all # TODO: rename
|
21
|
+
timestamp = Time.now
|
22
|
+
errors = false
|
23
|
+
|
24
|
+
gather_candidates do |records|
|
25
|
+
success = sync(records, timestamp)
|
26
|
+
errors = true unless success
|
27
|
+
end
|
28
|
+
|
29
|
+
return !errors
|
30
|
+
end
|
31
|
+
|
32
|
+
def sync(records, timestamp=nil)
|
33
|
+
timestamp ||= Time.now
|
34
|
+
|
35
|
+
success = push(records)
|
36
|
+
if success
|
37
|
+
records.each do |record|
|
38
|
+
record.update_attribute(:rdf_updated_at, timestamp)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
return success
|
43
|
+
end
|
44
|
+
|
45
|
+
def push(records)
|
46
|
+
data = records.inject({}) do |memo, record|
|
47
|
+
graph_uri = url_helpers.rdf_url(record.origin,
|
48
|
+
:host => URI.parse(@base_url).host, :format => nil, :lang => nil)
|
49
|
+
memo[graph_uri] = serialize(record)
|
50
|
+
memo
|
51
|
+
end
|
52
|
+
|
53
|
+
adaptor = IqTriplestorage::VirtuosoAdaptor.new(@target_host, @target_port,
|
54
|
+
@username, @password)
|
55
|
+
return adaptor.batch_update(data)
|
56
|
+
end
|
57
|
+
|
58
|
+
def serialize(record)
|
59
|
+
# while this method is really fugly, iQvoc essentially requires us to mock a
|
60
|
+
# view in order to get to the RDF serialization
|
61
|
+
|
62
|
+
doc = IqRdf::Document.new(@base_url)
|
63
|
+
Iqvoc.default_rdf_namespace_helper_methods.each do |meth|
|
64
|
+
doc.namespaces(@view_context.send(meth))
|
65
|
+
end
|
66
|
+
|
67
|
+
rdf_helper = Object.new.extend(RdfHelper)
|
68
|
+
if record.is_a? Iqvoc::Concept.base_class
|
69
|
+
rdf_helper.render_concept(doc, record)
|
70
|
+
else # XXX: must be extensible
|
71
|
+
raise NotImplementedError, "unable to render RDF for #{record.class}"
|
72
|
+
end
|
73
|
+
|
74
|
+
return doc.to_ntriples
|
75
|
+
end
|
76
|
+
|
77
|
+
# yields batches of candidates for synchronization
|
78
|
+
def gather_candidates # TODO: rename
|
79
|
+
Iqvoc::Sync.syncable_classes.each do |klass|
|
80
|
+
self.class.candidates(klass).find_in_batches(:batch_size => @batch_size) do |records|
|
81
|
+
yield records
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# returns one or multiple ActiveRecord::RelationS, depending on whether
|
87
|
+
# `klass` is provided
|
88
|
+
def self.candidates(klass=nil)
|
89
|
+
return klass ? klass.published.unsynced :
|
90
|
+
Iqvoc::Sync.syncable_classes.map { |klass| candidates(klass) }
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
module Iqvoc::RDFSync::Helper # TODO: rename -- XXX: does not belong here!?
|
96
|
+
|
97
|
+
def triplestore_syncer
|
98
|
+
base_url = root_url(:lang => nil) # XXX: brittle in the face of future changes?
|
99
|
+
|
100
|
+
host = URI.parse(Iqvoc.config["triplestore.url"])
|
101
|
+
port = host.port
|
102
|
+
host.port = 80 # XXX: hack to remove port from serialization
|
103
|
+
host = host.to_s
|
104
|
+
|
105
|
+
return Iqvoc::RDFSync.new(base_url, host, :port => port,
|
106
|
+
:username => Iqvoc.config["triplestore.username"].presence,
|
107
|
+
:password => Iqvoc.config["triplestore.password"].presence,
|
108
|
+
:view_context => view_context) # fugly, but necessary; cf. RDFSync#serialize
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
data/lib/iqvoc/version.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -0,0 +1,123 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Copyright 2011 innoQ Deutschland GmbH
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '../test_helper')
|
18
|
+
|
19
|
+
require 'iqvoc/rdf_sync'
|
20
|
+
|
21
|
+
class RDFSyncTest < ActiveSupport::TestCase
|
22
|
+
|
23
|
+
setup do
|
24
|
+
@rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
25
|
+
@skos = "http://www.w3.org/2004/02/skos/core#"
|
26
|
+
|
27
|
+
@base_url = "http://example.com/"
|
28
|
+
@target_host = "http://example.org"
|
29
|
+
@username = "johndoe"
|
30
|
+
|
31
|
+
class FakeViewContext # XXX: does not belong here
|
32
|
+
def iqvoc_default_rdf_namespaces
|
33
|
+
return Iqvoc.rdf_namespaces
|
34
|
+
end
|
35
|
+
end
|
36
|
+
@view_context = FakeViewContext.new
|
37
|
+
|
38
|
+
@sync = Iqvoc::RDFSync.new(@base_url, @target_host, :username => @username,
|
39
|
+
:view_context => @view_context)
|
40
|
+
|
41
|
+
@concepts = 15.times.map do
|
42
|
+
FactoryGirl.create(:concept, :narrower_relations => [])
|
43
|
+
end
|
44
|
+
|
45
|
+
# HTTP request mocking
|
46
|
+
@observers = [] # one per request
|
47
|
+
WebMock.disable_net_connect!
|
48
|
+
WebMock.stub_request(:any, /.*example.org.*/).with do |req|
|
49
|
+
# not using WebMock's custom assertions as those didn't seem to provide
|
50
|
+
# sufficient flexibility
|
51
|
+
fn = @observers.shift
|
52
|
+
raise(TypeError, "missing request observer: #{req.inspect}") unless fn
|
53
|
+
fn.call(req)
|
54
|
+
true
|
55
|
+
end.to_return do |req|
|
56
|
+
{ :status => 201 }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
teardown do
|
61
|
+
WebMock.reset!
|
62
|
+
WebMock.allow_net_connect!
|
63
|
+
raise(TypeError, "unhandled request observer") unless @observers.length == 0
|
64
|
+
end
|
65
|
+
|
66
|
+
test "serialization" do
|
67
|
+
concept = @concepts[0]
|
68
|
+
|
69
|
+
assert @sync.serialize(concept).include?(<<-EOS.strip)
|
70
|
+
<#{@base_url}#{concept.origin}> <#{@rdf}type> <#{@skos}Concept> .
|
71
|
+
EOS
|
72
|
+
end
|
73
|
+
|
74
|
+
test "single-batch syncronization" do
|
75
|
+
concepts = @concepts[0..4]
|
76
|
+
|
77
|
+
@observers << lambda do |req|
|
78
|
+
concepts.each do |concept|
|
79
|
+
uri = @base_url + concept.origin
|
80
|
+
assert req.body.include?("CLEAR GRAPH <#{uri}>")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
@observers << lambda do |req|
|
84
|
+
concepts.each do |concept|
|
85
|
+
path = req.uri.path
|
86
|
+
assert path.start_with?("/DAV/home/#{@username}/")
|
87
|
+
assert_equal 4, path.count("/")
|
88
|
+
uri = @base_url + concept.origin
|
89
|
+
assert req.body.include?("INSERT IN GRAPH <#{uri}> {")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
res = @sync.sync(concepts)
|
93
|
+
end
|
94
|
+
|
95
|
+
test "full synchronization" do
|
96
|
+
concepts = Iqvoc::Concept.base_class.published.unsynced
|
97
|
+
|
98
|
+
assert_not_equal 0, concepts.count
|
99
|
+
assert_not_equal 0, concepts.where(:rdf_updated_at => nil).count
|
100
|
+
|
101
|
+
2.times do # 3 * 2 requests (reset + insert per batch)
|
102
|
+
@observers << lambda { |req| } # no need to check details here
|
103
|
+
end
|
104
|
+
assert @sync.all
|
105
|
+
assert_equal 0, concepts.where(:rdf_updated_at => nil).count
|
106
|
+
end
|
107
|
+
|
108
|
+
test "request batches" do
|
109
|
+
concepts = Iqvoc::Concept.base_class.published.unsynced
|
110
|
+
concept_count = concepts.count
|
111
|
+
batch_count = 3
|
112
|
+
|
113
|
+
sync = Iqvoc::RDFSync.new(@base_url, @target_host, :username => @username,
|
114
|
+
:batch_size => (concept_count / batch_count).ceil,
|
115
|
+
:view_context => @view_context)
|
116
|
+
|
117
|
+
(batch_count * 2).times do # two requests (reset + insert) per batch
|
118
|
+
@observers << lambda { |req| } # no need to check details here
|
119
|
+
end
|
120
|
+
assert sync.all
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iqvoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,11 +11,11 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-11-
|
14
|
+
date: 2012-11-05 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
18
|
-
requirement: &
|
18
|
+
requirement: &70162871907980 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ~>
|
@@ -23,10 +23,10 @@ dependencies:
|
|
23
23
|
version: 3.2.1
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *70162871907980
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
|
-
requirement: &
|
29
|
+
requirement: &70162871905160 !ruby/object:Gem::Requirement
|
30
30
|
none: false
|
31
31
|
requirements:
|
32
32
|
- - ! '>='
|
@@ -34,10 +34,10 @@ dependencies:
|
|
34
34
|
version: '0'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
|
-
version_requirements: *
|
37
|
+
version_requirements: *70162871905160
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: kaminari
|
40
|
-
requirement: &
|
40
|
+
requirement: &70162871915900 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ! '>='
|
@@ -45,10 +45,10 @@ dependencies:
|
|
45
45
|
version: '0'
|
46
46
|
type: :runtime
|
47
47
|
prerelease: false
|
48
|
-
version_requirements: *
|
48
|
+
version_requirements: *70162871915900
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
name: authlogic
|
51
|
-
requirement: &
|
51
|
+
requirement: &70162871913820 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
53
53
|
requirements:
|
54
54
|
- - ! '>='
|
@@ -56,10 +56,10 @@ dependencies:
|
|
56
56
|
version: '0'
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
|
-
version_requirements: *
|
59
|
+
version_requirements: *70162871913820
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: cancan
|
62
|
-
requirement: &
|
62
|
+
requirement: &70162871911780 !ruby/object:Gem::Requirement
|
63
63
|
none: false
|
64
64
|
requirements:
|
65
65
|
- - ! '>='
|
@@ -67,10 +67,10 @@ dependencies:
|
|
67
67
|
version: '0'
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
|
-
version_requirements: *
|
70
|
+
version_requirements: *70162871911780
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: iq_rdf
|
73
|
-
requirement: &
|
73
|
+
requirement: &70162871922380 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
75
75
|
requirements:
|
76
76
|
- - ~>
|
@@ -78,10 +78,10 @@ dependencies:
|
|
78
78
|
version: 0.1.2
|
79
79
|
type: :runtime
|
80
80
|
prerelease: false
|
81
|
-
version_requirements: *
|
81
|
+
version_requirements: *70162871922380
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: json
|
84
|
-
requirement: &
|
84
|
+
requirement: &70162871933860 !ruby/object:Gem::Requirement
|
85
85
|
none: false
|
86
86
|
requirements:
|
87
87
|
- - ! '>='
|
@@ -89,10 +89,10 @@ dependencies:
|
|
89
89
|
version: '0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
|
-
version_requirements: *
|
92
|
+
version_requirements: *70162871933860
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: rails_autolink
|
95
|
-
requirement: &
|
95
|
+
requirement: &70162871942060 !ruby/object:Gem::Requirement
|
96
96
|
none: false
|
97
97
|
requirements:
|
98
98
|
- - ! '>='
|
@@ -100,10 +100,10 @@ dependencies:
|
|
100
100
|
version: '0'
|
101
101
|
type: :runtime
|
102
102
|
prerelease: false
|
103
|
-
version_requirements: *
|
103
|
+
version_requirements: *70162871942060
|
104
104
|
- !ruby/object:Gem::Dependency
|
105
105
|
name: fastercsv
|
106
|
-
requirement: &
|
106
|
+
requirement: &70162871941320 !ruby/object:Gem::Requirement
|
107
107
|
none: false
|
108
108
|
requirements:
|
109
109
|
- - ! '>='
|
@@ -111,10 +111,10 @@ dependencies:
|
|
111
111
|
version: '0'
|
112
112
|
type: :runtime
|
113
113
|
prerelease: false
|
114
|
-
version_requirements: *
|
114
|
+
version_requirements: *70162871941320
|
115
115
|
- !ruby/object:Gem::Dependency
|
116
116
|
name: simple_form
|
117
|
-
requirement: &
|
117
|
+
requirement: &70162871940440 !ruby/object:Gem::Requirement
|
118
118
|
none: false
|
119
119
|
requirements:
|
120
120
|
- - ! '>='
|
@@ -122,10 +122,10 @@ dependencies:
|
|
122
122
|
version: '0'
|
123
123
|
type: :runtime
|
124
124
|
prerelease: false
|
125
|
-
version_requirements: *
|
125
|
+
version_requirements: *70162871940440
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: sass-rails
|
128
|
-
requirement: &
|
128
|
+
requirement: &70162871939660 !ruby/object:Gem::Requirement
|
129
129
|
none: false
|
130
130
|
requirements:
|
131
131
|
- - ~>
|
@@ -133,7 +133,7 @@ dependencies:
|
|
133
133
|
version: 3.2.5
|
134
134
|
type: :runtime
|
135
135
|
prerelease: false
|
136
|
-
version_requirements: *
|
136
|
+
version_requirements: *70162871939660
|
137
137
|
description: iQvoc - a SKOS(-XL) vocabulary management system built on the Semantic
|
138
138
|
Web
|
139
139
|
email:
|
@@ -196,7 +196,7 @@ files:
|
|
196
196
|
- app/controllers/pages_controller.rb
|
197
197
|
- app/controllers/rdf_controller.rb
|
198
198
|
- app/controllers/search_results_controller.rb
|
199
|
-
- app/controllers/
|
199
|
+
- app/controllers/triplestore_sync_controller.rb
|
200
200
|
- app/controllers/user_sessions_controller.rb
|
201
201
|
- app/controllers/users_controller.rb
|
202
202
|
- app/helpers/application_helper.rb
|
@@ -250,7 +250,6 @@ files:
|
|
250
250
|
- app/models/note/skos/example.rb
|
251
251
|
- app/models/note/skos/history_note.rb
|
252
252
|
- app/models/note/skos/scope_note.rb
|
253
|
-
- app/models/rdf_store.rb
|
254
253
|
- app/models/search_extension.rb
|
255
254
|
- app/models/user.rb
|
256
255
|
- app/models/user_session.rb
|
@@ -328,7 +327,7 @@ files:
|
|
328
327
|
- app/views/search_results/_sidebar.html.erb
|
329
328
|
- app/views/search_results/index.html.erb
|
330
329
|
- app/views/search_results/index.iqrdf
|
331
|
-
- app/views/
|
330
|
+
- app/views/triplestore_sync/index.html.erb
|
332
331
|
- app/views/user_sessions/_form.html.erb
|
333
332
|
- app/views/user_sessions/new.html.erb
|
334
333
|
- app/views/users/_form.html.erb
|
@@ -410,6 +409,7 @@ files:
|
|
410
409
|
- lib/iqvoc/configuration/concept.rb
|
411
410
|
- lib/iqvoc/configuration/core.rb
|
412
411
|
- lib/iqvoc/configuration/label.rb
|
412
|
+
- lib/iqvoc/configuration/sync.rb
|
413
413
|
- lib/iqvoc/controller_extensions.rb
|
414
414
|
- lib/iqvoc/deep_cloning.rb
|
415
415
|
- lib/iqvoc/environments/development.rb
|
@@ -420,6 +420,7 @@ files:
|
|
420
420
|
- lib/iqvoc/maker.rb
|
421
421
|
- lib/iqvoc/origin.rb
|
422
422
|
- lib/iqvoc/rankable.rb
|
423
|
+
- lib/iqvoc/rdf_sync.rb
|
423
424
|
- lib/iqvoc/skos_importer.rb
|
424
425
|
- lib/iqvoc/version.rb
|
425
426
|
- lib/iqvoc/versioning.rb
|
@@ -452,6 +453,7 @@ files:
|
|
452
453
|
- test/unit/instance_configuration_test.rb
|
453
454
|
- test/unit/note_test.rb
|
454
455
|
- test/unit/origin_test.rb
|
456
|
+
- test/unit/rdf_sync_test.rb
|
455
457
|
- test/unit/skos_import_test.rb
|
456
458
|
- vendor/assets/images/ajax-loader.gif
|
457
459
|
- vendor/assets/images/bootstrap/glyphicons-halflings-white.png
|
@@ -548,4 +550,5 @@ test_files:
|
|
548
550
|
- test/unit/instance_configuration_test.rb
|
549
551
|
- test/unit/note_test.rb
|
550
552
|
- test/unit/origin_test.rb
|
553
|
+
- test/unit/rdf_sync_test.rb
|
551
554
|
- test/unit/skos_import_test.rb
|
@@ -1,45 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
# Copyright 2011 innoQ Deutschland GmbH
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
|
17
|
-
class TripleStoreSyncsController < ApplicationController
|
18
|
-
|
19
|
-
# TODO: This must definitely be rebuild!
|
20
|
-
|
21
|
-
def new
|
22
|
-
authorize! :use, :dashboard # TODO
|
23
|
-
end
|
24
|
-
|
25
|
-
def create
|
26
|
-
authorize! :use, :dashboard # TODO
|
27
|
-
|
28
|
-
time = Time.now
|
29
|
-
|
30
|
-
rdf_helper = Object.new.extend(RdfHelper)
|
31
|
-
|
32
|
-
Concept::Base.published.unsynced.find_each do |concept|
|
33
|
-
concept.update_attribute(:rdf_updated_at, time) if RdfStore.mass_import(concept.rdf_uri, rdf_helper.render_ttl_for_concept(concept))
|
34
|
-
end
|
35
|
-
|
36
|
-
Label::Base.published.unsynced.find_each do |label|
|
37
|
-
label.update_attribute(:rdf_updated_at, time) if RdfStore.mass_import(label.rdf_uri, rdf_helper.render_ttl_for_label(label))
|
38
|
-
end
|
39
|
-
|
40
|
-
flash.now[:notice] = I18n.t("txt.controllers.triple_store_syncs.success")
|
41
|
-
|
42
|
-
render :action => "new"
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
data/app/models/rdf_store.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
# Copyright 2011 innoQ Deutschland GmbH
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
|
17
|
-
class RdfStore
|
18
|
-
# TODO This must be modularized and refactored and the thread should be
|
19
|
-
# replaced by a direct rack call or usage of helpers
|
20
|
-
#
|
21
|
-
# * Modulization: The RdfStore should be more abstract. A special adapter
|
22
|
-
# (e.g. for virtuoso or sesame) should be implemented in a extending
|
23
|
-
# class.
|
24
|
-
# * No threads: throw out the JRuby stuff and replace it with:
|
25
|
-
# * Rack calls to the particluar action or
|
26
|
-
# * With the help of the RdfHelper#render_concept method
|
27
|
-
|
28
|
-
include Java rescue nil
|
29
|
-
include java.lang.Runnable rescue nil
|
30
|
-
|
31
|
-
@@conn = nil
|
32
|
-
|
33
|
-
def initialize(graph_uri, ttl_url, do_delete, ttl_content = nil)
|
34
|
-
if Rails.application.config.virtuoso_jdbc_driver_url
|
35
|
-
@graph_uri = graph_uri
|
36
|
-
@ttl_url = ttl_url
|
37
|
-
@ttl_content = ttl_content
|
38
|
-
@do_delete = do_delete
|
39
|
-
|
40
|
-
Rails.logger.info("** [RdfStore] Beginning virtuoso sync. Insert turtle into graph <#{@graph_uri}> from url: #{@ttl_url}; Clear graph first: #{@do_delete}.")
|
41
|
-
|
42
|
-
unless @@conn
|
43
|
-
# import "virtuoso.jdbc3.Driver"
|
44
|
-
java.lang.Class.forName("virtuoso.jdbc3.Driver", true, JRuby.runtime.jruby_class_loader)
|
45
|
-
@@conn = java.sql.DriverManager.getConnection(Rails.application.config.virtuoso_jdbc_driver_url)
|
46
|
-
Rails.logger.debug("** [RdfStore] JDBC connection is up.")
|
47
|
-
end
|
48
|
-
|
49
|
-
if Rails.application.config.virtuoso_sync_threaded
|
50
|
-
Rails.logger.debug("** [RdfStore] Starting sync thread.")
|
51
|
-
java.lang.Thread.new(self).start
|
52
|
-
else
|
53
|
-
self.run
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.insert(graph_uri, ttl_url)
|
59
|
-
return false unless Rails.application.config.virtuoso_jdbc_driver_url
|
60
|
-
RdfStore.new(graph_uri, ttl_url, false)
|
61
|
-
true
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.update(graph_uri, ttl_url)
|
65
|
-
return false unless Rails.application.config.virtuoso_jdbc_driver_url
|
66
|
-
RdfStore.new(graph_uri, ttl_url, true)
|
67
|
-
true
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.delete(graph_uri)
|
71
|
-
return false unless Rails.application.config.virtuoso_jdbc_driver_url
|
72
|
-
RdfStore.new(graph_uri, nil, true)
|
73
|
-
true
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.mass_import(graph_uri, turtle_content)
|
77
|
-
return false unless Rails.application.config.virtuoso_jdbc_driver_url
|
78
|
-
RdfStore.new(graph_uri, nil, true, turtle_content)
|
79
|
-
true
|
80
|
-
end
|
81
|
-
|
82
|
-
def run
|
83
|
-
if (@do_delete)
|
84
|
-
Rails.logger.debug("** [RdfStore] Executing SPARQL DELETE.")
|
85
|
-
@@conn.createStatement().execute("SPARQL CLEAR GRAPH <#{@graph_uri}>")
|
86
|
-
end
|
87
|
-
if (@ttl_url)
|
88
|
-
Rails.logger.debug("** [RdfStore] Executing turtle load from url.")
|
89
|
-
@@conn.createStatement().execute("DB.DBA.TTLP(HTTP_GET('#{@ttl_url}'), '', '#{@graph_uri}')")
|
90
|
-
end
|
91
|
-
if (@ttl_content)
|
92
|
-
@@conn.createStatement().execute("DB.DBA.TTLP('#{@ttl_content.gsub("\\", "\\\\\\").gsub("'", "\\\\'")}', '', '#{@graph_uri}')")
|
93
|
-
end
|
94
|
-
Rails.logger.info("** [RdfStore] Virtuoso sync done.")
|
95
|
-
end
|
96
|
-
end
|