active-fedora 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,33 @@
1
+ 1.2.3
2
+
3
+ Major: Switched flow of relationship assertions for file objects. Now children assert isPartOf rather than parents asserting hasCollectionMember (see HYDRA-70 and HYDRA-71)
4
+
5
+ New class method: ActiveFedora::Base#has_bidirectional_relationship creates relationship finder methods that search across bidirectional relationships (ie. finds all of the object's hasPart assertions as well as any objects pointing at it with isPartOf)
6
+
7
+ Feature: Fedora::Connection now returns the Fedora error in any ServerError messages
8
+
9
+ Documentation: Added RDoc code comments for experimental features from version 1.2
10
+
11
+ Bug: MetadataDatastream.update_indexed_attributes doesn't get tripped up by attribute names wrapped in arrays (previously wrapping the symbol in an array would cause an error
12
+
13
+ Bug: Applied some fixes to usage of URIs in SemanticNode
14
+
15
+ 1.2.2
16
+
17
+ Misc bug fixes
18
+
19
+ 1.2.1
20
+
21
+ TERMPORARY: removed solrizer from gem dependency list (cyclic reference breaks bundler)
22
+
23
+ 1.2
24
+
25
+ Now support using OM::XML::Terminologies in NokogiriDatastreams
26
+
27
+ resolved #504 -- Allow SSL certificate client authentication for connections to Fedora
28
+
29
+ Added Experimental methods for has_datastream, named_datastream, and remove_relationship (contributed by Rick Johnson at Notre Dame)
30
+
1
31
  1.1.13
2
32
 
3
33
  MetadataDatastream.update_indexed_attributes was no longer marking the object dirty when triggered. Resulted in changed datastreams not saving. Fixed now.
@@ -0,0 +1,25 @@
1
+ h1. Setting the XML in a NokogiriDatastream from a file
2
+
3
+ h2. Setting the Datastream's XML
4
+
5
+ We will make this smoother soon, but right now you have to manually parse your new xml as a Nokogiri XML Document and then put the Nokogiri Document in the datastream's ng_xml attribute.
6
+
7
+ Example (you will have to change the path to point to the xml file you want)
8
+
9
+ <pre>
10
+ my_path = "../om/spec/fixtures/mods_articles/hydrangea_article1.xml"
11
+ f = File.new(my_path)
12
+ xml = Nokogiri::XML::Document.parse(f)
13
+ ha = HydrangeaArticle.new
14
+ ha.datastreams["descMetadata"].to_xml
15
+ ha.datastreams["descMetadata"].ng_xml = xml
16
+ ha.datastreams["descMetadata"].to_xml
17
+ </pre>
18
+
19
+ h2. Saving the Datastream
20
+
21
+ In order to make sure that your updated datastream is saved to fedora, call .save _on the datastream_. If you call .save on the _object_, the changes you've made to the datastream might not be saved.
22
+
23
+ <pre>
24
+ ha.datastreams["descMetadata"].save
25
+ </pre>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.2
1
+ 1.2.3
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{active-fedora}
8
- s.version = "1.2.2"
8
+ s.version = "1.2.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Matt Zumwalt", "McClain Looney"]
12
- s.date = %q{2010-09-15}
12
+ s.date = %q{2010-10-18}
13
13
  s.description = %q{ActiveFedora provides for creating and managing objects in the Fedora Repository Architecture.}
14
14
  s.email = %q{matt.zumwalt@yourmediashelf.com}
15
15
  s.extra_rdoc_files = [
@@ -173,6 +173,7 @@ Gem::Specification.new do |s|
173
173
  "LICENSE",
174
174
  "License.txt",
175
175
  "Manifest.txt",
176
+ "NG_XML_DATASTREAM.textile",
176
177
  "PostInstall.txt",
177
178
  "README.textile",
178
179
  "Rakefile",
@@ -82,19 +82,22 @@ module ActiveFedora #:nodoc:
82
82
  end
83
83
 
84
84
 
85
- if ![].respond_to?(:count)
86
- class Array
87
- puts "active_fedora is Adding count method to Array"
88
- def count(&action)
89
- count = 0
90
- self.each { |v| count = count + 1}
91
- # self.each { |v| count = count + 1 if action.call(v) }
92
- return count
93
- end
94
- end
95
- end
96
85
 
97
- # module ActiveFedora
98
- # class ServerError < Fedora::ServerError; end # :nodoc:
86
+
87
+ # if ![].respond_to?(:count)
88
+ # class Array
89
+ # puts "active_fedora is Adding count method to Array"
90
+ # def count(&action)
91
+ # count = 0
92
+ # self.each { |v| count = count + 1}
93
+ # # self.each { |v| count = count + 1 if action.call(v) }
94
+ # return count
95
+ # end
96
+ # end
99
97
  # end
100
98
 
99
+ module ActiveFedora
100
+ class ServerError < Fedora::ServerError; end # :nodoc:
101
+ class ObjectNotFoundError < RuntimeError; end # :nodoc:
102
+ end
103
+
@@ -40,6 +40,8 @@ module ActiveFedora
40
40
 
41
41
 
42
42
  has_relationship "collection_members", :has_collection_member
43
+ has_relationship "part_of", :is_part_of
44
+ has_bidirectional_relationship "parts", :has_part, :is_part_of
43
45
 
44
46
 
45
47
  # Has this object been saved?
@@ -113,7 +115,7 @@ module ActiveFedora
113
115
  end
114
116
  end
115
117
  end
116
-
118
+
117
119
  Fedora::Repository.instance.delete(@inner_object)
118
120
  if ENABLE_SOLR_UPDATES
119
121
  ActiveFedora::SolrService.instance.conn.delete(pid)
@@ -244,6 +246,10 @@ module ActiveFedora
244
246
  # File Management
245
247
  #
246
248
 
249
+ # Add the given file as a datastream in the object
250
+ #
251
+ # @param [File] file the file to add
252
+ # @param [Hash] opts options: :dsid, :label
247
253
  def add_file_datastream(file, opts={})
248
254
  label = opts.has_key?(:label) ? opts[:label] : ""
249
255
  ds = ActiveFedora::Datastream.new(:dsLabel => label, :controlGroup => 'M', :blob => file)
@@ -251,12 +257,45 @@ module ActiveFedora
251
257
  add_datastream(ds)
252
258
  end
253
259
 
254
- def file_objects
255
- collection_members
260
+ # List the objects that assert isPartOf pointing at this object _plus_ all objects that this object asserts hasPart for
261
+ # Note: Previous versions of ActiveFedora used hasCollectionMember to represent this type of relationship.
262
+ # To accommodate this, until active-fedora-1.3, .file_assets will also return anything that this asserts hasCollectionMember for and will output a warning in the logs.
263
+ #
264
+ # @param [Hash] opts -- same options as auto-generated methods for relationships (ie. :response_format)
265
+ # @return [Array of ActiveFedora objects, Array of PIDs, or Solr::Result] -- same options as auto-generated methods for relationships (ie. :response_format)
266
+ def file_objects(opts={})
267
+ cm_array = collection_members(:response_format=>:id_array)
268
+
269
+ if !cm_array.empty?
270
+ logger.warn "This object has collection member assertions. hasCollectionMember will no longer be used to track file_object relationships after active_fedora 1.3. Use isPartOf assertions in the RELS-EXT of child objects instead."
271
+ if opts[:response_format] == :solr || opts[:response_format] == :load_from_solr
272
+ logger.warn ":solr and :load_from_solr response formats for file_objects search only uses parts relationships (usage of hasCollectionMember is no longer supported)"
273
+ result = parts(opts)
274
+ else
275
+ cm_result = collection_members(opts)
276
+ parts_result = parts(opts)
277
+ ary = cm_result+parts_result
278
+ result = ary.uniq
279
+ end
280
+ else
281
+ result = parts(opts)
282
+ end
283
+ return result
256
284
  end
257
285
 
286
+ # Add the given file as a datastream in the object
287
+ #
288
+ # @param [ActiveFedora::Base] obj the file to add
258
289
  def file_objects_append(obj)
259
- collection_members_append(obj)
290
+ # collection_members_append(obj)
291
+ unless obj.kind_of? ActiveFedora::Base
292
+ begin
293
+ obj = ActiveFedora::Base.load_instance(obj)
294
+ rescue ActiveFedora::ObjectNotFoundError
295
+ "You must provide either an ActiveFedora object or a valid pid to add it as a file object. You submitted #{obj.inspect}"
296
+ end
297
+ end
298
+ obj.add_relationship(:is_part_of, self)
260
299
  end
261
300
 
262
301
  def collection_members_append(obj)
@@ -267,19 +306,39 @@ module ActiveFedora
267
306
  # will rely on SemanticNode.remove_relationship once it is implemented
268
307
  end
269
308
 
309
+ # ** EXPERIMENTAL **
270
310
  #
271
- # Named Datastreams management
272
- #
311
+ # Returns array of datastream names defined for this object
273
312
  def datastream_names
274
313
  named_datastreams_desc.keys
275
314
  end
276
315
 
316
+ # ** EXPERIMENTAL **
317
+ #
318
+ # Calls add_named_datastream while assuming it will be managed content and sets :blob and :controlGroup values accordingly
319
+ # ====Parameters
320
+ # name: Datastream name
321
+ # file: The file to add for this datastream
322
+ # opts: Options hash. See +add_named_datastream+ for expected keys and values
277
323
  def add_named_file_datastream(name, file, opts={})
278
324
  opts.merge!({:blob=>file,:controlGroup=>'M'})
279
325
  add_named_datastream(name,opts)
280
326
  end
281
-
282
- # Creates a datastream with values
327
+
328
+ # ** EXPERIMENTAL **
329
+ #
330
+ # This object is used by [datastream_name]_append helper to add a named datastream
331
+ # but can also be called directly.
332
+ # ====Parameters
333
+ # name: name of datastream to add
334
+ # opts: hash defining datastream attributes
335
+ # The following are expected keys in opts hash:
336
+ # :label => Defaults to the file name
337
+ # :blob or :file => Required to point to the datastream file being added if managed content
338
+ # :controlGroup => defaults to 'M' for managed, can also be 'E' external and 'R' for redirected
339
+ # :content_type => required if the file does not respond to 'content_type' and should match :mimeType in has_datastream definition if defined
340
+ # :dsLocation => holds uri location of datastream. Required only if :controlGroup is type 'E' or 'R'.
341
+ # :dsid or :dsId => Optional, and used to update an existing datastream with dsid supplied. Will throw an error if dsid does not exist and does not match prefix pattern for datastream name
283
342
  def add_named_datastream(name,opts={})
284
343
 
285
344
  unless named_datastreams_desc.has_key?(name) && named_datastreams_desc[name].has_key?(:type)
@@ -335,10 +394,14 @@ module ActiveFedora
335
394
  add_datastream(ds,opts)
336
395
  end
337
396
 
338
- ########################################################################
339
- ### TODO: Currently requires you to update file if a managed datastream
340
- ## but could change to allow metadata only updates as well
341
- ########################################################################
397
+ # ** EXPERIMENTAL **
398
+ #
399
+ # Update an existing named datastream. It has same parameters as add_named_datastream
400
+ # except the :dsid key is now required.
401
+ #
402
+ # ====TODO
403
+ # Currently requires you to update file if a managed datastream
404
+ # but could change to allow metadata only updates as well
342
405
  def update_named_datastream(name, opts={})
343
406
  #check that dsid provided matches existing datastream with that name
344
407
  raise "You must define parameter dsid for datastream to update for #{pid}" unless opts.include?(:dsid)
@@ -346,14 +409,35 @@ module ActiveFedora
346
409
  add_named_datastream(name,opts)
347
410
  end
348
411
 
412
+ # ** EXPERIMENTAL **
413
+ #
414
+ # Throws an assertion failure unless the object 'o' is kind_of? class 't'
415
+ # ====Parameters
416
+ # n: Name of object
417
+ # o: The object to test
418
+ # t: The class type to check is kind_of?
349
419
  def assert_kind_of(n, o,t)
350
420
  raise "Assertion failure: #{n}: #{o} is not of type #{t}" unless o.kind_of?(t)
351
421
  end
352
422
 
423
+ # ** EXPERIMENTAL **
424
+ #
425
+ # Returns true if the name is a defined named datastream
353
426
  def is_named_datastream?(name)
354
427
  named_datastreams_desc.has_key?(name)
355
428
  end
356
429
 
430
+ # ** EXPERIMENTAL **
431
+ #
432
+ # Returns hash of datastream names defined by has_datastream calls mapped to
433
+ # array of datastream objects that have been added
434
+ # ====Example
435
+ # For the following has_datastream entries and a datastream defined for minivan only would be
436
+ # has_datastream :name=>"minivan", :prefix => "VAN", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'M'
437
+ # has_datastream :name=>"external_images", :prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'
438
+ #
439
+ # Returns
440
+ # {"external_images"=>[],"thumbnails"=>{#<ActiveFedora::Datastream:0x7ffd6512daf8 @new_object=true,...}}
357
441
  def named_datastreams
358
442
  ds_values = {}
359
443
  self.class.named_datastreams_desc.keys.each do |name|
@@ -362,6 +446,17 @@ module ActiveFedora
362
446
  return ds_values
363
447
  end
364
448
 
449
+ # ** EXPERIMENTAL **
450
+ #
451
+ # Returns hash of datastream names mapped to another hash
452
+ # of dsid to attributes for corresponding datastream objects
453
+ # === Example
454
+ # For the following has_datastream call, assume we have added one datastream.
455
+ #
456
+ # has_datastream :name=>"thumbnails",:prefix => "THUMB",:type=>ActiveFedora::Datastream, :mimeType=>"image/jpeg", :controlGroup=>'M'
457
+ #
458
+ # It would then return
459
+ # {"thumbnails"=>{"THUMB1"=>{:prefix=>"VAN", :type=>"ActiveFedora::Datastream", :dsid=>"THUMB1", :dsID=>"THUMB1", :pid=>"changme:33", :mimeType=>"image/jpeg", :dsLabel=>"", :name=>"thumbnails", :content_type=>"image/jpeg", :controlGroup=>"M"}}}
365
460
  def named_datastreams_attributes
366
461
  ds_values = {}
367
462
  self.class.named_datastreams_desc.keys.each do |name|
@@ -375,6 +470,17 @@ module ActiveFedora
375
470
  return ds_values
376
471
  end
377
472
 
473
+ # ** EXPERIMENTAL **
474
+ #
475
+ # Returns hash of datastream names mapped to an array
476
+ # of dsid's for named datastream objects
477
+ # === Example
478
+ # For the following has_datastream call, assume we have added two datastreams.
479
+ #
480
+ # has_datastream :name=>"thumbnails",:prefix => "THUMB",:type=>ActiveFedora::Datastream, :mimeType=>"image/jpeg", :controlGroup=>'M'
481
+ #
482
+ # It would then return
483
+ # {"thumbnails=>["THUMB1", "THUMB2"]}
378
484
  def named_datastreams_ids
379
485
  dsids = {}
380
486
  self.class.named_datastreams_desc.keys.each do |name|
@@ -384,6 +490,10 @@ module ActiveFedora
384
490
  return dsids
385
491
  end
386
492
 
493
+ # ** EXPERIMENTAL **
494
+ #
495
+ # For all datastream objects, this returns hash of dsid mapped to attribute hash within the corresponding
496
+ # datastream object.
387
497
  def datastreams_attributes
388
498
  ds_values = {}
389
499
  self.datastreams.each_pair do |dsid,ds|
@@ -392,10 +502,27 @@ module ActiveFedora
392
502
  return ds_values
393
503
  end
394
504
 
505
+ # ** EXPERIMENTAL **
506
+ #
507
+ # Returns the hash that stores arguments passed to has_datastream calls within an
508
+ # ActiveFedora::Base child class.
509
+ #
510
+ # has_datastream :name=>"audio_file", :prefix=>"AUDIO", :type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav"
511
+ # has_datastream :name=>"external_images", :prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'
512
+ #
513
+ # The above examples result in the following hash
514
+ # {"audio_file"=>{:prefix=>"AUDIO",:type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav", :controlGroup=>'M'},
515
+ # "external_images=>{:prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'}}
516
+ #
517
+ # This hash is later used when adding a named datastream such as an "audio_file" as defined above.
395
518
  def named_datastreams_desc
396
519
  @named_datastreams_desc ||= named_datastreams_desc_from_class
397
520
  end
398
521
 
522
+ # ** EXPERIMENTAL **
523
+ #
524
+ # Get class variable hash that stores has_datastream arguments.
525
+ # It is used to initialize the value returned by public named_datastreams_desc method
399
526
  def named_datastreams_desc_from_class
400
527
  self.class.named_datastreams_desc
401
528
  end
@@ -405,6 +532,33 @@ module ActiveFedora
405
532
  scope.const_get(const_name)}.new(opts)
406
533
  end
407
534
 
535
+ # ** EXPERIMENTAL **
536
+ #
537
+ # Allows for a datastream to be treated like any other attribute of a model class
538
+ # while enforcing mimeType and/or datastream type (ie. external, managed, etc.) if defined.
539
+ # ====Examples
540
+ #
541
+ # has_datastream :name=>"thumbnails",:prefix => "THUMB",:type=>ActiveFedora::Datastream, :mimeType=>"image/jpeg", :controlGroup=>'M'
542
+ # has_datastream :name=>"EADs", :type=>ActiveFedora::Datastream, :mimeType=>"application/xml", :controlGroup=>'M'
543
+ # has_datastream :name=>"external_images", :type=>ActiveFedora::Datastream, :controlGroup=>'E'
544
+ #
545
+ # Required Keys in args
546
+ # :name - name to give this datastream (must be unique)
547
+ #
548
+ # Optional Keys in args
549
+ # :prefix - used to create the DSID plus an index ie. THUMB1, THUMB2. If :prefix is not specified, defaults to :name value in all uppercase
550
+ # :type - defaults to ActiveFedora::Datastream if you would like content specific class to be used supply it here
551
+ # :mimeType - if supplied it will ensure any datastreams added are of this type, if not supplied any mimeType is acceptabl e
552
+ # :controlGroup - possible values "X", "M", "R", or "E" (InlineXML, Managed Content, Redirect, or External Referenced) If controlGroup is 'E' or 'R' it expects a dsLocation be defined when adding the datastream.
553
+ #
554
+ # You use the datastream attribute using helper methods created for each datastream name:
555
+ #
556
+ # ====Helper Method Examples
557
+ # thumbnails_append - Append a thumbnail datastream
558
+ # thumbnails - Get array of thumbnail datastreams
559
+ # thumbnails_ids - Get array of dsid's for thumbnail datastreams
560
+ #
561
+ # When loading the list of datastreams for a name from Fedora it uses the DSID prefix to find them in Fedora
408
562
  def self.has_datastream(args)
409
563
  unless args.has_key?(:name)
410
564
  return false
@@ -426,7 +580,15 @@ module ActiveFedora
426
580
  create_named_datastream_finders(args[:name],args[:prefix])
427
581
  create_named_datastream_update_methods(args[:name])
428
582
  end
429
-
583
+
584
+ # ** EXPERIMENTAL **
585
+ #
586
+ # Creates the following helper methods for a datastream name
587
+ # [datastream_name]_append - Add a named datastream
588
+ #
589
+ # ==== Examples for "thumbnails" datastream
590
+ # thumbnails_append - Append a thumbnail datastream
591
+ # TODO: Add [datastream_name]_remove
430
592
  def self.create_named_datastream_update_methods(name)
431
593
  append_file_method_name = "#{name.to_s.downcase}_file_append"
432
594
  append_method_name = "#{name.to_s.downcase}_append"
@@ -444,7 +606,16 @@ module ActiveFedora
444
606
  add_named_datastream(name,opts)
445
607
  end
446
608
  end
447
-
609
+
610
+ # ** EXPERIMENTAL **
611
+ #
612
+ # Creates the following helper methods for a datastream name
613
+ # [datastream_name] - Returns array of named datastreams
614
+ # [datastream_name]_ids - Returns array of named datastream dsids
615
+ #
616
+ # ==== Examples for "thumbnails" datastream
617
+ # thumbnails - Get array of thumbnail datastreams
618
+ # thumbnails_ids - Get array of dsid's for thumbnail datastreams
448
619
  def self.create_named_datastream_finders(name, prefix)
449
620
  class_eval <<-END
450
621
  def #{name}(opts={})
@@ -468,8 +639,20 @@ module ActiveFedora
468
639
  end
469
640
  END
470
641
  end
471
-
472
- # named datastreams desc are tracked as a hash of structure {name => args}}
642
+
643
+ # ** EXPERIMENTAL **
644
+ #
645
+ # Accessor for class variable for hash that stores arguments passed to has_datastream calls within an
646
+ # ActiveFedora::Base child class.
647
+ #
648
+ # has_datastream :name=>"audio_file", :prefix=>"AUDIO", :type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav"
649
+ # has_datastream :name=>"external_images", :prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'
650
+ #
651
+ # The above examples result in the following hash
652
+ # {"audio_file"=>{:prefix=>"AUDIO",:type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav", :controlGroup=>'M'},
653
+ # "external_images=>{:prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'}}
654
+ #
655
+ # This hash is later used when adding a named datastream such as an "audio_file" as defined above.
473
656
  def self.named_datastreams_desc
474
657
  @class_named_datastreams_desc ||= {}
475
658
  end
@@ -499,6 +682,11 @@ module ActiveFedora
499
682
  end
500
683
  end
501
684
 
685
+ # ** EXPERIMENTAL **
686
+ #
687
+ # Remove a Rels-Ext relationship from the Object.
688
+ # @param predicate
689
+ # @param object Either a string URI or an object that responds to .pid
502
690
  def remove_relationship(predicate, obj)
503
691
  r = ActiveFedora::Relationship.new(:subject=>:self, :predicate=>predicate, :object=>obj)
504
692
  rels_ext.remove_relationship(r)
@@ -656,17 +844,19 @@ module ActiveFedora
656
844
  return solr_doc
657
845
  end
658
846
 
659
- ###########################################################################################################
847
+ # ** EXPERIMENTAL **
660
848
  #
661
- # This method is comparable to load_instance except it populates an object from Solr instead of Fedora.
849
+ # This method can be used instead of ActiveFedora::Model::ClassMethods.load_instance.
850
+ # It works similarly except it populates an object from Solr instead of Fedora.
662
851
  # It is most useful for objects used in read-only displays in order to speed up loading time. If only
663
- # a pid is passed in it will attempt to load a solr document and then populate an ActiveFedora::Base object
664
- # based on the solr doc including any metadata datastreams and relationships.
852
+ # a pid is passed in it will query solr for a corresponding solr document and then use it
853
+ # to populate this object.
665
854
  #
666
- # solr_doc is an optional parameter and if a value is passed it will not query solr again and just use the
855
+ # If a value is passed in for optional parameter solr_doc it will not query solr again and just use the
667
856
  # one passed to populate the object.
668
857
  #
669
- ###########################################################################################################
858
+ # It will anything stored within solr such as metadata and relationships. Non-metadata datastreams will not
859
+ # be loaded and if needed you should use load_instance instead.
670
860
  def self.load_instance_from_solr(pid,solr_doc=nil)
671
861
  if solr_doc.nil?
672
862
  result = find_by_solr(pid)