[VIVO-1312] Implement Linked Data Fragment Server (#53)

* [VIVO-1312] Linked Data Fragments initial implementation

* [VIVO-1312] Use known ontologies in the prefixes config

* [VIVO-1312] Simplify SPARQL as when restricted to specific values, they don’t need ordering

* [VIVO-1312] Freemarker fixes

* [VIVO-1312] Remove blank nodes

* [VIVO-1312] Add access control header and standard prefixes for TPF

* [VIVO-1312] Render literals in form so that they will work on resubmit

* [VIVO-1312] Minor template update

* [VIVO-1312] Minor template update
This commit is contained in:
grahamtriggs 2016-12-23 21:55:08 +00:00 committed by GitHub
parent e9cb3de52e
commit 68a462b05a
63 changed files with 5215 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

View file

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="400px" height="220px" viewBox="0 0 400 220" enable-background="new 0 0 400 220" xml:space="preserve">
<g>
<path fill="#1D1D1B" d="M188.8,29.3v99.7h65.4v22.9h-89.9V29.3H188.8z"/>
<path fill="#1D1D1B" d="M266,151.8V29.2h47.2c38.1,0,57.2,20.5,57.2,61.3c0,40.8-19.1,61.3-57.2,61.3H266z M313.2,127.4
c21.7-0.1,32.6-12.3,32.7-36.8c-0.1-24.5-10.9-36.8-32.7-36.8h-22.7v73.6H313.2z"/>
</g>
<g>
<path fill="#1D1D1B" d="M29.2,170.4h4.3v20.5h10v3.6H29.2V170.4z"/>
<path fill="#1D1D1B" d="M45.7,170.8c0-1.4,1.1-2.4,2.6-2.4c1.5,0,2.6,1,2.6,2.4c0,1.4-1.1,2.4-2.6,2.4
C46.8,173.2,45.7,172.2,45.7,170.8z M46.2,176.4h4.2v18.1h-4.2V176.4z"/>
<path fill="#1D1D1B" d="M54.8,176.4h3.5l0.3,2.4h0.1c1.6-1.6,3.5-2.9,5.9-2.9c3.9,0,5.6,2.6,5.6,7.2v11.3H66v-10.8
c0-3-0.8-4.1-2.8-4.1c-1.6,0-2.6,0.8-4.1,2.2v12.6h-4.2V176.4z"/>
<path fill="#1D1D1B" d="M74.3,168.5h4.2v16.2h0.1l6.7-8.3h4.6l-6.2,7.4l6.8,10.7h-4.6l-4.6-7.8l-2.8,3.2v4.6h-4.2V168.5z"/>
<path fill="#1D1D1B" d="M98.7,175.9c4.9,0,7.5,3.5,7.5,8.6c0,0.8-0.1,1.5-0.2,2H94.6c0.4,3.3,2.4,5.1,5.3,5.1
c1.5,0,2.9-0.5,4.2-1.3l1.4,2.7c-1.7,1.1-3.9,2-6.2,2c-5,0-8.9-3.5-8.9-9.5C90.4,179.5,94.5,175.9,98.7,175.9z M102.5,183.8
c0-2.9-1.2-4.6-3.7-4.6c-2.1,0-4,1.6-4.3,4.6H102.5z"/>
<path fill="#1D1D1B" d="M115.8,175.9c2.1,0,3.3,0.8,4.7,2l-0.1-2.9v-6.6h4.2v26h-3.5l-0.3-2h-0.1c-1.3,1.3-3.2,2.4-5.1,2.4
c-4.5,0-7.4-3.5-7.4-9.5C108.1,179.5,111.8,175.9,115.8,175.9z M116.6,191.4c1.4,0,2.6-0.6,3.8-2v-8.4c-1.3-1.1-2.5-1.5-3.7-1.5
c-2.3,0-4.2,2.2-4.2,6C112.5,189.3,113.9,191.4,116.6,191.4z"/>
<path fill="#1D1D1B" d="M135.7,170.4h6.4c7.4,0,11.7,4,11.7,11.9c0,8-4.4,12.1-11.5,12.1h-6.6V170.4z M141.8,191
c4.9,0,7.7-2.8,7.7-8.7c0-5.9-2.8-8.5-7.7-8.5H140V191H141.8z"/>
<path fill="#1D1D1B" d="M167.1,182.9c0-1.9-0.8-3.5-3.3-3.5c-1.8,0-3.5,0.8-5.1,1.8l-1.5-2.8c2-1.3,4.5-2.4,7.4-2.4
c4.5,0,6.7,2.8,6.7,7.8v10.7h-3.5l-0.3-2h-0.1c-1.6,1.4-3.5,2.4-5.6,2.4c-3.2,0-5.4-2.1-5.4-5.3
C156.5,185.7,159.7,183.7,167.1,182.9z M163.2,191.6c1.5,0,2.6-0.7,3.9-2v-4c-4.9,0.6-6.5,1.9-6.5,3.7
C160.6,190.9,161.6,191.6,163.2,191.6z"/>
<path fill="#1D1D1B" d="M176,179.7h-2.6v-3.2l2.8-0.2l0.5-4.9h3.5v4.9h4.6v3.3h-4.6v8.6c0,2.1,0.8,3.2,2.5,3.2
c0.6,0,1.4-0.2,1.9-0.4l0.7,3.1c-1,0.3-2.2,0.7-3.7,0.7c-4.2,0-5.7-2.6-5.7-6.6V179.7z"/>
<path fill="#1D1D1B" d="M196.9,182.9c0-1.9-0.8-3.5-3.3-3.5c-1.8,0-3.5,0.8-5.1,1.8l-1.5-2.8c2-1.3,4.5-2.4,7.4-2.4
c4.5,0,6.7,2.8,6.7,7.8v10.7h-3.5l-0.3-2h-0.1c-1.6,1.4-3.5,2.4-5.6,2.4c-3.2,0-5.4-2.1-5.4-5.3
C186.3,185.7,189.5,183.7,196.9,182.9z M193,191.6c1.5,0,2.6-0.7,3.9-2v-4c-4.9,0.6-6.5,1.9-6.5,3.7
C190.4,190.9,191.5,191.6,193,191.6z"/>
<path fill="#1D1D1B" d="M212.1,170.4h14.5v3.6h-10.3v6.8h8.7v3.6h-8.7v10h-4.3V170.4z"/>
<path fill="#1D1D1B" d="M228.6,176.4h3.5l0.3,3.2h0.1c1.3-2.4,3.2-3.6,5.1-3.6c0.9,0,1.5,0.1,2.1,0.4l-0.7,3.7
c-0.6-0.2-1.1-0.3-1.9-0.3c-1.4,0-3.2,1-4.3,3.7v11h-4.2V176.4z"/>
<path fill="#1D1D1B" d="M250.1,182.9c0-1.9-0.8-3.5-3.3-3.5c-1.8,0-3.5,0.8-5.1,1.8l-1.5-2.8c2-1.3,4.5-2.4,7.4-2.4
c4.5,0,6.7,2.8,6.7,7.8v10.7h-3.5l-0.3-2h-0.1c-1.6,1.4-3.5,2.4-5.6,2.4c-3.2,0-5.4-2.1-5.4-5.3
C239.5,185.7,242.7,183.7,250.1,182.9z M246.1,191.6c1.5,0,2.6-0.7,3.9-2v-4c-4.9,0.6-6.5,1.9-6.5,3.7
C243.6,190.9,244.6,191.6,246.1,191.6z"/>
<path fill="#1D1D1B" d="M259.8,193.9v-0.1c-0.9-0.6-1.6-1.5-1.6-3c0-1.4,1-2.6,2-3.3v-0.1c-1.2-0.9-2.4-2.7-2.4-4.8
c0-4.2,3.3-6.5,7.1-6.5c1,0,1.9,0.2,2.6,0.4h6.5v3.1h-3.3c0.6,0.7,1,1.8,1,3.1c0,4-3,6.1-6.8,6.1c-0.8,0-1.7-0.1-2.5-0.5
c-0.6,0.5-0.9,0.9-0.9,1.7c0,1,0.7,1.7,2.9,1.7h3.2c4.3,0,6.6,1.3,6.6,4.5c0,3.6-3.8,6.4-9.6,6.4c-4.3,0-7.5-1.5-7.5-4.7
C257.2,196.2,258.1,194.9,259.8,193.9z M265.4,199.7c2.9,0,4.9-1.4,4.9-2.9c0-1.4-1.1-1.8-3.2-1.8h-2.5c-1,0-1.8-0.1-2.5-0.3
c-1,0.7-1.4,1.5-1.4,2.4C260.7,198.7,262.5,199.7,265.4,199.7z M268,182.4c0-2.2-1.4-3.6-3.1-3.6s-3.2,1.3-3.2,3.6
c0,2.3,1.4,3.6,3.2,3.6C266.6,186.1,268,184.7,268,182.4z"/>
<path fill="#1D1D1B" d="M276.5,176.4h3.5l0.3,2.5h0.1c1.5-1.6,3.3-2.9,5.5-2.9c2.6,0,4.2,1.2,5,3.2c1.7-1.8,3.5-3.2,5.8-3.2
c3.8,0,5.6,2.6,5.6,7.2v11.3h-4.3v-10.8c0-3-0.9-4.1-2.8-4.1c-1.1,0-2.4,0.7-3.8,2.2v12.6h-4.2v-10.8c0-3-0.9-4.1-2.8-4.1
c-1.1,0-2.4,0.7-3.8,2.2v12.6h-4.2V176.4z"/>
<path fill="#1D1D1B" d="M313.6,175.9c4.9,0,7.5,3.5,7.5,8.6c0,0.8-0.1,1.5-0.2,2h-11.5c0.4,3.3,2.4,5.1,5.3,5.1
c1.5,0,2.9-0.5,4.2-1.3l1.4,2.7c-1.7,1.1-3.9,2-6.2,2c-5,0-8.9-3.5-8.9-9.5C305.3,179.5,309.3,175.9,313.6,175.9z M317.4,183.8
c0-2.9-1.2-4.6-3.7-4.6c-2.1,0-4,1.6-4.3,4.6H317.4z"/>
<path fill="#1D1D1B" d="M324,176.4h3.5l0.3,2.4h0.1c1.6-1.6,3.5-2.9,5.9-2.9c3.9,0,5.6,2.6,5.6,7.2v11.3h-4.2v-10.8
c0-3-0.8-4.1-2.8-4.1c-1.6,0-2.6,0.8-4.1,2.2v12.6H324V176.4z"/>
<path fill="#1D1D1B" d="M344.2,179.7h-2.6v-3.2l2.8-0.2l0.5-4.9h3.5v4.9h4.6v3.3h-4.6v8.6c0,2.1,0.8,3.2,2.5,3.2
c0.6,0,1.4-0.2,1.9-0.4l0.7,3.1c-1,0.3-2.2,0.7-3.7,0.7c-4.2,0-5.7-2.6-5.7-6.6V179.7z"/>
<path fill="#1D1D1B" d="M356,189.7c1.6,1.3,3.2,2,5,2c2,0,2.9-0.9,2.9-2.2c0-1.5-2-2.2-3.9-2.9c-2.4-0.9-5.1-2.2-5.1-5.3
c0-3.2,2.5-5.4,6.6-5.4c2.5,0,4.5,1,6,2.2l-2,2.6c-1.3-0.9-2.5-1.5-4-1.5c-1.8,0-2.6,0.8-2.6,2c0,1.4,1.8,2,3.8,2.7
c2.5,0.9,5.2,2.1,5.2,5.5c0,3.1-2.5,5.6-7,5.6c-2.5,0-5.1-1.1-6.8-2.5L356,189.7z"/>
</g>
<g>
<path fill="#BE1622" d="M46.9,122.8H30.3l2.3-18.7H51l6.2-28.5H39.5l2.2-18h19.4l6.1-28.1h23.3l-6.1,28.1h24.5l6-28.1H138
l-6.1,28.1h18.2l-2.2,18H128l-6.2,28.5h18.6l-2.3,18.7h-20.4l-6.3,29.1H88.8l6.2-29.1H70l-6.3,29.1h-23L46.9,122.8z M98.9,104.1
l6.1-28.5H80.4l-6.3,28.5H98.9z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

@ -0,0 +1,247 @@
/*! @license ©2013 Ruben Verborgh - Multimedia Lab / iMinds / Ghent University */
html, input, th, td {
font-family: "Open Sans", Verdana, Arial, sans-serif;
font-size: 11pt;
}
html {
background: #f6f6f6;
}
body {
max-width: 800px;
margin: 0 auto;
line-height: 1.3;
color: #333333;
background-color: white;
padding: 10px 40px;
box-shadow: 2px 2px 15px 0px rgba(50, 50, 50, 0.75);
}
h1, h2, h3, legend {
margin: .4em 0 .2em;
overflow: hidden;
}
h1 {
margin-right: 180px;
}
h1 a {
color: black;
}
h2 {
color: #be1622;
}
h3 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
p {
margin: 0;
}
a {
color: #be1622;
text-decoration: none;
border-bottom: none 1px;
}
a:hover {
color: #be1622 !important;
border-bottom-style: solid;
}
ul {
padding: 0;
margin: 0 0 .5em 1.5em;
list-style: none;
}
pre {
margin: 0;
}
form {
margin: 0 0 1.5em;
}
fieldset {
border: none;
padding: .5em 0 0 20px;
}
fieldset ul {
margin-left: 0;
}
fieldset li {
line-height: 2em;
}
legend {
font-size: 1.17em;
font-weight: bold;
padding: 0;
margin-left: -20px;
}
label {
width: 100px;
display: block;
float: left;
clear: both;
font-weight: bold;
}
label:after {
content: ":";
}
input {
outline: none;
font-size: .95em;
}
fieldset input {
width: 500px;
color: #be1622;
background-color: transparent;
border: none;
border-bottom: 1px solid #bbbbbb;
cursor: pointer;
}
input[type=submit] {
font-weight: bold;
color: #be1622;
background-color: #f6f6f6;
border-radius: 3px;
padding: 5px 8px;
border: 1px solid #999999;
cursor: pointer;
}
input[type=submit]:hover {
border-color: #666666;
}
input[type=submit]:active {
padding: 6px 7px 4px 9px;
}
.uri {
font-family: "Droid Sans Mono", monospace;
}
header .logo {
text-align: right;
}
header .logo a {
position: absolute;
top: 20px;
margin-left: -100px;
border-bottom-width: 0px;
}
header .logo img {
width: 160px;
}
footer {
clear: both;
margin: 1.5em 0 .5em;
font-size: small;
}
footer * {
color: gray;
margin-right: 5px;
}
.counts {
color: gray;
}
ul.links {
margin: 0;
padding: 0;
display: inline;
}
ul.links li {
display: inline;
padding-left: 20px;
font-weight: bold;
}
ul.triples {
margin: .3em 0 1em 20px;
font-size: .95em;
line-height: 1.5;
font-family: "Droid Sans Mono", monospace;
overflow-x: hidden;
}
ul.triples li {
text-indent: -20px;
padding-left: 20px;
max-width: 100%;
max-height: 1.5em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
ul.triples li:hover {
max-height: 100em;
white-space: normal;
transition: max-height .5s ease-in;
transition-delay: .5s;
}
ul.triples li:not(:hover) a {
color: inherit;
}
ul.triples a:nth-child(2) {
margin: 0 1em;
}
abbr {
border: none;
}
.index {
margin-bottom: 2em;
}
.datasets {
margin: .5em 20px;
}
dt {
font-weight: bold;
display: block;
float: left;
clear: left;
}
dd {
color: gray;
margin: .1em 0 0 12em;
font-size: .95em;
}
#about {
margin-top: 1.5em;
font-size: .9em;
}
@media screen and (max-width: 700px) {
html, input, th, td {
font-size: 10pt;
}
body {
padding: 15px;
}
header figure {
display: none;
}
h1, legend {
margin: 0;
}
fieldset, ul.triples {
padding: .5em 0;
margin: 0;
}
fieldset input {
width: 70%;
}
label {
width: 80px;
}
ul.triples li {
margin: 1em 0;
}
}

View file

@ -0,0 +1,30 @@
<#-- @license ©2015 Miel Vander Sande - Multimedia Lab / iMinds / Ghent University -->
<#macro display_page>
<!DOCTYPE html>
<html lang="en" prefix="hydra: http://www.w3.org/ns/hydra/core# void: http://rdfs.org/ns/void#">
<head>
<meta charset="utf-8">
<title>Linked Data Fragments Server ${ (title!header)?ensure_starts_with("(")?ensure_ends_with(")") }</title>
<link rel="stylesheet" href="${ assetsPath }style.css" />
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Open+Sans:700italic,400,700|Droid+Sans+Mono" type="text/css" />
<meta name="viewport" content="width=device-width,minimum-scale=1,maximum-scale=1">
</head>
<body>
<header>
<h1><a href="${homePath}">Linked Data Fragments Server</a></h1>
<figure class="logo">
<a href="http://linkeddatafragments.org/"><img src="${ assetsPath }logo.svg" alt="Linked Data Fragments" /></a>
</figure>
</header>
<main>
<@contents/>
</main>
<footer>
<p>
Powered by a <a href="https://github.com/LinkedDataFragments/Server.java" target="_blank">Linked Data Fragments Server</a>
©2013${date?string.yyyy} Multimedia Lab iMinds Ghent University
</p>
</footer>
</body>
</html>
</#macro>

View file

@ -0,0 +1,7 @@
<#-- @license ©2015 Miel Vander Sande - Multimedia Lab / iMinds / Ghent University -->
<#assign title = datasource.getTitle() + ' | ' + title!"">
<#include "base.ftl.html">
<#macro contents>
<#include "fragment.ftl.html">
</#macro>
<@display_page/>

View file

@ -0,0 +1,11 @@
<#-- @license ©2015 Miel Vander Sande - Multimedia Lab / iMinds / Ghent University -->
<#include "base.ftl.html">
<#macro contents>
<h2>Error executing your request</h2>
<p>Your request could not be executed due to an internal server error.</p>
<p>Please try reloading the page or return to the <a href="/">index page</a>.</p>
<h3>Error details</h3>
<p><#if error??>${(error.getMessage())!error!""}</#if><p>
</#macro>
<@display_page/>

View file

@ -0,0 +1,83 @@
<#-- @license ©2015 Miel Vander Sande - Multimedia Lab / iMinds / Ghent University -->
<#setting url_escaping_charset='UTF-8'>
<div resource="${datasourceUrl}" typeof="void:datasource hydra:Collection">
<h2><a href="${datasourceUrl}">${datasource.getTitle()?cap_first}</a></h2>
<form action="?" method="GET" property="hydra:search" resource="#triplePattern">
<fieldset resource="#triplePattern">
<legend>Query ${datasource.getTitle()} by triple pattern</legend>
<ul>
<#list ['subject', 'predicate', 'object'] as component>
<li property="hydra:mapping" resource="#${component}">
<label for="${component}>"
about="#${component}" property="hydra:variable" lang="">${component}</label>
<input class="uri" id="${component}" name="${component}"
about="#${component}" property="hydra:property" resource="rdf:${component}" value="${(query[component]?html)!""}" />
</li>
</#list>
</ul>
</fieldset>
<p>
<input type="submit" value="Find matching triples" />
</p>
</form>
</div>
<h3>Matches in ${datasource.getTitle()} for <em class="pattern">${ (query["pattern"]?html)!"" }</em></h3>
<div class="counts">
<#if (triples?size > 0)>
Showing triples ${ start } to ${ end } of
<#if totalEstimate != end>±</#if>
<span property="void:triples hydra:totalItems" datatype="xsd:integer" content="${ totalEstimate }">${ totalEstimate }</span>
with <span property="hydra:itemsPerPage" datatype="xsd:integer" content="${ itemsPerPage }">${
itemsPerPage
}</span> triples per page.
<@pageLinks/>
<#else>
<p>
${datasource.getTitle()} contains
<span property="void:triples hydra:totalItems" datatype="xsd:integer" content="0">
no <#if (totalEstimate > 0) >more</#if>
</span>
triples that match this pattern.
</p>
</#if>
</div>
<ul class="triples">
<#list triples as triple>
<#assign subject = triple.getSubject().asNode().toString()>
<#assign predicate = triple.getPredicate().asNode().toString()>
<#assign object = triple.getObject().asNode().toString()>
<li>
<a href="?subject=${subject?url}">
<abbr title="${ subject }">${subject?keep_after_last("/")}</abbr>
</a>
<a href="?predicate=${predicate?url}">
<abbr title="${ predicate }">${predicate?keep_after_last("/")}</abbr>
</a>
<#if !triple.getObject().isLiteral()>
<a href="?object=${object?url}" resource="${ subject}">
<abbr title="${ object }" property="${ predicate }" resource="${ object }">${object?keep_after_last("/")}</abbr>
</a>.
<#else>
<a href="?object=${object?url}" resource="${ subject}">${object}</a>.
</#if>
</li>
</#list>
</ul>
<@pageLinks/>
<#macro pageLinks>
<ul class="links">
<#if previousPage??>
<li><a href="${ firstPage }" rel="first" property="hydra:firstPage">first</a></li>
<li><a href="${ previousPage }" rel="prev" property="hydra:previousPage">previous</a></li>
</#if>
<#if nextPage??>
<li><a href="${ nextPage }" rel="next" property="hydra:nextPage">next</a></li>
</#if>
</ul>
</#macro>

View file

@ -0,0 +1,21 @@
<#-- @license ©2015 Miel Vander Sande - Multimedia Lab / iMinds / Ghent University -->
<#include "base.ftl.html">
<#macro contents>
<div class="index">
<h2>Available datasets</h2>
<p>Browse the following datasets as <a href="http://linkeddatafragments.org/in-depth/#tpf">Triple Pattern Fragments</a>:</p>
<dl class="datasets">
<#if datasources??>
<#list datasources?keys as datasourceName>
<dt><a href="${homePath}/${datasourceName}">${datasources[datasourceName].getTitle() }</a></dt>
<dd>${ datasources[datasourceName].getDescription()!"" }</dd>
</#list>
</#if>
</dl>
<p>The current dataset <em class="dataset">index</em> contains metadata about these datasets.</p>
</div>
<#include "fragment.ftl.html">
</#macro>
<@display_page/>

View file

@ -0,0 +1,16 @@
<#-- @license ©2015 Miel Vander Sande - Multimedia Lab / iMinds / Ghent University -->
<#include "base.ftl.html">
<#macro contents>
<h2>Resource not found</h2>
<p>
No resource with URL <code>${ url!"" }</code> was found.
</p>
<h3>Available datasets</h3>
<ul>
<#list datasources?keys as datasourceName>
<li><a href="/${datasourceName}">${datasources[datasourceName].getTitle() }</a></li>
</#list>
</ul>
</#macro>
<@display_page/>