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.
Files changed (122) hide show
  1. data/VERSION.yml +2 -2
  2. data/config/talia_core.yml.example +37 -35
  3. data/generators/talia_admin/templates/app/models/fake_source.rb +93 -0
  4. data/generators/talia_admin/templates/app/models/talia_collection.rb +13 -37
  5. data/generators/talia_base/talia_base_generator.rb +0 -1
  6. data/generators/talia_base/templates/app/controllers/custom_templates_controller.rb +2 -1
  7. data/generators/talia_base/templates/app/controllers/sources_controller.rb +1 -1
  8. data/generators/talia_base/templates/script/configure_talia +56 -73
  9. data/generators/talia_swicky/talia_swicky_generator.rb +18 -0
  10. data/generators/talia_swicky/templates/app/controllers/swicky_notebooks_controller.rb +111 -0
  11. data/generators/talia_swicky/templates/app/helpers/swicky_notebooks_helper.rb +29 -0
  12. data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.builder +6 -0
  13. data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.html.erb +10 -0
  14. data/generators/talia_swicky/templates/app/views/swicky_notebooks/show.html.erb +11 -0
  15. data/generators/talia_swicky/templates/test/fixtures/notebook.rdf +862 -0
  16. data/generators/talia_swicky/templates/test/functional/swicky_notebooks_controller_test.rb +44 -0
  17. data/lib/core_ext/boolean.rb +23 -0
  18. data/lib/core_ext/jdbc_rake_monkeypatch.rb +22 -0
  19. data/lib/core_ext/nil_class.rb +11 -0
  20. data/lib/core_ext/object.rb +34 -0
  21. data/lib/core_ext/string.rb +15 -0
  22. data/lib/custom_template.rb +3 -1
  23. data/lib/loader_helper.rb +16 -3
  24. data/lib/mysql.rb +7 -7
  25. data/lib/progressbar.rb +2 -2
  26. data/lib/swicky/exhibit_json/item.rb +129 -0
  27. data/lib/swicky/exhibit_json/item_collection.rb +129 -0
  28. data/lib/swicky/fragment.rb +0 -0
  29. data/lib/swicky/note.rb +7 -0
  30. data/lib/swicky/notebook.rb +78 -12
  31. data/lib/talia_core/active_source.rb +45 -13
  32. data/lib/talia_core/active_source_parts/class_methods.rb +154 -26
  33. data/lib/talia_core/active_source_parts/finders.rb +49 -26
  34. data/lib/talia_core/active_source_parts/predicate_handler.rb +71 -23
  35. data/lib/talia_core/active_source_parts/rdf/ntriples_reader.rb +13 -0
  36. data/lib/talia_core/active_source_parts/rdf/rdf_reader.rb +99 -0
  37. data/lib/talia_core/active_source_parts/rdf/rdfxml_reader.rb +12 -0
  38. data/lib/talia_core/active_source_parts/{rdf.rb → rdf_handler.rb} +52 -19
  39. data/lib/talia_core/active_source_parts/xml/generic_reader.rb +151 -260
  40. data/lib/talia_core/active_source_parts/xml/generic_reader_add_statements.rb +97 -0
  41. data/lib/talia_core/active_source_parts/xml/generic_reader_helpers.rb +88 -0
  42. data/lib/talia_core/active_source_parts/xml/generic_reader_import_statements.rb +239 -0
  43. data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +14 -7
  44. data/lib/talia_core/active_source_parts/xml/source_builder.rb +7 -3
  45. data/lib/talia_core/active_source_parts/xml/source_reader.rb +17 -2
  46. data/lib/talia_core/collection.rb +192 -1
  47. data/lib/talia_core/data_types/data_loader.rb +88 -18
  48. data/lib/talia_core/data_types/data_record.rb +24 -2
  49. data/lib/talia_core/data_types/delayed_copier.rb +13 -3
  50. data/lib/talia_core/data_types/file_record.rb +24 -13
  51. data/lib/talia_core/data_types/file_store.rb +111 -94
  52. data/lib/talia_core/data_types/iip_data.rb +104 -23
  53. data/lib/talia_core/data_types/iip_loader.rb +102 -56
  54. data/lib/talia_core/data_types/image_data.rb +3 -1
  55. data/lib/talia_core/data_types/media_link.rb +4 -1
  56. data/lib/talia_core/data_types/mime_mapping.rb +65 -38
  57. data/lib/talia_core/data_types/path_helpers.rb +23 -17
  58. data/lib/talia_core/data_types/pdf_data.rb +9 -6
  59. data/lib/talia_core/data_types/simple_text.rb +5 -4
  60. data/lib/talia_core/data_types/xml_data.rb +53 -25
  61. data/lib/talia_core/dummy_handler.rb +3 -2
  62. data/lib/talia_core/errors.rb +13 -27
  63. data/lib/talia_core/initializer.rb +44 -4
  64. data/lib/talia_core/oai/active_source_model.rb +13 -6
  65. data/lib/talia_core/oai/active_source_oai_adapter.rb +13 -12
  66. data/lib/talia_core/rdf_import.rb +1 -1
  67. data/lib/talia_core/rdf_resource.rb +2 -1
  68. data/lib/talia_core/semantic_collection_wrapper.rb +143 -151
  69. data/lib/talia_core/semantic_property.rb +4 -0
  70. data/lib/talia_core/semantic_relation.rb +84 -33
  71. data/lib/talia_core/source.rb +45 -25
  72. data/lib/talia_core/source_fragment.rb +7 -0
  73. data/lib/talia_core/source_transfer_object.rb +3 -1
  74. data/lib/talia_core/source_types/agent.rb +16 -0
  75. data/lib/talia_core/source_types/dc_resource.rb +3 -3
  76. data/lib/talia_core/source_types/marcont_resource.rb +15 -0
  77. data/lib/talia_core/source_types/skos_concept.rb +17 -0
  78. data/lib/talia_dependencies.rb +1 -1
  79. data/lib/talia_util.rb +1 -1
  80. data/lib/talia_util/bar_progressor.rb +1 -1
  81. data/lib/talia_util/image_conversions.rb +8 -2
  82. data/lib/talia_util/import_job_helper.rb +40 -3
  83. data/lib/talia_util/io_helper.rb +15 -4
  84. data/lib/talia_util/progressable.rb +50 -1
  85. data/lib/talia_util/rake_tasks.rb +3 -21
  86. data/lib/talia_util/test_helpers.rb +6 -1
  87. data/lib/talia_util/util.rb +108 -27
  88. data/lib/talia_util/xml/base_builder.rb +28 -1
  89. data/lib/talia_util/xml/rdf_builder.rb +81 -5
  90. data/lib/tasks/talia_core_tasks.rake +2 -0
  91. data/test/core_ext/boolean_test.rb +26 -0
  92. data/test/core_ext/nil_class_test.rb +14 -0
  93. data/test/core_ext/object_test.rb +26 -0
  94. data/test/core_ext/string_test.rb +11 -0
  95. data/test/swicky/json_encoder_test.rb +51 -42
  96. data/test/swicky/notebook_test.rb +13 -6
  97. data/test/talia_core/active_source_finder_interface_test.rb +30 -0
  98. data/test/talia_core/active_source_test.rb +445 -34
  99. data/test/talia_core/collection_test.rb +332 -0
  100. data/test/talia_core/data_types/file_record_test.rb +2 -23
  101. data/test/talia_core/ntriples_reader_test.rb +49 -0
  102. data/test/talia_core/rdfxml_reader_test.rb +51 -0
  103. data/test/talia_core/source_test.rb +12 -0
  104. data/test/talia_util/import_job_helper_test.rb +19 -12
  105. metadata +190 -90
  106. data/config/database.yml +0 -19
  107. data/config/rdfstore.yml +0 -13
  108. data/config/talia_core.yml +0 -24
  109. data/generators/talia_base/templates/migrations/bj_migration.rb +0 -10
  110. data/lib/JXslt/jxslt.rb +0 -60
  111. data/lib/swicky/json_encoder.rb +0 -179
  112. data/lib/talia_core/agent.rb +0 -14
  113. data/lib/talia_core/background_jobs/job.rb +0 -82
  114. data/lib/talia_core/background_jobs/progress_job.rb +0 -68
  115. data/lib/talia_core/data_types/temp_file_handling.rb +0 -85
  116. data/lib/talia_core/ordered_source.rb +0 -228
  117. data/lib/talia_core/semantic_collection_item.rb +0 -94
  118. data/lib/talia_core/source_types/collection.rb +0 -15
  119. data/lib/talia_util/progressbar.rb +0 -236
  120. data/tasks/talia_core_tasks.rake +0 -2
  121. data/test/talia_core/ordered_source_test.rb +0 -394
  122. 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
- # All class methods that are used for finding sources.
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
- # Finder also accepts uris as "ids". There are also some additional options
9
- # that are accepted:
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
- # [*:find_through*] accepts and array with an predicate name and an object
12
- # value/uri, to search for predicates that match the given predicate/value
13
- # combination
14
- # [*:type*] specifically looks for sources with the given type.
15
- # [*:find_through_inv*] like :find_through, but for the "inverse" lookup
16
- # [*:prefetch_relations*] if set to "true", this will pre-load all semantic
17
- # relations for the sources (experimental, not fully implemented yet)
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
- # Modify the count helper so that it can use the advanced options of the
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
- # Sources in system:
63
- # * http://talia.org/one
64
- # * http://talia.org/two
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 use a MySQL function, as sql condition, to find the local name of the uri.
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
- # It's useful for admin pane, because users visit:
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.size > 2) ? f_through[2] : !(obj_val.to_s =~ /:/)
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
- conditions = { :subject_id => src_hash.keys }
21
- joins = ActiveSource.sources_join
22
- joins << ActiveSource.props_join
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
- # Returns if the Facsimile is of the given type
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 objects on the given predicate. This will be cached internally
51
- # so that the object will always be the same as long as the parent source
52
- # lives.
53
- def get_objects_on(predicate)
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
- # Go through the existing relation wrappers and save the (new) items
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 existing wrapper to the block
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
- # Clear the source (this will force reloading of elements and discard
88
- # unsaved changes
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' predicate relation on a source
94
- def inject_predicate(fat_relation)
95
- wrapper = get_objects_on(fat_relation.predicate_uri)
96
- wrapper.inject_fat_item(fat_relation)
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,13 @@
1
+ module TaliaCore
2
+ module ActiveSourceParts
3
+ module Rdf
4
+ class NtriplesReader < RdfReader
5
+ require 'rdf/ntriples'
6
+ def format
7
+ :ntriples
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -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
@@ -0,0 +1,12 @@
1
+ module TaliaCore
2
+ module ActiveSourceParts
3
+ module Rdf
4
+ class RdfxmlReader < RdfReader
5
+ require 'rdf/raptor'
6
+ def format
7
+ :rdfxml
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,24 +1,35 @@
1
1
  module TaliaCore
2
2
  module ActiveSourceParts
3
3
 
4
- module Rdf
5
- # This file contains the RDF handling elements of the ActiveSource class
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
- # This can be used to turn of automatic rdf creation. *Attention:* Improperly
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
- # Set the autosave property. See autosave_rdf?
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: :false for normal operation,
40
- # :force for forcing a complete rewrite and :create - the latter will
41
- # avoid the cleaning of the elements in the RDF store in case the
42
- # source is completely new and no triples exist.
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 erase the
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.relation }
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.relation }
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