active-fedora 1.0.5 → 1.1.0

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