Extending "Famulus" using arbitrary data models

“Famulus” has always been the codename for our “Research Output Repository Platform”, which I’ve discussed in previous posts. I am mentioning the codename in public for the first time only now because it makes the discussion of code samples so much easier. When we come up with the official name (I promise, we’re trying out best not to choose a boring name), I’ll start using that. For now… “Famulus” = “the codename for the Research Output Repository Platform”.

While amongst the primary goals of the platform has been the support of the scholarly communication community, we also wanted to make sure that developers of repository tools and services had great support for extensibility. Famulus comes with a predefined data model, which we created after an analysis of common usage scenarios. We came up with a model of entities and relationships that we baked into Famulus (e.g. Papers, Technical Reports, Thesis, Books, Videos, Downloads, etc.). We also populated the store with a collection of “known” predicates (e.g. Cites, Presenter, Author, etc.). However, we were fully aware that our data model might not meet the needs of the developers 100%. So, we started working on an extensibility story for Famulus.

While adding new predicates and using them is trivial (see example below) or associating new properties with existing entities are trivial tasks, we wanted to do even better. We started working on an extensibility story that would allow developers to introduce completely new entities into the store. Based on that extensibility model, we are now building support for RDFS and, if we don’t run out of time, OWL.

Here’s an example of how one could create a relationship between two entities, in this case a “cites” relationship.

         1: TechnicalReport tr1 = new TechnicalReport { Title = "TechRep 1" };
         2: TechnicalReport tr2 = new TechnicalReport { Title = "TechRep 2" };
         3:
         4:
      // Using our "well known" Cites predicate
         5: tr1.CitesResources.Add(tr2);
         6:
         7:
      // Alternatively, one could do the same as above using our generic API
         8: Predicate cites = (from p in famulus.Predicates
         9:
      where p.Uri == "urn:microsoft:predicates:cites"
        10:                    select p).First();
        11:
      // Now that we have a reference to the predicate object, we can use it
        12:
      // to associate entities
        13: tr1.RelationshipsAsSubject.Add(new Relationship { Predicate = cites, Subject = tr2 });

Given the latter, more verbose, syntax here’s a way to introduce new predicates into the store programmatically.

         1: TechnicalReport tr = new TechnicalReport { Title = "TechRep 1" };
         2: Person jim = new Person { FirstName = "Jim", LastName = "Webber" };
         3:
         4:
      // Create a new predicate and added to the store
         5: Predicate reviewer = new Predicate { Uri = "urn:mypredicates:reviewer" };
         6: famulus.AddToPredicates(reviewer);
         7:
         8:
      // we can now use it
         9: tr.RelationshipsAsSubject.Add(new Relationship { Predicate = reviewer, Subject = jim });

Great! But this only allows us to introduce new predicates. How about new entities (types)?

Well, we have an API for that as well. It’ll be part of the Famulus Beta next month. However, I am not going to bother you with the details since we are going to abstract its usage. In the future, you’ll only have to deal with RDFS. The motivation for supporting an extensible store came from the interest we got from domains other than the ones we were originally planning. I’ve been experimenting with how the support for RDFS would look like by writing some code. I created a small XML-based vocabulary for describing a data model, like the one you see below.

<model xmlns ="urn:microsoft:famulus:datamodel">
  <type name ="Artifact" basetype ="Microsoft.Famulus.Core.Resource" namespace ="Museum" uri ="urn:museum:artifact">
    <property name ="DateDiscovered" type ="DateTime" nullable ="true" />
    <property name ="DateAddedToCollection" type ="DateTime" nullable ="true" />
  </type>
</model>

Using that as input to a DataModel->Famulus tool I wrote over our extensibility API, I can configure the Famulus store to accept “Artifact” entities. I don’t need to worry about the SQL Server schema, tables, etc. Famulus takes care of everything. We also give you a .NET DLL which you can use in your application so that you get experience like this (including great Visual Studio integration). So writing applications against our “Museum” data model is now easy.

         1: Artifact artifact = new Artifact();
         2: artifact.DateAddedToCollection = DateTime.Now;
         3: artifact.DateDiscovered = new DateTime(1000, 1, 1);
         4:
      // The base of all entities is Microsoft.Famulus.Core.Resource,
         5:
      // which comes with a set of common properties
         6: artifact.Uri = "http://museum.example.org/artifact";
         7: artifact.Notes = "Artifact notes";

The next step is to easily support relationships as well in the declarative model (i.e. tuples of the form <subject, predicate, object, attribute, …>).