Class: Rubydora::Datastream
- Inherits:
-
Object
- Object
- Rubydora::Datastream
- Extended by:
- ActiveModel::Callbacks
- Includes:
- ActiveModel::Dirty
- Defined in:
- lib/rubydora/datastream.rb
Overview
This class represents a Fedora datastream object and provides helper methods for creating and manipulating them.
Constant Summary collapse
- DS_ATTRIBUTES =
mapping datastream attributes (and api parameters) to datastream profile names
{:controlGroup => :dsControlGroup, :dsLocation => :dsLocation, :altIDs => nil, :dsLabel => :dsLabel, :versionable => :dsVersionable, :dsState => :dsState, :formatURI => :dsFormatURI, :checksumType => :dsChecksumType, :checksum => :dsChecksum, :mimeType => :dsMIME, :logMessage => nil, :ignoreContent => nil, :lastModifiedDate => nil, :content => nil, :asOfDateTime => nil}
- DS_DEFAULT_ATTRIBUTES =
{ :controlGroup => 'M', :dsState => 'A', :versionable => true }
- DS_READONLY_ATTRIBUTES =
[ :dsCreateDate , :dsSize, :dsVersionID ]
Instance Attribute Summary collapse
-
#digital_object ⇒ Object
readonly
Returns the value of attribute digital_object.
-
#dsid ⇒ Object
readonly
Returns the value of attribute dsid.
Class Method Summary collapse
Instance Method Summary collapse
- #asOfDateTime(asOfDateTime = nil) ⇒ Object
- #changed? ⇒ Boolean
-
#content ⇒ Object
(also: #read)
This method is overridden in ActiveFedora, so we didn’t.
-
#content=(new_content) ⇒ String or IO
Set the content of the datastream.
- #content_changed? ⇒ Boolean
- #content_loaded? ⇒ Boolean
-
#create ⇒ Rubydora::Datastream
Add datastream to Fedora.
- #current_version? ⇒ Boolean
- #datastream_content ⇒ Object
- #datastream_will_change! ⇒ Object
- #default_attributes ⇒ Object
- #default_attributes=(attributes) ⇒ Object
-
#delete ⇒ Rubydora::Datastream
Purge the datastream from Fedora.
- #empty? ⇒ Boolean
-
#external? ⇒ boolean
Is this an external datastream?.
- #has_content? ⇒ Boolean
-
#initialize(digital_object, dsid, options = {}, default_instance_attributes = {}) ⇒ Datastream
constructor
Initialize a Rubydora::Datastream object, which may or may not already exist in the datastore.
-
#inline? ⇒ boolean
Is this an inline datastream?.
-
#local_or_remote_content(ensure_fetch = true) ⇒ String
Retrieve the content of the datastream (and cache it).
-
#managed? ⇒ boolean
Is this a managed datastream?.
-
#new? ⇒ Boolean
Does this datastream already exist?.
-
#pid ⇒ Object
Helper method to get digital object pid.
-
#profile(opts = {}) ⇒ Hash
Retrieve the datastream profile as a hash (and cache it).
- #profile=(profile_hash) ⇒ Object
-
#redirect? ⇒ boolean
Is this a redirect datastream?.
-
#save ⇒ Rubydora::Datastream
Modify or save the datastream.
-
#stream(from = 0, length = nil) ⇒ Object
Returns a streaming response of the datastream.
-
#url ⇒ String
Get the URL for the datastream content.
- #versions ⇒ Object
Constructor Details
#initialize(digital_object, dsid, options = {}, default_instance_attributes = {}) ⇒ Datastream
Initialize a Rubydora::Datastream object, which may or may not already exist in the datastore.
Provides ‘after_initialize` callback for extensions
100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/rubydora/datastream.rb', line 100 def initialize(digital_object, dsid, = {}, default_instance_attributes = {}) run_callbacks :initialize do @digital_object = digital_object @dsid = dsid @options = @default_attributes = default_attributes.merge(default_instance_attributes) .each do |key, value| self.send(:"#{key}=", value) end end end |
Instance Attribute Details
#digital_object ⇒ Object (readonly)
Returns the value of attribute digital_object.
16 17 18 |
# File 'lib/rubydora/datastream.rb', line 16 def digital_object @digital_object end |
#dsid ⇒ Object (readonly)
Returns the value of attribute dsid.
16 17 18 |
# File 'lib/rubydora/datastream.rb', line 16 def dsid @dsid end |
Class Method Details
.default_attributes ⇒ Object
79 80 81 |
# File 'lib/rubydora/datastream.rb', line 79 def self.default_attributes DS_DEFAULT_ATTRIBUTES end |
Instance Method Details
#asOfDateTime(asOfDateTime = nil) ⇒ Object
71 72 73 74 75 76 77 |
# File 'lib/rubydora/datastream.rb', line 71 def asOfDateTime(asOfDateTime = nil) if asOfDateTime.nil? return @asOfDateTime end self.class.new(@digital_object, dsid, @options.merge(:asOfDateTime => asOfDateTime)) end |
#changed? ⇒ Boolean
201 202 203 |
# File 'lib/rubydora/datastream.rb', line 201 def changed? super || content_changed? end |
#content ⇒ Object Also known as: read
This method is overridden in ActiveFedora, so we didn’t
127 128 129 |
# File 'lib/rubydora/datastream.rb', line 127 def content local_or_remote_content(true) end |
#content=(new_content) ⇒ String or IO
Set the content of the datastream
175 176 177 178 |
# File 'lib/rubydora/datastream.rb', line 175 def content=(new_content) raise "Can't change values on older versions" if @asOfDateTime @content = new_content end |
#content_changed? ⇒ Boolean
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/rubydora/datastream.rb', line 180 def content_changed? return false if ['E','R'].include? controlGroup return false unless content_loaded? return true if new? && !local_or_remote_content(false).blank? # new datastreams must have content if controlGroup == "X" if self.eager_load_datastream_content return !EquivalentXml.equivalent?(Nokogiri::XML(content), Nokogiri::XML(datastream_content)) else return !EquivalentXml.equivalent?(Nokogiri::XML(content), Nokogiri::XML(@datastream_content)) end else if self.eager_load_datastream_content return local_or_remote_content(false) != datastream_content else return local_or_remote_content(false) != @datastream_content end end super end |
#content_loaded? ⇒ Boolean
219 220 221 |
# File 'lib/rubydora/datastream.rb', line 219 def content_loaded? !@content.nil? end |
#create ⇒ Rubydora::Datastream
Add datastream to Fedora
299 300 301 302 303 304 305 306 307 |
# File 'lib/rubydora/datastream.rb', line 299 def create check_if_read_only run_callbacks :create do p = repository.add_datastream( to_api_params.merge({ :pid => pid, :dsid => dsid, :content => content })) || {} reset_profile_attributes self.profile= p unless p.empty? self.class.new(digital_object, dsid, @options) end end |
#current_version? ⇒ Boolean
291 292 293 294 295 |
# File 'lib/rubydora/datastream.rb', line 291 def current_version? return true if new? vers = versions vers.empty? || dsVersionID == vers.first.dsVersionID end |
#datastream_content ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/rubydora/datastream.rb', line 152 def datastream_content return nil if new? @datastream_content ||=begin = { :pid => pid, :dsid => dsid } [:asOfDateTime] = asOfDateTime if asOfDateTime repository.datastream_dissemination rescue RestClient::ResourceNotFound end end |
#datastream_will_change! ⇒ Object
338 339 340 |
# File 'lib/rubydora/datastream.rb', line 338 def datastream_will_change! attribute_will_change! :profile end |
#default_attributes ⇒ Object
83 84 85 |
# File 'lib/rubydora/datastream.rb', line 83 def default_attributes @default_attributes ||= self.class.default_attributes end |
#default_attributes=(attributes) ⇒ Object
87 88 89 |
# File 'lib/rubydora/datastream.rb', line 87 def default_attributes=(attributes) @default_attributes = default_attributes.merge attributes end |
#delete ⇒ Rubydora::Datastream
Purge the datastream from Fedora
328 329 330 331 332 333 334 335 336 |
# File 'lib/rubydora/datastream.rb', line 328 def delete check_if_read_only run_callbacks :destroy do repository.purge_datastream(:pid => pid, :dsid => dsid) unless self.new? digital_object.datastreams.delete(dsid) reset_profile_attributes self end end |
#empty? ⇒ Boolean
223 224 225 |
# File 'lib/rubydora/datastream.rb', line 223 def empty? !has_content? end |
#external? ⇒ boolean
Returns is this an external datastream?.
343 344 345 |
# File 'lib/rubydora/datastream.rb', line 343 def external? controlGroup == 'E' end |
#has_content? ⇒ Boolean
205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/rubydora/datastream.rb', line 205 def has_content? # persisted objects are required to have content return true unless new? # type E and R have content if dsLocation is set. return dsLocation.present? if ['E','R'].include? controlGroup # type M has content if dsLocation is not empty return true if controlGroup == 'M' && dsLocation.present? # if we've set content, then we have content behaves_like_io?(@content) || content.present? end |
#inline? ⇒ boolean
Returns is this an inline datastream?.
358 359 360 |
# File 'lib/rubydora/datastream.rb', line 358 def inline? controlGroup == 'X' end |
#local_or_remote_content(ensure_fetch = true) ⇒ String
Retrieve the content of the datastream (and cache it)
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/rubydora/datastream.rb', line 134 def local_or_remote_content(ensure_fetch = true) return @content if new? @content ||= ensure_fetch ? datastream_content : @datastream_content if behaves_like_io?(@content) begin @content.rewind @content.read ensure @content.rewind end else @content end end |
#managed? ⇒ boolean
Returns is this a managed datastream?.
353 354 355 |
# File 'lib/rubydora/datastream.rb', line 353 def managed? controlGroup == 'M' end |
#new? ⇒ Boolean
Does this datastream already exist?
119 120 121 122 123 124 |
# File 'lib/rubydora/datastream.rb', line 119 def new? digital_object.nil? || (digital_object.respond_to?(:new_record?) && digital_object.new_record?) || (digital_object.respond_to?(:new?) && digital_object.new?) || profile.empty? end |
#pid ⇒ Object
Helper method to get digital object pid
113 114 115 |
# File 'lib/rubydora/datastream.rb', line 113 def pid digital_object.pid end |
#profile(opts = {}) ⇒ Hash
Retrieve the datastream profile as a hash (and cache it)
268 269 270 271 272 273 274 275 276 277 |
# File 'lib/rubydora/datastream.rb', line 268 def profile(opts= {}) if @profile && !(opts[:validateChecksum] && !@profile.has_key?('dsChecksumValid')) ## Force a recheck of the profile if they've passed :validateChecksum and we don't have dsChecksumValid return @profile end return @profile = {} unless digital_object.respond_to? :repository @profile = repository.datastream_profile(pid, dsid, opts[:validateChecksum], asOfDateTime) end |
#profile=(profile_hash) ⇒ Object
279 280 281 282 |
# File 'lib/rubydora/datastream.rb', line 279 def profile=(profile_hash) raise ArgumentError, "Must pass a profile, you passed #{profile_hash.class}" unless profile_hash.kind_of? Hash @profile = profile_hash end |
#redirect? ⇒ boolean
Returns is this a redirect datastream?.
348 349 350 |
# File 'lib/rubydora/datastream.rb', line 348 def redirect? controlGroup == 'R' end |
#save ⇒ Rubydora::Datastream
Modify or save the datastream
311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/rubydora/datastream.rb', line 311 def save check_if_read_only run_callbacks :save do raise RubydoraError.new("Unable to save #{self.inspect} without content") unless has_content? if new? create else p = repository.modify_datastream(to_api_params.merge({ :pid => pid, :dsid => dsid })) || {} reset_profile_attributes self.profile= p unless p.empty? self.class.new(digital_object, dsid, @options) end end end |
#stream(from = 0, length = nil) ⇒ Object
Returns a streaming response of the datastream. This is ideal for large datasteams because it doesn’t require holding the entire content in memory. If you specify the from and length parameters it simulates a range request. Unfortunatly Fedora 3 doesn’t have range requests, so this method needs to download the whole thing and just seek to the part you care about.
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/rubydora/datastream.rb', line 234 def stream (from = 0, length = nil) counter = 0 Enumerator.new do |blk| repository.datastream_dissemination(:pid => pid, :dsid => dsid) do |response| unless length size = external? ? entity_size(response) : dsSize raise "Can't determine content length" unless size length = size - from end response.read_body do |chunk| last_counter = counter counter += chunk.size if (counter > from) # greater than the range minimum if counter > from + length # At the end of what we need. Write the beginning of what was read. offset = (length + from) - counter - 1 blk << chunk[0..offset] elsif from >= last_counter # At the end of what we beginning of what we need. Write the end of what was read. offset = from - last_counter blk << chunk[offset..-1] else # In the middle. We need all of this blk << chunk end end end end end end |
#url ⇒ String
Get the URL for the datastream content
166 167 168 169 170 |
# File 'lib/rubydora/datastream.rb', line 166 def url = { } [:asOfDateTime] = asOfDateTime if asOfDateTime repository.datastream_url(pid, dsid, ) + "/content" end |
#versions ⇒ Object
284 285 286 287 288 289 |
# File 'lib/rubydora/datastream.rb', line 284 def versions versions = repository.versions_for_datastream(pid, dsid) versions.map do |asOfDateTime, profile| self.class.new(@digital_object, dsid, asOfDateTime: asOfDateTime, profile: profile) end end |