talia_core 0.5.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/config/talia_core.yml.example +37 -35
- data/generators/talia_admin/templates/app/models/fake_source.rb +93 -0
- data/generators/talia_admin/templates/app/models/talia_collection.rb +13 -37
- data/generators/talia_base/talia_base_generator.rb +0 -1
- data/generators/talia_base/templates/app/controllers/custom_templates_controller.rb +2 -1
- data/generators/talia_base/templates/app/controllers/sources_controller.rb +1 -1
- data/generators/talia_base/templates/script/configure_talia +56 -73
- data/generators/talia_swicky/talia_swicky_generator.rb +18 -0
- data/generators/talia_swicky/templates/app/controllers/swicky_notebooks_controller.rb +111 -0
- data/generators/talia_swicky/templates/app/helpers/swicky_notebooks_helper.rb +29 -0
- data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.builder +6 -0
- data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.html.erb +10 -0
- data/generators/talia_swicky/templates/app/views/swicky_notebooks/show.html.erb +11 -0
- data/generators/talia_swicky/templates/test/fixtures/notebook.rdf +862 -0
- data/generators/talia_swicky/templates/test/functional/swicky_notebooks_controller_test.rb +44 -0
- data/lib/core_ext/boolean.rb +23 -0
- data/lib/core_ext/jdbc_rake_monkeypatch.rb +22 -0
- data/lib/core_ext/nil_class.rb +11 -0
- data/lib/core_ext/object.rb +34 -0
- data/lib/core_ext/string.rb +15 -0
- data/lib/custom_template.rb +3 -1
- data/lib/loader_helper.rb +16 -3
- data/lib/mysql.rb +7 -7
- data/lib/progressbar.rb +2 -2
- data/lib/swicky/exhibit_json/item.rb +129 -0
- data/lib/swicky/exhibit_json/item_collection.rb +129 -0
- data/lib/swicky/fragment.rb +0 -0
- data/lib/swicky/note.rb +7 -0
- data/lib/swicky/notebook.rb +78 -12
- data/lib/talia_core/active_source.rb +45 -13
- data/lib/talia_core/active_source_parts/class_methods.rb +154 -26
- data/lib/talia_core/active_source_parts/finders.rb +49 -26
- data/lib/talia_core/active_source_parts/predicate_handler.rb +71 -23
- data/lib/talia_core/active_source_parts/rdf/ntriples_reader.rb +13 -0
- data/lib/talia_core/active_source_parts/rdf/rdf_reader.rb +99 -0
- data/lib/talia_core/active_source_parts/rdf/rdfxml_reader.rb +12 -0
- data/lib/talia_core/active_source_parts/{rdf.rb → rdf_handler.rb} +52 -19
- data/lib/talia_core/active_source_parts/xml/generic_reader.rb +151 -260
- data/lib/talia_core/active_source_parts/xml/generic_reader_add_statements.rb +97 -0
- data/lib/talia_core/active_source_parts/xml/generic_reader_helpers.rb +88 -0
- data/lib/talia_core/active_source_parts/xml/generic_reader_import_statements.rb +239 -0
- data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +14 -7
- data/lib/talia_core/active_source_parts/xml/source_builder.rb +7 -3
- data/lib/talia_core/active_source_parts/xml/source_reader.rb +17 -2
- data/lib/talia_core/collection.rb +192 -1
- data/lib/talia_core/data_types/data_loader.rb +88 -18
- data/lib/talia_core/data_types/data_record.rb +24 -2
- data/lib/talia_core/data_types/delayed_copier.rb +13 -3
- data/lib/talia_core/data_types/file_record.rb +24 -13
- data/lib/talia_core/data_types/file_store.rb +111 -94
- data/lib/talia_core/data_types/iip_data.rb +104 -23
- data/lib/talia_core/data_types/iip_loader.rb +102 -56
- data/lib/talia_core/data_types/image_data.rb +3 -1
- data/lib/talia_core/data_types/media_link.rb +4 -1
- data/lib/talia_core/data_types/mime_mapping.rb +65 -38
- data/lib/talia_core/data_types/path_helpers.rb +23 -17
- data/lib/talia_core/data_types/pdf_data.rb +9 -6
- data/lib/talia_core/data_types/simple_text.rb +5 -4
- data/lib/talia_core/data_types/xml_data.rb +53 -25
- data/lib/talia_core/dummy_handler.rb +3 -2
- data/lib/talia_core/errors.rb +13 -27
- data/lib/talia_core/initializer.rb +44 -4
- data/lib/talia_core/oai/active_source_model.rb +13 -6
- data/lib/talia_core/oai/active_source_oai_adapter.rb +13 -12
- data/lib/talia_core/rdf_import.rb +1 -1
- data/lib/talia_core/rdf_resource.rb +2 -1
- data/lib/talia_core/semantic_collection_wrapper.rb +143 -151
- data/lib/talia_core/semantic_property.rb +4 -0
- data/lib/talia_core/semantic_relation.rb +84 -33
- data/lib/talia_core/source.rb +45 -25
- data/lib/talia_core/source_fragment.rb +7 -0
- data/lib/talia_core/source_transfer_object.rb +3 -1
- data/lib/talia_core/source_types/agent.rb +16 -0
- data/lib/talia_core/source_types/dc_resource.rb +3 -3
- data/lib/talia_core/source_types/marcont_resource.rb +15 -0
- data/lib/talia_core/source_types/skos_concept.rb +17 -0
- data/lib/talia_dependencies.rb +1 -1
- data/lib/talia_util.rb +1 -1
- data/lib/talia_util/bar_progressor.rb +1 -1
- data/lib/talia_util/image_conversions.rb +8 -2
- data/lib/talia_util/import_job_helper.rb +40 -3
- data/lib/talia_util/io_helper.rb +15 -4
- data/lib/talia_util/progressable.rb +50 -1
- data/lib/talia_util/rake_tasks.rb +3 -21
- data/lib/talia_util/test_helpers.rb +6 -1
- data/lib/talia_util/util.rb +108 -27
- data/lib/talia_util/xml/base_builder.rb +28 -1
- data/lib/talia_util/xml/rdf_builder.rb +81 -5
- data/lib/tasks/talia_core_tasks.rake +2 -0
- data/test/core_ext/boolean_test.rb +26 -0
- data/test/core_ext/nil_class_test.rb +14 -0
- data/test/core_ext/object_test.rb +26 -0
- data/test/core_ext/string_test.rb +11 -0
- data/test/swicky/json_encoder_test.rb +51 -42
- data/test/swicky/notebook_test.rb +13 -6
- data/test/talia_core/active_source_finder_interface_test.rb +30 -0
- data/test/talia_core/active_source_test.rb +445 -34
- data/test/talia_core/collection_test.rb +332 -0
- data/test/talia_core/data_types/file_record_test.rb +2 -23
- data/test/talia_core/ntriples_reader_test.rb +49 -0
- data/test/talia_core/rdfxml_reader_test.rb +51 -0
- data/test/talia_core/source_test.rb +12 -0
- data/test/talia_util/import_job_helper_test.rb +19 -12
- metadata +190 -90
- data/config/database.yml +0 -19
- data/config/rdfstore.yml +0 -13
- data/config/talia_core.yml +0 -24
- data/generators/talia_base/templates/migrations/bj_migration.rb +0 -10
- data/lib/JXslt/jxslt.rb +0 -60
- data/lib/swicky/json_encoder.rb +0 -179
- data/lib/talia_core/agent.rb +0 -14
- data/lib/talia_core/background_jobs/job.rb +0 -82
- data/lib/talia_core/background_jobs/progress_job.rb +0 -68
- data/lib/talia_core/data_types/temp_file_handling.rb +0 -85
- data/lib/talia_core/ordered_source.rb +0 -228
- data/lib/talia_core/semantic_collection_item.rb +0 -94
- data/lib/talia_core/source_types/collection.rb +0 -15
- data/lib/talia_util/progressbar.rb +0 -236
- data/tasks/talia_core_tasks.rake +0 -2
- data/test/talia_core/ordered_source_test.rb +0 -394
- data/test/talia_core/semantic_collection_item_test.rb +0 -125
@@ -1,20 +1,31 @@
|
|
1
1
|
module TaliaCore
|
2
2
|
module ActiveSourceParts
|
3
3
|
|
4
|
-
#
|
4
|
+
# Class method for ActiveSource that deal with #find and friends, and other forms of querying the
|
5
|
+
# data store.
|
5
6
|
module Finders
|
6
7
|
|
7
8
|
|
8
|
-
#
|
9
|
-
#
|
9
|
+
# Extends the functionality of the ActiveRecord #find. This version also accepts URIs as
|
10
|
+
# "ids" and has a few additional options:
|
10
11
|
#
|
11
|
-
# [
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# [
|
15
|
-
# [
|
16
|
-
# [
|
17
|
-
#
|
12
|
+
# [*find_through*] accepts and array with an predicate name and an object
|
13
|
+
# value/uri, to search for predicates that match the given predicate/value
|
14
|
+
# combination
|
15
|
+
# [*type*] specifically looks for sources with the given type.
|
16
|
+
# [*find_through_inv*] like :find_through, but for the "inverse" lookup
|
17
|
+
# [*prefetch_relations*] if set to "true", this will pre-load all semantic
|
18
|
+
# relations for the sources (experimental, not fully implemented yet)
|
19
|
+
#
|
20
|
+
# == Examples:
|
21
|
+
# # With a URI as id
|
22
|
+
# ActiveSource.find(N::LOCAL.mySource)
|
23
|
+
#
|
24
|
+
# # A URI as a string, same as above
|
25
|
+
# ActiveSource.find('http://www.foobar.org')
|
26
|
+
#
|
27
|
+
# # Find through a given attribute, and prefetch all attributes for the found sources
|
28
|
+
# ActiveSource.find(:all, :find_through => [N::DCT.creator, N::LOCAL.schopenhauer], :prefetch_relations => true)
|
18
29
|
def find(*args)
|
19
30
|
prefetching = false
|
20
31
|
if(args.last.is_a?(Hash))
|
@@ -45,8 +56,7 @@ module TaliaCore
|
|
45
56
|
result
|
46
57
|
end
|
47
58
|
|
48
|
-
#
|
49
|
-
# ActiveSource #find routine
|
59
|
+
# The count for ActiveSource will accept the same options as the find method
|
50
60
|
def count(*args)
|
51
61
|
if((options = args.last).is_a?(Hash))
|
52
62
|
options.to_options!
|
@@ -57,23 +67,28 @@ module TaliaCore
|
|
57
67
|
end
|
58
68
|
|
59
69
|
# Find a list of sources which contains the given token inside the local name.
|
60
|
-
# This means that the namespace it will be excluded
|
70
|
+
# This means that the namespace it will be excluded from the toke search
|
71
|
+
#
|
72
|
+
# == Example
|
61
73
|
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
74
|
+
# Sources in system:
|
75
|
+
# * http://talia.org/one
|
76
|
+
# * http://talia.org/two
|
77
|
+
#
|
78
|
+
# With these sources, you will get:
|
65
79
|
#
|
66
80
|
# Source.find_by_uri_token('a') # => [ ]
|
67
81
|
# Source.find_by_uri_token('o') # => [ 'http://talia.org/one', 'http://talia.org/two' ]
|
68
82
|
#
|
69
|
-
# NOTE: It internally
|
83
|
+
# NOTE: It internally uses a MySQL function, as sql condition, to find the local name of the uri.
|
70
84
|
def find_by_uri_token(token, options = {})
|
71
85
|
find(:all, {
|
72
86
|
:conditions => [ "LOWER(SUBSTRING_INDEX(uri, '/', -1)) LIKE ?", '%' + token.downcase + '%' ],
|
73
87
|
:order => "uri ASC" }.merge!(options))
|
74
88
|
end
|
75
89
|
|
76
|
-
# Find the Sources within the given namespace by a partial local name
|
90
|
+
# Find the Sources within the given namespace by a partial local name. Works like
|
91
|
+
# #find_by_uri_token, except that only sources from the given namspace are returned
|
77
92
|
def find_by_partial_local(namespace, local_part, options = {})
|
78
93
|
namesp = N::URI[namespace]
|
79
94
|
return [] unless(namesp)
|
@@ -82,12 +97,8 @@ module TaliaCore
|
|
82
97
|
:order => "uri ASC"}.merge!(options))
|
83
98
|
end
|
84
99
|
|
85
|
-
# Find the fist Source that matches the given URI.
|
86
|
-
#
|
87
|
-
# /admin/sources/<source_id>/edit
|
88
|
-
# but that information is not enough, since we store
|
89
|
-
# into the database the whole reference as URI:
|
90
|
-
# http://localnode.org/av_media_sources/source_id
|
100
|
+
# Find the fist Source that matches the given URI. This works like #find_by_uri_token,
|
101
|
+
# except that the whole URI is matched, not only the local name.
|
91
102
|
def find_by_partial_uri(id, options = {})
|
92
103
|
find(:all, { :conditions => ["uri LIKE ?", '%' + id + '%'] }.merge!(options))
|
93
104
|
end
|
@@ -111,18 +122,30 @@ module TaliaCore
|
|
111
122
|
raise(ArgumentError, "Cannot pass custom join conditions with :find_through") if(options.has_key?(:joins))
|
112
123
|
predicate = f_through[0]
|
113
124
|
obj_val = f_through[1]
|
114
|
-
search_prop = (f_through
|
125
|
+
search_prop = check_if_search_value(f_through)
|
115
126
|
options[:joins] = default_joins(!search_prop, search_prop)
|
116
127
|
options[:conditions] ||= {}
|
117
128
|
options[:conditions]['semantic_relations.predicate_uri'] = predicate.to_s
|
118
129
|
if(search_prop)
|
119
130
|
options[:conditions]['obj_props.value'] = obj_val.to_s
|
120
131
|
else
|
121
|
-
options[:conditions]['obj_sources.uri'] = obj_val.to_s
|
132
|
+
options[:conditions]['obj_sources.uri'] = (obj_val.respond_to?(:uri) ? obj_val.uri.to_s : obj_val.to_s)
|
122
133
|
end
|
123
134
|
end
|
124
135
|
end
|
125
136
|
|
137
|
+
# Checks if the given find_through options should search for a value or
|
138
|
+
# an object. See #check_for_find_through
|
139
|
+
def check_if_search_value(finder_array)
|
140
|
+
if(finder_array.size > 2)
|
141
|
+
finder_array[2]
|
142
|
+
elsif(finder_array[1].respond_to?(:uri))
|
143
|
+
false
|
144
|
+
else
|
145
|
+
!(finder_array[1].to_s =~ /:/)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
126
149
|
# Check for the :find_through_inv option. This expects the 2 basic values
|
127
150
|
# in the same way as :find_through.
|
128
151
|
#
|
@@ -1,9 +1,20 @@
|
|
1
1
|
module TaliaCore
|
2
2
|
module ActiveSourceParts
|
3
|
+
|
4
|
+
# Methods for ActiveSource objects for accessing and handling predicates, which are the
|
5
|
+
# properties connected to the source. When accessing a predicate/property of an ActiveSource,
|
6
|
+
# the system will return a SemanticCollectionWrapper.
|
7
|
+
#
|
8
|
+
# Once a predicate is loaded, the ActiveSource will cache the SemanticCollectionWrapper
|
9
|
+
# internally, and will re-use it on subsequent accesses.
|
10
|
+
#
|
11
|
+
# If the relations are prefetched (usually by providing the :prefetch_relations option to
|
12
|
+
# the find Method, see the Finders module), all wrappers for the source are loaded at once;
|
13
|
+
# the actual prefetching is done by the prefetch_relations_for method, which can also be
|
14
|
+
# used directly on a collection of sources.
|
3
15
|
module PredicateHandler
|
4
|
-
# This file contains the handling of the "predicate wrapper" lists
|
5
|
-
# that represent the properties/objects a class has for a given predicate
|
6
16
|
|
17
|
+
# Predicate-related class methods. See the PredicateHandler module for more
|
7
18
|
module ClassMethods
|
8
19
|
|
9
20
|
# Attempts to fetch all relations on the given sources at once, so that
|
@@ -12,18 +23,21 @@ module TaliaCore
|
|
12
23
|
# For safety reasons, there is a limit on the number of sources that is
|
13
24
|
# accepted. (For a web application, if you go over the default, you're
|
14
25
|
# probably doing it wrong).
|
26
|
+
#
|
27
|
+
# When prefetching, all the relations/properties for the given sources are
|
28
|
+
# loaded in a single request, and the data is injected in the internal cache
|
29
|
+
# of the sources.
|
30
|
+
#
|
31
|
+
# A source with prefetched relations will not cause database queries if you
|
32
|
+
# access its properties.
|
15
33
|
def prefetch_relations_for(sources, limit = 1024)
|
16
34
|
sources = [ sources ] if(sources.is_a?(ActiveSource))
|
17
35
|
raise(RangeError, "Too many sources for prefetching.") if(sources.size > limit)
|
18
36
|
src_hash = {}
|
19
37
|
sources.each { |src| src_hash[src.id] = src }
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
relations = SemanticRelation.find(:all, :conditions => conditions,
|
24
|
-
:joins => joins,
|
25
|
-
:select => SemanticRelation.fat_record_select
|
26
|
-
)
|
38
|
+
|
39
|
+
relations = SemanticRelation.find(:all, :conditions => { :subject_id => src_hash.keys }, :include => [:subject, :object])
|
40
|
+
|
27
41
|
relations.each do |rel|
|
28
42
|
src_hash[rel.subject_id].inject_predicate(rel)
|
29
43
|
end
|
@@ -37,20 +51,28 @@ module TaliaCore
|
|
37
51
|
|
38
52
|
end # End class methods
|
39
53
|
|
40
|
-
# Gets the types
|
54
|
+
# Gets the RDF types for the source. This is equivalent to accessing the
|
55
|
+
# rdf:type predicate.
|
41
56
|
def types
|
42
57
|
get_objects_on(N::RDF.type.to_s)
|
43
58
|
end
|
44
59
|
|
45
|
-
#
|
60
|
+
# Checks if the source has the given RDF type
|
46
61
|
def has_type?(type)
|
47
62
|
(self.types.include?(type))
|
48
63
|
end
|
49
64
|
|
50
|
-
# Returns the
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
65
|
+
# Returns the SemanticCollectionWrapper for the given predicate. The collection
|
66
|
+
# wrapper will be cached internally, so that subsequent calls will receive the
|
67
|
+
# same collection wrapper again.
|
68
|
+
#
|
69
|
+
# This also means that any modifications to the wrapper are preserved in the
|
70
|
+
# cache - if a wrapper is modified in memory, and accessed again _on the same
|
71
|
+
# source_, a subsequent access will return the modified wrapper.
|
72
|
+
#
|
73
|
+
# Modified wrappers are saved when the ActiveSource itself is saved (through
|
74
|
+
# save_wrappers, which is automatically called)
|
75
|
+
def get_wrapper_on(predicate)
|
54
76
|
@type_cache ||= {}
|
55
77
|
active_wrapper = @type_cache[predicate.to_s]
|
56
78
|
|
@@ -66,8 +88,30 @@ module TaliaCore
|
|
66
88
|
|
67
89
|
active_wrapper
|
68
90
|
end
|
91
|
+
|
92
|
+
# Returns the values for the given predicate. This will work like #get_wrapper_on
|
93
|
+
# _except_ if the predicate is declared as a :singular_property with ActiveSouce.property_options
|
94
|
+
# (or singular_property, or multi_property). In that case, it will
|
95
|
+
# return only a single value. However, if the predicate is declare singular and
|
96
|
+
# there already is more than one value, it will return the wrapper (and fail an assit).
|
97
|
+
# In general, a property that was defined singular and contains more than one value
|
98
|
+
# indicates a problem with the application.
|
99
|
+
def get_objects_on(predicate)
|
100
|
+
singular = property_options_for(predicate)[:singular_property].true?
|
101
|
+
wrapper = get_wrapper_on(predicate)
|
102
|
+
|
103
|
+
if(singular && wrapper.size <= 1)
|
104
|
+
wrapper.first
|
105
|
+
else
|
106
|
+
assit(!singular, 'Was expecting a single value (property is defined as singular). Got more than one.')
|
107
|
+
wrapper
|
108
|
+
end
|
109
|
+
end
|
69
110
|
|
70
|
-
#
|
111
|
+
# Goes through the existing SemanticCollectionWrappers in the cache, and
|
112
|
+
# saves any modifications that may exist.
|
113
|
+
#
|
114
|
+
# This is automatically called when the source is saved.
|
71
115
|
def save_wrappers
|
72
116
|
each_cached_wrapper do |wrap|
|
73
117
|
# Load unloaded if we're not rdf_autosaving. Quick hack since otherwise
|
@@ -78,22 +122,26 @@ module TaliaCore
|
|
78
122
|
end
|
79
123
|
end
|
80
124
|
|
81
|
-
# Loops through the cache and passes each
|
125
|
+
# Loops through the wrapper cache and passes each of the SemanticCollectionWrappers
|
126
|
+
# in the cache to the block given to this method
|
82
127
|
def each_cached_wrapper
|
83
128
|
return unless(@type_cache)
|
84
129
|
@type_cache.each_value { |wrap| yield(wrap) }
|
85
130
|
end
|
86
131
|
|
87
|
-
#
|
88
|
-
#
|
132
|
+
# Resets the internal cache of wrappers/properties. Any unsaved changes on
|
133
|
+
# the wrappers are lost, and get_object_on will have to reload all data when it is
|
134
|
+
# called again
|
89
135
|
def reset!
|
90
136
|
@type_cache = nil
|
91
137
|
end
|
92
138
|
|
93
|
-
# Injects a 'fat'
|
94
|
-
|
95
|
-
|
96
|
-
|
139
|
+
# Injects a 'fat relation' into the cache/wrappter. A "fat" relation is a
|
140
|
+
# SemanticRelation which contains additional fields (e.g. the subject uri, all
|
141
|
+
# object information, etc.) - See also the SemanticCollectionWrapper documentation.
|
142
|
+
def inject_predicate(relation)
|
143
|
+
wrapper = get_wrapper_on(relation.predicate_uri)
|
144
|
+
wrapper.insert_item(relation)
|
97
145
|
end
|
98
146
|
end
|
99
147
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
|
3
|
+
module TaliaCore
|
4
|
+
module ActiveSourceParts
|
5
|
+
module Rdf
|
6
|
+
|
7
|
+
# Import class for rdf ntriples files using rdf.rb (http://rdf.rubyforge.org/).
|
8
|
+
# See GenericReader for more information on Talia import classes in general.
|
9
|
+
class RdfReader
|
10
|
+
|
11
|
+
extend TaliaUtil::IoHelper
|
12
|
+
include TaliaUtil::IoHelper
|
13
|
+
include TaliaUtil::Progressable
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# See TaliaCore::ActiveSourceParts::Xml::GenericReader#sources_from_url
|
17
|
+
def sources_from_url(url, options=nil, progressor=nil)
|
18
|
+
open_generic(url, options) {|io| sources_from(io, progressor, url)}
|
19
|
+
end
|
20
|
+
|
21
|
+
# See TaliaCore::ActiveSourceParts::Xml::GenericReader#sources_from
|
22
|
+
def sources_from(source, progressor=nil, base_url=nil)
|
23
|
+
reader = self.new(source)
|
24
|
+
reader.progressor = progressor
|
25
|
+
reader.sources
|
26
|
+
end
|
27
|
+
|
28
|
+
end # End class methods
|
29
|
+
|
30
|
+
# On inititalization:
|
31
|
+
# * We are going to use Class.subclasses_of method to determine the talia type of the source.
|
32
|
+
# Due to the autoload functionality of rails we need to be sure any possible source type class file
|
33
|
+
# is loaded when we actually use that method. This is what TaliaUtil::Util::load_all_models does.
|
34
|
+
# * Works only with format=:ntriples for now.
|
35
|
+
def initialize(source)
|
36
|
+
TaliaUtil::Util.load_all_models
|
37
|
+
source = StringIO.new(source) if(source.is_a? String)
|
38
|
+
@reader = RDF::Reader.for(format).new(source)
|
39
|
+
end
|
40
|
+
|
41
|
+
# See TaliaCore::ActiveSourceParts::Xml::GenericReader#sources
|
42
|
+
def sources
|
43
|
+
return @sources if(@sources)
|
44
|
+
@sources = {}
|
45
|
+
run_with_progress('RdfRead', 0) do |progress|
|
46
|
+
@reader.each_statement do |statement|
|
47
|
+
source = (@sources[statement.subject.to_s] ||= {})
|
48
|
+
source['uri'] ||= statement.subject.to_s
|
49
|
+
update_source_type(source, statement)
|
50
|
+
source[statement.predicate.to_s] ||= []
|
51
|
+
object = if(statement.object.literal?)
|
52
|
+
parsed_string = PropertyString.parse(statement.object.value)
|
53
|
+
parsed_string.lang = statement.object.language.to_s if(statement.object.language)
|
54
|
+
parsed_string
|
55
|
+
else
|
56
|
+
"<#{statement.object.to_s}>"
|
57
|
+
end
|
58
|
+
source[statement.predicate.to_s] << object
|
59
|
+
progress.inc
|
60
|
+
end
|
61
|
+
end
|
62
|
+
# Set all empty source types to ActiveSource, to prevent DummySource type objects to
|
63
|
+
# be created. (Reason: When we import RDF, we assume that all sources are "valid", and should
|
64
|
+
# never be marked as DummySource)
|
65
|
+
@sources = @sources.values
|
66
|
+
@sources.each { |s| s['type'] ||= 'TaliaCore::ActiveSource' }
|
67
|
+
@sources
|
68
|
+
end
|
69
|
+
|
70
|
+
# Update the Talia source type. The type can be contained explicitly as object of a N::TALIA.type
|
71
|
+
# predicate or can be inferred from the rdf type if a N::RDF.type predicate is present.
|
72
|
+
#
|
73
|
+
# The method works in the way that a N::TALIA type attribute always overwrites the type, while an
|
74
|
+
# N::RDF.type will only be used if no type has been set on the source
|
75
|
+
def update_source_type(source, statement)
|
76
|
+
return if(statement.object.literal?)
|
77
|
+
case(statement.predicate.to_s)
|
78
|
+
when N::TALIA.type.to_s
|
79
|
+
source['type'] = statement.object.to_s
|
80
|
+
when N::RDF.type.to_s
|
81
|
+
source['type'] ||= rdf_to_talia_type statement.object.to_s
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Tries to gues at the talia type of a source given its rdf type.
|
86
|
+
def rdf_to_talia_type(rdf_type)
|
87
|
+
Class.subclasses_of(TaliaCore::ActiveSource).detect do |c|
|
88
|
+
c.additional_rdf_types.include? rdf_type
|
89
|
+
end.try :name
|
90
|
+
end
|
91
|
+
|
92
|
+
def format
|
93
|
+
raise NotImplementedError
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -1,24 +1,35 @@
|
|
1
1
|
module TaliaCore
|
2
2
|
module ActiveSourceParts
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
# Methods for the ActiveSource class to automatically create the RDF triples
|
5
|
+
# for a source and to access the RDF data of the source.
|
6
|
+
#
|
7
|
+
# The RDF for a source will be automatically created through the auto_create_rdf
|
8
|
+
# callback when the source is set (and autosave_rdf is set)
|
9
|
+
module RdfHandler
|
6
10
|
|
7
|
-
#
|
8
|
-
# used this may compromise the integrity of the RDF data. However, it may
|
9
|
-
# be used in order to speed up "create" operations that save a record
|
10
|
-
# several times and don't need the RDF data in the meantime.
|
11
|
+
# Returns the value of the autosave_rdf flag, as set by autosave_rdf=
|
11
12
|
def autosave_rdf?
|
12
13
|
@autosave_rdf = true unless(defined?(@autosave_rdf))
|
13
14
|
@autosave_rdf
|
14
15
|
end
|
15
16
|
|
16
|
-
#
|
17
|
+
# This can be used to turn of automatic rdf creation. If set to true,
|
18
|
+
# create_rdf will *not* be called automatically after saving the source.
|
19
|
+
#
|
20
|
+
# *Attention*: Improper use will compromise the integrity of the RDF data.
|
21
|
+
# However, it may
|
22
|
+
# be used in order to speed up operations that save a record
|
23
|
+
# several times and don't need the RDF data in the meantime.
|
17
24
|
def autosave_rdf=(value)
|
18
25
|
@autosave_rdf = value
|
19
26
|
end
|
20
27
|
|
21
|
-
# Returns the RDF object to use for this ActiveSource
|
28
|
+
# Returns the RDF object to use for this ActiveSource. This
|
29
|
+
# will return a RdfResource, which has a similiar (but more
|
30
|
+
# limited API) than the ActiveSource itself. All operations and
|
31
|
+
# queries on that resource will go to the RDF store instead of the
|
32
|
+
# database
|
22
33
|
def my_rdf
|
23
34
|
@rdf_resource ||= begin
|
24
35
|
src = RdfResource.new(uri)
|
@@ -36,10 +47,20 @@ module TaliaCore
|
|
36
47
|
# will not changed, but if database objects were not added through the
|
37
48
|
# standard API they'll be missed
|
38
49
|
#
|
39
|
-
# The force option may have three values:
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
50
|
+
# The force option may have three values:
|
51
|
+
#
|
52
|
+
# [*false*] Normal operation. This retrieves the data for each of the
|
53
|
+
# cached SemanticCollectionWrappers that may have been modified and rewrites
|
54
|
+
# the respective attribute in the RDF store. (see the PredicateHandler
|
55
|
+
# module for an explanation of the wrapper cache). It will ignore wrappers that
|
56
|
+
# are obviously "clean", but will do a "retrieve and write" for each wrapper
|
57
|
+
# separately.
|
58
|
+
# [*force*] Force a complete rewrite of the RDF data for this source. This will erase the
|
59
|
+
# RDF and write all triples for this source in one go. It will also remove
|
60
|
+
# any triples for this source that may have been added externally.
|
61
|
+
# [*create*] Do not check for any existing data, just write out the data that is in the
|
62
|
+
# cache. This is fast, but must *only* be used for new sources where it is
|
63
|
+
# certain that no data for the source exists in the RDF store.
|
43
64
|
def create_rdf(force = :false)
|
44
65
|
self.class.benchmark("\033[32m\033[4m\033[1mActiveSource::RD\033[0m Creating RDF for source", Logger::DEBUG, false) do
|
45
66
|
assit(!new_record?, "Record must exist here: #{self.uri}")
|
@@ -58,6 +79,7 @@ module TaliaCore
|
|
58
79
|
# the value. If not the RDF handler will detect the #uri method and
|
59
80
|
# will add it as Resource.
|
60
81
|
obj = sem_ref.object
|
82
|
+
assit(obj, "Must have an object here. #{sem_ref.inspect}")
|
61
83
|
value = obj.is_a?(SemanticProperty) ? obj.value : obj
|
62
84
|
my_rdf.direct_write_predicate(N::URI.new(sem_ref.predicate_uri), value)
|
63
85
|
end
|
@@ -66,7 +88,8 @@ module TaliaCore
|
|
66
88
|
end
|
67
89
|
end
|
68
90
|
|
69
|
-
# Creates an RDF/XML resprentation of the source
|
91
|
+
# Creates an RDF/XML resprentation of the source. See the Xml::RdfBuilder and the
|
92
|
+
# Xml::SourceReader for more information.
|
70
93
|
def to_rdf
|
71
94
|
rdf = String.new
|
72
95
|
|
@@ -80,7 +103,9 @@ module TaliaCore
|
|
80
103
|
private
|
81
104
|
|
82
105
|
# Get the "standard" predicates to write (which is just the ones changed
|
83
|
-
# through the standard API. This will
|
106
|
+
# through the standard API. This will go through each of the cached
|
107
|
+
# SemanticCollectionWrapper(s) and it will erase the triples for each
|
108
|
+
# of the wrappers separately.
|
84
109
|
def prepare_predicates_to_write
|
85
110
|
preds_to_write = []
|
86
111
|
each_cached_wrapper do |wrap|
|
@@ -89,17 +114,17 @@ module TaliaCore
|
|
89
114
|
# Remove the existing data. TODO: Not using contexts
|
90
115
|
my_rdf.remove(N::URI.new(wrap.instance_variable_get(:@assoc_predicate)))
|
91
116
|
items = wrap.send(:items) # Get the items
|
92
|
-
items.each { |it| preds_to_write << it
|
117
|
+
items.each { |it| preds_to_write << it }
|
93
118
|
end
|
94
119
|
preds_to_write
|
95
120
|
end
|
96
121
|
|
97
122
|
# This will get all existing predicates from the database. This will also
|
98
|
-
# erase the rdf for this source completely
|
99
|
-
# TODO: Could load with a single sql
|
123
|
+
# erase the rdf for this source completely in one go
|
100
124
|
def prepare_all_predicates_to_write
|
125
|
+
# TODO: Could load with a single sql
|
101
126
|
my_rdf.clear_rdf # TODO: Not using contexts here
|
102
|
-
SemanticRelation.find(:all, :conditions => { :subject_id => self.id })
|
127
|
+
SemanticRelation.find(:all, :conditions => { :subject_id => self.id }, :include => [ :object ])
|
103
128
|
end
|
104
129
|
|
105
130
|
# ATTENTION: This is a speed hack that avoids the usual checks based
|
@@ -111,7 +136,7 @@ module TaliaCore
|
|
111
136
|
next if(wrap.clean?)
|
112
137
|
# Evil, we get the items directly to avoid a useless load
|
113
138
|
items = wrap.instance_variable_get(:@items)
|
114
|
-
items.each { |it| preds_to_create << it
|
139
|
+
items.each { |it| preds_to_create << it }
|
115
140
|
end
|
116
141
|
preds_to_create
|
117
142
|
end
|
@@ -125,6 +150,14 @@ module TaliaCore
|
|
125
150
|
def auto_create_rdf
|
126
151
|
create_rdf(:create) if(autosave_rdf?)
|
127
152
|
end
|
153
|
+
|
154
|
+
# Cleans out the RDF data before the source is destroyed
|
155
|
+
def clear_rdf
|
156
|
+
if autosave_rdf?
|
157
|
+
ActiveRDF::FederationManager.delete(self, :predicate, :object)
|
158
|
+
ActiveRDF::FederationManager.delete(:subject, :predicate, self)
|
159
|
+
end
|
160
|
+
end
|
128
161
|
|
129
162
|
end
|
130
163
|
end
|