active-fedora 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/.hg/00changelog.i +0 -0
  4. data/.hg/branch +1 -0
  5. data/.hg/branch.cache +2 -0
  6. data/.hg/dirstate +0 -0
  7. data/.hg/hgrc +2 -0
  8. data/.hg/requires +2 -0
  9. data/.hg/store/00changelog.i +0 -0
  10. data/.hg/store/00manifest.i +0 -0
  11. data/.hg/store/data/.hgignore.i +0 -0
  12. data/.hg/store/data/.hgtags.i +0 -0
  13. data/.hg/store/data/_c_o_p_y_i_n_g.txt.i +0 -0
  14. data/.hg/store/data/_c_o_y_i_n_g._l_e_s_s_e_r.txt.i +0 -0
  15. data/.hg/store/data/_history.txt.i +0 -0
  16. data/.hg/store/data/_license.txt.i +0 -0
  17. data/.hg/store/data/_manifest.txt.i +0 -0
  18. data/.hg/store/data/_post_install.txt.i +0 -0
  19. data/.hg/store/data/_r_e_a_d_m_e.rdoc.i +0 -0
  20. data/.hg/store/data/_r_e_a_d_m_e.txt.i +0 -0
  21. data/.hg/store/data/_rakefile.i +0 -0
  22. data/.hg/store/data/_v_e_r_s_i_o_n.i +0 -0
  23. data/.hg/store/data/active-fedora.gemspec.i +0 -0
  24. data/.hg/store/data/active__fedora/_history.txt.i +0 -0
  25. data/.hg/store/data/active__fedora/_manifest.txt.i +0 -0
  26. data/.hg/store/data/active__fedora/_post_install.txt.i +0 -0
  27. data/.hg/store/data/active__fedora/_r_e_a_d_m_e.rdoc.i +0 -0
  28. data/.hg/store/data/active__fedora/_rakefile.i +0 -0
  29. data/.hg/store/data/active__fedora/lib/active__fedora.rb.i +0 -0
  30. data/.hg/store/data/active__fedora/script/console.i +0 -0
  31. data/.hg/store/data/active__fedora/script/destroy.i +0 -0
  32. data/.hg/store/data/active__fedora/script/generate.i +0 -0
  33. data/.hg/store/data/active__fedora/spec/active__fedora__spec.rb.i +0 -0
  34. data/.hg/store/data/active__fedora/spec/spec__helper.rb.i +0 -0
  35. data/.hg/store/data/config/fedora.yml.i +0 -0
  36. data/.hg/store/data/config/solr__mappings.yml.i +0 -0
  37. data/.hg/store/data/config/solr__mappings__af__0.1.yml.i +0 -0
  38. data/.hg/store/data/config/solr__mappings__bl__2.4.yml.i +0 -0
  39. data/.hg/store/data/lib/active-fedora.rb.i +0 -0
  40. data/.hg/store/data/lib/active__fedora.rb.i +0 -0
  41. data/.hg/store/data/lib/active__fedora/base.rb.i +0 -0
  42. data/.hg/store/data/lib/active__fedora/content__model.rb.i +0 -0
  43. data/.hg/store/data/lib/active__fedora/datastream.rb.i +0 -0
  44. data/.hg/store/data/lib/active__fedora/fedora__object.rb.i +0 -0
  45. data/.hg/store/data/lib/active__fedora/metadata__datastream.rb.i +0 -0
  46. data/.hg/store/data/lib/active__fedora/model.rb.i +0 -0
  47. data/.hg/store/data/lib/active__fedora/property.rb.i +0 -0
  48. data/.hg/store/data/lib/active__fedora/qualified__dublin__core__datastream.rb.i +0 -0
  49. data/.hg/store/data/lib/active__fedora/relationship.rb.i +0 -0
  50. data/.hg/store/data/lib/active__fedora/rels__ext__datastream.rb.i +0 -0
  51. data/.hg/store/data/lib/active__fedora/semantic__node.rb.i +0 -0
  52. data/.hg/store/data/lib/active__fedora/solr__mapper.rb.i +0 -0
  53. data/.hg/store/data/lib/active__fedora/solr__service.rb.i +0 -0
  54. data/.hg/store/data/lib/fedora/base.rb.i +0 -0
  55. data/.hg/store/data/lib/fedora/connection.rb.i +0 -0
  56. data/.hg/store/data/lib/fedora/datastream.rb.i +0 -0
  57. data/.hg/store/data/lib/fedora/fedora__object.rb.i +0 -0
  58. data/.hg/store/data/lib/fedora/formats.rb.i +0 -0
  59. data/.hg/store/data/lib/fedora/generic__search.rb.i +0 -0
  60. data/.hg/store/data/lib/fedora/repository.rb.i +0 -0
  61. data/.hg/store/data/lib/ruby-fedora.rb.i +0 -0
  62. data/.hg/store/data/lib/util/class__level__inheritable__attributes.rb.i +0 -0
  63. data/.hg/store/data/script/console.i +0 -0
  64. data/.hg/store/data/script/destroy.i +0 -0
  65. data/.hg/store/data/script/generate.i +0 -0
  66. data/.hg/store/data/solr/config/schema-1.5.xml.i +0 -0
  67. data/.hg/store/data/solr/config/schema.xml.i +0 -0
  68. data/.hg/store/data/solr/config/solrconfig-1.5.xml.i +0 -0
  69. data/.hg/store/data/spec/fixtures/changeme155.xml.i +0 -0
  70. data/.hg/store/data/spec/fixtures/dino.jpg.i +0 -0
  71. data/.hg/store/data/spec/fixtures/minivan.jpg.d +0 -0
  72. data/.hg/store/data/spec/fixtures/minivan.jpg.i +0 -0
  73. data/.hg/store/data/spec/fixtures/test__12.foxml.xml.i +0 -0
  74. data/.hg/store/data/spec/integration/active__fedora/base__spec.rb.i +0 -0
  75. data/.hg/store/data/spec/integration/active__fedora/datastream__spec.rb.i +0 -0
  76. data/.hg/store/data/spec/integration/active__fedora/fedora__object__spec.rb.i +0 -0
  77. data/.hg/store/data/spec/integration/active__fedora/full__featured__model__spec.rb.i +0 -0
  78. data/.hg/store/data/spec/integration/active__fedora/model__spec.rb.i +0 -0
  79. data/.hg/store/data/spec/integration/active__fedora/rels__ext__datastream__spec.rb.i +0 -0
  80. data/.hg/store/data/spec/integration/active__fedora/semantic__node__spec.rb.i +0 -0
  81. data/.hg/store/data/spec/integration/base__file__management__spec.rb.i +0 -0
  82. data/.hg/store/data/spec/integration/base__spec.rb.i +0 -0
  83. data/.hg/store/data/spec/integration/bug__spec.rb.i +0 -0
  84. data/.hg/store/data/spec/integration/datastream__spec.rb.i +0 -0
  85. data/.hg/store/data/spec/integration/datastreams__crud__spec.rb.i +0 -0
  86. data/.hg/store/data/spec/integration/fedora__object__spec.rb.i +0 -0
  87. data/.hg/store/data/spec/integration/full__featured__model__spec.rb.i +0 -0
  88. data/.hg/store/data/spec/integration/model__spec.rb.i +0 -0
  89. data/.hg/store/data/spec/integration/rels__ext__datastream__spec.rb.i +0 -0
  90. data/.hg/store/data/spec/integration/repository__spec.rb.i +0 -0
  91. data/.hg/store/data/spec/integration/rf__fedora__object__spec.rb.i +0 -0
  92. data/.hg/store/data/spec/integration/semantic__node__spec.rb.i +0 -0
  93. data/.hg/store/data/spec/integration/solr__service__spec.rb.i +0 -0
  94. data/.hg/store/data/spec/samples/models/audio__record.rb.i +0 -0
  95. data/.hg/store/data/spec/samples/models/image.rb.i +0 -0
  96. data/.hg/store/data/spec/samples/models/oral__history.rb.i +0 -0
  97. data/.hg/store/data/spec/samples/models/seminar.rb.i +0 -0
  98. data/.hg/store/data/spec/samples/models/seminar__audio__file.rb.i +0 -0
  99. data/.hg/store/data/spec/samples/oh__qdc.xml.i +0 -0
  100. data/.hg/store/data/spec/samples/oral__history.rb.i +0 -0
  101. data/.hg/store/data/spec/samples/oral__history__sample.xml.i +0 -0
  102. data/.hg/store/data/spec/samples/oral__history__sample__model.rb.i +0 -0
  103. data/.hg/store/data/spec/samples/oral__history__xml.xml.i +0 -0
  104. data/.hg/store/data/spec/spec.opts.i +0 -0
  105. data/.hg/store/data/spec/spec__helper.rb.i +0 -0
  106. data/.hg/store/data/spec/unit/active__fedora/base__cma__spec.rb.i +0 -0
  107. data/.hg/store/data/spec/unit/active__fedora/base__extra__spec.rb.i +0 -0
  108. data/.hg/store/data/spec/unit/active__fedora/base__spec.rb.i +0 -0
  109. data/.hg/store/data/spec/unit/active__fedora/content__model__spec.rb.i +0 -0
  110. data/.hg/store/data/spec/unit/active__fedora/datastream__spec.rb.i +0 -0
  111. data/.hg/store/data/spec/unit/active__fedora/inheritance__spec.rb.i +0 -0
  112. data/.hg/store/data/spec/unit/active__fedora/metadata__datastream__spec.rb.i +0 -0
  113. data/.hg/store/data/spec/unit/active__fedora/model__spec.rb.i +0 -0
  114. data/.hg/store/data/spec/unit/active__fedora/property__spec.rb.i +0 -0
  115. data/.hg/store/data/spec/unit/active__fedora/qualified__dublin__core__datastream__spec.rb.i +0 -0
  116. data/.hg/store/data/spec/unit/active__fedora/relationship__spec.rb.i +0 -0
  117. data/.hg/store/data/spec/unit/active__fedora/rels__ext__datastream__spec.rb.i +0 -0
  118. data/.hg/store/data/spec/unit/active__fedora/semantic__node__spec.rb.i +0 -0
  119. data/.hg/store/data/spec/unit/active__fedora/solr__service__spec.rb.i +0 -0
  120. data/.hg/store/data/spec/unit/active__fedora__spec.rb.i +0 -0
  121. data/.hg/store/data/spec/unit/base__cma__spec.rb.i +0 -0
  122. data/.hg/store/data/spec/unit/base__datastream__management__spec.rb.i +0 -0
  123. data/.hg/store/data/spec/unit/base__extra__spec.rb.i +0 -0
  124. data/.hg/store/data/spec/unit/base__file__management__spec.rb.i +0 -0
  125. data/.hg/store/data/spec/unit/base__loader__spec.rb.i +0 -0
  126. data/.hg/store/data/spec/unit/base__spec.rb.i +0 -0
  127. data/.hg/store/data/spec/unit/connection__spec.rb.i +0 -0
  128. data/.hg/store/data/spec/unit/content__model__spec.rb.i +0 -0
  129. data/.hg/store/data/spec/unit/datastream__concurrency__spec.rb.i +0 -0
  130. data/.hg/store/data/spec/unit/datastream__spec.rb.i +0 -0
  131. data/.hg/store/data/spec/unit/fedora__object__spec.rb.i +0 -0
  132. data/.hg/store/data/spec/unit/inheritance__spec.rb.i +0 -0
  133. data/.hg/store/data/spec/unit/metadata__datastream__spec.rb.i +0 -0
  134. data/.hg/store/data/spec/unit/model__spec.rb.i +0 -0
  135. data/.hg/store/data/spec/unit/property__spec.rb.i +0 -0
  136. data/.hg/store/data/spec/unit/qualified__dublin__core__datastream__spec.rb.i +0 -0
  137. data/.hg/store/data/spec/unit/relationship__spec.rb.i +0 -0
  138. data/.hg/store/data/spec/unit/rels__ext__datastream__spec.rb.i +0 -0
  139. data/.hg/store/data/spec/unit/repository__spec.rb.i +0 -0
  140. data/.hg/store/data/spec/unit/rf__datastream__spec.rb.i +0 -0
  141. data/.hg/store/data/spec/unit/semantic__node__spec.rb.i +0 -0
  142. data/.hg/store/data/spec/unit/solr__config__options__spec.rb.i +0 -0
  143. data/.hg/store/data/spec/unit/solr__mapper__spec.rb.i +0 -0
  144. data/.hg/store/data/spec/unit/solr__service__spec.rb.i +0 -0
  145. data/.hg/store/data/tasks/rspec.rake.i +0 -0
  146. data/.hg/store/undo +0 -0
  147. data/.hg/undo.branch +1 -0
  148. data/.hg/undo.dirstate +0 -0
  149. data/.hgignore +7 -0
  150. data/.hgtags +14 -0
  151. data/COPYING.txt +674 -0
  152. data/COYING.LESSER.txt +165 -0
  153. data/History.txt +34 -0
  154. data/LICENSE +20 -0
  155. data/License.txt +58 -0
  156. data/Manifest.txt +1 -1
  157. data/README.rdoc +13 -54
  158. data/README.txt +59 -0
  159. data/Rakefile +35 -0
  160. data/VERSION +1 -0
  161. data/active-fedora.gemspec +359 -0
  162. data/config/fedora.yml +16 -0
  163. data/config/solr_mappings.yml +14 -0
  164. data/config/solr_mappings_af_0.1.yml +16 -0
  165. data/config/solr_mappings_bl_2.4.yml +14 -0
  166. data/lib/active_fedora.rb +66 -6
  167. data/lib/active_fedora/base.rb +59 -23
  168. data/lib/active_fedora/datastream.rb +1 -1
  169. data/lib/active_fedora/metadata_datastream.rb +14 -7
  170. data/lib/active_fedora/model.rb +4 -4
  171. data/lib/active_fedora/rels_ext_datastream.rb +1 -1
  172. data/lib/active_fedora/semantic_node.rb +4 -3
  173. data/lib/active_fedora/solr_mapper.rb +17 -0
  174. data/lib/active_fedora/solr_service.rb +44 -2
  175. data/lib/fedora/base.rb +38 -0
  176. data/lib/fedora/connection.rb +210 -0
  177. data/lib/fedora/datastream.rb +56 -0
  178. data/lib/fedora/fedora_object.rb +161 -0
  179. data/lib/fedora/formats.rb +30 -0
  180. data/lib/fedora/generic_search.rb +71 -0
  181. data/lib/fedora/repository.rb +287 -0
  182. data/lib/ruby-fedora.rb +20 -0
  183. data/lib/util/class_level_inheritable_attributes.rb +23 -0
  184. data/script/console +15 -0
  185. data/script/destroy +14 -0
  186. data/script/generate +14 -0
  187. data/solr/config/schema-1.5.xml +468 -0
  188. data/solr/config/schema.xml +174 -212
  189. data/solr/config/solrconfig-1.5.xml +1069 -0
  190. data/spec/active_fedora_spec.rb +7 -0
  191. data/spec/fixtures/changeme155.xml +255 -0
  192. data/spec/fixtures/dino.jpg +0 -0
  193. data/spec/fixtures/minivan.jpg +0 -0
  194. data/spec/fixtures/test_12.foxml.xml +121 -0
  195. data/spec/integration/base_file_management_spec.rb +20 -0
  196. data/spec/integration/base_spec.rb +196 -0
  197. data/spec/integration/bug_spec.rb +57 -0
  198. data/spec/integration/datastream_spec.rb +60 -0
  199. data/spec/integration/datastreams_crud_spec.rb +208 -0
  200. data/spec/integration/fedora_object_spec.rb +77 -0
  201. data/spec/integration/full_featured_model_spec.rb +207 -0
  202. data/spec/integration/model_spec.rb +54 -0
  203. data/spec/integration/rels_ext_datastream_spec.rb +67 -0
  204. data/spec/integration/repository_spec.rb +297 -0
  205. data/spec/integration/rf_fedora_object_spec.rb +95 -0
  206. data/spec/integration/semantic_node_spec.rb +95 -0
  207. data/spec/integration/solr_service_spec.rb +33 -0
  208. data/spec/samples/models/audio_record.rb +29 -0
  209. data/spec/samples/models/image.rb +5 -0
  210. data/spec/samples/models/oral_history.rb +50 -0
  211. data/spec/samples/models/seminar.rb +29 -0
  212. data/spec/samples/models/seminar_audio_file.rb +34 -0
  213. data/spec/samples/oh_qdc.xml +32 -0
  214. data/spec/samples/oral_history_sample.xml +38 -0
  215. data/spec/samples/oral_history_sample_model.rb +39 -0
  216. data/spec/samples/oral_history_xml.xml +35 -0
  217. data/spec/spec.opts +5 -0
  218. data/spec/spec_helper.rb +41 -0
  219. data/spec/unit/active_fedora_spec.rb +15 -0
  220. data/spec/unit/base_cma_spec.rb +25 -0
  221. data/spec/unit/base_datastream_management_spec.rb +119 -0
  222. data/spec/unit/base_extra_spec.rb +108 -0
  223. data/spec/unit/base_file_management_spec.rb +90 -0
  224. data/spec/unit/base_loader_spec.rb +43 -0
  225. data/spec/unit/base_spec.rb +584 -0
  226. data/spec/unit/connection_spec.rb +25 -0
  227. data/spec/unit/content_model_spec.rb +51 -0
  228. data/spec/unit/datastream_concurrency_spec.rb +59 -0
  229. data/spec/unit/datastream_spec.rb +85 -0
  230. data/spec/unit/fedora_object_spec.rb +66 -0
  231. data/spec/unit/inheritance_spec.rb +46 -0
  232. data/spec/unit/metadata_datastream_spec.rb +290 -0
  233. data/spec/unit/model_spec.rb +186 -0
  234. data/spec/unit/property_spec.rb +50 -0
  235. data/spec/unit/qualified_dublin_core_datastream_spec.rb +177 -0
  236. data/spec/unit/relationship_spec.rb +77 -0
  237. data/spec/unit/rels_ext_datastream_spec.rb +99 -0
  238. data/spec/unit/repository_spec.rb +136 -0
  239. data/spec/unit/rf_datastream_spec.rb +49 -0
  240. data/spec/unit/semantic_node_spec.rb +354 -0
  241. data/spec/unit/solr_config_options_spec.rb +98 -0
  242. data/spec/unit/solr_mapper_spec.rb +31 -0
  243. data/spec/unit/solr_service_spec.rb +83 -0
  244. data/tasks/hoe.rake +0 -0
  245. data/tasks/rspec.rake +29 -0
  246. metadata +373 -55
@@ -6,7 +6,7 @@ SOLR_DOCUMENT_ID = "id" unless defined?(SOLR_DOCUMENT_ID)
6
6
  ENABLE_SOLR_UPDATES = true unless defined?(ENABLE_SOLR_UPDATES)
7
7
 
8
8
  module ActiveFedora
9
-
9
+
10
10
  # This class ties together many of the lower-level modules, and
11
11
  # implements something akin to an ActiveRecord-alike interface to
12
12
  # fedora. If you want to represent a fedora object in the ruby
@@ -32,6 +32,7 @@ module ActiveFedora
32
32
  ms_inheritable_attributes :ds_specs
33
33
  include Model
34
34
  include SemanticNode
35
+ include SolrMapper
35
36
 
36
37
  has_relationship "collection_members", :has_collection_member
37
38
 
@@ -56,7 +57,7 @@ module ActiveFedora
56
57
  attrs = attrs.merge!({:pid=>Fedora::Repository.instance.nextid})
57
58
  @new_object=true
58
59
  else
59
- @new_object=false
60
+ @new_object = attrs[:new_object] == false ? false : true
60
61
  end
61
62
  @inner_object = Fedora::FedoraObject.new(attrs)
62
63
  @datastreams = {}
@@ -75,23 +76,24 @@ module ActiveFedora
75
76
  #Saves a Base object, and any dirty datastreams, then updates
76
77
  #the Solr index for this object.
77
78
  def save
78
- metadata_is_dirty = false
79
+ #@metadata_is_dirty = false
79
80
  # If it's a new object, set the conformsTo relationship for Fedora CMA
80
81
  if new_object?
81
- add_relationship(:conforms_to, ActiveFedora::ContentModel.pid_from_ruby_class(self.class))
82
- metadata_is_dirty = true
82
+ result = create
83
+ else
84
+ result = update
83
85
  end
84
86
  @new_object = false
85
- Fedora::Repository.instance.save(@inner_object)
86
- datastreams_in_memory.each do |k,ds|
87
- if ds.dirty? || ds.new_object?
88
- if ds.kind_of?(ActiveFedora::MetadataDatastream) || ds.instance_of?(ActiveFedora::RelsExtDatastream)
89
- metadata_is_dirty = true
90
- end
91
- ds.save
92
- end
93
- end
94
- self.update_index if metadata_is_dirty == true && ENABLE_SOLR_UPDATES
87
+ self.update_index if @metadata_is_dirty == true && ENABLE_SOLR_UPDATES
88
+ @metadata_is_dirty == false
89
+ return result
90
+ end
91
+
92
+ # Refreshes the object's info from Fedora
93
+ # Note: Currently just registers any new datastreams that have appeared in fedora
94
+ def refresh
95
+ inner_object.load_attributes_from_fedora
96
+ @datastreams = datastreams_in_fedora.merge(datastreams_in_memory)
95
97
  end
96
98
 
97
99
  #Deletes a Base object, also deletes the info indexed in Solr, and
@@ -115,7 +117,8 @@ module ActiveFedora
115
117
  if @new_object
116
118
  @datastreams = datastreams_in_memory
117
119
  else
118
- @datastreams = datastreams_in_fedora.merge(datastreams_in_memory)
120
+ @datastreams = (@datastreams == {}) ? datastreams_in_fedora : datastreams_in_memory
121
+ #@datastreams = datastreams_in_fedora.merge(datastreams_in_memory)
119
122
  end
120
123
 
121
124
  end
@@ -327,10 +330,11 @@ module ActiveFedora
327
330
  def self.deserialize(doc) #:nodoc:
328
331
  pid = doc.elements['/foxml:digitalObject'].attributes['PID']
329
332
 
330
- proto = self.new(:pid=>pid)
333
+ proto = self.new(:pid=>pid, :new_object=>false)
331
334
  proto.datastreams.each do |name,ds|
332
- ds.new_object = false
333
335
  doc.elements.each("//foxml:datastream[@ID='#{name}']") do |el|
336
+ # datastreams remain marked as new if the foxml doesn't have an entry for that datastream
337
+ ds.new_object = false
334
338
  proto.datastreams[name]=ds.class.from_xml(ds, el)
335
339
  end
336
340
  end
@@ -343,7 +347,7 @@ module ActiveFedora
343
347
  #system_create_date, system_modified_date, active_fedora_model_field,
344
348
  #and the object id.
345
349
  def fields
346
- fields = {:id => {:values => [pid]}, :system_create_date => {:values => [self.create_date]}, :system_modified_date => {:values => [self.modified_date]}, :active_fedora_model_field => {:values => [self.class.inspect]}}
350
+ fields = {:id => {:values => [pid]}, :system_create_date => {:values => [self.create_date], :type=>:date}, :system_modified_date => {:values => [self.modified_date], :type=>:date}, :active_fedora_model => {:values => [self.class.inspect], :type=>:symbol}}
347
351
  datastreams.values.each do |ds|
348
352
  fields.merge!(ds.fields) if ds.kind_of?(ActiveFedora::MetadataDatastream)
349
353
  end
@@ -353,7 +357,7 @@ module ActiveFedora
353
357
  #Returns the xml version of this object as a string.
354
358
  def to_xml(xml=REXML::Document.new("<xml><fields/><content/></xml>"))
355
359
  fields_xml = xml.root.elements['fields']
356
- {:id => pid, :system_create_date => self.create_date, :system_modified_date => self.modified_date, :active_fedora_model_field => self.class.inspect}.each_pair do |attribute_name, value|
360
+ {:id => pid, :system_create_date => self.create_date, :system_modified_date => self.modified_date, :active_fedora_model => self.class.inspect}.each_pair do |attribute_name, value|
357
361
  el = REXML::Element.new(attribute_name.to_s)
358
362
  el.text = value
359
363
  fields_xml << el
@@ -366,7 +370,7 @@ module ActiveFedora
366
370
 
367
371
  #Return a Solr::Document version of this object.
368
372
  def to_solr(solr_doc = Solr::Document.new)
369
- solr_doc << {SOLR_DOCUMENT_ID.to_sym => pid, :system_create_date => self.create_date, :system_modified_date => self.modified_date, :active_fedora_model_field => self.class.inspect}
373
+ solr_doc << {SOLR_DOCUMENT_ID.to_sym => pid, solr_name(:system_create, :date) => self.create_date, solr_name(:system_modified, :date) => self.modified_date, solr_name(:active_fedora_model, :symbol) => self.class.inspect}
370
374
  datastreams.each_value do |ds|
371
375
  solr_doc = ds.to_solr(solr_doc) if ds.kind_of?(ActiveFedora::MetadataDatastream) || ds.kind_of?(ActiveFedora::RelsExtDatastream)
372
376
  end
@@ -440,7 +444,9 @@ module ActiveFedora
440
444
  else
441
445
  ds_array = datastreams.values
442
446
  end
447
+ result = params.dup
443
448
  params.each do |key,value|
449
+ result[key] = value.dup
444
450
  ds_array.each do |dstream|
445
451
  if dstream.fields[key.to_sym]
446
452
  aname="#{key}_values"
@@ -454,13 +460,20 @@ module ActiveFedora
454
460
  false
455
461
  end
456
462
  end
457
- cpv.each { |y,z| curval<<z}#just append everything left
463
+ cpv.each do |y,z|
464
+ curval<<z #just append everything left
465
+ if y == "-1"
466
+ new_array_index = curval.length - 1
467
+ result[key][new_array_index.to_s] = params[key]["-1"]
468
+ end
469
+ end
458
470
  curval.delete_if {|x| x == :delete || x == "" || x == nil}
459
471
  dstream.send("#{aname}=", curval) #write it back to the ds
460
472
  end
461
473
  end
474
+ result[key].delete("-1")
462
475
  end
463
-
476
+ return result
464
477
  end
465
478
 
466
479
  def self.pids_from_uris(uris)
@@ -485,6 +498,29 @@ module ActiveFedora
485
498
  end
486
499
  end
487
500
  end
501
+
502
+ # Deals with preparing new object to be saved to Fedora, then pushes it and its datastreams into Fedora.
503
+ def create
504
+ add_relationship(:has_model, ActiveFedora::ContentModel.pid_from_ruby_class(self.class))
505
+ @metadata_is_dirty = true
506
+ update
507
+ #@datastreams = datastreams_in_fedora
508
+ end
509
+
510
+ # Pushes the object and all of its new or dirty datastreams into Fedora
511
+ def update
512
+ result = Fedora::Repository.instance.save(@inner_object)
513
+ datastreams_in_memory.each do |k,ds|
514
+ if ds.dirty? || ds.new_object?
515
+ if ds.kind_of?(ActiveFedora::MetadataDatastream) || ds.instance_of?(ActiveFedora::RelsExtDatastream)
516
+ @metadata_is_dirty = true
517
+ end
518
+ result = ds.save
519
+ end
520
+ end
521
+ refresh
522
+ return result
523
+ end
488
524
 
489
525
 
490
526
  end
@@ -6,7 +6,7 @@ module ActiveFedora
6
6
 
7
7
  attr_accessor :dirty, :last_modified, :fields
8
8
 
9
- def initialize(attrs = nil)
9
+ def initialize(attrs = {})
10
10
  @fields={}
11
11
  @dirty = false
12
12
  super
@@ -1,6 +1,9 @@
1
1
  module ActiveFedora
2
2
  #this class represents a MetadataDatastream, a special case of ActiveFedora::Datastream
3
3
  class MetadataDatastream < Datastream
4
+
5
+ include ActiveFedora::SolrMapper
6
+
4
7
  attr_accessor :fields
5
8
 
6
9
  #constructor, calls up to ActiveFedora::Datastream's constructor
@@ -110,13 +113,17 @@ module ActiveFedora
110
113
  protected
111
114
 
112
115
  def generate_solr_symbol(field_name, field_type) # :nodoc:
113
- if field_name.to_s[-field_type.to_s.length - 1 .. -1] == "_#{field_type.to_s}"
114
- return field_name.to_sym
115
- elsif field_type == :string
116
- return "#{field_name.to_s}_field".to_sym
117
- else
118
- return "#{field_name.to_s}_#{field_type.to_s}".to_sym
119
- end
116
+ solr_name(field_name, field_type)
117
+ # #if field_name.to_s[-field_type.to_s.length - 1 .. -1] == "_#{field_type.to_s}"
118
+ # # return field_name.to_sym
119
+ # case field_type
120
+ # when :date
121
+ # return "#{field_name.to_s}_dt".to_sym
122
+ # when :string
123
+ # return "#{field_name.to_s}_t".to_sym
124
+ # else
125
+ # return "#{field_name.to_s}_t".to_sym
126
+ # end
120
127
  end
121
128
 
122
129
  end
@@ -56,14 +56,14 @@ module ActiveFedora
56
56
  def find(args)
57
57
  if args == :all
58
58
  escaped_class_name = self.name.gsub(/(:)/, '\\:')
59
- q = "active_fedora_model_field:#{escaped_class_name}"
59
+ q = "active_fedora_model_s:#{escaped_class_name}"
60
60
  elsif args.class == String
61
61
  escaped_id = args.gsub(/(:)/, '\\:')
62
62
  q = "#{SOLR_DOCUMENT_ID}:#{escaped_id}"
63
63
  end
64
64
  hits = SolrService.instance.conn.query(q).hits
65
65
  results = hits.map do |hit|
66
- obj = Fedora::Repository.instance.find_model(hit["id"], self)
66
+ obj = Fedora::Repository.instance.find_model(hit[SOLR_DOCUMENT_ID], self)
67
67
  #obj.inner_object.new_object = false
68
68
  #return obj
69
69
  end
@@ -77,7 +77,7 @@ module ActiveFedora
77
77
 
78
78
 
79
79
  # If query is :all, this method will query Solr for all instances
80
- # of self.type (based on active_fedora_model_field as indexed
80
+ # of self.type (based on active_fedora_model_s as indexed
81
81
  # by Solr). If the query is any other string, this method simply does
82
82
  # a pid based search (id:query).
83
83
  #
@@ -89,7 +89,7 @@ module ActiveFedora
89
89
  def find_by_solr(query, args={})
90
90
  if query == :all
91
91
  escaped_class_name = self.name.gsub(/(:)/, '\\:')
92
- SolrService.instance.conn.query("active_fedora_model_field:#{escaped_class_name}", args)
92
+ SolrService.instance.conn.query("active_fedora_model_s:#{escaped_class_name}", args)
93
93
  elsif query.class == String
94
94
  escaped_id = query.gsub(/(:)/, '\\:')
95
95
  SolrService.instance.conn.query("#{SOLR_DOCUMENT_ID}:#{escaped_id}", args)
@@ -43,7 +43,7 @@ module ActiveFedora
43
43
  if subject == :self || subject == "info:fedora/#{self.pid}"
44
44
  predicates.each_pair do |predicate, values|
45
45
  values.each do |val|
46
- solr_doc << Solr::Field.new("#{predicate}_field" => val)
46
+ solr_doc << Solr::Field.new("#{predicate}_s" => val)
47
47
  end
48
48
  end
49
49
  end
@@ -26,7 +26,8 @@ module ActiveFedora
26
26
  :is_annotation_of => "isAnnotationOf",
27
27
  :has_annotation => "hasAnnotation",
28
28
  :has_equivalent => "hasEquivalent",
29
- :conforms_to => "conformsTo"]
29
+ :conforms_to => "conformsTo",
30
+ :has_model => "hasModel"]
30
31
  PREDICATE_MAPPINGS.freeze
31
32
 
32
33
  def self.included(klass)
@@ -147,14 +148,14 @@ module ActiveFedora
147
148
  class_eval <<-END
148
149
  def #{name}(opts={})
149
150
  escaped_uri = self.internal_uri.gsub(/(:)/, '\\:')
150
- solr_result = SolrService.instance.conn.query("#{predicate}_field:\#{escaped_uri}")
151
+ solr_result = SolrService.instance.conn.query("#{predicate}_s:\#{escaped_uri}")
151
152
  if opts[:response_format] == :solr
152
153
  return solr_result
153
154
  else
154
155
  if opts[:response_format] == :id_array
155
156
  id_array = []
156
157
  solr_result.hits.each do |hit|
157
- id_array << hit["id"]
158
+ id_array << hit[SOLR_DOCUMENT_ID]
158
159
  end
159
160
  return id_array
160
161
  else
@@ -0,0 +1,17 @@
1
+ require 'active_fedora/solr_service'
2
+
3
+ module ActiveFedora
4
+ module SolrMapper
5
+
6
+ # Generates solr field names from settings in solr_mappings
7
+ def solr_name(field_name, field_type)
8
+ name = field_name.to_s + ActiveFedora::SolrService.mappings[field_type.to_s].to_s
9
+ if field_name.kind_of?(Symbol)
10
+ return name.to_sym
11
+ else
12
+ return name.to_s
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -1,7 +1,9 @@
1
1
  require 'solr'
2
2
  module ActiveFedora
3
3
  class SolrService
4
+ @@mappings = {}
4
5
  attr_reader :conn
6
+
5
7
  def self.register(host=nil, args={})
6
8
  Thread.current[:solr_service]=self.new(host, args)
7
9
 
@@ -11,26 +13,29 @@ module ActiveFedora
11
13
  opts = {:autocommit=>:on}.merge(args)
12
14
  @conn = Solr::Connection.new(host, opts)
13
15
  end
16
+
14
17
  def self.instance
15
18
  raise SolrNotInitialized unless Thread.current[:solr_service]
16
19
  Thread.current[:solr_service]
17
20
  end
21
+
18
22
  def self.reify_solr_results(solr_result)
19
23
  unless solr_result.is_a?(Solr::Response::Standard)
20
24
  raise ArgumentError.new("Only solr responses (Solr::Response::Standard) are allowed. You provided a #{solr_result.class}")
21
25
  end
22
26
  results = []
23
27
  solr_result.hits.each do |hit|
24
- model_value = hit["active_fedora_model_field"].first
28
+ model_value = hit["active_fedora_model_s"].first
25
29
  if model_value.include?("::")
26
30
  classname = eval(model_value)
27
31
  else
28
32
  classname = Kernel.const_get(model_value)
29
33
  end
30
- results << Fedora::Repository.instance.find_model(hit["id"], classname)
34
+ results << Fedora::Repository.instance.find_model(hit[SOLR_DOCUMENT_ID], classname)
31
35
  end
32
36
  return results
33
37
  end
38
+
34
39
  def self.construct_query_for_pids(pid_array)
35
40
  query = ""
36
41
  pid_array.each_index do |i|
@@ -40,9 +45,46 @@ module ActiveFedora
40
45
  query = "id:NEVER_USE_THIS_ID" if query.empty? || query == "id:"
41
46
  return query
42
47
  end
48
+
43
49
  def self.escape_uri_for_query(uri)
44
50
  return uri.gsub(/(:)/, '\\:')
45
51
  end
52
+
53
+ def self.mappings
54
+ @@mappings
55
+ end
56
+ def self.mappings=(mappings)
57
+ @@mappings = mappings
58
+ end
59
+
60
+ def self.logger
61
+ @logger ||= defined?(RAILS_DEFAULT_LOGGER) ? RAILS_DEFAULT_LOGGER : Logger.new(STDOUT)
62
+ end
63
+
64
+ # Loads solr mappings from yml file.
65
+ # @config_path This is the path to the directory where your mappings file is stored. @default "RAILS_ROOT/config/solr_mappings.yml"
66
+ # @mappings_file This is the filename for your solr mappings YAML file. @default solr_mappings.yml
67
+ def self.load_mappings( config_path=nil )
68
+
69
+ if config_path.nil?
70
+ if defined?(RAILS_ROOT)
71
+ config_path = File.join(RAILS_ROOT, "config", "solr_mappings.yml")
72
+ end
73
+ # Default to using the config file within the gem
74
+ if !File.exist?(config_path.to_s)
75
+ config_path = File.join(File.dirname(__FILE__), "..", "..", "config", "solr_mappings.yml")
76
+ end
77
+ end
78
+
79
+ logger.info("FEDORA: loading SolrService mappings from #{File.expand_path(config_path)}")
80
+
81
+ @@mappings = YAML::load(File.open(config_path))
82
+
83
+ mappings["id"] = "id" unless mappings["id"]
84
+ end
85
+
86
+ self.load_mappings
87
+
46
88
  end
47
89
  class SolrNotInitialized < StandardError;end
48
90
  end
@@ -0,0 +1,38 @@
1
+ require 'xmlsimple'
2
+
3
+ class Hash
4
+ # {:q => 'test', :num => 5}.to_query # => 'q=test&num=5'
5
+ # let's avoid stomping on rails' version eh?
6
+ def to_fedora_query
7
+ self.collect { |key, value| "#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}" }.sort * '&'
8
+ end
9
+
10
+ def self.from_xml(xml)
11
+ XmlSimple.xml_in(xml, 'ForceArray' => false)
12
+ end
13
+ end
14
+
15
+ class Fedora::BaseObject
16
+ attr_accessor :attributes, :blob, :uri
17
+ attr_reader :errors, :uri
18
+ attr_writer :new_object
19
+
20
+ # == Parameters
21
+ # attrs<Hash>:: object attributes
22
+ #-
23
+ def initialize(attrs = {})
24
+ @new_object = true
25
+ @attributes = attrs || {}
26
+ @errors = []
27
+ @blob = attributes.delete(:blob)
28
+ @repository = Fedora::Repository.instance
29
+ end
30
+
31
+ def [](key)
32
+ @attributes[key]
33
+ end
34
+
35
+ def new_object?
36
+ @new_object
37
+ end
38
+ end
@@ -0,0 +1,210 @@
1
+ require "base64"
2
+ gem 'multipart-post'
3
+ require 'net/http/post/multipart'
4
+ require 'cgi'
5
+ require "mime/types"
6
+ require 'net/http'
7
+ require 'net/https'
8
+
9
+
10
+
11
+ module Fedora
12
+ # This class is based on ActiveResource::Connection so MIT license applies.
13
+ class ConnectionError < StandardError # :nodoc:
14
+ attr_reader :response
15
+
16
+ def initialize(response, message = nil)
17
+ @response = response
18
+ @message = message
19
+ end
20
+
21
+ def to_s
22
+ "Failed with #{response.code} #{response.message if response.respond_to?(:message)}"
23
+ end
24
+ end
25
+
26
+ # 3xx Redirection
27
+ class Redirection < ConnectionError # :nodoc:
28
+ def to_s; response['Location'] ? "#{super} => #{response['Location']}" : super; end
29
+ end
30
+
31
+ # 4xx Client Error
32
+ class ClientError < ConnectionError; end # :nodoc:
33
+
34
+ # 400 Bad Request
35
+ class BadRequest < ClientError; end # :nodoc
36
+
37
+ # 401 Unauthorized
38
+ class UnauthorizedAccess < ClientError; end # :nodoc
39
+
40
+ # 403 Forbidden
41
+ class ForbiddenAccess < ClientError; end # :nodoc
42
+
43
+ # 404 Not Found
44
+ class ResourceNotFound < ClientError; end # :nodoc:
45
+
46
+ # 409 Conflict
47
+ class ResourceConflict < ClientError; end # :nodoc:
48
+
49
+ # 5xx Server Error
50
+ class ServerError < ConnectionError; end # :nodoc:
51
+
52
+ # 405 Method Not Allowed
53
+ class MethodNotAllowed < ClientError # :nodoc:
54
+ def allowed_methods
55
+ @response['Allow'].split(',').map { |verb| verb.strip.downcase.to_sym }
56
+ end
57
+ end
58
+
59
+ # Class to handle connections to remote web services.
60
+ # This class is used by ActiveResource::Base to interface with REST
61
+ # services.
62
+ class Connection
63
+ attr_reader :site, :surrogate
64
+ attr_accessor :format
65
+
66
+ class << self
67
+ def requests
68
+ @@requests ||= []
69
+ end
70
+ end
71
+
72
+ # The +site+ parameter is required and will set the +site+
73
+ # attribute to the URI for the remote resource service.
74
+ def initialize(site, format = ActiveResource::Formats[:xml], surrogate=nil)
75
+ raise ArgumentError, 'Missing site URI' unless site
76
+ self.site = site
77
+ self.format = format
78
+ @surrogate=surrogate
79
+ end
80
+
81
+ # Set URI for remote service.
82
+ def site=(site)
83
+ @site = site.is_a?(URI) ? site : URI.parse(site)
84
+ end
85
+
86
+ # Execute a GET request.
87
+ # Used to get (find) resources.
88
+ def get(path, headers = {})
89
+ format.decode(request(:get, path, build_request_headers(headers)).body)
90
+ end
91
+
92
+ # Execute a DELETE request (see HTTP protocol documentation if unfamiliar).
93
+ # Used to delete resources.
94
+ def delete(path, headers = {})
95
+ request(:delete, path, build_request_headers(headers))
96
+ end
97
+
98
+
99
+
100
+ def raw_get(path, headers = {})
101
+ request(:get, path, build_request_headers(headers))
102
+ end
103
+ def post(path, body='', headers={})
104
+ do_method(:post, path, body, headers)
105
+ end
106
+ def put( path, body='', headers={})
107
+ do_method(:put, path, body, headers)
108
+ end
109
+
110
+ private
111
+ def do_method(method, path, body = '', headers = {})
112
+ meth_map={:put=>Net::HTTP::Put::Multipart, :post=>Net::HTTP::Post::Multipart}
113
+ raise "undefined method: #{method}" unless meth_map.has_key? method
114
+ headers = build_request_headers(headers)
115
+ if body.respond_to?(:read)
116
+ if body.respond_to?(:original_filename?)
117
+ filename = File.basename(body.original_filename)
118
+ io = UploadIO.new(body, mime_type,filename)
119
+ elsif body.path
120
+ filename = File.basename(body.path)
121
+ else
122
+ filename="NOFILE"
123
+ end
124
+ mime_types = MIME::Types.of(filename)
125
+ mime_type ||= mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
126
+
127
+ io = nil
128
+ if body.is_a?(File)
129
+ io = UploadIO.new(body.path,mime_type)
130
+ else
131
+ io =UploadIO.new(body, mime_type, filename)
132
+ end
133
+
134
+ req = meth_map[method].new(path, {:file=>io}, headers)
135
+ multipart_request(req)
136
+ else
137
+ request(method, path, body.to_s, headers)
138
+ end
139
+ end
140
+ def multipart_request(req)
141
+ result = nil
142
+ result = http.start do |conn|
143
+ conn.read_timeout=60600 #these can take a while
144
+ conn.request(req)
145
+ end
146
+ handle_response(result)
147
+
148
+ end
149
+
150
+ # Makes request to remote service.
151
+ def request(method, path, *arguments)
152
+ result = http.send(method, path, *arguments)
153
+ handle_response(result)
154
+ end
155
+
156
+ # Handles response and error codes from remote service.
157
+ def handle_response(response)
158
+ case response.code.to_i
159
+ when 301,302
160
+ raise(Redirection.new(response))
161
+ when 200...400
162
+ response
163
+ when 400
164
+ raise(BadRequest.new(response))
165
+ when 401
166
+ raise(UnauthorizedAccess.new(response))
167
+ when 403
168
+ raise(ForbiddenAccess.new(response))
169
+ when 404
170
+ raise(ResourceNotFound.new(response))
171
+ when 405
172
+ raise(MethodNotAllowed.new(response))
173
+ when 409
174
+ raise(ResourceConflict.new(response))
175
+ when 422
176
+ raise(ResourceInvalid.new(response))
177
+ when 401...500
178
+ raise(ClientError.new(response))
179
+ when 500...600
180
+ raise(ServerError.new(response))
181
+ else
182
+ raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
183
+ end
184
+ end
185
+
186
+ # Creates new Net::HTTP instance for communication with
187
+ # remote service and resources.
188
+ def http
189
+ http = Net::HTTP.new(@site.host, @site.port)
190
+ http.use_ssl = @site.is_a?(URI::HTTPS)
191
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
192
+ http
193
+ end
194
+
195
+ def default_header
196
+ @default_header ||= { 'Content-Type' => format.mime_type }
197
+ end
198
+
199
+ # Builds headers for request to remote service.
200
+ def build_request_headers(headers)
201
+ headers.merge!({"From"=>surrogate}) if @surrogate
202
+ authorization_header.update(default_header).update(headers)
203
+ end
204
+
205
+ # Sets authorization header; authentication information is pulled from credentials provided with site URI.
206
+ def authorization_header
207
+ (@site.user || @site.password ? { 'Authorization' => 'Basic ' + ["#{@site.user}:#{ @site.password}"].pack('m').delete("\r\n") } : {})
208
+ end
209
+ end
210
+ end