Class: Moab::StorageObject

Inherits:
Object
  • Object
show all
Defined in:
lib/moab/storage_object.rb

Overview

Note:

Copyright © 2012 by The Board of Trustees of the Leland Stanford Junior University. All rights reserved. See LICENSE for details.

A class to represent a digital object’s repository storage location and methods for

  • packaging a bag for ingest of a new object version to the repository

  • ingesting a bag

  • disseminating a bag containing a reconstructed object version

Data Model

  • StorageRepository = represents a digital object repository storage node

    • StorageServices = supports application layer access to the repository’s objects, data, and metadata

    • StorageObject = represents a digital object’s repository storage location and ingest/dissemination methods

      • StorageObjectVersion [1..*] = represents a version subdirectory within an object’s home directory

        • Bagger [1] = utility for creating bagit packages for ingest or dissemination

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(object_id, object_dir, mkpath = false) ⇒ StorageObject

Returns a new instance of StorageObject.

Parameters:

  • object_id (String)

    The digital object identifier

  • object_dir (Pathname, String)

    The location of the object’s storage home directory



31
32
33
34
35
# File 'lib/moab/storage_object.rb', line 31

def initialize(object_id, object_dir, mkpath = false)
  @digital_object_id = object_id
  @object_pathname = Pathname.new(object_dir)
  initialize_storage if mkpath
end

Instance Attribute Details

#digital_object_idString

Returns The digital object ID (druid).

Returns:

  • (String)

    The digital object ID (druid)



21
22
23
# File 'lib/moab/storage_object.rb', line 21

def digital_object_id
  @digital_object_id
end

#object_pathnamePathname

Returns The location of the object’s storage home directory.

Returns:

  • (Pathname)

    The location of the object’s storage home directory



24
25
26
# File 'lib/moab/storage_object.rb', line 24

def object_pathname
  @object_pathname
end

#storage_rootPathname

Returns The location of the storage filesystem that contains (or will contain) the object.

Returns:

  • (Pathname)

    The location of the storage filesystem that contains (or will contain) the object



27
28
29
# File 'lib/moab/storage_object.rb', line 27

def storage_root
  @storage_root
end

Class Method Details

.version_dirname(version_id) ⇒ String

Returns The directory name of the version, relative to the digital object home directory (e.g v0002).

Parameters:

  • version_id (Integer)

    The version identifier of an object version

Returns:

  • (String)

    The directory name of the version, relative to the digital object home directory (e.g v0002)



126
127
128
# File 'lib/moab/storage_object.rb', line 126

def self.version_dirname(version_id)
  format('v%04d', version_id)
end

Instance Method Details

#current_versionStorageObjectVersion

Returns The most recent version in the storage object.

Returns:



160
161
162
# File 'lib/moab/storage_object.rb', line 160

def current_version
  storage_object_version(current_version_id)
end

#current_version_idInteger

Returns The identifier of the latest version of this object, or 0 if no versions exist.

Returns:

  • (Integer)

    The identifier of the latest version of this object, or 0 if no versions exist



155
156
157
# File 'lib/moab/storage_object.rb', line 155

def current_version_id
  @current_version_id ||= version_id_list.last || 0
end

#deposit_bag_pathnamePathname

Returns The absolute location of this object’s deposit bag.

Returns:

  • (Pathname)

    The absolute location of this object’s deposit bag



54
55
56
# File 'lib/moab/storage_object.rb', line 54

def deposit_bag_pathname
  deposit_home.join(StorageServices.deposit_branch(digital_object_id))
end

#deposit_homePathname

Returns The absolute location of the area in which bags are deposited.

Returns:

  • (Pathname)

    The absolute location of the area in which bags are deposited



49
50
51
# File 'lib/moab/storage_object.rb', line 49

def deposit_home
  storage_root.join(StorageServices.deposit_trunk)
end

#empty?Boolean

Returns true if there are no versions yet in this object.

Returns:

  • (Boolean)

    true if there are no versions yet in this object



149
150
151
# File 'lib/moab/storage_object.rb', line 149

def empty?
  version_id_list.empty?
end

#exist?Boolean

Returns true if the object’s storage directory exists.

Returns:

  • (Boolean)

    true if the object’s storage directory exists



38
39
40
# File 'lib/moab/storage_object.rb', line 38

def exist?
  @object_pathname.exist?
end

#find_object_version(version_id = nil) ⇒ StorageObjectVersion

Returns The representation of an existing version’s storage area.

Parameters:

  • version_id (Integer) (defaults to: nil)

    The existing version to return. If nil, return latest version

Returns:



178
179
180
181
182
183
184
185
186
187
188
# File 'lib/moab/storage_object.rb', line 178

def find_object_version(version_id = nil)
  current = current_version_id
  case version_id
  when nil
    StorageObjectVersion.new(self, current)
  when 1..current
    StorageObjectVersion.new(self, version_id)
  else
    raise(MoabRuntimeError, "Version ID #{version_id} does not exist")
  end
end

#ingest_bag(bag_dir = deposit_bag_pathname, use_links: true) ⇒ void

This method returns an undefined value.

Returns Ingest a new object version contained in a bag into this objects storage area.

Examples:

Parameters:

  • bag_dir (Pathname, String) (defaults to: deposit_bag_pathname)

    The location of the bag to be ingested

  • use_links (Boolean) (defaults to: true)

    If true, use hard links; if false, make copies



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/moab/storage_object.rb', line 63

def ingest_bag(bag_dir = deposit_bag_pathname, use_links: true)
  bag_dir = Pathname(bag_dir)
  current_version = StorageObjectVersion.new(self, current_version_id)
  current_inventory = current_version.file_inventory('version')
  new_version = StorageObjectVersion.new(self, current_version_id + 1)
  if FileInventory.xml_pathname_exist?(bag_dir, 'version')
    new_inventory = FileInventory.read_xml_file(bag_dir, 'version')
  elsif current_version.version_id == 0
    new_inventory = versionize_bag(bag_dir, current_version, new_version)
  end
  validate_new_inventory(new_inventory)
  new_version.ingest_bag_data(bag_dir, use_links: use_links)
  new_version.update_catalog(current_version.signature_catalog, new_inventory)
  new_version.generate_differences_report(current_inventory, new_inventory)
  new_version.generate_manifest_inventory
  new_version
end

#initialize_storagevoid

This method returns an undefined value.

Returns Create the directory for the digital object home unless it already exists.



44
45
46
# File 'lib/moab/storage_object.rb', line 44

def initialize_storage
  @object_pathname.mkpath
end

#reconstruct_version(version_id, bag_dir) ⇒ void

This method returns an undefined value.

Returns Reconstruct an object version and package it in a bag for dissemination.

Examples:

Parameters:

  • version_id (Integer)

    The version identifier of the object version to be disseminated

  • bag_dir (Pathname, String)

    The location of the bag to be created



105
106
107
108
109
110
111
# File 'lib/moab/storage_object.rb', line 105

def reconstruct_version(version_id, bag_dir)
  storage_version = StorageObjectVersion.new(self, version_id)
  version_inventory = storage_version.file_inventory('version')
  signature_catalog = storage_version.signature_catalog
  bagger = Bagger.new(version_inventory, signature_catalog, bag_dir)
  bagger.fill_bag(:reconstructor, @object_pathname)
end

#restore_object(recovery_path) ⇒ Boolean

Returns Restore all recovered versions to online storage and verify results.

Parameters:

  • recovery_path (Pathname, String)

    The location of the recovered object versions

Returns:

  • (Boolean)

    Restore all recovered versions to online storage and verify results



214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/moab/storage_object.rb', line 214

def restore_object(recovery_path)
  timestamp = Time.now
  recovery_object = StorageObject.new(@digital_object_id, recovery_path, false)
  recovery_object.versions.each do |recovery_version|
    version_id = recovery_version.version_id
    storage_version = storage_object_version(version_id)
    # rename/save the original
    storage_version.deactivate(timestamp)
    # copy the recovered version into place
    FileUtils.cp_r(recovery_version.version_pathname.to_s, storage_version.version_pathname.to_s)
  end
  self
end

#sizeInteger

Returns the size occupied on disk by the storage object, in bytes. this is the entire moab (all versions).

Returns:

  • (Integer)

    the size occupied on disk by the storage object, in bytes. this is the entire moab (all versions).



229
230
231
232
233
234
235
# File 'lib/moab/storage_object.rb', line 229

def size
  size = 0
  Find.find(object_pathname) do |path|
    size += FileTest.size(path) unless FileTest.directory?(path)
  end
  size
end

#storage_filepath(catalog_filepath) ⇒ Pathname

Returns The absolute storage path of the file, including the object’s home directory.

Parameters:

  • catalog_filepath (String)

    The object-relative path of the file

Returns:

  • (Pathname)

    The absolute storage path of the file, including the object’s home directory

Raises:



115
116
117
118
119
120
121
# File 'lib/moab/storage_object.rb', line 115

def storage_filepath(catalog_filepath)
  storage_filepath = @object_pathname.join(catalog_filepath)
  errmsg = "#{catalog_filepath} missing from storage location #{storage_filepath}"
  raise FileNotFoundException, errmsg unless storage_filepath.exist?

  storage_filepath
end

#storage_object_version(version_id) ⇒ StorageObjectVersion

  • Version 0 is a special case used to generate empty manifests

  • Current version + 1 is used for creation of a new version

Parameters:

  • version_id (Integer)

    The version to return. OK if version does not exist

Returns:

Raises:



195
196
197
198
199
# File 'lib/moab/storage_object.rb', line 195

def storage_object_version(version_id)
  raise(MoabRuntimeError, 'Version ID not specified') unless version_id

  StorageObjectVersion.new(self, version_id)
end

#validate_new_inventory(version_inventory) ⇒ Boolean

Returns Tests whether the new version number is one higher than the current version number.

Parameters:

  • version_inventory (FileInventory)

    The inventory of the object version to be ingested

Returns:

  • (Boolean)

    Tests whether the new version number is one higher than the current version number



167
168
169
170
171
172
173
# File 'lib/moab/storage_object.rb', line 167

def validate_new_inventory(version_inventory)
  if version_inventory.version_id != (current_version_id + 1)
    raise(MoabRuntimeError, "version mismatch - current: #{current_version_id} new: #{version_inventory.version_id}")
  end

  true
end

#verify_object_storageVerificationResult

Return result of storage verification

Returns:



202
203
204
205
206
207
208
209
210
# File 'lib/moab/storage_object.rb', line 202

def verify_object_storage
  result = VerificationResult.new(digital_object_id)
  version_list.each do |version|
    result.subentities << version.verify_version_storage
  end
  result.subentities << current_version.verify_signature_catalog
  result.verified = result.subentities.all?(&:verified)
  result
end

#version_id_listArray<Integer>

Returns The list of all version ids for this object.

Returns:

  • (Array<Integer>)

    The list of all version ids for this object



131
132
133
134
135
136
137
138
139
140
# File 'lib/moab/storage_object.rb', line 131

def version_id_list
  list = []
  return list unless @object_pathname.exist?

  @object_pathname.children.each do |dirname|
    vnum = dirname.basename.to_s
    list << vnum[1..].to_i if vnum =~ /^v(\d+)$/
  end
  list.sort
end

#version_listArray<StorageObjectVersion> Also known as: versions

Returns The list of all versions in this storage object.

Returns:



143
144
145
# File 'lib/moab/storage_object.rb', line 143

def version_list
  version_id_list.collect { |id| storage_object_version(id) }
end

#versionize_bag(bag_dir, current_version, new_version) ⇒ FileInventory

Returns The file inventory of the specified type for this version.

Parameters:

  • bag_dir (Pathname)

    The location of the bag to be ingested

  • current_version (StorageObjectVersion)

    The current latest version of the object

  • new_version (StorageObjectVersion)

    The version to be added

Returns:

  • (FileInventory)

    The file inventory of the specified type for this version



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/moab/storage_object.rb', line 86

def versionize_bag(bag_dir, current_version, new_version)
  new_inventory = FileInventory.new(
    type: 'version',
    digital_object_id: @digital_object_id,
    version_id: new_version.version_id,
    inventory_datetime: Time.now
  )
  new_inventory.inventory_from_bagit_bag(bag_dir)
  new_inventory.write_xml_file(bag_dir)
  version_additions = current_version.signature_catalog.version_additions(new_inventory)
  version_additions.write_xml_file(bag_dir)
  new_inventory
end