Fedora Repository Views
...
But the angle one views the repository might also affect the number of entries seen. The above, recursive approach will always lead to one entry per data object. The remedy for this is to mark some classes as Entries for a certain view angle. This means that to compute the records for a given view angle, the view of all objects of a class that is an Entry should be computed. This is the view of the repository.
Fedora Implementation
This section describes how the above could be implemented in Fedora.
...
We want to be able to return all Views in a given Collection for a given State that have been modified after a given Time. To do this, we maintain a database of Views that is updated on all changes of an object.
Maintaining state
Whenever one of the components of a View is changed, the whole View counts as updated. As such, any services that subscribe to the View in any way need to be notified. If there is a search index for the Views, and one is updated, its state in the index must be recomputed.
The problem arrives when trying to do this. The View system is designed to ease the computing of a View when knowing the Entry object. The reverse is finding the Views, ie. the Entry objects, that have this data object in their View. Rather than encoding this information in the model, we chose to keep an external record of all the views.
...
- collectionPid
- state
- viewAngle
- offset
- limit
This can esily easily be found by a simple query in the ENTRIES table.
...
Changing an object and marking the view as updated
There are a fixed number of operations that can be done on objects in doms. For each of these, this is what should be done on the index as a result
...
Each of these operations will be elaborated below
Object State Changed
When the object state changes, we will have to update the state in the object, and possibly in any view containing the state.
So for each ENTRIES object containing this object, we update it with a new timestamp and state
- Active, if the new state is Active and all other objects in the view are current Active
- Deleted, if this is the entry object, and
- Inactive, otherwise
...
language | java |
---|
...
Basically, we need three kinds of operations to handle updates:
- We need to update the time for when a bundle was last updated. We'll call this "updateTimestamps"
- We need to update which bundles in which states exist. We'll call this "modifyState"
- We need to update which objects are part of the view. We'll call this "recalculateView"
There are a fixed number of operations that can be done on objects in doms.
For each of these, this is what should be done on the index as a result
Object Created: The Object was created in DOMS
Fedora operations:
- ingest
Action:Code Block modifystate() recalculateview()
Object Deleted: The Object was purged from DOMS
Fedora operations:
- purgeObject
Action:Code Block modifystate('D')
Object State Changed: The Object changed state in DOMS
Fedora operations:
- modifyObject
Action:Code Block modifystate()
Datastream Changed: The Object datastreams changed. Handled differently depending on whether this is the relations datastream
Fedora operations:
- addDatastream
- modifyDatastreamByReference
- modifyDatastreamByValue
- purgeDatastream
- setDatastreamState
- setDatastreamVersionable
- updatetimestamp
Action:Code Block if RELS-EXT recalculateview() else updatetimestamp()
Object Relations Changed: The Object changed in a fashion that DOES require the view to be recomputed.
Fedora operations:
- addRelationship
- purgeRelationship
Action:Code Block recalculateview()
Each of these operations will be elaborated below
Modifystate
When the object state changes, we will have to update the state in the object, and possibly in any view containing the state.
So for each ENTRIES object containing this object, we update it with a new timestamp and state
- Active, if the new state is Active and all other objects in the view are current Active
- Deleted, if this is the entry object, and
- Inactive, otherwise
Code Block | ||
---|---|---|
| ||
modifystate(pid, date, state) { //If this object was previously unknown and is an entry object, add it as a new entry object if (!OBJECTS.contains(pid)) { List<viewangle,cmpid,collection> viewEntries = doms.getViewEntries(); updateEntry(result.entryPid, foreach (viewEntry : viewEntries) { ENTRIES.add(pid,date,state,viewangle,cmpid,collection) 'Active', OBJECTS.add(pid,pid,viewangle) } } //Find the DomsObject rows that regard this result.viewAngle, object. //There will be one per entry/viewAngle combination results = OBJECTS.list(objectPid=pid); //Find all Entries that include this object foreach (result : results) { date); oldstate = result.entryPid.state; }newstate = calculatestate(result.entryPid, pid, timestamp, state) //AlwaysTODO! markMissing them as updated for the inactive state updateEntry(result.entryPid, // If this deletes the entry, handle that if (newstate = 'D') { 'Inactive', if (oldstate != 'D') { ENTRIES.removeAll(result.viewAngle,entryPid) OBJECTS.removeAll(entryPid=result.entryPid) date); ENTRIES.add(entryPid,'D',timestamp) } } // Find} view Info for this object List<ViewInfo> viewInfoList = fedora.getViewInfo(pid, date); for (ViewInfo viewInfo : viewInfoList) { return } // If it is anset entry objectactive, setremove itany indeleted the ENTRIESentries table if (viewInfo.isEntry()) { if (viewAnglenewstate = 'ActiveA') && allActive(pid, viewInfo.viewangle)) {{ updateEntry(pidENTRIES.remove(result.entryPid, 'Active', viewInfo.viewAngle, dateD'); } updateEntry(pid, 'Inactive', viewInfo.viewAngle, date); } else if (viewAngle = 'Deleted') { updatetimestamp() |
Updatetimestamp
Code Block |
---|
// Update the Entries table regarding a change void updatetimestamps(String pid, Date date) { objects = OBJECTS.list(objectPid=pid); //Find all Entries that include this object foreach (object : objects) { // TODO: Should we remove allstate objects referring to this viewangle?= calculatestate(object.entryPid) //TODO! Missing //If entry is currently deleted, skip updateEntry(pid, 'Deleted', viewInfo.viewAngle, date); if (state = 'D') { } else { return; updateEntry(pid, 'Inactive', viewInfo.viewAngle, date); } //Find the Entry objects that fulfill }these restrictions } } } // UpdateList<Entry> theresults Entries table regarding a change void updateEntry(String entryPid, String state, String viewAngle, Date date= ENTRIES.list(entrypid = object.entrypid) for (Entry result : results) { //Find the Entry objects that fulfill these restrictions//Only update active entry if List<Entry>bundle resultsis = ENTRIES.list(entrypid,state,viewangle)active //There might be no Entry, but if we are here, we know that an entry should exist, so create it.(result.state = 'A' and state != 'A') { if (results.size() == 0) { ENTRIES.insert(new Entry(entryPid, viewAngle, state, date)); continue } else { for (Entry result : results) { } //Is this entry older than the current change? if (result.getDateForChange().getTime() < date.getTime()) { resultENTRIES.setDateForChangeupdate(result, date); } result.setEntryPid(entryPid); } } result.setState(state); result.setViewAngle(viewAngle); } //Save the entry ENTRIES.update(result); } } } void updateDomsObjects(String objectPid, String entryPid, String viewAngle) { list<DomsObject> results = OBJECTS.list(objectPid,entryPid,viewAngle) if (results.size() == 0) {} |
Recalculateview
An object's relations changed. This could change which objects are in which entry's views.
We find all the Entries that contain this object by listing OBJECTS.
For each of these, we recalculate the view bundle and update the relevant rows in OBJECTS and ENTRIES.
Each row in OBJECTS specify that an object is contained in a named view for a specific entry object.
Then we update the ENTRIES table to mark that the view is changed.
This may also update content model or collection relations, which is handled separately
Code Block |
---|
objectRelationsChanged(pid, date) { //This code is pseudo'er than the rest if relation changes collection if it is an entry object update collection field for inactive if entry object is active update OBJECTS.insert(new DomsObject(objectPid, entryPid, viewAngle));collection field for active }//This } |
Object Relations Changed
An object's relations changed. This could change which objects are in which entry's views.
We find all the Entries that contain this object by listing OBJECTS.
For each of these, we recalculate the view bundle and update the relevant rows in OBJECTS and ENTRIES.
Each row in OBJECTS specify that an object is contained in a named view for a specific entry object.
Then we update the ENTRIES table to mark that the view is changed.
TODO: This may ALSO update content models or collections. I think we can fix this by calling objectModified when these specific relations are called
Code Block |
---|
void objectRelationsChanged(String pid, Date date) {code is pseudo'er than the rest if relation changes content model if it is previously an entry object remove if it is now an entry object ingest return //This can change the structure of the views and we must therefore recaculate the views //if a current entry object use this object, we will need to recalculate the view of that object //This method will only be called on objects that already exist. //ObjectModified() creates an Entry row, if the object is an entry object. As such, there will always be // the correct Entry entries when this method is called, and these should just be recalculated List<DomsObject> results = OBJECTS.list(objectPid=pid); //we now have a list of all the entries that include this object. for (DomsObject result : results) { //get the ViewBundle from fedora ViewBundle bundle = fedora.calcViewBundle(result.getEntryPid(), result.getViewAngle(), date); //First, remove all the objects in this bundle from the table removeNotListedFromDomsObjects(bundleOBJECTS.getContaineddelete(), result.getEntryPid(), result.getViewAngle()); //Add all the objects from the bundle to the objects Table. for (String objectPid : bundle.getContained()) { updateDomsObjects(objectPid, bundle.getEntryOBJECTS.addAll(result.getEntryPid(), result.getViewAngle(), bundle.getViewAnglegetObjects()); } updateEntryupdateTimestamp(bundle.getEntry(), STATE_INPROGRESS, bundle.getViewAngle(), date); } } void removeNotListedFromDomsObjects(List<String> objectPid, String entryPid, String viewAngle) { List<DomsObject> results = OBJECTS.list(entryPid,viewAngle); for (DomsObject result : results) { if (!objectPid.contains(result.getObjectPid())) { OBJECTS.delete(result); } } } |
With these two functions, the rest of the events can be modelled as from them
Object Changed
This is the same as Object State Changed, if the state did not really change. If the state is not changed, this method will just update timestamps in ENTRIES.
Object Created
An object that is created will not, per default, be part of any views, except any where it is the entry object, as these are defined through relations, and a newly created object will not reference any other objects.
As such, it is the same as Object State Changed.
Object Deleted
The Object was purged from DOMS.
Find the object as an entrypid in ENTRIES (if it is not an entry, it will not be there).
if is an entry
Mark is as deleted with the new date.
Find all the rows in OBJECTS which refer to this entrypid and viewangles, and remove them.
Remove the object from OBJECTS
TODO pseudocode
...