*Deprecated* This material is for historical purposes only See https://wiki.duraspace.org/display/VIVODOC/All+Documentation for current documentation
*Deprecated* See https://wiki.duraspace.org/display/VIVODOC/All+Documentation for current documentation
Clarify goals: move presentation logic out of the business layer
Add mention of DataGetters hanging on templates
Add a Plan section after Goals and before Specification
With Custom List View, explain how it will differ, and how the logic is moving out of the back end. Talk about collating, sorting on a field
How does a Faux Property fit in here? Need to at least mention it
Allow byClassOf and byProperty to be optional (can we use both?), to take the place of Page DataGetters. Add that to the Goals and Plan sections.
Simplify goals.
The DataView directive is an attempt to add power to the user interface. Keeping the ability to use RDF to determine the appearance of the application, but also giving more control to the template writer. Removing redundant customization mechanisms, with the ensuing simplification of the code base. Providing easy integration of AJAX with Freemarker. By creating the ability to do custom list views in the presentation layer, allow us to remove complicated presentation logic from the controllers.
<@DataView setting="Sort", byClassOf=individualUri, byProperty=property ajax values=hash>
Where:
setting | required | The name of the view type. This might be "Sort", "Browse", "ListView", etc. This will be used as the primary selection criterion. Must match exactly to the view spec. |
byClassOf | requires exactly one | A 2nd selection criterion. Provide either a String containing the URI of the individual in question, or an IndividualTemplateModel representing that individual. The class of the individual, or a parent class, must match the view. |
byProperty | A 2nd (and possibly 3rd and 4th) selection criterion. If a String, then it is the URI of the property to match. If a PropertyTemplateModel, then the property URI must match, as well as the class of the subject (domain) and the class of the object (range). | |
ajax | optional | If present, this view will be satisfied by an AJAX call. |
values | optional | A hash of values that will be added to the environment before the view template is rendered. |
The DataView directive searches the Display model for a DataView object. If found, the DataGetter associated with the DataView is executed, and the template associated with the DataView is rendered and included in the calling template.
If more than one eligible DataView object is found, the most specific DataView object is selected, according to the rules in View Selection.
If no eligible DataView object is found, no action is taken.
The byClassOf
parameter specifies the URI of an Individual. The directive searches for a view with the correct setting
property, and with the most specific match in a restrictByClass
property.
In this case, "most specific match" means searching for a view with a restrictByClass
property that is equal to the most specific class of the specified individual. If no such view is found, and the most specific class of the individual has a parent class, the search is repeated using that parent class. This continues until a view is found, or until there is no parent class to search for.
If a matching view is found at any step in the search, it is selected. If more than one view is found on a particular step of the search, one of the matching views will be arbitrarily selected. If no matching view is found during the entire search sequence, no action is taken.
Table of search order
The byProperty
parameter specifies a PropertyTemplateObject.
If the property is a data property, the directive searches for a view with the correct setting
property, and the most specific match in a restrictByDomain
property and a restrictByProperty
property. In this case, most specific match means searching for an exact match, then searching for matches to the super-classes of the domain of the specified proeprty, and then repeating that sequence for matches to the super-properties of the specified property.
If the property is an object property, the directive searches includes a match for the restrictByRange
property and its super-classes, before trying less specific matches for the domain and te property URI.
The search for a byProperty
match must be optimized using some form of caching, since on an object property it could result in (d+1) x (p + 1) x (r + 1)
queries, where
d
is the number of super-classes of the domain classp
is the number of super-properties of the specified propertyr
is the number of super-classes of the range classTable of search order
A DataView object may have zero or more DataGetter objects associated with it. When the DataView object is selected, the DataGetter objects will be instantiated and run, in an arbitrary order. When ordering is important, the multiple DataGetter objects should be specified within a single SequenceDataGetter object.
A DataView object may have zero or one freemarker template associated with it. If a DataView object has an associated freemarker template, that template will be rendered in the context of the DataView directive, after any associated DataGetters have been run. Absence of an associated template is not treated as an error.
After the directive <#DataView setting="foobar">
, the variable dataView_foobar
will be set to true if a suitable view was found, otherwise will be set to false. This allows a construct like this:
<@DataView setting="sort" byClass=individual /> <#if !dataView_sort> <!-- specify the default view --> </#if>
An equivalent mechanism would be to specify the default view with a class of owl:Thing. That view would always be used if no other match was found.
If "ajax" is specified in the directive, the selection process is performed as usual, but the process stops there. Instead of executing any associated DataGetter object and rendering the template, a JavaScript segment is created which will perform those steps asynchronously, after the page has been loaded.
The directive should have the same net effect, with one caveat: when the associated template is rendered, the Freemarker body map will appear as it did when the main page completed rendering. DataGetters executed by an asynchronous DataView directive have no effect on other DataView directives, whether synchronous or asynchronous. Variable assignments made by an asynchronous DataView directive also are not visible to other DataView directives.
This might not be in the first implementation.
Let's look at how we select the correct template for a profile page.
Currently, the IndividualTemplateLocator
class searches for the correct template to use when displaying an individual profile page. The data model contains these statements:
foaf:Person vitro:customDisplayViewAnnot "individual--foaf-person.ftl"^^xsd:string . foaf:Organization vitro:customDisplayViewAnnot "individual--foaf-organization.ftl"^^xsd:string . skos:Concept vitro:customDisplayViewAnnot "individual--skos-concept.ftl"^^xsd:string .
Using DataView
, we can accomplish the same thing without the IndividualTemplateLocator
class. Here are two ways to do it.
Owl:Thing
, that can never happen.Use these statements in individual.ftl
:
<@DataView setting="INDIVIDUAL_PROFILE" byClassOf=individualUri> <#if !dataView_INDIVIDUAL_PROFILE> <#include "individual--default.ftl"> </#if>
and these statements in the data model
display:individualProfileViewPerson a display:DataView; display:setting "INDIVIDUAL_PROFILE" ; display:restrictByClass foaf:person ; display:hasTemplate "individual--foaf-person.ftl"^^xsd:string . display:individualProfileViewOrganization a display:DataView; display:setting "INDIVIDUAL_PROFILE" ; display:restrictByClass foaf:organization ; display:hasTemplate "individual--foaf-organization.ftl"^^xsd:string . display:individualProfileViewConcept a display:DataView; display:setting "INDIVIDUAL_PROFILE" ; display:restrictByClass skos:Concept ; display:hasTemplate "individual--skos-concept.ftl"^^xsd:string .
If the class of the individual does not match foaf:Person
, foaf:Organization
, or skos:Concept
, the template explicitly says that we will render the individual using individual--default.ftl
.
Use this statement in individual.ftl
:
<@DataView setting="INDIVIDUAL_PROFILE" byClassOf=individualUri>
and these statements in the data model
display:individualProfileViewPerson a display:DataView; display:setting "INDIVIDUAL_PROFILE" ; display:restrictByClass foaf:person ; display:hasTemplate "individual--foaf-person.ftl"^^xsd:string . display:individualProfileViewOrganization a display:DataView; display:setting "INDIVIDUAL_PROFILE" ; display:restrictByClass foaf:organization ; display:hasTemplate "individual--foaf-organization.ftl"^^xsd:string . display:individualProfileViewConcept a display:DataView; display:setting "INDIVIDUAL_PROFILE" ; display:restrictByClass skos:Concept ; display:hasTemplate "individual--skos-concept.ftl"^^xsd:string . display:individualProfileViewDefault a display:DataView; display:setting "INDIVIDUAL_PROFILE" ; display:restrictByClass owl:Thing ; display:hasTemplate "individual--default.ftl"^^xsd:string .
Here, there is no chance of not finding a match, because every individual will be an instance of owl:Thing.
When the current short view mechanism was implemented in release 1.5, it was with the assumption that it would be driven by the application ontology. Since the application ontology was not ready for release 1.5, a temporary driving mechanism was created.
The driver for short views is the FakeApplicationOntologyService
class. This is quite limited, in the sense that it only recognizes a match to the most specific class of the Individual being displayed. So, if you want to configure a short view for foaf:Person
and all of its sub-classes, you must do it explicitly with one statement for each such sub-class. Also, we should note that the FakeApplicationOntologyService
code contains a hard-coded exception to its matching algorithm, in order to retain compatibility with earlier implementations. This exception is buried deep in the code, and would remain a mystery to the template author.
As an example, the short view in the search results is invoked this way, in search-pagedResults.ftl
:
<@shortView uri=individual.uri viewContext="search" />
With the DataView directive, this becomes:
<@DataView setting="SEARCH_RESULT" byClassOf=individual.uri />
The short view is configured by a file called shortview_config.n3
. For a custom short view in the sort results, the file might contain these structures:
vivo:FacultyMember display:hasCustomView mydomain:facultySearchView . mydomain:facultySearchView a display:customViewForIndividual ; display:appliesToContext "SEARCH" ; display:hasTemplate "view-search-faculty.ftl" ; display:hasDataGetter mydomain:facultyDepartmentDG . mydomain:facultyDepartmentDG a datagetters:SparqlQueryDataGetter ; display:saveToVar "details" ; display:query """ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX vivo: <http://vivoweb.org/ontology/core#> SELECT ?deptName WHERE { ?individualUri vivo:hasMemberRole ?membership . ?membership vivo:roleContributesTo ?deptUri . ?deptUri a vivo:AcademicDepartment ; rdfs:label ?deptName . } LIMIT 20 """ .
These statements define a customViewForIndividual
, assign it to the SEARCH
context, add a template and a data getter, and associate it with the class vivo:FacultyMember
With the DataView directive, these statements would change only trivially:
display:facultySearchView a display:DataView; display:setting "SEARCH_RESULT" ; display:restrictByClass vivo:FacultyMember ; display:hasTemplate "view-search-faculty.ftl" ; display:hasDataGetter mydomain:facultyDepartmentDG . mydomain:facultyDepartmentDG ... unchanged ...
A primary distinction between <@shortview>
and <@DataView>
is the behavior when no view is found. In this case,
<@shortview>
renders a default template, whose name is embedded somewhere in the Java code.<@DataView>
takes no action beyond setting a Freemarker variable. This allows the template author to test for a matching view, and to specify explicitly what the default action should be (as illustrated in the previous example).
TBD
TBD
Assign labels to the various DataGetter classes, etc., to help with the GUI.
TBD
values
parameter to add values to the environment, and then not have those values persist?foaf:Person
or one of it's super-classes?