Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Before reading through this, it would be good to review the Fedora Specification Versioning Section as well as understand the Memento Terminology. 

This design relates specifically to how versioning could be done in the Modeshape Implementation of Fedora 4

...

  1. Enable Versioning on a LDPR

    1. A PUT or POST request to create an object will make a resource versionable if it includes header Link: rel="type" with type of http://fedora.info/definitions/fcrepo#VersionedResource

      1. A LDPR will be created as a LDPRv with the versioning type.

      2. A LDPCv will be created, from which a TimeMap can be generated.

      3. A LDPRm will be generated, contained by the LDPCv.

      4. Any subsequent responses from the LDPRv will include the appropriate memento links in the header: Timegate, Timemap

    2. A PUT request to an Existing LDPR will make a resource versionable if it includes header Link: rel="type" with type of http://fedora.info/definitions/fcrepo#VersionedResource

      1. The versioning type will be added to the LDPR, making it a LDPRv.

      2. A LDPCv will be created, from which a TimeMap can be generated.

      3. A LDPRm will be generated, contained by the LDPCv.

      4. Any subsequent responses from the LDPRv will include the appropriate memento links in the header: timegate, timemap

  2. Check if a resource is versionable and discover the TimeMap/LDPCv

    1. A HEAD request on the LDPRv will return response with Link rel="type" http://fedora.info/definitions/fcrepo#VersionedResource which indicates versioning support and a 'Link rel="timemap"' points to the URL of the LDPCv/TimeMap.

  3. Check if the client can create versions

    1. An OPTIONS request on LDPCv/TimeMap that contains an "Allow: POST" header indicates that versions can be created by a client.

  4. Creating a new version of a LDPRv 

    • Note: when creating a new version of the LDPRv, only the single resource itself will be versioned. There is no concept of "tree" snapshots anymore. 

    1. A POST request to the LDPCv with an empty body and no "Memento-Datetime" header will cause a new memento of the LDPRv to be created with current date/time. 

    2. A POST request to the LDPCv with header "Memento-Datetime" and no body will create a historic verision with current state of the LDPRv an empty resource with the specificed date/time. 

    3. A POST request to the LDPCv with header "Memento-Datetime" and a body will create a historic version with the specified body and date/time.

    4. A POST request to the LDPCv with a body and no "Memento-Datetime" header to create a version with the specified body and the current datetime.

  5. Access the TimeMap (LDPCv) to see what versions exist

    1. A GET request to the LDPCv with the "Accept: application/link-format" header will cause the TimeMap to be returned. 

    2. A GET request to the LDPCv with no "Accept:" header, or one specificying an RDF format will result in the LDPCv being returned in rdf format. 

    3. The response from the GET will include a "Vary-Post: Memento-Datetime" to indicate that a client can request a specific time be associated with a memento when it's created via a POST. 

  6. Access an existing version (LDPRm)

    1. A GET request to the TimeGate Resource (the LDPRv itself) with "Accept-Datetime" header specified will return a 302 response, with a 'Location' header providing the URI of the LDPRm associated with that datetime, or the closest one if there is not an exact match. 

      • example header usage:  "Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT"a

      • See: Datetime negotiation algorithm example for Accept-Datetime negotiation details.

      • We are currently planning to follow Memento Datetime negotiation pattern 1.1, see: section 4.1.1. Link header will be in the response to show the TimeGate URI 

    2. A GET request to LDPRm/Memento (if the LDPRm/Memento has its own URI), will result in the memento being returned if it exists.See: Datetime negotiation algorithm example for Accept-Datetime negotiation details.

    3. Any response from the LDPRv will include link relation headers of type "timegate" (referring to the LDPRv), "original" (also referring to this LDPRv), and "timemap" (referencing the URI of the LDPCv). 

  7. Delete an existing version (LDPRm)

    1. A DELETE request to LDPRm/Memento will result in that memento being deleted. 

  8. Restore an existing version (LDPRm) 

    • Note: This interaction still needs to be ironed out as this is currently under discussion in Spec Issue 217

    1. A PUT request to LDPRv/TimeGate with header (can't be Content-Location, but something like it) pointing to the LDPRm/Memento URI to indicate the version to restore

...

  1. LDPRv  – has child → LDPCv – has children → LDPRm(s)
    as long as we do not generate ldp:contains triples on the LDPRv for the LDPCv using this Predicate. We can ensure that deleting a LDPRv will remove the LDPCv and deleting the LDPCv with delete all the LDPRm(s).
  2. How do we do the above filtering? 
    1. Do we add new RDF types (fcrepo-specification issue 233)
    2. Do we just add a property to the JCR node?
  3. A GET or HEAD request to a timemap (LDPCv) should return all LDRm(s) and their start-end ranges. 
    1. Do we want to generate this list on the fly or store it on the LDPCv and update it on any create/update or delete?
    2. The Memento-Datetime provided when creating a LDPRm (or the current date) indicates the start datetime of that version.
      1. would the end datetime be the next update to the LDPRv?
      2. would it be the lastModified date of the LDPRv?

Design Implementation

If some of this is crazy or overkill, please don't do it. I'm finding it harder to create interface and classes than I expected without actually writing any code.

...

  • Repurpose isVersioned(), enableVersioning() and disableVersioning() in FedoraResource interface, add getTimeMap() function this is our LDPRv.
  • Create TimeMap interace defining getVersions(), getVersion(final Date/Instant d), createVersion(), createVersion(final Date/Instant d), getOriginal() and Modeshape implementing class (LDPCv)
    • VersionService interface and VersionServiceImpl functions/code (if useful) can be moved to TimeMap class. createVersion() for instance.
  • Repurpose FedoraVersion interface and FedoraVersionImpl, perhaps need getOriginal() and getTimemap() for them (LDPRm)
  1. Datetime negotiation of the LDPRv (URI-R) meaning a request to the LDPRv with an Accept-Datetime header can return either
    1. a 200 OK status and a Content-Location header with the address of the LDPRm (URI-M), if this is a GET request the LDPRm body should be returned too.
    2. a 302 Found status and a Location header with the address of the LDPRm (URI-M), the client must make a direct GET request to the provided Location URI.
    3. which of the above two is better. A provides the body in one request (a GET to the LDPRv), but B does not use Content-Location that we already use for external content.

Design Implementation

If some of this is crazy or overkill, please don't do it. I'm finding it harder to create interface and classes than I expected without actually writing any code.

  • In fcrepo-kernel-api and fcrepo-kernel-modeshape
    • Repurpose isVersioned(), enableVersioning() and disableVersioning() in FedoraResource interface, add getTimeMap() function this is our LDPRv.
    • Create TimeMap interace defining getVersions(), getVersion(final Date/Instant d), createVersion(), createVersion(final Date/Instant d), getOriginal() and Modeshape implementing class (LDPCv)
      • VersionService interface and VersionServiceImpl functions/code (if useful) can be moved to TimeMap class. createVersion() for instance.
    • Repurpose FedoraVersion interface and FedoraVersionImpl, perhaps need getOriginal() and getTimemap() for them (LDPRm)
  • In fcrepo-http-api
    • Repurpose FedoraVersioning paths for use with TimeMap
    • Repurpose FedoraVersions to allow direct access to a specific Memento via its URI. (/fcrepo/rest/foo/fcr:versions/1234-5678)
    • Add new handing of headers and setting of response headers in FedoraLdp (
      Jira
      serverDuraSpace JIRA
      serverIdc815ca92-fd23-34c2-8fe3-956808caf8c5
      keyFCREPO-2612
      )
    • Handle DateTime negotiation on LDPRvs in FedoraLdp (
      Jira
      serverDuraSpace JIRA
      serverIdc815ca92-fd23-34c2-8fe3-956808caf8c5
      keyFCREPO-2613
      )

...


REST Interaction questions

(POST w/o body) → LDPCv → (copy) LDPRv → LDPRm

  1. POST to LDPCv without body and with or without Memento-Datetime header
  2. (If WebAC enabled)
    1. Locate ACL on LDPCv, and up tree.
    2. Verify Read/Write permissions.
    3. Throw Exception if not permitted
  3. Get LDPRv and create new child of LDPCv with this body.
  4. Add rdf:type or identifier of Memento type (Identify as a Memento)
    1. If we use a rdf:type to mark a Memento then should we display that when the Memento is requested?
    2. Should we just call Mementos anything inside of a TimeMap?
  5. Add snapshot datetime as property
    1. Where do we store the snapshot datetime? Property on the node?

(POST w body) → LDPCv → (compare LDP subtype) LDPRv → LDPRm

  1. POST to LDPCv with a new body and with or without Memento-Datetime header
    1. Can you provide a body and NOT provide a date?
  2. (If WebAC enabled)
    1. Locate ACL on LDPCv, and up tree.
    2. Verify Read/Write permissions.
    3. Throw Exception if not permitted
  3. Compare the rdf:type of resource because we can't provide a LDP-NR as a Memento of a LDP-RS or vice versa
  4. Set the entity body as the new resource.
  5. Identify as a Memento?
  6. Add snapshot datetime as property.

(GET/HEAD w Accept: application/link-format) → LDPCv 

  1. GET/HEAD to LDPCv
  2. (If WebAC enabled)
    1. Locate ACL on LDPCv, and up tree.
    2. Verify Read permissions.
    3. Throw Exception if not permitted
    4. Locate ACL on ??? for LDPRm(s) 
      1. where do we put the ACL for all the Mementos?
    5. Verify Read permissions.
    6. Throw Exception if not permitted.
  3. Get all children Mementos, generate list of Mementos and return

(GET/HEAD w Accept-Datetime: header) → LDPRv

  1. GET/HEAD to LDPRv
  2. (If WebAC enabled)
    1. Locate ACL on LDPRv and up tree
    2. Verify Read permissions.
    3. Throw Exception if not permitted.
    4. Locate ACL on LDPCv and up tree
    5. Verify Read permissions.
    6. Throw Exception if not permitted.
    7. Locate ACL on LDPRm(s)
    8. Verify Read permissions.
    9. Throw Exception if not permitted.
  3. Get list of all LDPRm(s) and snapshot datetimes.
  4. Find closest LDPRm(s)
  5. Return 302 Found and Location: <path to chosen LDPRm>


General interaction questions.

  1. How do you set the ACL that covers all Mementos?
    1. Can't POST/PUT to LDPRm(s) as Mementos are immutable

...

Jira
serverDuraSpace JIRA
serverIdc815ca92-fd23-34c2-8fe3-956808caf8c5
keyFCREPO-2612

...

Jira
serverDuraSpace JIRA
serverIdc815ca92-fd23-34c2-8fe3-956808caf8c5
keyFCREPO-2613

...