iqvoc 4.0.3 → 4.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|