5. Sheepdip Integration

DMS is designed to make it easy to handle not one, but as many different repositories as you like. To that end, it supports Sheepdip, so you can use custom domain objects to manage the database metadata, making it easy for you to extend and customize the DMS tables. In fact, the default implementation actually uses a simple Sheepdip object, though you don't see it. In this section, we will cover how you can create your own custom Sheepdip object to manage metadata.

Let's say you have an Sheepdip class called Podcast. In this case, you want a DMS repo that is tailored to holding podcast files and data. It is defined as follows:


    
   <table name="Podcast" namespace="Public">
     <columns>
       <column name="contentType" typeid="&text_t;" null="false" default="'text/html'"/>
       <column name="ctime" typeid="&i32_t;"/>
       <column name="deleted" typeid="&bool_t;" null="false" default="false"/>
       <column name="podcastId" typeid="&id_t;"/>
       <column name="guid" typeid="&text_t;" null="false" default="uuid_generate_v1()"/>
       <column name="hash" typeid="&string_t;" length="255" null="false" default=""/>
       <column name="mtime" typeid="&i32_t;"/>
       <column name="name" typeid="&string_t;" length="255" null="false"/>
       <column name="size" typeid="&i32_t;"/>
       <column name="title" typeid="&text_t;"/>
       <column name="description" typeid="&string_t;" length="255" null="false" default=""/>
       <column name="date" typeid="&date_t;"/>
       <column name="bitrate" typeid="&i32_t;"/>
       <column name="length" typeid="&i32_t;"/>
     </columns>
     <indexes>
       <index name="PRIMARY">
         <fields>
           <field name="podcastId"/>
         </fields>
         <constraints>
           <constraint type="UNIQUE"/>
         </constraints>
       </index>
     </indexes>
   </table>

The last five columns are custom columns we've added that relate to podcast files. From this, Sheepdip generates the following code:


#-------------------------------------------------------------------------------
#          THIS CODE WAS AUTOMATICALLY GENERATED: DO NOT MODIFY
#
# File       : podcast.rb
# Source     : site
# Version    : 0.0.1
# Created    : 2010-07-01 21:09:08 -0500
#-------------------------------------------------------------------------------

require 'jw/sheepdip/app'
require 'jw/sheepdip/object'

module Podcast

class Schema < JW::Sheepdip::Schema

  def initialize(a=nil)   
    super(Podcast, 'public', a, '0.0.1')
  
    create('bitrate', Fixnum, false, '') 
    create('contentType', String, false, '') 
    create('ctime', Fixnum, false, '') 
    create('date', String, false, '') 
    create('deleted', ::Object, false, '') 
    create('description', String, true, '') 
    create('podcastId', Fixnum, false, '') 
    create('guid', String, false, '') 
    create('hash', String, true, '') 
    create('length', Fixnum, false, '') 
    create('mtime', Fixnum, false, '') 
    create('name', String, true, '') 
    create('size', Fixnum, false, '') 
    create('title', String, false, '') 
  end 
end

class Object < JW::Sheepdip::Object

  set_schema Schema.new()

  def initialize(db, id = -1)
    super(db)

    @id = id
  
    self.class.addAttribute('bitrate')
    self.class.addAttribute('contentType')
    self.class.addAttribute('ctime')
    self.class.addAttribute('date')
    self.class.addAttribute('deleted')
    self.class.addAttribute('description')
    self.class.addAttribute('podcastId')
    self.class.addAttribute('guid')
    self.class.addAttribute('hash')
    self.class.addAttribute('length')
    self.class.addAttribute('mtime')
    self.class.addAttribute('name')
    self.class.addAttribute('size')
    self.class.addAttribute('title')
  end

  def schema()
    return self.class.schema
  end

end

end # module Podcast


Now we can use this domain object by passing it into the Repository class's constructor. It will store a reference to the class object and use it to create Podcast objects which it will pass to new DMS::File objects. Each file object carries with it its associated Sheepdip object that represents the database table for the repository. That object is accessible via the File.metadata member. The following code illustrates the whole process of using our new Podcast class.


require 'mylib/podcast'

db = JW::DBI::Database.new()

if db.open(vars) == false
  raise "Failed to connect: #{db.error()}"
end

# Create DMS connection
dms = JW::DMS::Repository.new(db, path, uuid, Podcast::Object)

# Create a podcast file
fileId = dms.createFile(name)

# Open it and write some data to it.
file = dms.openFile(fileId, 'w')
file.write(fileData)

# Now before we close it, set the custom attributes. The podcast sheepdip object
# associated with the file is accessible via the metadata member.

podcast             = file.metadata
podcast.title       = 'Is this Your Heart?'
podcast.description = 'Real Radio with Jack Hibbs'
podcast.date        = '2010-07-01'
podcast.bitrate     = 128
podcast.length      = 26*60

# Now close the file. All the metadata will be written to the DB using the
# podcast sheepdip object (e.g. to its associated podcast table in this case).

file.close()

# Example 2: Import a file and set metadata

# first is path, second is name
fileId = dms.importFile('run', 'run');
    
assert(fileId != nil)
info = dms.fileInfo(fileId)
assert info['name'] == 'run'

# Get domain object for file from DMS (as opposed to file)
podcast = dms.object(fileId)

# Make changes
podcast.title       = 'Is this Your Heart?'
podcast.description = 'Real Radio with Jack Hibbs'
podcast.date        = '2010-07-01'
podcast.bitrate     = 128
podcast.length      = 26*60

# Since we don't have a file object open, use Sheepdip to save object.
dip = JW::Sheepdip::App::instance()

# Save metadata changes
dip.save podcast