Skip to content

Commit

Permalink
EditMode optimization (constraints, constructors, and shapes now lo…
Browse files Browse the repository at this point in the history
…aded at document level)

Indirect graph identification using `?graph`
Function cleanup
  • Loading branch information
namedgraph committed Nov 16, 2023
1 parent a96e8f5 commit 67676f4
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.atomgraph.client.vocabulary.AC;
import com.atomgraph.linkeddatahub.vocabulary.LAPP;
import com.atomgraph.linkeddatahub.vocabulary.LDH;
import com.atomgraph.linkeddatahub.writer.Mode;
import java.io.IOException;
import java.util.Collections;
Expand All @@ -26,10 +27,17 @@
import java.util.stream.Collectors;
import jakarta.annotation.Priority;
import jakarta.inject.Inject;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.UriBuilder;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map.Entry;
import org.apache.jena.rdf.model.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -63,7 +71,38 @@ public void filter(ContainerRequestContext request) throws IOException

com.atomgraph.linkeddatahub.apps.model.Application app = appResource.as(com.atomgraph.linkeddatahub.apps.model.Application.class);
request.setProperty(LAPP.Application.getURI(), app); // wrap into a helper class so it doesn't interfere with injection of Application
request.setRequestUri(app.getBaseURI(), request.getUriInfo().getRequestUri()); // there's always ldt:base

// use the ?graph URL parameter to override the effective request URI if its URI value is relative to the app's base URI
final URI requestURI;
if (request.getUriInfo().getQueryParameters().containsKey(LDH.graph.getLocalName()))
try
{
URI graphURI = new URI(request.getUriInfo().getQueryParameters().getFirst(LDH.graph.getLocalName()));
if (!app.getBaseURI().relativize(graphURI).isAbsolute()) // if ?graph query param value is relative to the app's base URI
{
// pass on query parameters except ?graph
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap();
queryParams.putAll(request.getUriInfo().getQueryParameters());
queryParams.remove(LDH.graph.getLocalName());
queryParams.remove(AC.uri.getLocalName());

UriBuilder builder = UriBuilder.fromUri(graphURI);;

for (Entry<String, List<String>> params : queryParams.entrySet())
for (String value : params.getValue())
builder.queryParam(params.getKey(), value);

requestURI = builder.build();
}
else requestURI = request.getUriInfo().getRequestUri();
}
catch (URISyntaxException ex)
{
if (log.isErrorEnabled()) log.error("Graph URI syntax error", ex);
throw new BadRequestException(ex);
}
else requestURI = request.getUriInfo().getRequestUri();
request.setRequestUri(app.getBaseURI(), requestURI); // there's always ldt:base

// override "Accept" header using then ?accept= param value. TO-DO: move to a separate ContainerRequestFilter?
// has to go before ?uri logic because that will change the UriInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.atomgraph.linkeddatahub.resource.admin.RequestAccess;
import com.atomgraph.linkeddatahub.resource.admin.SignUp;
import com.atomgraph.linkeddatahub.resource.graph.Item;
import com.atomgraph.linkeddatahub.vocabulary.LDH;
import java.util.Optional;
import jakarta.inject.Inject;
import jakarta.ws.rs.Path;
Expand Down Expand Up @@ -69,7 +70,7 @@ public Dispatcher(@Context UriInfo uriInfo, Optional<Dataset> dataset, com.atomg
* Returns proxy class that takes precedence over the default JAX-RS path matching.
* The request is proxied in two cases:
* <ul>
* <li>externally (URI specified by the <code>?uri</code> query param)</li>
* <li>externally (URI specified by the <code>?uri</code> query param, when <code>?graph</code> query param not set)</li>
* <li>internally if it matches a <code>lapp:Dataset</code> specified in the system app config</li>
* </ul>
* @return optional class
Expand Down Expand Up @@ -98,7 +99,7 @@ public Optional<Class> getProxyClass()
@Path("{path: .*}")
public Class getSubResource()
{
return getProxyClass().orElse(getResourceClass());
return getProxyClass().orElse(getDocumentClass());
}

// TO-DO: move @Path annotations onto respective classes?
Expand Down Expand Up @@ -252,7 +253,7 @@ public Class getOAuth2Login()
*
* @return resource class
*/
public Class getResourceClass()
public Class getDocumentClass()
{
return Item.class;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@
*/
package com.atomgraph.linkeddatahub.server.util;

import com.atomgraph.linkeddatahub.vocabulary.LDH;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import jakarta.ws.rs.core.UriBuilder;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.util.ResourceUtils;
import org.apache.jena.util.iterator.ExtendedIterator;
Expand All @@ -37,19 +35,6 @@ public class Skolemizer implements Function<Model, Model>
{

private final String base;
private final Property fragmentProperty;

/**
* Constructs skolemizer from base URI and optional fragment property.
*
* @param base URI that fragments will be resolved against
* @param fragmentProperty if specified, the skolemizer will use the value of this property as the fragment ID
*/
public Skolemizer(String base, Property fragmentProperty)
{
this.base = base;
this.fragmentProperty = fragmentProperty;
}

/**
* Constructs skolemizer from base URI.
Expand All @@ -58,11 +43,11 @@ public Skolemizer(String base, Property fragmentProperty)
*/
public Skolemizer(String base)
{
this(base, LDH.fragment);
this.base = base;
}

/**
* Skolemizes RDF graph by replacing blank node resources with fragment URI resources.
* Skolemizes RDF graph by replacing blank node resources with hash-URI resources.
*
* @param model input model
* @return skolemized model
Expand All @@ -80,9 +65,7 @@ public Model apply(Model model)
{
Resource bnode = it.next();

final String fragment;
if (bnode.hasProperty(getFragmentProperty())) fragment = bnode.getProperty(getFragmentProperty()).getString();
else fragment = "id" + UUID.randomUUID().toString(); // UUID can start with a number which is not legal for a fragment ID
final String fragment = "id" + UUID.randomUUID().toString(); // UUID can start with a number which is not legal for a fragment ID

bnodes.put(bnode, fragment);
}
Expand All @@ -94,8 +77,6 @@ public Model apply(Model model)

bnodes.entrySet().forEach(entry ->
{
if (getFragmentProperty() != null) entry.getKey().removeAll(getFragmentProperty()); // remove the fragment slug

ResourceUtils.renameResource(entry.getKey(), UriBuilder.fromUri(getBase()).
fragment(entry.getValue()).
build().
Expand All @@ -115,14 +96,4 @@ public String getBase()
return base;
}

/**
* Returns the property which can be used to specify the fragment ID.
*
* @return RDF property
*/
public Property getFragmentProperty()
{
return fragmentProperty;
}

}
15 changes: 4 additions & 11 deletions src/main/java/com/atomgraph/linkeddatahub/vocabulary/LDH.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,6 @@ public static String getURI()
/** Base property */
public static final ObjectProperty base = m_model.createObjectProperty( NS + "base" );

/** Violation property */
public static final ObjectProperty violation = m_model.createObjectProperty( NS + "violation" );

/** File property */
public static final ObjectProperty file = m_model.createObjectProperty( NS + "file" );

Expand All @@ -89,26 +86,18 @@ public static String getURI()
/** Delimiter property */
public static final DatatypeProperty delimiter = m_model.createDatatypeProperty( NS + "delimiter" );

/** Resource type property */
public static final ObjectProperty resourceType = m_model.createObjectProperty( NS + "resourceType" );

/** Violation value property */
public static final DatatypeProperty violationValue = m_model.createDatatypeProperty( NS + "violationValue" );

/** Access to property */
public static final ObjectProperty access_to = m_model.createObjectProperty(NS + "access-to"); // TO-DO: move to client-side?

/** Absolute path property */
public static final ObjectProperty absolutePath = m_model.createObjectProperty(NS + "absolutePath");

/** Request URI property */
public static final ObjectProperty requestUri = m_model.createObjectProperty(NS + "requestUri");

/** Create graph property */
public static final DatatypeProperty createGraph = m_model.createDatatypeProperty( NS + "createGraph" );

/** Fragment property */
public static final DatatypeProperty fragment = m_model.createDatatypeProperty( NS + "fragment" );

/** Service property */
public static final DatatypeProperty service = m_model.createDatatypeProperty( NS + "service" );
Expand All @@ -117,4 +106,8 @@ public static String getURI()
* For shape property */
public static final ObjectProperty forShape = m_model.createObjectProperty( NS + "forShape" );

/**
* Graph URI property */
public static final ObjectProperty graph = m_model.createObjectProperty( NS + "graph" );

}
3 changes: 3 additions & 0 deletions src/main/resources/com/atomgraph/linkeddatahub/ldh.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -240,13 +240,16 @@

:ContentInstanceConstructor a :Constructor ;
sp:text """
PREFIX ldh: <https://w3id.org/atomgraph/linkeddatahub#>
PREFIX ac: <https://w3id.org/atomgraph/client#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX sd: <http://www.w3.org/ns/sparql-service-description#>
CONSTRUCT {
$this rdf:value [ a rdfs:Resource ] ;
ldh:graph [ a rdfs:Resource ] ;
ac:mode [ a rdfs:Resource ] ;
rdfs:label [ a xsd:string ] .
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ exclude-result-prefixes="#all"

<xsl:template match="*[*][@rdf:about]" mode="ldh:RenderContent">
<xsl:param name="container" as="element()"/>
<xsl:param name="graph" as="xs:anyURI?"/>
<xsl:param name="mode" as="xs:anyURI?"/>
<xsl:param name="refresh-content" as="xs:boolean?"/>

Expand All @@ -355,6 +356,7 @@ exclude-result-prefixes="#all"

<xsl:variable name="row" as="node()*">
<xsl:apply-templates select="." mode="bs2:Row">
<xsl:with-param name="graph" select="$graph" tunnel="yes"/>
<xsl:with-param name="mode" select="$mode"/>
</xsl:apply-templates>
</xsl:variable>
Expand Down Expand Up @@ -954,7 +956,7 @@ exclude-result-prefixes="#all"

<!-- start dragging content (or its descendants) -->

<xsl:template match="div[ac:mode(base-uri()) = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')]/descendant-or-self::*" mode="ixsl:ondragstart">
<xsl:template match="div[ixsl:query-params()?mode = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')]/descendant-or-self::*" mode="ixsl:ondragstart">
<xsl:choose>
<!-- allow drag on the content <div> -->
<xsl:when test="self::div[contains-token(@class, 'content')][contains-token(@class, 'row-fluid')]">
Expand All @@ -971,18 +973,18 @@ exclude-result-prefixes="#all"

<!-- dragging content over other content -->

<xsl:template match="div[ac:mode(base-uri()) = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')][acl:mode() = '&acl;Write']" mode="ixsl:ondragover">
<xsl:template match="div[ixsl:query-params()?mode = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')][acl:mode() = '&acl;Write']" mode="ixsl:ondragover">
<xsl:sequence select="ixsl:call(ixsl:event(), 'preventDefault', [])"/>
<ixsl:set-property name="dataTransfer.dropEffect" select="'move'" object="ixsl:event()"/>
</xsl:template>

<!-- change the style of elements when content is dragged over them -->

<xsl:template match="div[ac:mode(base-uri()) = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')][acl:mode() = '&acl;Write']" mode="ixsl:ondragenter">
<xsl:template match="div[ixsl:query-params()?mode = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')][acl:mode() = '&acl;Write']" mode="ixsl:ondragenter">
<xsl:sequence select="ixsl:call(ixsl:get(., 'classList'), 'toggle', [ 'drag-over', true() ])[current-date() lt xs:date('2000-01-01')]"/>
</xsl:template>

<xsl:template match="div[ac:mode(base-uri()) = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')][acl:mode() = '&acl;Write']" mode="ixsl:ondragleave">
<xsl:template match="div[ixsl:query-params()?mode = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')][acl:mode() = '&acl;Write']" mode="ixsl:ondragleave">
<xsl:variable name="related-target" select="ixsl:get(ixsl:event(), 'relatedTarget')" as="element()?"/> <!-- the element drag entered (optional) -->

<!-- only remove class if the related target does not have this div as ancestor (is not its child) -->
Expand All @@ -993,7 +995,7 @@ exclude-result-prefixes="#all"

<!-- dropping content over other content -->

<xsl:template match="div[ac:mode(base-uri()) = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')][acl:mode() = '&acl;Write']" mode="ixsl:ondrop">
<xsl:template match="div[ixsl:query-params()?mode = '&ldh;ContentMode'][contains-token(@class, 'content')][contains-token(@class, 'row-fluid')][acl:mode() = '&acl;Write']" mode="ixsl:ondrop">
<xsl:sequence select="ixsl:call(ixsl:event(), 'preventDefault', [])"/>
<xsl:variable name="container" select="." as="element()"/>
<xsl:variable name="content-uri" select="@about" as="xs:anyURI"/>
Expand Down Expand Up @@ -1034,6 +1036,7 @@ exclude-result-prefixes="#all"
<xsl:variable name="this" select="ancestor::div[@about][1]/@about" as="xs:anyURI"/>
<xsl:variable name="content-uri" select="(@about, $this)[1]" as="xs:anyURI"/> <!-- fallback to @about for charts, queries etc. -->
<xsl:variable name="content-value" select="ixsl:get(., 'dataset.contentValue')" as="xs:anyURI"/> <!-- get the value of the @data-content-value attribute -->
<xsl:variable name="graph" select="if (ixsl:contains(., 'dataset.contentGraph')) then xs:anyURI(ixsl:get(., 'dataset.contentGraph')) else ()" as="xs:anyURI?"/> <!-- get the value of the @data-content-graph attribute -->
<xsl:variable name="mode" select="if (ixsl:contains(., 'dataset.contentMode')) then xs:anyURI(ixsl:get(., 'dataset.contentMode')) else ()" as="xs:anyURI?"/> <!-- get the value of the @data-content-mode attribute -->
<xsl:variable name="container" select="." as="element()"/>
<xsl:variable name="progress-container" select="if (contains-token(@class, 'row-fluid')) then ./div[contains-token(@class, 'main')] else ." as="element()"/>
Expand All @@ -1049,14 +1052,16 @@ exclude-result-prefixes="#all"
</xsl:result-document>
</xsl:for-each>

<xsl:variable name="request-uri" select="ldh:href($ldt:base, ac:absolute-path(base-uri()), map{}, $content-value)" as="xs:anyURI"/>
<!-- don't use base-uri() because it's value comes from the last HTML document load -->
<xsl:variable name="request-uri" select="ldh:href($ldt:base, if (starts-with($graph, $ldt:base)) then $graph else ac:absolute-path(xs:anyURI(ixsl:location())), map{}, $content-value, $graph, ())" as="xs:anyURI"/>
<xsl:variable name="request" as="item()*">
<ixsl:schedule-action http-request="map{ 'method': 'GET', 'href': ac:document-uri($request-uri), 'headers': map{ 'Accept': 'application/rdf+xml' } }">
<xsl:call-template name="onContentValueLoad">
<xsl:with-param name="this" select="$this"/>
<xsl:with-param name="content-uri" select="$content-uri"/>
<xsl:with-param name="content-value" select="$content-value"/>
<xsl:with-param name="container" select="$container"/>
<xsl:with-param name="graph" select="$graph"/>
<xsl:with-param name="mode" select="$mode"/>
<xsl:with-param name="acl-modes" select="$acl-modes"/>
<xsl:with-param name="refresh-content" select="$refresh-content"/>
Expand All @@ -1075,6 +1080,7 @@ exclude-result-prefixes="#all"
<xsl:param name="container-id" select="ixsl:get($container, 'id')" as="xs:string"/>
<xsl:param name="content-uri" as="xs:anyURI"/>
<xsl:param name="content-value" as="xs:anyURI"/>
<xsl:param name="graph" as="xs:anyURI?"/>
<xsl:param name="mode" as="xs:anyURI?"/>
<xsl:param name="acl-modes" as="xs:anyURI*"/>
<xsl:param name="refresh-content" as="xs:boolean?"/>
Expand All @@ -1097,6 +1103,7 @@ exclude-result-prefixes="#all"
<xsl:apply-templates select="$value" mode="ldh:RenderContent">
<xsl:with-param name="this" select="$this"/>
<xsl:with-param name="container" select="$container"/>
<xsl:with-param name="graph" select="$graph"/>
<xsl:with-param name="mode" select="$mode"/>
<xsl:with-param name="refresh-content" select="$refresh-content"/>
</xsl:apply-templates>
Expand Down Expand Up @@ -1140,6 +1147,7 @@ exclude-result-prefixes="#all"
<xsl:with-param name="content-uri" select="$content-uri"/>
<xsl:with-param name="content-value" select="$content-value"/>
<xsl:with-param name="container" select="$container"/>
<xsl:with-param name="graph" select="$graph"/>
<xsl:with-param name="mode" select="$mode"/>
<xsl:with-param name="acl-modes" select="$acl-modes"/>
</xsl:call-template>
Expand Down
Loading

0 comments on commit 67676f4

Please sign in to comment.