├── .gitignore ├── LICENSE ├── README.md ├── pom.xml ├── release.sh └── src ├── main ├── java │ └── com │ │ └── atomgraph │ │ └── core │ │ ├── Application.java │ │ ├── MediaType.java │ │ ├── MediaTypes.java │ │ ├── client │ │ ├── ClientBase.java │ │ ├── EndpointClientBase.java │ │ ├── GraphStoreClient.java │ │ ├── LinkedDataClient.java │ │ ├── QuadStoreClient.java │ │ └── SPARQLClient.java │ │ ├── exception │ │ ├── BadGatewayException.java │ │ └── ConfigurationException.java │ │ ├── factory │ │ ├── ClientFactory.java │ │ ├── DataManagerFactory.java │ │ ├── MediaTypesFactory.java │ │ └── ServiceFactory.java │ │ ├── io │ │ ├── DatasetProvider.java │ │ ├── ModelProvider.java │ │ ├── QueryProvider.java │ │ ├── ResultSetProvider.java │ │ └── UpdateRequestProvider.java │ │ ├── mapper │ │ ├── BadGatewayExceptionMapper.java │ │ ├── NoReaderForLangExceptionMapper.java │ │ └── RiotExceptionMapper.java │ │ ├── model │ │ ├── Application.java │ │ ├── DatasetAccessor.java │ │ ├── DatasetQuadAccessor.java │ │ ├── EndpointAccessor.java │ │ ├── GraphStore.java │ │ ├── QuadStore.java │ │ ├── QueriedResource.java │ │ ├── RemoteService.java │ │ ├── Resource.java │ │ ├── SPARQLEndpoint.java │ │ ├── Service.java │ │ ├── impl │ │ │ ├── GraphStoreImpl.java │ │ │ ├── QuadStoreImpl.java │ │ │ ├── QueriedResourceBase.java │ │ │ ├── ResourceBase.java │ │ │ ├── Response.java │ │ │ ├── SPARQLEndpointImpl.java │ │ │ ├── dataset │ │ │ │ ├── DatasetAccessorImpl.java │ │ │ │ ├── DatasetQuadAccessorImpl.java │ │ │ │ ├── EndpointAccessorImpl.java │ │ │ │ └── ServiceImpl.java │ │ │ └── remote │ │ │ │ ├── DatasetAccessorImpl.java │ │ │ │ ├── DatasetQuadAccessorImpl.java │ │ │ │ ├── EndpointAccessorImpl.java │ │ │ │ └── ServiceImpl.java │ │ └── remote │ │ │ ├── GraphStore.java │ │ │ ├── QuadStore.java │ │ │ └── SPARQLEndpoint.java │ │ ├── provider │ │ └── QueryParamProvider.java │ │ ├── riot │ │ ├── RDFLanguages.java │ │ └── lang │ │ │ ├── RDFPostReader.java │ │ │ ├── RDFPostReaderFactory.java │ │ │ ├── TokenizerRDFPost.java │ │ │ └── TokenizerText.java │ │ ├── util │ │ ├── Link.java │ │ ├── ModelUtils.java │ │ ├── ResultSetUtils.java │ │ └── jena │ │ │ ├── DataManager.java │ │ │ ├── DataManagerImpl.java │ │ │ └── StartupListener.java │ │ └── vocabulary │ │ ├── A.java │ │ └── SD.java ├── resources │ ├── com │ │ └── atomgraph │ │ │ └── core │ │ │ └── ns.ttl │ └── log4j.properties └── webapp │ ├── META-INF │ └── context.xml │ └── WEB-INF │ └── web.xml └── test └── java └── com └── atomgraph └── core ├── client └── GraphStoreClientTest.java ├── io └── ModelProviderTest.java ├── model └── impl │ ├── GraphStoreImplTest.java │ ├── LocaleEntityTagTest.java │ ├── QueriedResourceBaseTest.java │ └── SPARQLEndpointImplTest.java └── riot └── lang └── RDFPostReaderTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /nb-configuration.xml 3 | /target/ 4 | *.iml 5 | /.idea 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Core is a Linked Data framework. It crosses Apache Jena RDF API with the JAX-RS REST API (Eclipse Jersey implementation), providing in a uniform Linked Data API. 2 | 3 | Core serves as a base for [AtomGraph Processor](../../../Processor). It is implemented as a Java Web application (uses Maven). 4 | 5 | Features 6 | -------- 7 | 8 | AtomGraph Core server provides features similar to that of [Pubby](http://wifo5-03.informatik.uni-mannheim.de/pubby/): 9 | * serving Linked Data from a SPARQL endpoint 10 | * HTTP Basic authentication for endpoints 11 | 12 | For more advanced features and configuration, see [AtomGraph Processor](../../../Processor). 13 | 14 | Configuration 15 | ------------- 16 | 17 | The Core is configured in [web.xml](../../blob/master/src/main/webapp/WEB-INF/web.xml) 18 | 19 | Uncomment `http://www.w3.org/ns/sparql-service-description#endpoint` and `https://w3id.org/atomgraph/core#graphStore` init parameters and provide their values. Otherwise the server will not start. 20 | 21 | Linked Data API 22 | -------------- 23 | * low-level access to remote Linked Data resources and SPARQL endpoints 24 | * JAX-RS interfaces and implementations of a Linked Data resources 25 | * JAX-RS providers for input and output of RDF data 26 | 27 | Documentation 28 | ------------- 29 | * [JavaDoc](https://atomgraph.github.io/Core/apidocs/) 30 | 31 | Dependencies 32 | -------------- 33 | 34 | * [Apache Jena](http://jena.apache.org) 35 | * [Jersey](https://eclipse-ee4j.github.io/jersey/) 36 | * [SL4J](http://www.slf4j.org) 37 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mvn release:clean release:prepare 4 | 5 | mvn release:perform -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/MediaType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core; 18 | 19 | import java.util.Map; 20 | import org.apache.jena.atlas.web.ContentType; 21 | import org.apache.jena.riot.Lang; 22 | import org.apache.jena.riot.resultset.ResultSetLang; 23 | 24 | /** 25 | * Extends standard JAX-RS media type with RDF media types 26 | * 27 | * @see jakarta.ws.rs.core.MediaType 28 | * @author Martynas Jusevičius {@literal } 29 | */ 30 | public class MediaType extends jakarta.ws.rs.core.MediaType 31 | { 32 | 33 | /** "application/rdf+xml" */ 34 | public final static String APPLICATION_RDF_XML = Lang.RDFXML.getContentType().getContentTypeStr(); 35 | /** "application/rdf+xml" */ 36 | public final static MediaType APPLICATION_RDF_XML_TYPE = new MediaType(Lang.RDFXML.getContentType().getType(), Lang.RDFXML.getContentType().getSubType()); 37 | 38 | /** "text/turtle" */ 39 | public final static String TEXT_TURTLE = Lang.TURTLE.getContentType().getContentTypeStr(); 40 | /** "text/turtle" */ 41 | public final static MediaType TEXT_TURTLE_TYPE = new MediaType(Lang.TURTLE.getContentType().getType(), Lang.TURTLE.getContentType().getSubType()); 42 | 43 | /** "text/trig" */ 44 | public final static String TEXT_TRIG = Lang.TRIG.getContentType().getContentTypeStr(); 45 | /** "text/trig" */ 46 | public final static MediaType TEXT_TRIG_TYPE = new MediaType(Lang.TRIG.getContentType().getType(), Lang.TRIG.getContentType().getSubType()); 47 | 48 | /** "application/n-triples" */ 49 | public final static String APPLICATION_NTRIPLES = Lang.NTRIPLES.getContentType().getContentTypeStr(); 50 | /** "application/n-triples" */ 51 | public final static MediaType APPLICATION_NTRIPLES_TYPE = new MediaType(Lang.NTRIPLES.getContentType().getType(), Lang.NTRIPLES.getContentType().getSubType()); 52 | 53 | /** "application/n-quads" */ 54 | public final static String TEXT_NQUADS = Lang.NQUADS.getContentType().getContentTypeStr(); 55 | /** "application/n-quads" */ 56 | public final static MediaType TEXT_NQUADS_TYPE = new MediaType(Lang.NQUADS.getContentType().getType(), Lang.NQUADS.getContentType().getSubType()); 57 | 58 | /** "application/ld+json" */ 59 | public final static String APPLICATION_LD_JSON = Lang.JSONLD.getContentType().getContentTypeStr(); 60 | /** "application/ld+json" */ 61 | public final static MediaType APPLICATION_LD_JSON_TYPE = new MediaType(Lang.JSONLD.getContentType().getType(), Lang.JSONLD.getContentType().getSubType()); 62 | 63 | /** "application/sparql-results+xml" */ 64 | public final static String APPLICATION_SPARQL_RESULTS_XML = ResultSetLang.RS_XML.getContentType().getContentTypeStr(); 65 | /** "application/sparql-results+xml" */ 66 | public final static MediaType APPLICATION_SPARQL_RESULTS_XML_TYPE = new MediaType(ResultSetLang.RS_XML.getContentType().getType(), ResultSetLang.RS_XML.getContentType().getSubType()); 67 | 68 | /** "application/sparql-results+json" */ 69 | public final static String APPLICATION_SPARQL_RESULTS_JSON = ResultSetLang.RS_JSON.getContentType().getContentTypeStr(); 70 | /** "application/sparql-results+json" */ 71 | public final static MediaType APPLICATION_SPARQL_RESULTS_JSON_TYPE = new MediaType(ResultSetLang.RS_JSON.getContentType().getType(), ResultSetLang.RS_JSON.getContentType().getSubType()); 72 | 73 | /** "text/csv" */ 74 | public final static String APPLICATION_SPARQL_RESULTS_CSV = ResultSetLang.RS_CSV.getContentType().getContentTypeStr(); 75 | /** "text/csv" */ 76 | public final static MediaType APPLICATION_SPARQL_RESULTS_CSV_TYPE = new MediaType(ResultSetLang.RS_CSV.getContentType().getType(), ResultSetLang.RS_CSV.getContentType().getSubType()); 77 | 78 | /** "text/tab-separated-values" */ 79 | public final static String APPLICATION_SPARQL_RESULTS_TSV = ResultSetLang.RS_TSV.getContentType().getContentTypeStr(); 80 | /** "text/tab-separated-values" */ 81 | public final static MediaType APPLICATION_SPARQL_RESULTS_TSV_TYPE = new MediaType(ResultSetLang.RS_TSV.getContentType().getType(), ResultSetLang.RS_TSV.getContentType().getSubType()); 82 | 83 | /** "application/sparql-query" */ 84 | public final static String APPLICATION_SPARQL_QUERY = "application/sparql-query"; 85 | /** "application/sparql-query" */ 86 | public final static MediaType APPLICATION_SPARQL_QUERY_TYPE = new MediaType("application", "sparql-query"); 87 | 88 | /** "application/sparql-update" */ 89 | public final static String APPLICATION_SPARQL_UPDATE = "application/sparql-update"; 90 | /** "application/sparql-update" */ 91 | public final static MediaType APPLICATION_SPARQL_UPDATE_TYPE = new MediaType("application", "sparql-update"); 92 | 93 | /** "application/rdf+x-www-form-urlencoded" */ 94 | public final static String APPLICATION_RDF_URLENCODED = "application/rdf+x-www-form-urlencoded"; 95 | /** "application/rdf+x-www-form-urlencoded" */ 96 | public final static MediaType APPLICATION_RDF_URLENCODED_TYPE = new MediaType("application","rdf+x-www-form-urlencoded"); 97 | 98 | public MediaType(Lang lang) 99 | { 100 | this(lang.getContentType()); 101 | } 102 | 103 | public MediaType(Lang lang, Map parameters) 104 | { 105 | this(lang.getContentType(), parameters); 106 | } 107 | 108 | public MediaType(ContentType ct) 109 | { 110 | this(ct.getType(), ct.getSubType()); 111 | } 112 | 113 | public MediaType(ContentType ct, Map parameters) 114 | { 115 | this(ct.getType(), ct.getSubType(), parameters); 116 | } 117 | 118 | public MediaType(String type, String subtype, Map parameters) 119 | { 120 | super(type, subtype, parameters); 121 | } 122 | 123 | public MediaType(String type, String subtype) 124 | { 125 | super(type, subtype); 126 | } 127 | 128 | public MediaType() 129 | { 130 | super(); 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/client/ClientBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.client; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import java.util.List; 20 | import java.util.Map; 21 | import jakarta.ws.rs.client.ClientRequestFilter; 22 | import jakarta.ws.rs.client.Entity; 23 | import jakarta.ws.rs.client.Invocation; 24 | import jakarta.ws.rs.client.WebTarget; 25 | import jakarta.ws.rs.core.MediaType; 26 | import jakarta.ws.rs.core.MultivaluedHashMap; 27 | import jakarta.ws.rs.core.MultivaluedMap; 28 | import jakarta.ws.rs.core.Response; 29 | import org.glassfish.jersey.uri.UriComponent; 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | 33 | /** 34 | * A common base class for all HTTP-based protocol clients. 35 | * Note that Response objects returned by methods of this class are not closed. 36 | * 37 | * @author Martynas Jusevičius {@literal } 38 | */ 39 | public abstract class ClientBase 40 | { 41 | 42 | private static final Logger log = LoggerFactory.getLogger(ClientBase.class); 43 | 44 | private final MediaTypes mediaTypes; 45 | 46 | protected ClientBase(MediaTypes mediaTypes) 47 | { 48 | if (mediaTypes == null) throw new IllegalArgumentException("MediaTypes cannot be null"); 49 | this.mediaTypes = mediaTypes; 50 | } 51 | 52 | public abstract MediaType getDefaultMediaType(); 53 | 54 | public MediaType[] getReadableMediaTypes(Class clazz) 55 | { 56 | return getMediaTypes().getReadable(clazz).toArray(jakarta.ws.rs.core.MediaType[]::new); 57 | } 58 | 59 | public MediaTypes getMediaTypes() 60 | { 61 | return mediaTypes; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/client/EndpointClientBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.client; 18 | 19 | import com.atomgraph.core.MediaTypes; 20 | import java.util.List; 21 | import java.util.Map; 22 | import jakarta.ws.rs.client.ClientRequestFilter; 23 | import jakarta.ws.rs.client.Entity; 24 | import jakarta.ws.rs.client.Invocation; 25 | import jakarta.ws.rs.client.WebTarget; 26 | import jakarta.ws.rs.core.MediaType; 27 | import jakarta.ws.rs.core.MultivaluedHashMap; 28 | import jakarta.ws.rs.core.MultivaluedMap; 29 | import jakarta.ws.rs.core.Response; 30 | import org.glassfish.jersey.uri.UriComponent; 31 | 32 | /** 33 | * 34 | * @author {@literal Martynas Jusevičius } 35 | */ 36 | public abstract class EndpointClientBase extends ClientBase 37 | { 38 | 39 | private final WebTarget endpoint; 40 | 41 | protected EndpointClientBase(MediaTypes mediaTypes, WebTarget endpoint) 42 | { 43 | super(mediaTypes); 44 | this.endpoint = endpoint; 45 | } 46 | 47 | public EndpointClientBase register(ClientRequestFilter filter) 48 | { 49 | if (filter == null) throw new IllegalArgumentException("ClientRequestFilter cannot be null"); 50 | 51 | getEndpoint().register(filter); 52 | 53 | return this; 54 | } 55 | 56 | protected WebTarget applyParams(MultivaluedMap params) 57 | { 58 | return applyParams(getEndpoint(), params); 59 | } 60 | 61 | protected WebTarget applyParams(WebTarget webTarget, MultivaluedMap params) 62 | { 63 | if (params != null) 64 | for (Map.Entry> entry : params.entrySet()) 65 | for (String value : entry.getValue()) 66 | webTarget = webTarget.queryParam(UriComponent.encode(entry.getKey(), UriComponent.Type.UNRESERVED), 67 | UriComponent.encode(value, UriComponent.Type.UNRESERVED)); 68 | 69 | return webTarget; 70 | } 71 | 72 | protected Invocation.Builder applyHeaders(Invocation.Builder builder, MultivaluedMap headers) 73 | { 74 | if (headers != null) 75 | for (Map.Entry> entry : headers.entrySet()) 76 | for (Object value : entry.getValue()) 77 | builder = builder.header(entry.getKey(), value); 78 | 79 | return builder; 80 | } 81 | 82 | public Response head(jakarta.ws.rs.core.MediaType[] acceptedTypes) 83 | { 84 | return head(acceptedTypes, new MultivaluedHashMap(), new MultivaluedHashMap()); 85 | } 86 | 87 | public Response head(jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params) 88 | { 89 | return head(acceptedTypes, params, new MultivaluedHashMap()); 90 | } 91 | 92 | public Response head(jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params, MultivaluedMap headers) 93 | { 94 | return applyHeaders(applyParams(params).request(acceptedTypes), headers).head(); 95 | } 96 | 97 | public Response get(jakarta.ws.rs.core.MediaType[] acceptedTypes) 98 | { 99 | return get(acceptedTypes, new MultivaluedHashMap(), new MultivaluedHashMap()); 100 | } 101 | 102 | public Response get(jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params) 103 | { 104 | return get(acceptedTypes, params, new MultivaluedHashMap()); 105 | } 106 | 107 | public Response get(jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params, MultivaluedMap headers) 108 | { 109 | return applyHeaders(applyParams(params).request(acceptedTypes), headers).get(); 110 | } 111 | 112 | public Response post(Object body, MediaType contentType, jakarta.ws.rs.core.MediaType[] acceptedTypes) 113 | { 114 | return post(body, contentType, acceptedTypes, new MultivaluedHashMap(), new MultivaluedHashMap()); 115 | } 116 | 117 | public Response post(Object body, MediaType contentType, jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params) 118 | { 119 | return post(body, contentType, acceptedTypes, params, new MultivaluedHashMap()); 120 | } 121 | 122 | public Response post(Object body, MediaType contentType, jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params, MultivaluedMap headers) 123 | { 124 | return applyHeaders(applyParams(params).request(acceptedTypes), headers).post(Entity.entity(body, contentType)); 125 | } 126 | 127 | public Response put(Object body, MediaType contentType, jakarta.ws.rs.core.MediaType[] acceptedTypes) 128 | { 129 | return put(body, contentType, acceptedTypes, new MultivaluedHashMap(), new MultivaluedHashMap()); 130 | } 131 | 132 | public Response put(Object body, MediaType contentType, jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params) 133 | { 134 | return put(body, contentType, acceptedTypes, params, new MultivaluedHashMap()); 135 | } 136 | 137 | public Response put(Object body, MediaType contentType, jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params, MultivaluedMap headers) 138 | { 139 | return applyHeaders(applyParams(params).request(acceptedTypes), headers).put(Entity.entity(body, contentType)); 140 | } 141 | 142 | public Response delete(jakarta.ws.rs.core.MediaType[] acceptedTypes) 143 | { 144 | return delete(acceptedTypes, new MultivaluedHashMap(), new MultivaluedHashMap()); 145 | } 146 | 147 | public Response delete(jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params) 148 | { 149 | return delete(acceptedTypes, params, new MultivaluedHashMap()); 150 | } 151 | 152 | public Response delete(jakarta.ws.rs.core.MediaType[] acceptedTypes, MultivaluedMap params, MultivaluedMap headers) 153 | { 154 | return applyHeaders(applyParams(params).request(acceptedTypes), headers).delete(); 155 | } 156 | 157 | public final WebTarget getEndpoint() 158 | { 159 | return endpoint; 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/client/LinkedDataClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.client; 18 | 19 | import com.atomgraph.core.MediaType; 20 | import com.atomgraph.core.MediaTypes; 21 | import com.atomgraph.core.io.ModelProvider; 22 | import com.atomgraph.core.model.DatasetAccessor; 23 | import java.net.URI; 24 | import jakarta.ws.rs.client.Client; 25 | import jakarta.ws.rs.client.ClientRequestFilter; 26 | import jakarta.ws.rs.client.Entity; 27 | import jakarta.ws.rs.client.WebTarget; 28 | import jakarta.ws.rs.core.Response; 29 | import jakarta.ws.rs.core.Response.Status; 30 | import org.apache.jena.rdf.model.Model; 31 | 32 | /** 33 | * Linked Data client. 34 | * 35 | * @author Martynas Jusevičius {@literal } 36 | */ 37 | public class LinkedDataClient extends ClientBase implements DatasetAccessor 38 | { 39 | 40 | private final Client client; 41 | 42 | protected LinkedDataClient(Client client, MediaTypes mediaTypes) 43 | { 44 | super(mediaTypes); 45 | this.client = client; 46 | } 47 | 48 | public static LinkedDataClient create(Client client, MediaTypes mediaTypes) 49 | { 50 | return new LinkedDataClient(client, mediaTypes); 51 | } 52 | 53 | /** 54 | * Registers client filter. 55 | * Can cause performance problems with ApacheConnector. 56 | * 57 | * @param filter client request filter 58 | * @return this SPARQL client 59 | * @see How To Use Jersey Client Efficiently 60 | */ 61 | public LinkedDataClient register(ClientRequestFilter filter) 62 | { 63 | if (filter == null) throw new IllegalArgumentException("ClientRequestFilter cannot be null"); 64 | 65 | getClient().register(filter); 66 | 67 | return this; 68 | } 69 | 70 | // default graph is not supported 71 | 72 | @Override 73 | public Model getModel() 74 | { 75 | throw new UnsupportedOperationException("Default graph is not supported -- all RDF graphs in Linked Data are named"); 76 | } 77 | 78 | @Override 79 | public void add(Model model) 80 | { 81 | throw new UnsupportedOperationException("Default graph is not supported -- all RDF graphs in Linked Data are named"); 82 | } 83 | 84 | @Override 85 | public void deleteDefault() 86 | { 87 | throw new UnsupportedOperationException("Default graph is not supported -- all RDF graphs in Linked Data are named"); 88 | } 89 | 90 | @Override 91 | public void putModel(Model model) 92 | { 93 | throw new UnsupportedOperationException("Default graph is not supported -- all RDF graphs in Linked Data are named"); 94 | } 95 | 96 | protected WebTarget getWebTarget(URI uri) 97 | { 98 | return getClient().target(uri); 99 | } 100 | 101 | public Response head(URI uri, jakarta.ws.rs.core.MediaType[] acceptedTypes) 102 | { 103 | return getWebTarget(uri).request(acceptedTypes).head(); 104 | } 105 | 106 | public Response head(URI uri) 107 | { 108 | return head(uri, getReadableMediaTypes(Model.class)); 109 | } 110 | 111 | @Override 112 | public boolean containsModel(String uri) 113 | { 114 | try (Response cr = head(URI.create(uri))) 115 | { 116 | return cr.getStatusInfo().equals(Status.OK); 117 | } 118 | } 119 | 120 | public Response get(URI uri, jakarta.ws.rs.core.MediaType[] acceptedTypes) 121 | { 122 | return getWebTarget(uri).request(acceptedTypes).get(); 123 | } 124 | 125 | public Response get(URI uri) 126 | { 127 | return get(uri, getReadableMediaTypes(Model.class)); 128 | } 129 | 130 | @Override 131 | public Model getModel(String uri) 132 | { 133 | try (Response cr = get(URI.create(uri))) 134 | { 135 | cr.getHeaders().putSingle(ModelProvider.REQUEST_URI_HEADER, uri); // provide a base URI hint to ModelProvider 136 | return cr.readEntity(Model.class); 137 | } 138 | } 139 | 140 | public Response post(URI uri, jakarta.ws.rs.core.MediaType[] acceptedTypes, Entity entity) 141 | { 142 | return getWebTarget(uri).request(acceptedTypes).post(entity); 143 | } 144 | 145 | public Response post(URI uri, jakarta.ws.rs.core.MediaType[] acceptedTypes, Object body, jakarta.ws.rs.core.MediaType contentType) 146 | { 147 | return post(uri, acceptedTypes, Entity.entity(body, contentType)); 148 | } 149 | 150 | public Response post(URI uri, jakarta.ws.rs.core.MediaType[] acceptedTypes, Model model) 151 | { 152 | return post(uri, acceptedTypes, model, getDefaultMediaType()); 153 | } 154 | 155 | public Response post(URI uri, Object body, jakarta.ws.rs.core.MediaType contentType) 156 | { 157 | return post(uri, getReadableMediaTypes(Model.class), body, contentType); 158 | } 159 | 160 | public Response post(URI uri, Model model) 161 | { 162 | return post(uri, model, getDefaultMediaType()); 163 | } 164 | 165 | @Override 166 | public void add(String uri, Model model) 167 | { 168 | post(URI.create(uri), getReadableMediaTypes(Model.class), model, getDefaultMediaType()).close(); 169 | } 170 | 171 | public Response put(URI uri, jakarta.ws.rs.core.MediaType[] acceptedTypes, Entity entity) 172 | { 173 | return getWebTarget(uri).request(acceptedTypes).put(entity); 174 | } 175 | 176 | public Response put(URI uri, jakarta.ws.rs.core.MediaType[] acceptedTypes, Object body, jakarta.ws.rs.core.MediaType contentType) 177 | { 178 | return put(uri, acceptedTypes, Entity.entity(body, contentType)); 179 | } 180 | 181 | public Response put(URI uri, jakarta.ws.rs.core.MediaType[] acceptedTypes, Model model) 182 | { 183 | return put(uri, acceptedTypes, model, getDefaultMediaType()); 184 | } 185 | 186 | public Response put(URI uri, Object body, jakarta.ws.rs.core.MediaType contentType) 187 | { 188 | return put(uri, getReadableMediaTypes(Model.class), body, contentType); 189 | } 190 | 191 | public Response put(URI uri, Model model) 192 | { 193 | return put(uri, model, getDefaultMediaType()); 194 | } 195 | 196 | @Override 197 | public void putModel(String uri, Model model) 198 | { 199 | put(URI.create(uri), getReadableMediaTypes(Model.class), model, getDefaultMediaType()).close(); 200 | } 201 | 202 | public Response delete(URI uri, jakarta.ws.rs.core.MediaType[] acceptedTypes) 203 | { 204 | return getWebTarget(uri).request(getReadableMediaTypes(Model.class)).delete(); 205 | } 206 | 207 | public Response delete(URI uri) 208 | { 209 | return delete(uri, getReadableMediaTypes(Model.class)); 210 | } 211 | 212 | @Override 213 | public void deleteModel(String uri) 214 | { 215 | delete(URI.create(uri)).close(); 216 | } 217 | 218 | @Override 219 | public MediaType getDefaultMediaType() 220 | { 221 | return MediaType.APPLICATION_NTRIPLES_TYPE; 222 | } 223 | 224 | public Client getClient() 225 | { 226 | return client; 227 | } 228 | 229 | } 230 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/client/QuadStoreClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.client; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import jakarta.ws.rs.core.MultivaluedMap; 20 | import jakarta.ws.rs.core.Response; 21 | import org.apache.jena.query.Dataset; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | import com.atomgraph.core.model.DatasetQuadAccessor; 25 | import jakarta.ws.rs.HttpMethod; 26 | import jakarta.ws.rs.client.ClientRequestFilter; 27 | import jakarta.ws.rs.client.Entity; 28 | import jakarta.ws.rs.client.WebTarget; 29 | import jakarta.ws.rs.core.MediaType; 30 | import jakarta.ws.rs.core.MultivaluedHashMap; 31 | 32 | /** 33 | * Quad Store client. 34 | * 35 | * @author Martynas Jusevičius {@literal } 36 | * @see Extending SPARQL Graph Store HTTP Protocol with quad semantics 37 | */ 38 | public class QuadStoreClient extends EndpointClientBase implements DatasetQuadAccessor 39 | { 40 | private static final Logger log = LoggerFactory.getLogger(QuadStoreClient.class); 41 | 42 | public QuadStoreClient(MediaTypes mediaTypes, WebTarget endpoint) 43 | { 44 | super(mediaTypes, endpoint); 45 | } 46 | 47 | public QuadStoreClient(WebTarget endpoint) 48 | { 49 | this(new MediaTypes(), endpoint); 50 | } 51 | 52 | public static QuadStoreClient create(MediaTypes mediaTypes, WebTarget endpoint) 53 | { 54 | return new QuadStoreClient(mediaTypes, endpoint); 55 | } 56 | 57 | public static QuadStoreClient create(WebTarget endpoint) 58 | { 59 | return new QuadStoreClient(endpoint); 60 | } 61 | 62 | /** 63 | * Registers client filter. 64 | * Can cause performance problems with ApacheConnector. 65 | * 66 | * @param filter client request filter 67 | * @return this SPARQL client 68 | * @see How To Use Jersey Client Efficiently 69 | */ 70 | @Override 71 | public QuadStoreClient register(ClientRequestFilter filter) 72 | { 73 | if (filter == null) throw new IllegalArgumentException("ClientRequestFilter cannot be null"); 74 | 75 | super.register(filter); 76 | 77 | return this; 78 | } 79 | 80 | @Override 81 | public MediaType getDefaultMediaType() 82 | { 83 | return com.atomgraph.core.MediaType.TEXT_NQUADS_TYPE; 84 | } 85 | 86 | @Override 87 | public Dataset get() 88 | { 89 | try (Response cr = get(getReadableMediaTypes(Dataset.class))) 90 | { 91 | return cr.readEntity(Dataset.class); 92 | } 93 | } 94 | 95 | @Override 96 | public void add(Dataset dataset) 97 | { 98 | post(dataset, getDefaultMediaType(), new MediaType[]{}).close(); 99 | } 100 | 101 | @Override 102 | public void replace(Dataset dataset) 103 | { 104 | put(dataset, getDefaultMediaType(), new MediaType[]{}).close(); 105 | } 106 | 107 | @Override 108 | public void delete() 109 | { 110 | delete(new MediaType[]{}).close(); 111 | } 112 | 113 | @Override 114 | public void patch(Dataset dataset) 115 | { 116 | patch(dataset, new MultivaluedHashMap()).close(); 117 | } 118 | 119 | public Response patch(Dataset dataset, MultivaluedMap params) 120 | { 121 | WebTarget target = applyParams(params); 122 | if (log.isDebugEnabled()) log.debug("PATCH Dataset to Quad Store {}", getEndpoint().getUri()); 123 | 124 | return target.request().method(HttpMethod.PATCH, Entity.entity(dataset, getDefaultMediaType())); 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/client/SPARQLClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.client; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import jakarta.ws.rs.ServerErrorException; 22 | import jakarta.ws.rs.client.ClientRequestFilter; 23 | import jakarta.ws.rs.client.Entity; 24 | import jakarta.ws.rs.client.WebTarget; 25 | import jakarta.ws.rs.core.MediaType; 26 | import jakarta.ws.rs.core.MultivaluedHashMap; 27 | import jakarta.ws.rs.core.MultivaluedMap; 28 | import jakarta.ws.rs.core.Response; 29 | import org.apache.jena.query.Dataset; 30 | import org.apache.jena.query.Query; 31 | import org.apache.jena.query.ResultSet; 32 | import org.apache.jena.query.ResultSetRewindable; 33 | import org.apache.jena.rdf.model.Model; 34 | import org.apache.jena.riot.resultset.ResultSetLang; 35 | import org.apache.jena.sparql.resultset.ResultsReader; 36 | import org.apache.jena.update.UpdateRequest; 37 | import org.slf4j.Logger; 38 | import org.slf4j.LoggerFactory; 39 | 40 | /** 41 | * SPARQL Protocol client. 42 | * 43 | * @author Martynas Jusevičius {@literal } 44 | * @see SPARQL 1.1 Protocol 45 | */ 46 | public class SPARQLClient extends EndpointClientBase 47 | { 48 | 49 | private static final Logger log = LoggerFactory.getLogger(SPARQLClient.class); 50 | 51 | public static final String QUERY_PARAM_NAME = "query"; 52 | public static final String UPDATE_PARAM_NAME = "update"; 53 | 54 | private final int maxGetRequestSize; 55 | 56 | protected SPARQLClient(MediaTypes mediaTypes, WebTarget endpoint, int maxGetRequestSize) 57 | { 58 | super(mediaTypes, endpoint); 59 | this.maxGetRequestSize = maxGetRequestSize; 60 | } 61 | 62 | protected SPARQLClient(MediaTypes mediaTypes, WebTarget endpoint) 63 | { 64 | this(mediaTypes, endpoint, 8192); 65 | } 66 | 67 | protected SPARQLClient(WebTarget endpoint) 68 | { 69 | this(new MediaTypes(), endpoint); 70 | } 71 | 72 | public static SPARQLClient create(MediaTypes mediaTypes, WebTarget endpoint, int maxGetRequestSize) 73 | { 74 | return new SPARQLClient(mediaTypes, endpoint, maxGetRequestSize); 75 | } 76 | 77 | public static SPARQLClient create(MediaTypes mediaTypes, WebTarget endpoint) 78 | { 79 | return new SPARQLClient(mediaTypes, endpoint); 80 | } 81 | 82 | public static SPARQLClient create(WebTarget endpoint) 83 | { 84 | return new SPARQLClient(endpoint); 85 | } 86 | 87 | /** 88 | * Registers client filter. 89 | * Can cause performance problems with ApacheConnector. 90 | * 91 | * @param filter client request filter 92 | * @return this SPARQL client 93 | * @see How To Use Jersey Client Efficiently 94 | */ 95 | @Override 96 | public SPARQLClient register(ClientRequestFilter filter) 97 | { 98 | if (filter == null) throw new IllegalArgumentException("ClientRequestFilter cannot be null"); 99 | 100 | super.register(filter); 101 | 102 | return this; 103 | } 104 | 105 | public int getQueryURLLength(MultivaluedMap params) 106 | { 107 | return applyParams(params).getUri().toString().length(); 108 | } 109 | 110 | public Response query(Query query, Class clazz) 111 | { 112 | return query(query, clazz, new MultivaluedHashMap()); 113 | } 114 | 115 | public Response query(Query query, Class clazz, MultivaluedMap params) 116 | { 117 | return query(query, clazz, params, new MultivaluedHashMap()); 118 | } 119 | 120 | public Response query(Query query, Class clazz, MultivaluedMap params, MultivaluedMap headers) 121 | { 122 | if (params == null) throw new IllegalArgumentException("MultivaluedMap params cannot be null"); 123 | if (headers == null) throw new IllegalArgumentException("MultivaluedMap headers cannot be null"); 124 | 125 | MultivaluedMap mergedParams = new MultivaluedHashMap(); 126 | mergedParams.putAll(params); 127 | mergedParams.putSingle(QUERY_PARAM_NAME, query.toString()); 128 | 129 | if (getQueryURLLength(params) > getMaxGetRequestSize()) 130 | return applyHeaders(getEndpoint().request(getReadableMediaTypes(clazz)), headers).post(Entity.form(mergedParams)); 131 | else 132 | return applyHeaders(applyParams(mergedParams).request(getReadableMediaTypes(clazz)), headers).get(); 133 | } 134 | 135 | public Model loadModel(Query query) 136 | { 137 | try (Response cr = query(query, Model.class)) 138 | { 139 | return cr.readEntity(Model.class); 140 | } 141 | } 142 | 143 | public Dataset loadDataset(Query query) 144 | { 145 | try (Response cr = query(query, Dataset.class)) 146 | { 147 | return cr.readEntity(Dataset.class); 148 | } 149 | } 150 | 151 | public ResultSetRewindable select(Query query) 152 | { 153 | try (Response cr = query(query, ResultSet.class)) 154 | { 155 | return cr.readEntity(ResultSetRewindable.class); 156 | } 157 | } 158 | 159 | public boolean ask(Query query) 160 | { 161 | try (Response cr = query(query, ResultSet.class)) 162 | { 163 | try 164 | { 165 | return parseBoolean(cr); 166 | } 167 | catch (IOException ex) 168 | { 169 | if (log.isErrorEnabled()) log.error("Could not parse ASK result: {}", ex); 170 | throw new ServerErrorException(cr, ex); 171 | } 172 | } 173 | } 174 | 175 | public static boolean parseBoolean(Response cr) throws IOException 176 | { 177 | try (InputStream is = cr.readEntity(InputStream.class)) 178 | { 179 | if (cr.getMediaType().isCompatible(com.atomgraph.core.MediaType.APPLICATION_SPARQL_RESULTS_JSON_TYPE)) 180 | return ResultsReader.create().lang(ResultSetLang.RS_JSON).build().readAny(is).getBooleanResult(); 181 | 182 | if (cr.getMediaType().isCompatible(com.atomgraph.core.MediaType.APPLICATION_SPARQL_RESULTS_XML_TYPE)) 183 | return ResultsReader.create().lang(ResultSetLang.RS_XML).build().readAny(is).getBooleanResult(); 184 | 185 | throw new IllegalStateException("Unsupported ResultSet format"); 186 | } 187 | } 188 | 189 | /** 190 | * POSTs update to a remote SPARQL endpoint. 191 | * 192 | * @param updateRequest post request 193 | * @param params name/value pairs of request parameters or null, if none 194 | */ 195 | public void update(UpdateRequest updateRequest, MultivaluedMap params) 196 | { 197 | MultivaluedMap formData = new MultivaluedHashMap(); 198 | if (params != null) formData.putAll(params); 199 | formData.putSingle(UPDATE_PARAM_NAME, updateRequest.toString()); 200 | 201 | post(formData, MediaType.APPLICATION_FORM_URLENCODED_TYPE, new MediaType[]{}, null).close(); 202 | } 203 | 204 | public int getMaxGetRequestSize() 205 | { 206 | return maxGetRequestSize; 207 | } 208 | 209 | @Override 210 | public MediaType getDefaultMediaType() 211 | { 212 | return MediaType.APPLICATION_FORM_URLENCODED_TYPE; 213 | } 214 | 215 | } 216 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/exception/BadGatewayException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.exception; 17 | 18 | import jakarta.ws.rs.InternalServerErrorException; 19 | import jakarta.ws.rs.core.Response; 20 | 21 | /** 22 | * 23 | * @author Martynas Jusevičius {@literal } 24 | */ 25 | public class BadGatewayException extends InternalServerErrorException 26 | { 27 | 28 | public BadGatewayException() 29 | { 30 | } 31 | 32 | public BadGatewayException(String message) 33 | { 34 | super(message); 35 | } 36 | 37 | public BadGatewayException(Response response) 38 | { 39 | super(response); 40 | } 41 | 42 | public BadGatewayException(String message, Response response) 43 | { 44 | super(message, response); 45 | } 46 | 47 | public BadGatewayException(Throwable cause) 48 | { 49 | super(cause); 50 | } 51 | 52 | public BadGatewayException(String message, Throwable cause) 53 | { 54 | super(message, cause); 55 | } 56 | 57 | public BadGatewayException(Response response, Throwable cause) 58 | { 59 | super(response, cause); 60 | } 61 | 62 | public BadGatewayException(String message, Response response, Throwable cause) 63 | { 64 | super(message, response, cause); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/exception/ConfigurationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.exception; 18 | 19 | import org.apache.jena.rdf.model.Property; 20 | 21 | /** 22 | * Exception thrown when configuration is invalid. 23 | * 24 | * @author Martynas Jusevičius {@literal } 25 | */ 26 | public class ConfigurationException extends RuntimeException 27 | { 28 | 29 | public ConfigurationException(Property property) 30 | { 31 | super("Property '" + property.getURI() + "' not defined in configuration"); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/factory/ClientFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.factory; 18 | 19 | import org.glassfish.hk2.api.Factory; 20 | import jakarta.inject.Singleton; 21 | import jakarta.ws.rs.client.Client; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * JAX-RS provider for HTTP client. 27 | * Needs to be registered in the JAX-RS application. 28 | * 29 | * @author Martynas Jusevičius {@literal } 30 | * @see jakarta.ws.rs.client.Client 31 | * @see jakarta.ws.rs.core.Context 32 | */ 33 | @Singleton 34 | public class ClientFactory implements Factory 35 | { 36 | 37 | private static final Logger log = LoggerFactory.getLogger(ClientFactory.class); 38 | 39 | private final Client client; 40 | 41 | public ClientFactory(final Client client) 42 | { 43 | this.client = client; 44 | } 45 | 46 | @Override 47 | public Client provide() 48 | { 49 | return getClient(); 50 | } 51 | 52 | @Override 53 | public void dispose(Client t) 54 | { 55 | t.close(); 56 | } 57 | 58 | public Client getClient() 59 | { 60 | return client; 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/factory/DataManagerFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.atomgraph.core.factory; 19 | 20 | import com.atomgraph.core.util.jena.DataManager; 21 | import org.glassfish.hk2.api.Factory; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * JAX-RS provider for data manager. 27 | * Needs to be registered in the JAX-RS application. 28 | * 29 | * @author Martynas Jusevičius {@literal } 30 | * @see com.atomgraph.core.util.jena.DataManager 31 | * @see jakarta.ws.rs.core.Context 32 | */ 33 | public class DataManagerFactory implements Factory 34 | { 35 | 36 | private static final Logger log = LoggerFactory.getLogger(DataManagerFactory.class); 37 | 38 | private final DataManager dataManager; 39 | 40 | public DataManagerFactory(final DataManager dataManager) 41 | { 42 | this.dataManager = dataManager; 43 | } 44 | 45 | @Override 46 | public DataManager provide() 47 | { 48 | return getDataManager(); 49 | } 50 | 51 | @Override 52 | public void dispose(DataManager dataManager) 53 | { 54 | } 55 | 56 | /** 57 | * Returns default data manager instance. 58 | * @return data manager instance 59 | */ 60 | public DataManager getDataManager() 61 | { 62 | return dataManager; 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/factory/MediaTypesFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.factory; 18 | 19 | import com.atomgraph.core.MediaTypes; 20 | import org.glassfish.hk2.api.Factory; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | /** 25 | * JAX-RS provider for media type registry. 26 | * Needs to be registered in the JAX-RS application. 27 | * 28 | * @author Martynas Jusevičius {@literal } 29 | * @see com.atomgraph.core.MediaTypes 30 | * @see jakarta.ws.rs.core.Context 31 | */ 32 | public class MediaTypesFactory implements Factory 33 | { 34 | 35 | private static final Logger log = LoggerFactory.getLogger(MediaTypesFactory.class); 36 | 37 | private final MediaTypes mediaTypes; 38 | 39 | public MediaTypesFactory(final MediaTypes mediaTypes) 40 | { 41 | this.mediaTypes = mediaTypes; 42 | } 43 | 44 | @Override 45 | public MediaTypes provide() 46 | { 47 | return getMediaTypes(); 48 | } 49 | 50 | @Override 51 | public void dispose(MediaTypes t) 52 | { 53 | } 54 | 55 | public MediaTypes getMediaTypes() 56 | { 57 | return mediaTypes; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/factory/ServiceFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.factory; 17 | 18 | import com.atomgraph.core.model.Service; 19 | import jakarta.ws.rs.ext.Provider; 20 | import org.glassfish.hk2.api.Factory; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | /** 25 | * JAX-RS provider for application's SPARQL service. 26 | * Needs to be registered in the JAX-RS application. 27 | * 28 | * @author Martynas Jusevičius {@literal } 29 | * @see com.atomgraph.core.model.Service 30 | */ 31 | //@Provider 32 | public class ServiceFactory implements Factory 33 | { 34 | 35 | private static final Logger log = LoggerFactory.getLogger(ServiceFactory.class); 36 | 37 | private final Service service; 38 | 39 | public ServiceFactory(final Service service) 40 | { 41 | this.service = service; 42 | } 43 | 44 | @Override 45 | public Service provide() 46 | { 47 | return getService(); 48 | } 49 | 50 | @Override 51 | public void dispose(Service t) 52 | { 53 | } 54 | 55 | public Service getService() 56 | { 57 | return service; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/io/DatasetProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.io; 18 | 19 | import org.apache.jena.query.Dataset; 20 | import org.apache.jena.query.DatasetFactory; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.OutputStream; 24 | import java.lang.annotation.Annotation; 25 | import java.lang.reflect.Type; 26 | import jakarta.ws.rs.WebApplicationException; 27 | import jakarta.ws.rs.core.MediaType; 28 | import jakarta.ws.rs.core.MultivaluedMap; 29 | import jakarta.ws.rs.ext.MessageBodyReader; 30 | import jakarta.ws.rs.ext.MessageBodyWriter; 31 | import jakarta.ws.rs.ext.Provider; 32 | import org.apache.jena.rdf.model.Model; 33 | import org.apache.jena.riot.Lang; 34 | import org.apache.jena.riot.RDFDataMgr; 35 | import org.apache.jena.riot.RDFLanguages; 36 | import org.apache.jena.riot.RDFParserRegistry; 37 | import org.apache.jena.riot.RDFWriterRegistry; 38 | import org.slf4j.Logger; 39 | import org.slf4j.LoggerFactory; 40 | 41 | /** 42 | * JAX-RS provider for reading RDF dataset from request and writing it to response. 43 | * Needs to be registered in the JAX-RS application. 44 | * 45 | * @author Martynas Jusevičius {@literal } 46 | * @see org.apache.jena.query.Dataset 47 | * @see jakarta.ws.rs.ext.MessageBodyReader 48 | * @see jakarta.ws.rs.ext.MessageBodyWriter 49 | */ 50 | 51 | @Provider 52 | public class DatasetProvider implements MessageBodyReader, MessageBodyWriter 53 | { 54 | 55 | private static final Logger log = LoggerFactory.getLogger(DatasetProvider.class); 56 | 57 | public static final String REQUEST_URI_HEADER = "X-Request-URI"; 58 | 59 | // READER 60 | 61 | @Override 62 | public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) 63 | { 64 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 65 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); 66 | if (lang == null) return false; 67 | return type == Model.class && RDFParserRegistry.isRegistered(lang); // can write both quads and triples (default graph) 68 | } 69 | 70 | @Override 71 | public Dataset readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException 72 | { 73 | if (log.isTraceEnabled()) log.trace("Reading Dataset with HTTP headers: {} MediaType: {}", httpHeaders, mediaType); 74 | 75 | Dataset dataset = DatasetFactory.create(); 76 | 77 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 78 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); // cannot be null - isReadable() checks that 79 | 80 | String baseURI = null; 81 | // attempt to retrieve base URI from a special-purpose header (workaround for JAX-RS 1.x limitation) 82 | if (httpHeaders.containsKey(REQUEST_URI_HEADER)) baseURI = httpHeaders.getFirst(REQUEST_URI_HEADER); 83 | 84 | RDFDataMgr.read(dataset, entityStream, baseURI, lang); 85 | 86 | return dataset; 87 | } 88 | 89 | // WRITER 90 | 91 | @Override 92 | public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) 93 | { 94 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 95 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); 96 | if (lang == null) return false; 97 | return Model.class.isAssignableFrom(type) && RDFWriterRegistry.contains(lang); // can write both quads and triples (default graph) 98 | } 99 | 100 | @Override 101 | public long getSize(Dataset dataset, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) 102 | { 103 | return -1; 104 | } 105 | 106 | @Override 107 | public void writeTo(Dataset dataset, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException 108 | { 109 | if (log.isTraceEnabled()) log.trace("Writing Dataset with HTTP headers: {} MediaType: {}", httpHeaders, mediaType); 110 | 111 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 112 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); // cannot be null - isWritable() checks that 113 | 114 | // if we need to provide triples, then we write only the default graph of the dataset 115 | if (RDFLanguages.isTriples(lang)) dataset.getDefaultModel().write(entityStream, lang.getName()); 116 | else RDFDataMgr.write(entityStream, dataset, lang); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/io/ModelProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.io; 18 | 19 | import jakarta.ws.rs.core.Context; 20 | import org.apache.jena.rdf.model.Model; 21 | import org.apache.jena.rdf.model.ModelFactory; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.OutputStream; 25 | import java.lang.annotation.Annotation; 26 | import java.lang.reflect.Type; 27 | import jakarta.ws.rs.core.MediaType; 28 | import jakarta.ws.rs.core.MultivaluedMap; 29 | import jakarta.ws.rs.core.UriInfo; 30 | import jakarta.ws.rs.ext.MessageBodyReader; 31 | import jakarta.ws.rs.ext.MessageBodyWriter; 32 | import jakarta.ws.rs.ext.Provider; 33 | import org.apache.jena.riot.Lang; 34 | import org.apache.jena.riot.RDFLanguages; 35 | import org.apache.jena.riot.RDFParser; 36 | import org.apache.jena.riot.RDFParserRegistry; 37 | import org.apache.jena.riot.RDFWriterRegistry; 38 | import org.apache.jena.riot.system.ErrorHandler; 39 | import org.apache.jena.riot.system.ErrorHandlerFactory; 40 | import org.apache.jena.riot.system.StreamRDFLib; 41 | import org.slf4j.Logger; 42 | import org.slf4j.LoggerFactory; 43 | 44 | /** 45 | * JAX-RS provider for reading RDF model from request and writing it to response. 46 | * Needs to be registered in the JAX-RS application. 47 | * 48 | * @author Martynas Jusevičius {@literal } 49 | * @see org.apache.jena.rdf.model.Model 50 | * @see jakarta.ws.rs.ext.MessageBodyReader 51 | * @see jakarta.ws.rs.ext.MessageBodyWriter 52 | */ 53 | @Provider 54 | public class ModelProvider implements MessageBodyReader, MessageBodyWriter 55 | { 56 | private static final Logger log = LoggerFactory.getLogger(ModelProvider.class); 57 | 58 | public static final String REQUEST_URI_HEADER = "X-Request-URI"; 59 | public static final String RESPONSE_URI_HEADER = "X-Response-URI"; 60 | 61 | @Context UriInfo uriInfo; 62 | 63 | // READER 64 | 65 | @Override 66 | public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) 67 | { 68 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 69 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); 70 | if (lang == null) return false; 71 | return type == Model.class && RDFParserRegistry.isRegistered(lang) && RDFLanguages.isTriples(lang); 72 | } 73 | 74 | @Override 75 | public Model readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException 76 | { 77 | if (log.isTraceEnabled()) log.trace("Reading Model with HTTP headers: {} MediaType: {}", httpHeaders, mediaType); 78 | 79 | Model model = ModelFactory.createDefaultModel(); 80 | 81 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 82 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); // cannot be null - isReadable() checks that 83 | if (log.isDebugEnabled()) log.debug("RDF language used to read Model: {}", lang); 84 | 85 | String baseURI = null; 86 | // attempt to retrieve base URI from a special-purpose header (workaround for JAX-RS 1.x limitation) 87 | if (httpHeaders.containsKey(REQUEST_URI_HEADER)) baseURI = httpHeaders.getFirst(REQUEST_URI_HEADER); 88 | if (getUriInfo() != null) baseURI = getUriInfo().getAbsolutePath().toString(); 89 | 90 | return read(model, entityStream, lang, baseURI); // extract base URI from httpHeaders? 91 | } 92 | 93 | public Model read(Model model, InputStream is, Lang lang, String baseURI) 94 | { 95 | ErrorHandler errorHandler = ErrorHandlerFactory.errorHandlerStrict; // throw exceptions on all parse errors 96 | return read(model, is, lang, baseURI, errorHandler); 97 | } 98 | 99 | public Model read(Model model, InputStream is, Lang lang, String baseURI, ErrorHandler errorHandler) 100 | { 101 | if (model == null) throw new IllegalArgumentException("Model must be not null"); 102 | if (is == null) throw new IllegalArgumentException("InputStream must be not null"); 103 | if (lang == null) throw new IllegalArgumentException("Lang must be not null"); 104 | 105 | RDFParser parser = RDFParser.create(). 106 | lang(lang). 107 | errorHandler(errorHandler). 108 | checking(true). // otherwise exceptions will not be thrown for invalid URIs! 109 | base(baseURI). 110 | source(is). 111 | build(); 112 | 113 | parser.parse(StreamRDFLib.graph(model.getGraph())); 114 | 115 | return model; 116 | } 117 | 118 | // WRITER 119 | 120 | @Override 121 | public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) 122 | { 123 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 124 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); 125 | if (lang == null) return false; 126 | return Model.class.isAssignableFrom(type) && RDFWriterRegistry.contains(lang) && RDFLanguages.isTriples(lang); 127 | } 128 | 129 | @Override 130 | public long getSize(Model model, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) 131 | { 132 | return -1; 133 | } 134 | 135 | @Override 136 | public void writeTo(Model model, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException 137 | { 138 | if (log.isTraceEnabled()) log.trace("Writing Model with HTTP headers: {} MediaType: {}", httpHeaders, mediaType); 139 | 140 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 141 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); // cannot be null - isWritable() checks that 142 | if (log.isDebugEnabled()) log.debug("RDF language used to read Model: {}", lang); 143 | 144 | String baseURI = null; 145 | // attempt to retrieve base URI from a special-purpose header (workaround for JAX-RS 1.x limitation) 146 | if (httpHeaders.containsKey(RESPONSE_URI_HEADER)) baseURI = httpHeaders.getFirst(RESPONSE_URI_HEADER).toString(); 147 | if (getUriInfo() != null) baseURI = getUriInfo().getAbsolutePath().toString(); 148 | 149 | write(model, entityStream, lang, baseURI); 150 | } 151 | 152 | public Model write(Model model, OutputStream os, Lang lang, String baseURI) 153 | { 154 | if (model == null) throw new IllegalArgumentException("Model must be not null"); 155 | if (os == null) throw new IllegalArgumentException("OutputStream must be not null"); 156 | if (lang == null) throw new IllegalArgumentException("Lang must be not null"); 157 | 158 | String syntax = lang.getName(); 159 | if (log.isDebugEnabled()) log.debug("Syntax used to write Model: {}", syntax); 160 | 161 | return model.write(os, syntax); 162 | } 163 | 164 | public UriInfo getUriInfo() 165 | { 166 | return uriInfo; 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/io/QueryProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.io; 18 | 19 | import org.apache.jena.query.Query; 20 | import java.io.IOException; 21 | import java.io.OutputStream; 22 | import java.lang.annotation.Annotation; 23 | import java.lang.reflect.Type; 24 | import java.nio.charset.Charset; 25 | import jakarta.ws.rs.Produces; 26 | import jakarta.ws.rs.core.MultivaluedMap; 27 | import jakarta.ws.rs.ext.MessageBodyWriter; 28 | import jakarta.ws.rs.ext.Provider; 29 | import com.atomgraph.core.MediaType; 30 | import java.io.InputStream; 31 | import java.nio.charset.StandardCharsets; 32 | import jakarta.ws.rs.BadRequestException; 33 | import jakarta.ws.rs.Consumes; 34 | import jakarta.ws.rs.WebApplicationException; 35 | import jakarta.ws.rs.ext.MessageBodyReader; 36 | import org.apache.commons.io.IOUtils; 37 | import org.apache.jena.query.QueryFactory; 38 | import org.apache.jena.query.QueryParseException; 39 | import org.slf4j.Logger; 40 | import org.slf4j.LoggerFactory; 41 | 42 | /** 43 | * JAX-RS provider for reading/writing SPARQL queries. 44 | * Needs to be registered in the JAX-RS application. 45 | * 46 | * @author Martynas Jusevičius {@literal } 47 | * @see org.apache.jena.query.Query 48 | */ 49 | @Provider 50 | @Consumes(MediaType.APPLICATION_SPARQL_QUERY) 51 | @Produces(MediaType.APPLICATION_SPARQL_QUERY) 52 | public class QueryProvider implements MessageBodyReader, MessageBodyWriter 53 | { 54 | private static final Logger log = LoggerFactory.getLogger(QueryProvider.class); 55 | 56 | // READER 57 | 58 | @Override 59 | public boolean isReadable(Class type, Type genericType, Annotation[] annotations, jakarta.ws.rs.core.MediaType mediaType) 60 | { 61 | return type == Query.class; 62 | } 63 | 64 | @Override 65 | public Query readFrom(Class type, Type genericType, Annotation[] annotations, jakarta.ws.rs.core.MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException 66 | { 67 | try 68 | { 69 | return QueryFactory.create(IOUtils.toString(entityStream, StandardCharsets.UTF_8)); 70 | } 71 | catch (QueryParseException ex) 72 | { 73 | throw new BadRequestException(ex); 74 | } 75 | } 76 | 77 | // WRITER 78 | 79 | @Override 80 | public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, jakarta.ws.rs.core.MediaType mediaType) 81 | { 82 | return type == Query.class; 83 | } 84 | 85 | @Override 86 | public long getSize(Query query, Class type, Type genericType, Annotation[] annotations, jakarta.ws.rs.core.MediaType mediaType) 87 | { 88 | return -1; 89 | } 90 | 91 | @Override 92 | public void writeTo(Query query, Class type, Type genericType, Annotation[] annotations, jakarta.ws.rs.core.MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException 93 | { 94 | entityStream.write(query.toString().getBytes(Charset.forName("UTF-8"))); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/io/ResultSetProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.io; 18 | 19 | import org.apache.jena.query.ResultSet; 20 | import org.apache.jena.query.ResultSetFactory; 21 | import org.apache.jena.query.ResultSetFormatter; 22 | import org.apache.jena.query.ResultSetRewindable; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.io.OutputStream; 26 | import java.lang.annotation.Annotation; 27 | import java.lang.reflect.Type; 28 | import jakarta.ws.rs.core.MediaType; 29 | import jakarta.ws.rs.core.MultivaluedMap; 30 | import jakarta.ws.rs.ext.MessageBodyReader; 31 | import jakarta.ws.rs.ext.MessageBodyWriter; 32 | import jakarta.ws.rs.ext.Provider; 33 | import org.apache.jena.riot.Lang; 34 | import org.apache.jena.riot.RDFLanguages; 35 | import org.apache.jena.riot.ResultSetMgr; 36 | import org.apache.jena.riot.resultset.ResultSetReaderRegistry; 37 | import org.apache.jena.riot.resultset.ResultSetWriterRegistry; 38 | import org.slf4j.Logger; 39 | import org.slf4j.LoggerFactory; 40 | 41 | /** 42 | * JAX-RS provider for writing SPARQL result set to the response. 43 | * Needs to be registered in the JAX-RS application. 44 | * 45 | * @author Martynas Jusevičius {@literal } 46 | * @see SPARQL Query Results XML Format 47 | * @see org.apache.jena.query.ResultSet 48 | * @see jakarta.ws.rs.ext.MessageBodyReader 49 | * @see jakarta.ws.rs.ext.MessageBodyWriter 50 | */ 51 | @Provider 52 | public class ResultSetProvider implements MessageBodyReader, MessageBodyWriter 53 | { 54 | private static final Logger log = LoggerFactory.getLogger(ResultSetProvider.class); 55 | 56 | @Override 57 | public boolean isReadable(Class type, Type type1, Annotation[] antns, jakarta.ws.rs.core.MediaType mediaType) 58 | { 59 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 60 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); 61 | if (lang == null) return false; 62 | return type == ResultSetRewindable.class && ResultSetReaderRegistry.isRegistered(lang); 63 | } 64 | 65 | @Override 66 | public ResultSetRewindable readFrom(Class type, Type type1, Annotation[] antns, jakarta.ws.rs.core.MediaType mediaType, MultivaluedMap httpHeaders, InputStream in) throws IOException 67 | { 68 | if (log.isTraceEnabled()) log.trace("Reading ResultSet with HTTP headers: {} MediaType: {}", httpHeaders, mediaType); 69 | 70 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 71 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); // cannot be null - isReadable() checks that 72 | if (log.isDebugEnabled()) log.debug("RDF language used to read ResultSet: {}", lang); 73 | 74 | // result set needs to be rewindable because results might be processed multiple times, e.g. to calculate hash and write response 75 | return ResultSetFactory.makeRewindable(ResultSetMgr.read(in, lang)); 76 | } 77 | 78 | @Override 79 | public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) 80 | { 81 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 82 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); 83 | if (lang == null) return false; 84 | return ResultSet.class.isAssignableFrom(type) && ResultSetWriterRegistry.isRegistered(lang); 85 | } 86 | 87 | @Override 88 | public long getSize(ResultSet t, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) 89 | { 90 | return -1; 91 | } 92 | 93 | @Override 94 | public void writeTo(ResultSet results, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException 95 | { 96 | if (log.isTraceEnabled()) log.trace("Writing ResultSet with HTTP headers: {} MediaType: {}", httpHeaders, mediaType); 97 | 98 | MediaType formatType = new MediaType(mediaType.getType(), mediaType.getSubtype()); // discard charset param 99 | Lang lang = RDFLanguages.contentTypeToLang(formatType.toString()); // cannot be null - isWritable() checks that 100 | if (log.isDebugEnabled()) log.debug("RDF language used to write ResultSet: {}", lang); 101 | 102 | ResultSetFormatter.output(entityStream, results, lang); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/io/UpdateRequestProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.io; 18 | 19 | import org.apache.jena.update.UpdateFactory; 20 | import org.apache.jena.update.UpdateRequest; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.lang.annotation.Annotation; 24 | import java.lang.reflect.Type; 25 | import jakarta.ws.rs.Consumes; 26 | import jakarta.ws.rs.WebApplicationException; 27 | import jakarta.ws.rs.core.MultivaluedMap; 28 | import jakarta.ws.rs.ext.MessageBodyReader; 29 | import jakarta.ws.rs.ext.Provider; 30 | import com.atomgraph.core.MediaType; 31 | import java.io.OutputStream; 32 | import java.io.OutputStreamWriter; 33 | import java.nio.charset.StandardCharsets; 34 | import jakarta.ws.rs.BadRequestException; 35 | import jakarta.ws.rs.Produces; 36 | import jakarta.ws.rs.ext.MessageBodyWriter; 37 | import org.apache.jena.query.QueryParseException; 38 | import org.slf4j.Logger; 39 | import org.slf4j.LoggerFactory; 40 | 41 | /** 42 | * JAX-RS provider for reading SPARQL Update from request body. 43 | * Needs to be registered in the JAX-RS application. 44 | * 45 | * @author Martynas Jusevičius {@literal } 46 | * @see org.apache.jena.update.UpdateRequest 47 | * @see jakarta.ws.rs.ext.MessageBodyReader 48 | */ 49 | @Provider 50 | @Consumes(MediaType.APPLICATION_SPARQL_UPDATE) 51 | @Produces(MediaType.APPLICATION_SPARQL_UPDATE) 52 | public class UpdateRequestProvider implements MessageBodyReader, MessageBodyWriter 53 | { 54 | 55 | private static final Logger log = LoggerFactory.getLogger(UpdateRequestProvider.class); 56 | 57 | @Override 58 | public boolean isReadable(Class type, Type type1, Annotation[] antns, jakarta.ws.rs.core.MediaType mt) 59 | { 60 | return type == UpdateRequest.class; 61 | } 62 | 63 | @Override 64 | public UpdateRequest readFrom(Class type, Type type1, Annotation[] antns, jakarta.ws.rs.core.MediaType mediaType, MultivaluedMap httpHeaders, InputStream in) throws IOException, WebApplicationException 65 | { 66 | if (log.isTraceEnabled()) log.trace("Reading UpdateRequest with HTTP headers: {} MediaType: {}", httpHeaders, mediaType); 67 | try 68 | { 69 | return UpdateFactory.read(in); 70 | } 71 | catch (QueryParseException ex) 72 | { 73 | if (log.isWarnEnabled()) log.warn("Supplied SPARQL update string could not be parsed, check syntax"); 74 | throw new BadRequestException(ex); 75 | } 76 | } 77 | 78 | @Override 79 | public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, jakarta.ws.rs.core.MediaType mediaType) 80 | { 81 | return UpdateRequest.class.isAssignableFrom(type); 82 | } 83 | 84 | @Override 85 | public void writeTo(UpdateRequest updateRequest, Class type, Type genericType, Annotation[] annotations, jakarta.ws.rs.core.MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException 86 | { 87 | if (log.isTraceEnabled()) log.trace("Writing UpdateRequest with HTTP headers: {} MediaType: {}", httpHeaders, mediaType); 88 | new OutputStreamWriter(entityStream, StandardCharsets.UTF_8).write(updateRequest.toString()); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/mapper/BadGatewayExceptionMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.mapper; 18 | 19 | import com.atomgraph.core.exception.BadGatewayException; 20 | import jakarta.ws.rs.core.Response; 21 | import jakarta.ws.rs.ext.ExceptionMapper; 22 | 23 | /** 24 | * Maps client exception to response. 25 | * Needs to be registered in the JAX-RS application. 26 | * 27 | * @author Martynas Jusevičius {@literal } 28 | */ 29 | public class BadGatewayExceptionMapper implements ExceptionMapper 30 | { 31 | 32 | @Override 33 | public Response toResponse(BadGatewayException exception) 34 | { 35 | return Response.status(Response.Status.BAD_GATEWAY).build(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/mapper/NoReaderForLangExceptionMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.mapper; 17 | 18 | import jakarta.ws.rs.core.Response; 19 | import jakarta.ws.rs.ext.ExceptionMapper; 20 | import org.apache.jena.shared.NoReaderForLangException; 21 | 22 | /** 23 | * 24 | * @author Martynas Jusevičius {@literal } 25 | */ 26 | public class NoReaderForLangExceptionMapper implements ExceptionMapper 27 | { 28 | 29 | @Override 30 | public Response toResponse(NoReaderForLangException ex) 31 | { 32 | return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE).build(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/mapper/RiotExceptionMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.mapper; 17 | 18 | import jakarta.ws.rs.core.Response; 19 | import jakarta.ws.rs.ext.ExceptionMapper; 20 | import org.apache.jena.riot.RiotException; 21 | 22 | /** 23 | * 24 | * @author Martynas Jusevičius {@literal } 25 | */ 26 | public class RiotExceptionMapper implements ExceptionMapper 27 | { 28 | 29 | @Override 30 | public Response toResponse(RiotException ex) 31 | { 32 | return Response.status(Response.Status.BAD_REQUEST).build(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model; 17 | 18 | /** 19 | * Linked Data application backed by SPARQL service. 20 | * 21 | * @author Martynas Jusevičius {@literal } 22 | */ 23 | public interface Application 24 | { 25 | 26 | Service getService(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/DatasetAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model; 17 | 18 | import org.apache.jena.rdf.model.Model; 19 | 20 | /** 21 | * 22 | * @author Martynas Jusevičius {@literal } 23 | */ 24 | public interface DatasetAccessor 25 | { 26 | /** Get the default model of a Dataset 27 | * @return model*/ 28 | public Model getModel(); 29 | 30 | /** Get a named model of a Dataset 31 | * @param graphUri graph name 32 | * @return model */ 33 | public Model getModel(String graphUri); 34 | 35 | /** 36 | * Does the Dataset contain a named graph? 37 | * @param graphURI graph name 38 | * @return true if graph exists 39 | */ 40 | public boolean containsModel(String graphURI); 41 | 42 | /** 43 | * Put (replace) the default model of a Dataset 44 | * @param data payload model 45 | */ 46 | public void putModel(Model data); 47 | 48 | /** 49 | * Put (create/replace) a named model of a Dataset 50 | * @param graphUri graph name 51 | * @param data payload model 52 | */ 53 | public void putModel(String graphUri, Model data); 54 | 55 | /** 56 | * Delete (which means clear) the default model of a Dataset 57 | */ 58 | public void deleteDefault() ; 59 | 60 | /** 61 | * Delete a named model of a Dataset 62 | * @param graphUri graph name 63 | */ 64 | public void deleteModel(String graphUri); 65 | 66 | /** 67 | * Add statements to the default model of a Dataset 68 | * @param data payload model 69 | */ 70 | public void add(Model data); 71 | 72 | /** 73 | * Add statements to a named model of a Dataset 74 | * @param graphUri graph name 75 | * @param data payload model 76 | */ 77 | public void add(String graphUri, Model data); 78 | 79 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/DatasetQuadAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model; 17 | 18 | import org.apache.jena.query.Dataset; 19 | 20 | /** 21 | * Quad-based accessor to an RDF dataset. 22 | * Quads can be retrieved, added, replaced, patched, and removed. 23 | * 24 | * @author Martynas Jusevičius {@literal } 25 | */ 26 | public interface DatasetQuadAccessor 27 | { 28 | 29 | Dataset get(); 30 | 31 | void add(Dataset dataset); 32 | 33 | void replace(Dataset dataset); 34 | 35 | void patch(Dataset dataset); 36 | 37 | void delete(); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/EndpointAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model; 17 | 18 | import java.net.URI; 19 | import java.util.List; 20 | import org.apache.jena.query.Dataset; 21 | import org.apache.jena.query.Query; 22 | import org.apache.jena.query.ResultSetRewindable; 23 | import org.apache.jena.rdf.model.Model; 24 | import org.apache.jena.update.UpdateRequest; 25 | 26 | /** 27 | * Uniform interface for SPARQL endpoints and clients. 28 | * 29 | * @author Martynas Jusevičius {@literal } 30 | */ 31 | public interface EndpointAccessor 32 | { 33 | 34 | Dataset loadDataset(Query query, List defaultGraphUris, List namedGraphUris); 35 | 36 | Model loadModel(Query query, List defaultGraphUris, List namedGraphUris); 37 | 38 | ResultSetRewindable select(Query query, List defaultGraphUris, List namedGraphUris); 39 | 40 | boolean ask(Query query, List defaultGraphUris, List namedGraphUris); 41 | 42 | void update(UpdateRequest updateRequest, List usingGraphUris, List usingNamedGraphUris); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/GraphStore.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.model; 18 | 19 | import org.apache.jena.rdf.model.Model; 20 | import java.net.URI; 21 | import jakarta.ws.rs.*; 22 | import jakarta.ws.rs.core.Response; 23 | 24 | /** 25 | * Generic SPARQL 1.1 Graph Store HTTP Protocol interface 26 | * 27 | * @author Martynas Jusevičius {@literal } 28 | * @see SPARQL 1.1 Graph Store HTTP Protocol 29 | */ 30 | public interface GraphStore 31 | { 32 | /** 33 | * Handles GET query request and returns result as response 34 | * 35 | * @param defaultGraph indicates whether default graph is used 36 | * @param graphUri named graph URI 37 | * @return result response 38 | * @see 5.2 HTTP GET 39 | */ 40 | @GET Response get(@QueryParam("default") Boolean defaultGraph, @QueryParam("graph") URI graphUri); 41 | 42 | /** 43 | * Handles POST query request and returns result as response 44 | * 45 | * @param model RDF payload model 46 | * @param defaultGraph indicates whether default graph is used 47 | * @param graphUri named graph URI 48 | * @return result response 49 | * @see 5.5 HTTP POST 50 | */ 51 | @POST Response post(Model model, @QueryParam("default") Boolean defaultGraph, @QueryParam("graph") URI graphUri); 52 | 53 | /** 54 | * Handles PUT query request and returns result as response 55 | * 56 | * @param model RDF payload model 57 | * @param defaultGraph indicates whether default graph is used 58 | * @param graphUri named graph URI 59 | * @return result response 60 | * @see 5.3 HTTP PUT 61 | */ 62 | @PUT Response put(Model model, @QueryParam("default") Boolean defaultGraph, @QueryParam("graph") URI graphUri); 63 | 64 | /** 65 | * Handles DELETE query request and returns result as response 66 | * 67 | * @param defaultGraph indicates whether default graph is used 68 | * @param graphUri named graph URI 69 | * @return result response 70 | * @see 5.4 HTTP DELETE 71 | */ 72 | @DELETE Response delete(@QueryParam("default") Boolean defaultGraph, @QueryParam("graph") URI graphUri); 73 | 74 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/QuadStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model; 17 | 18 | import jakarta.ws.rs.DELETE; 19 | import jakarta.ws.rs.GET; 20 | import jakarta.ws.rs.POST; 21 | import jakarta.ws.rs.PUT; 22 | import jakarta.ws.rs.core.Response; 23 | import org.apache.jena.query.Dataset; 24 | 25 | /** 26 | * SPARQL 1.1 Graph Store HTTP Protocol interface extended to support quads 27 | * 28 | * @author Martynas Jusevičius {@literal } 29 | */ 30 | public interface QuadStore 31 | { 32 | 33 | /** 34 | * Response with dataset. 35 | * 36 | * @return result response 37 | */ 38 | @GET Response get(); 39 | 40 | /** 41 | * Appends request dataset entity. 42 | * 43 | * @param dataset RDF payload dataset 44 | * @return result response 45 | */ 46 | @POST Response post(Dataset dataset); 47 | 48 | /** 49 | * Replaces the dataset with request dataset entity. 50 | * 51 | * @param dataset RDF payload dataset 52 | * @return result response 53 | */ 54 | @PUT Response put(Dataset dataset); 55 | 56 | /** 57 | * Handles DELETE query request and returns result as response 58 | * 59 | * @return result response 60 | */ 61 | @DELETE Response delete(); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/QueriedResource.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.model; 18 | 19 | import org.apache.jena.query.Query; 20 | import org.apache.jena.rdf.model.Model; 21 | 22 | /** 23 | * RDF resource, representation of which was queried from a SPARQL endpoint. 24 | * 25 | * @author Martynas Jusevičius {@literal } 26 | * @see ARQ Query 27 | */ 28 | public interface QueriedResource 29 | { 30 | /** 31 | * Returns SPARQL query that was used to retrieve the RDF representation (DESCRIBE or CONSTRUCT) 32 | * 33 | * @return query object 34 | * @see DESCRIBE 35 | * @see CONSTRUCT 36 | */ 37 | Query getQuery(); 38 | 39 | /** 40 | * Returns RDF description of this resource. It is retrieved by executing the query on the SPARQL endpoint. 41 | * 42 | * @return description RDF model 43 | */ 44 | Model describe(); 45 | 46 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/RemoteService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model; 17 | 18 | import com.atomgraph.core.client.GraphStoreClient; 19 | import com.atomgraph.core.client.QuadStoreClient; 20 | import com.atomgraph.core.client.SPARQLClient; 21 | 22 | /** 23 | * Remote SPARQL service with SPARQL 1.1 Protocol and Graph Store support. 24 | * 25 | * @author Martynas Jusevičius {@literal } 26 | */ 27 | public interface RemoteService extends Service 28 | { 29 | SPARQLClient getSPARQLClient(); 30 | 31 | org.apache.jena.rdf.model.Resource getSPARQLEndpoint(); 32 | 33 | GraphStoreClient getGraphStoreClient(); 34 | 35 | org.apache.jena.rdf.model.Resource getGraphStore(); 36 | 37 | QuadStoreClient getQuadStoreClient(); 38 | 39 | org.apache.jena.rdf.model.Resource getQuadStore(); 40 | 41 | String getAuthUser(); 42 | 43 | String getAuthPwd(); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/Resource.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.model; 18 | 19 | import java.net.URI; 20 | import jakarta.ws.rs.DELETE; 21 | import jakarta.ws.rs.GET; 22 | import jakarta.ws.rs.POST; 23 | import jakarta.ws.rs.PUT; 24 | import jakarta.ws.rs.core.Response; 25 | import org.apache.jena.rdf.model.Model; 26 | 27 | /** 28 | * Read-write Linked Data resource. 29 | * 30 | * @author Martynas Jusevičius {@literal } 31 | */ 32 | public interface Resource 33 | { 34 | 35 | /** 36 | * Returns URI of the resource. 37 | * @return absolute path (excludes the query string) 38 | */ 39 | public URI getURI(); 40 | 41 | /** 42 | * Handles GET request and returns response 43 | * 44 | * @return response to the current request 45 | * @see Response 46 | * @see Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content 5.3.1. GET 47 | */ 48 | @GET Response get(); 49 | 50 | /** 51 | * Handles POST methods with RDF request body and returns response 52 | * 53 | * @param model the RDF payload 54 | * @return response to current request 55 | * @see Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content 5.3.3. POST 56 | */ 57 | @POST Response post(Model model); 58 | 59 | /** 60 | * Handles PUT methods with RDF request body and returns response 61 | * 62 | * @param model the RDF payload 63 | * @return response to current request 64 | * @see Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content 5.3.4. PUT 65 | */ 66 | @PUT Response put(Model model); 67 | 68 | /** 69 | * Handles DELETE methods 70 | * 71 | * @return response to current request 72 | * @see Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content 5.3.5. DELETE 73 | */ 74 | @DELETE Response delete(); 75 | 76 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/SPARQLEndpoint.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.model; 18 | 19 | import org.apache.jena.query.Query; 20 | import org.apache.jena.update.UpdateRequest; 21 | import java.net.URI; 22 | import jakarta.ws.rs.Consumes; 23 | import jakarta.ws.rs.FormParam; 24 | import jakarta.ws.rs.GET; 25 | import jakarta.ws.rs.POST; 26 | import jakarta.ws.rs.QueryParam; 27 | import jakarta.ws.rs.core.Response; 28 | import com.atomgraph.core.MediaType; 29 | import java.util.List; 30 | 31 | /** 32 | * Generic SPARQL 1.1 Protocol interface 33 | * 34 | * @author Martynas Jusevičius {@literal } 35 | * @see org.apache.jena.query.Query 36 | * @see org.apache.jena.update.UpdateRequest 37 | * @see SPARQL Protocol for RDF 38 | * 39 | */ 40 | public interface SPARQLEndpoint 41 | { 42 | 43 | public static String QUERY = "query"; 44 | public static String UPDATE = "update"; 45 | public static String DEFAULT_GRAPH_URI = "default-graph-uri"; 46 | public static String NAMED_GRAPH_URI = "named-graph-uri"; 47 | public static String USING_GRAPH_URI = "using-graph-uri"; 48 | public static String USING_NAMED_GRAPH_URI = "using-named-graph-uri"; 49 | 50 | /** 51 | * Handles GET query request and returns result as response 52 | * 53 | * @param query the submitted SPARQL query 54 | * @param defaultGraphUris default graph URI 55 | * @param namedGraphUris named graph URI 56 | * @return result response (in one of the representation variants) 57 | * @see 2.1.1 query via GET 58 | */ 59 | @GET Response get(@QueryParam(QUERY) Query query, @QueryParam(DEFAULT_GRAPH_URI) List defaultGraphUris, @QueryParam(NAMED_GRAPH_URI) List namedGraphUris); 60 | 61 | /** 62 | * Handles URL-encoded POST query request and returns result as response. 63 | * Query and UpdateRequest would be more appropriate form parameter types, 64 | * but the injection provider does not have access to request entity or form parameters. 65 | * 66 | * @param queryString submitted SPARQL query string 67 | * @param updateString submitted SPARQL update string 68 | * @param defaultGraphUris default graph URI 69 | * @param namedGraphUris named graph URI 70 | * @param usingGraphUris default graph URI 71 | * @param usingNamedGraphUris named graph URI 72 | * @return result response (in one of the representation variants) 73 | * @see 2.1.2 query via POST with URL-encoded parameters 74 | * @see 2.2.1 update via POST with URL-encoded parameters 75 | */ 76 | @POST @Consumes(MediaType.APPLICATION_FORM_URLENCODED) Response post(@FormParam(QUERY) String queryString, @FormParam(UPDATE) String updateString, @FormParam(DEFAULT_GRAPH_URI) List defaultGraphUris, @FormParam(NAMED_GRAPH_URI) List namedGraphUris, @FormParam(USING_GRAPH_URI) List usingGraphUris, @FormParam(USING_NAMED_GRAPH_URI) List usingNamedGraphUris); 77 | 78 | /** 79 | * Handles direct POST query request and returns result as response 80 | * 81 | * @param query the submitted SPARQL query 82 | * @param defaultGraphUris default graph URI 83 | * @param namedGraphUris named graph URI 84 | * @return result response (in one of the representation variants) 85 | * @see 2.1.3 query via POST directly 86 | */ 87 | @POST @Consumes(MediaType.APPLICATION_SPARQL_QUERY) Response post(Query query, @QueryParam(DEFAULT_GRAPH_URI) List defaultGraphUris, @QueryParam(NAMED_GRAPH_URI) List namedGraphUris); 88 | 89 | /** 90 | * Handles direct POST update request and returns result as response 91 | * 92 | * @param update update request (possibly multiple operations) 93 | * @param usingGraphUris default graph URI 94 | * @param usingNamedGraphUris named graph URI 95 | * @return success or failure response 96 | * @see 2.2.2 update via POST directly 97 | */ 98 | @POST @Consumes(MediaType.APPLICATION_SPARQL_UPDATE) Response post(UpdateRequest update, @QueryParam(USING_GRAPH_URI) List usingGraphUris, @QueryParam(USING_NAMED_GRAPH_URI) List usingNamedGraphUris); 99 | 100 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/Service.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model; 17 | 18 | /** 19 | * SPARQL 1.1 service with endpoint and graph store. 20 | * 21 | * @author Martynas Jusevičius {@literal } 22 | */ 23 | public interface Service 24 | { 25 | 26 | EndpointAccessor getEndpointAccessor(); 27 | 28 | DatasetAccessor getDatasetAccessor(); 29 | 30 | DatasetQuadAccessor getDatasetQuadAccessor(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/QuadStoreImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.impl; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import com.atomgraph.core.model.QuadStore; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Locale; 23 | import jakarta.ws.rs.DELETE; 24 | import jakarta.ws.rs.GET; 25 | import jakarta.ws.rs.POST; 26 | import jakarta.ws.rs.PUT; 27 | import jakarta.ws.rs.core.Context; 28 | import jakarta.ws.rs.core.Request; 29 | import org.apache.jena.query.Dataset; 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | import com.atomgraph.core.model.DatasetQuadAccessor; 33 | import com.atomgraph.core.model.Service; 34 | import java.util.Collections; 35 | import jakarta.inject.Inject; 36 | import jakarta.ws.rs.core.EntityTag; 37 | import jakarta.ws.rs.core.MediaType; 38 | 39 | /** 40 | * 41 | * @author Martynas Jusevičius {@literal } 42 | */ 43 | public class QuadStoreImpl implements QuadStore 44 | { 45 | private static final Logger log = LoggerFactory.getLogger(QuadStoreImpl.class); 46 | 47 | private final Request request; 48 | private final DatasetQuadAccessor accessor; 49 | private final MediaTypes mediaTypes; 50 | 51 | /** 52 | * Constructs Graph Store from request metadata. 53 | * 54 | * @param request request 55 | * @param service SPARQL service 56 | * @param mediaTypes supported media types 57 | */ 58 | @Inject 59 | public QuadStoreImpl(@Context Request request, Service service, MediaTypes mediaTypes) 60 | { 61 | this(request, service.getDatasetQuadAccessor(), mediaTypes); 62 | } 63 | 64 | public QuadStoreImpl(Request request, DatasetQuadAccessor accessor, MediaTypes mediaTypes) 65 | { 66 | if (request == null) throw new IllegalArgumentException("Request cannot be null"); 67 | if (accessor == null) throw new IllegalArgumentException("DatasetQuadAccessor cannot be null"); 68 | if (mediaTypes == null) throw new IllegalArgumentException("MediaTypes cannot be null"); 69 | 70 | this.request = request; 71 | this.accessor = accessor; 72 | this.mediaTypes = mediaTypes; 73 | } 74 | 75 | /** 76 | * Returns response for the given RDF dataset. 77 | * 78 | * @param dataset RDF dataset 79 | * @return response object 80 | */ 81 | public jakarta.ws.rs.core.Response getResponse(Dataset dataset) 82 | { 83 | return getResponseBuilder(dataset).build(); 84 | } 85 | 86 | /** 87 | * Returns response builder for the given RDF dataset. 88 | * 89 | * @param dataset RDF dataset 90 | * @return response builder 91 | */ 92 | public jakarta.ws.rs.core.Response.ResponseBuilder getResponseBuilder(Dataset dataset) 93 | { 94 | return new com.atomgraph.core.model.impl.Response(getRequest(), 95 | dataset, 96 | null, 97 | getEntityTag(dataset), 98 | getWritableMediaTypes(Dataset.class), 99 | getLanguages(), 100 | getEncodings()). 101 | getResponseBuilder(); 102 | } 103 | 104 | /** 105 | * Generate the ETag response header value of the current RDF dataset. 106 | * 107 | * @param dataset RDF dataset 108 | * @return hash value 109 | */ 110 | public EntityTag getEntityTag(Dataset dataset) 111 | { 112 | return new EntityTag(Long.toHexString(com.atomgraph.core.model.impl.Response.hashDataset(dataset))); 113 | } 114 | 115 | /** 116 | * Returns a list of supported languages. 117 | * 118 | * @return list of languages 119 | */ 120 | public List getLanguages() 121 | { 122 | return new ArrayList<>(); 123 | } 124 | 125 | /** 126 | * Returns a list of supported HTTP encodings. 127 | * Note: this is different from content encodings such as UTF-8. 128 | * 129 | * @return list of encodings 130 | */ 131 | public List getEncodings() 132 | { 133 | return new ArrayList<>(); 134 | } 135 | 136 | /** 137 | * Implements GET method of SPARQL Graph Store Protocol. 138 | * 139 | * @return response 140 | */ 141 | @GET 142 | @Override 143 | public jakarta.ws.rs.core.Response get() 144 | { 145 | return getResponse(getQuadDatasetAccessor().get()); 146 | } 147 | 148 | /** 149 | * Implements POST method of SPARQL Graph Store Protocol. 150 | * 151 | * @param dataset RDF request body 152 | * @return response 153 | */ 154 | @POST 155 | @Override 156 | public jakarta.ws.rs.core.Response post(Dataset dataset) 157 | { 158 | getQuadDatasetAccessor().add(dataset); 159 | return jakarta.ws.rs.core.Response.ok().build(); 160 | } 161 | 162 | /** 163 | * Implements PUT method of SPARQL Graph Store Protocol. 164 | * 165 | * @param dataset RDF request body 166 | * @return response 167 | */ 168 | @PUT 169 | @Override 170 | public jakarta.ws.rs.core.Response put(Dataset dataset) 171 | { 172 | getQuadDatasetAccessor().replace(dataset); 173 | return jakarta.ws.rs.core.Response.ok().build(); 174 | } 175 | 176 | /** 177 | * Implements DELETE method of SPARQL Graph Store Protocol. 178 | * 179 | * @return response 180 | */ 181 | @DELETE 182 | @Override 183 | public jakarta.ws.rs.core.Response delete() 184 | { 185 | getQuadDatasetAccessor().delete(); 186 | return jakarta.ws.rs.core.Response.noContent().build(); 187 | } 188 | 189 | public List getWritableMediaTypes(Class clazz) 190 | { 191 | return getMediaTypes().getWritable(clazz); 192 | } 193 | 194 | public Request getRequest() 195 | { 196 | return request; 197 | } 198 | 199 | public DatasetQuadAccessor getQuadDatasetAccessor() 200 | { 201 | return accessor; 202 | } 203 | 204 | public MediaTypes getMediaTypes() 205 | { 206 | return mediaTypes; 207 | } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/QueriedResourceBase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.model.impl; 18 | 19 | import com.atomgraph.core.MediaTypes; 20 | import org.apache.jena.query.Query; 21 | import org.apache.jena.query.QueryFactory; 22 | import java.net.URI; 23 | import jakarta.ws.rs.GET; 24 | import jakarta.ws.rs.Path; 25 | import jakarta.ws.rs.core.Context; 26 | import jakarta.ws.rs.core.Request; 27 | import jakarta.ws.rs.core.Response; 28 | import jakarta.ws.rs.core.UriInfo; 29 | import com.atomgraph.core.model.QueriedResource; 30 | import com.atomgraph.core.model.Service; 31 | import java.util.Collections; 32 | import jakarta.inject.Inject; 33 | import jakarta.ws.rs.NotAllowedException; 34 | import jakarta.ws.rs.NotFoundException; 35 | import org.apache.jena.rdf.model.Model; 36 | import org.slf4j.Logger; 37 | import org.slf4j.LoggerFactory; 38 | 39 | /** 40 | * Base class of generic read-only Linked Data resources with RDF representations queried from SPARQL endpoints. 41 | * 42 | * @author Martynas Jusevičius {@literal } 43 | * @see com.atomgraph.core.model.SPARQLEndpoint 44 | * @see ARQ Query 45 | */ 46 | @Path("/") 47 | public class QueriedResourceBase extends ResourceBase implements QueriedResource 48 | { 49 | private static final Logger log = LoggerFactory.getLogger(QueriedResourceBase.class); 50 | 51 | private final Service service; 52 | 53 | /** 54 | * JAX-RS-compatible resource constructor with injected initialization objects. 55 | * The URI of the resource being created is the absolute path of the current request URI. 56 | * 57 | * @param mediaTypes mediaTypes 58 | * @param uriInfo URI information of the request 59 | * @param request current request object 60 | * @param service SPARQL service 61 | * @see JAX-RS UriInfo 62 | */ 63 | @Inject 64 | public QueriedResourceBase(@Context UriInfo uriInfo, @Context Request request, MediaTypes mediaTypes, Service service) 65 | { 66 | this(uriInfo, request, mediaTypes, uriInfo.getAbsolutePath(), service); 67 | } 68 | 69 | protected QueriedResourceBase(final UriInfo uriInfo, final Request request, final MediaTypes mediaTypes, final URI uri, final Service service) 70 | { 71 | super(uriInfo, request, mediaTypes, uri); 72 | if (service == null) throw new IllegalArgumentException("Service cannot be null"); 73 | 74 | this.service = service; 75 | } 76 | 77 | public Service getService() 78 | { 79 | return service; 80 | } 81 | 82 | @Path("{path: .+}") 83 | public Object getSubResource() 84 | { 85 | if (getUriInfo().getAbsolutePath().equals(getUriInfo().getBaseUriBuilder().path("sparql").build())) 86 | return new SPARQLEndpointImpl(getRequest(), getService(), getMediaTypes()); 87 | 88 | if (getUriInfo().getAbsolutePath().equals(getUriInfo().getBaseUriBuilder().path("service").build())) 89 | return new GraphStoreImpl(getRequest(), getService(), getMediaTypes()); 90 | 91 | return this; 92 | } 93 | 94 | /** 95 | * Returns RDF description of this resource. 96 | * The description is the result of a query executed on the SPARQL endpoint of this resource. 97 | * By default, the query is DESCRIBE with URI of this resource. 98 | * The response from the endpoint does not depend on the current request, to make sure we always get a Model entity back (and not only response headers). 99 | * 100 | * @return RDF description 101 | * @see getQuery() 102 | */ 103 | @Override 104 | public Model describe() 105 | { 106 | return getService().getEndpointAccessor().loadModel(getQuery(), Collections.emptyList() , Collections.emptyList()); 107 | } 108 | 109 | /** 110 | * Handles GET request and returns response with RDF description of this resource. 111 | * 112 | * @return response with RDF description 113 | */ 114 | @GET 115 | @Override 116 | public Response get() 117 | { 118 | final Model model = describe(); 119 | 120 | if (model.isEmpty()) 121 | { 122 | if (log.isDebugEnabled()) log.debug("Query result Dataset is empty; returning 404 Not Found"); 123 | throw new NotFoundException("Query result Dataset is empty"); 124 | } 125 | 126 | return getResponse(model); 127 | } 128 | 129 | /** 130 | * Handles POST method, stores the submitted RDF model in the SPARQL endpoint, and returns response. 131 | * 132 | * @param model RDF payload 133 | * @return response 134 | */ 135 | @Override 136 | public Response post(Model model) 137 | { 138 | if (log.isWarnEnabled()) log.warn("POST request is not allowed. AtomGraph Core is read-only! Only GET is supported"); 139 | throw new NotAllowedException("POST is not allowed"); 140 | } 141 | 142 | /** 143 | * Handles PUT method, stores the submitted RDF model in the SPARQL endpoint, and returns response. 144 | * 145 | * @param model RDF payload 146 | * @return response 147 | */ 148 | @Override 149 | public Response put(Model model) 150 | { 151 | if (log.isWarnEnabled()) log.warn("PUT request is not allowed. AtomGraph Core is read-only! Only GET is supported"); 152 | throw new NotAllowedException("PUT is not allowed"); 153 | } 154 | 155 | /** 156 | * Handles DELETE method, deletes the RDF representation of this resource from the SPARQL endpoint, and 157 | * returns response. 158 | * 159 | * @return response 160 | */ 161 | @Override 162 | public Response delete() 163 | { 164 | if (log.isWarnEnabled()) log.warn("DELETE request with RDF payload: {}. AtomGraph Core is read-only! Only GET is supported"); 165 | throw new NotAllowedException("DELETE is not allowed"); 166 | } 167 | 168 | /** 169 | * Returns query used to retrieve RDF description of this resource 170 | * 171 | * @return query object 172 | */ 173 | @Override 174 | public Query getQuery() 175 | { 176 | return getQuery(getURI()); 177 | } 178 | 179 | /** 180 | * Given a resource URI, returns query that can be used to retrieve its RDF description 181 | * 182 | * @param uri resource URI 183 | * @return query object 184 | */ 185 | public Query getQuery(URI uri) 186 | { 187 | if (uri == null) throw new IllegalArgumentException("URI cannot be null"); 188 | return QueryFactory.create("DESCRIBE <" + uri.toString() + ">"); 189 | } 190 | 191 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/ResourceBase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.model.impl; 18 | 19 | import org.apache.jena.rdf.model.*; 20 | import java.net.URI; 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | import java.util.Locale; 24 | import jakarta.ws.rs.core.Context; 25 | import jakarta.ws.rs.core.Request; 26 | import jakarta.ws.rs.core.Response; 27 | import jakarta.ws.rs.core.Response.ResponseBuilder; 28 | import jakarta.ws.rs.core.UriInfo; 29 | import com.atomgraph.core.MediaTypes; 30 | import com.atomgraph.core.model.Resource; 31 | import com.atomgraph.core.util.ModelUtils; 32 | import java.util.Date; 33 | import jakarta.inject.Inject; 34 | import jakarta.ws.rs.core.EntityTag; 35 | import org.slf4j.Logger; 36 | import org.slf4j.LoggerFactory; 37 | 38 | /** 39 | * Base class of generic read-only Linked Data resources. 40 | * 41 | * @see Jena Resource 42 | * @author Martynas Jusevičius {@literal } 43 | */ 44 | public abstract class ResourceBase implements Resource 45 | { 46 | private static final Logger log = LoggerFactory.getLogger(ResourceBase.class); 47 | 48 | private final UriInfo uriInfo; 49 | private final Request request; 50 | private final MediaTypes mediaTypes; 51 | private final URI uri; 52 | 53 | /** 54 | * JAX-RS-compatible resource constructor with injected request metadata. 55 | * The URI of the resource being created is the absolute path of the current request URI. 56 | * 57 | * @param uriInfo URI information of the request 58 | * @param request current request object 59 | * @param mediaTypes media types 60 | * @see JAX-RS UriInfo.getAbsolutePath() 61 | */ 62 | @Inject 63 | public ResourceBase(@Context UriInfo uriInfo, @Context Request request, MediaTypes mediaTypes) 64 | { 65 | this(uriInfo, request, mediaTypes, uriInfo.getAbsolutePath()); 66 | } 67 | 68 | protected ResourceBase(final UriInfo uriInfo, final Request request, final MediaTypes mediaTypes, final URI uri) 69 | { 70 | if (uriInfo == null) throw new IllegalArgumentException("UriInfo cannot be null"); 71 | if (request == null) throw new IllegalArgumentException("Request cannot be null"); 72 | if (mediaTypes == null) throw new IllegalArgumentException("MediaTypes cannot be null"); 73 | if (uri == null) throw new IllegalArgumentException("URI cannot be null"); 74 | 75 | this.uriInfo = uriInfo; 76 | this.request = request; 77 | this.mediaTypes = mediaTypes; 78 | this.uri = uri; 79 | if (log.isDebugEnabled()) log.debug("Request URI: {}", uriInfo.getRequestUri()); 80 | } 81 | 82 | /** 83 | * Returns response for the given RDF graph. 84 | * 85 | * @param model RDF model 86 | * @return response object 87 | */ 88 | public Response getResponse(Model model) 89 | { 90 | return getResponseBuilder(model).build(); 91 | } 92 | 93 | /** 94 | * Extract the Last-Modified response header value of the current resource from its RDF model. 95 | * 96 | * @param model RDF model 97 | * @return date of last modification 98 | */ 99 | public Date getLastModified(Model model) 100 | { 101 | return null; 102 | } 103 | 104 | /** 105 | * Generate the ETag response header value of the current resource from its RDF model. 106 | * 107 | * @param model RDF model 108 | * @return entity tag 109 | */ 110 | public EntityTag getEntityTag(Model model) 111 | { 112 | return new EntityTag(Long.toHexString(ModelUtils.hashModel(model))); 113 | } 114 | 115 | /** 116 | * Returns response builder for the given RDF graph. 117 | * 118 | * @param model RDF model 119 | * @return response builder 120 | */ 121 | public ResponseBuilder getResponseBuilder(Model model) 122 | { 123 | return new com.atomgraph.core.model.impl.Response(getRequest(), 124 | model, 125 | getLastModified(model), 126 | getEntityTag(model), 127 | getWritableMediaTypes(Model.class), 128 | getLanguages(), 129 | getEncodings()). 130 | getResponseBuilder(); 131 | } 132 | 133 | public List getWritableMediaTypes(Class clazz) 134 | { 135 | return getMediaTypes().getWritable(clazz); 136 | } 137 | 138 | public MediaTypes getMediaTypes() 139 | { 140 | return mediaTypes; 141 | } 142 | 143 | public List getLanguages() 144 | { 145 | return new ArrayList<>(); 146 | } 147 | 148 | public List getEncodings() 149 | { 150 | return new ArrayList<>(); 151 | } 152 | 153 | /** 154 | * Returns URI of this resource 155 | * 156 | * @return URI of this resource 157 | */ 158 | @Override 159 | public final URI getURI() 160 | { 161 | return uri; 162 | } 163 | 164 | /** 165 | * Returns URI information. 166 | * 167 | * @return URI info object 168 | */ 169 | public UriInfo getUriInfo() 170 | { 171 | return uriInfo; 172 | } 173 | 174 | /** 175 | * Returns current request. 176 | * 177 | * @return request object 178 | */ 179 | public Request getRequest() 180 | { 181 | return request; 182 | } 183 | 184 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/dataset/DatasetAccessorImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.atomgraph.core.model.impl.dataset; 19 | 20 | import com.atomgraph.core.model.DatasetAccessor; 21 | import org.apache.jena.query.Dataset; 22 | import org.apache.jena.rdf.model.Model; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * Base class for dataset-backed Graph Stores. 28 | * Implementation of Graph Store Protocol on Jena dataset. 29 | * 30 | * @author Martynas Jusevičius {@literal } 31 | * @see SPARQL 1.1 Graph Store HTTP Protocol 32 | */ 33 | public class DatasetAccessorImpl implements DatasetAccessor 34 | { 35 | private static final Logger log = LoggerFactory.getLogger(DatasetAccessorImpl.class); 36 | 37 | private final Dataset dataset; 38 | 39 | public DatasetAccessorImpl(Dataset dataset) 40 | { 41 | if (dataset == null) throw new IllegalArgumentException("Dataset cannot be null"); 42 | this.dataset = dataset; 43 | } 44 | 45 | @Override 46 | public Model getModel() 47 | { 48 | return getDataset().getDefaultModel(); 49 | } 50 | 51 | @Override 52 | public Model getModel(String uri) 53 | { 54 | return getDataset().getNamedModel(uri); 55 | } 56 | 57 | @Override 58 | public boolean containsModel(String uri) 59 | { 60 | return getDataset().containsNamedModel(uri); 61 | } 62 | 63 | @Override 64 | public void putModel(Model model) 65 | { 66 | getDataset().setDefaultModel(model); 67 | } 68 | 69 | @Override 70 | public void putModel(String uri, Model model) 71 | { 72 | getDataset().replaceNamedModel(uri, model); 73 | } 74 | 75 | @Override 76 | public void deleteDefault() 77 | { 78 | getDataset().setDefaultModel(null); 79 | } 80 | 81 | @Override 82 | public void deleteModel(String uri) 83 | { 84 | getDataset().removeNamedModel(uri); 85 | } 86 | 87 | @Override 88 | public void add(Model model) 89 | { 90 | getDataset().getDefaultModel().add(model); 91 | } 92 | 93 | @Override 94 | public void add(String uri, Model model) 95 | { 96 | getDataset().addNamedModel(uri, model); 97 | } 98 | 99 | public Dataset getDataset() 100 | { 101 | return dataset; 102 | } 103 | 104 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/dataset/DatasetQuadAccessorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.impl.dataset; 17 | 18 | import com.atomgraph.core.model.DatasetQuadAccessor; 19 | import java.util.Iterator; 20 | import jakarta.ws.rs.core.Context; 21 | import org.apache.jena.query.Dataset; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * 27 | * @author Martynas Jusevičius {@literal } 28 | */ 29 | public class DatasetQuadAccessorImpl implements DatasetQuadAccessor 30 | { 31 | private static final Logger log = LoggerFactory.getLogger(DatasetQuadAccessorImpl.class); 32 | 33 | private final Dataset dataset; 34 | 35 | public DatasetQuadAccessorImpl(@Context Dataset dataset) 36 | { 37 | if (dataset == null) throw new IllegalArgumentException("Dataset cannot be null"); 38 | this.dataset = dataset; 39 | } 40 | 41 | @Override 42 | public Dataset get() 43 | { 44 | return getDataset(); 45 | } 46 | 47 | @Override 48 | public void add(Dataset dataset) 49 | { 50 | getDataset().getDefaultModel().add(dataset.getDefaultModel()); 51 | 52 | Iterator it = dataset.listNames(); 53 | while (it.hasNext()) 54 | { 55 | String graphURI = it.next(); 56 | getDataset().addNamedModel(graphURI, dataset.getNamedModel(graphURI)); 57 | } 58 | } 59 | 60 | @Override 61 | public void replace(Dataset dataset) 62 | { 63 | delete(); 64 | 65 | add(dataset); 66 | } 67 | 68 | @Override 69 | public void delete() 70 | { 71 | getDataset().getDefaultModel().removeAll(); 72 | 73 | Iterator it = getDataset().listNames(); 74 | while (it.hasNext()) 75 | getDataset().removeNamedModel(it.next()); 76 | } 77 | 78 | @Override 79 | public void patch(Dataset dataset) 80 | { 81 | getDataset().getDefaultModel().removeAll(); 82 | getDataset().getDefaultModel().add(dataset.getDefaultModel()); 83 | 84 | Iterator it = dataset.listNames(); 85 | while (it.hasNext()) 86 | { 87 | String graphURI = it.next(); 88 | getDataset().replaceNamedModel(graphURI, dataset.getNamedModel(graphURI)); 89 | } 90 | } 91 | 92 | public Dataset getDataset() 93 | { 94 | return dataset; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/dataset/ServiceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.impl.dataset; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import com.atomgraph.core.model.DatasetAccessor; 20 | import com.atomgraph.core.model.DatasetQuadAccessor; 21 | import com.atomgraph.core.model.EndpointAccessor; 22 | import com.atomgraph.core.model.Service; 23 | import org.apache.jena.query.Dataset; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | /** 28 | * 29 | * @author Martynas Jusevičius {@literal } 30 | */ 31 | public class ServiceImpl implements Service 32 | { 33 | 34 | private static final Logger log = LoggerFactory.getLogger(ServiceImpl.class); 35 | 36 | private final Dataset dataset; 37 | private final MediaTypes mediaTypes; 38 | 39 | public ServiceImpl(Dataset dataset, MediaTypes mediaTypes) 40 | { 41 | if (dataset == null) throw new IllegalArgumentException("Dataset must be not null"); 42 | 43 | this.dataset = dataset; 44 | this.mediaTypes = mediaTypes; 45 | } 46 | 47 | @Override 48 | public EndpointAccessor getEndpointAccessor() 49 | { 50 | return new EndpointAccessorImpl(getDataset()); 51 | } 52 | 53 | @Override 54 | public DatasetAccessor getDatasetAccessor() 55 | { 56 | return new DatasetAccessorImpl(getDataset()); 57 | } 58 | 59 | @Override 60 | public DatasetQuadAccessor getDatasetQuadAccessor() 61 | { 62 | return new DatasetQuadAccessorImpl(getDataset()); 63 | } 64 | 65 | protected Dataset getDataset() 66 | { 67 | return dataset; 68 | } 69 | 70 | protected MediaTypes getMediaTypes() 71 | { 72 | return mediaTypes; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/remote/DatasetAccessorImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.atomgraph.core.model.impl.remote; 19 | 20 | import org.apache.jena.rdf.model.Model; 21 | import com.atomgraph.core.client.GraphStoreClient; 22 | import com.atomgraph.core.exception.BadGatewayException; 23 | import com.atomgraph.core.model.DatasetAccessor; 24 | import jakarta.ws.rs.ClientErrorException; 25 | import jakarta.ws.rs.NotFoundException; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | /** 30 | * Proxy implementation of Graph Store. 31 | * This class forwards requests to a remote origin. 32 | * 33 | * @author Martynas Jusevičius {@literal } 34 | */ 35 | @Deprecated 36 | public class DatasetAccessorImpl implements DatasetAccessor 37 | { 38 | private static final Logger log = LoggerFactory.getLogger(DatasetAccessorImpl.class); 39 | 40 | private final GraphStoreClient graphStoreClient; 41 | 42 | /** 43 | * Constructs Graph Store proxy from request metadata and origin URI. 44 | * 45 | * @param graphStoreClient SPARQL 1.1 Graph Store Protocol client 46 | */ 47 | public DatasetAccessorImpl(GraphStoreClient graphStoreClient) 48 | { 49 | if (graphStoreClient == null) throw new IllegalArgumentException("GraphStoreClient cannot be null"); 50 | this.graphStoreClient = graphStoreClient; 51 | } 52 | 53 | @Override 54 | public Model getModel() 55 | { 56 | try 57 | { 58 | return getGraphStoreClient().getModel(); 59 | } 60 | catch (ClientErrorException ex) 61 | { 62 | if (log.isDebugEnabled()) log.debug("Graph Store backend client error", ex); 63 | throw new BadGatewayException(ex); 64 | } 65 | } 66 | 67 | @Override 68 | public Model getModel(String uri) 69 | { 70 | try 71 | { 72 | return getGraphStoreClient().getModel(uri); 73 | } 74 | catch (NotFoundException ex) 75 | { 76 | if (log.isDebugEnabled()) log.debug("Graph with URI <{}> not found", ex, uri); 77 | throw ex; 78 | } 79 | catch (ClientErrorException ex) 80 | { 81 | if (log.isDebugEnabled()) log.debug("Graph Store backend client error", ex); 82 | throw new BadGatewayException(ex); 83 | } 84 | } 85 | 86 | @Override 87 | public boolean containsModel(String uri) 88 | { 89 | try 90 | { 91 | return getGraphStoreClient().containsModel(uri); 92 | } 93 | catch (NotFoundException ex) 94 | { 95 | if (log.isDebugEnabled()) log.debug("Graph with URI <{}> not found", ex, uri); 96 | throw ex; 97 | } 98 | catch (ClientErrorException ex) 99 | { 100 | if (log.isDebugEnabled()) log.debug("Graph Store backend client error", ex); 101 | throw new BadGatewayException(ex); 102 | } 103 | } 104 | 105 | @Override 106 | public void putModel(Model model) 107 | { 108 | try 109 | { 110 | getGraphStoreClient().putModel(model); 111 | } 112 | catch (ClientErrorException ex) 113 | { 114 | if (log.isDebugEnabled()) log.debug("Graph Store backend client error", ex); 115 | throw new BadGatewayException(ex); 116 | } 117 | } 118 | 119 | @Override 120 | public void putModel(String uri, Model model) 121 | { 122 | try 123 | { 124 | getGraphStoreClient().putModel(uri, model); 125 | } 126 | catch (ClientErrorException ex) 127 | { 128 | if (log.isDebugEnabled()) log.debug("Graph Store backend client error", ex); 129 | throw new BadGatewayException(ex); 130 | } 131 | } 132 | 133 | @Override 134 | public void deleteDefault() 135 | { 136 | try 137 | { 138 | getGraphStoreClient().deleteDefault(); 139 | } 140 | catch (ClientErrorException ex) 141 | { 142 | if (log.isDebugEnabled()) log.debug("Graph Store backend client error", ex); 143 | throw new BadGatewayException(ex); 144 | } 145 | } 146 | 147 | @Override 148 | public void deleteModel(String uri) 149 | { 150 | try 151 | { 152 | getGraphStoreClient().deleteModel(uri); 153 | } 154 | catch (NotFoundException ex) 155 | { 156 | if (log.isDebugEnabled()) log.debug("Graph with URI <{}> not found", ex, uri); 157 | throw ex; 158 | } 159 | catch (ClientErrorException ex) 160 | { 161 | if (log.isDebugEnabled()) log.debug("Graph Store backend client error", ex); 162 | throw new BadGatewayException(ex); 163 | } 164 | } 165 | 166 | @Override 167 | public void add(Model model) 168 | { 169 | try 170 | { 171 | getGraphStoreClient().add(model); 172 | } 173 | catch (ClientErrorException ex) 174 | { 175 | if (log.isDebugEnabled()) log.debug("Graph Store backend client error", ex); 176 | throw new BadGatewayException(ex); 177 | } 178 | } 179 | 180 | @Override 181 | public void add(String uri, Model model) 182 | { 183 | try 184 | { 185 | getGraphStoreClient().add(uri, model); 186 | } 187 | catch (ClientErrorException ex) 188 | { 189 | if (log.isDebugEnabled()) log.debug("Graph Store backend client error", ex); 190 | throw new BadGatewayException(ex); 191 | } 192 | } 193 | 194 | public String getURI() // needs to align with Jena's Resource.getURI() which returns String 195 | { 196 | return getGraphStoreClient().getEndpoint().getUri().toString(); 197 | } 198 | 199 | public GraphStoreClient getGraphStoreClient() 200 | { 201 | return graphStoreClient; 202 | } 203 | 204 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/remote/DatasetQuadAccessorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.impl.remote; 17 | 18 | import com.atomgraph.core.client.QuadStoreClient; 19 | import com.atomgraph.core.exception.BadGatewayException; 20 | import com.atomgraph.core.model.DatasetQuadAccessor; 21 | import jakarta.ws.rs.ClientErrorException; 22 | import org.apache.jena.query.Dataset; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * 28 | * @author Martynas Jusevičius {@literal } 29 | */ 30 | public class DatasetQuadAccessorImpl implements DatasetQuadAccessor 31 | { 32 | private static final Logger log = LoggerFactory.getLogger(DatasetQuadAccessorImpl.class); 33 | 34 | private final QuadStoreClient quadStoreClient; 35 | 36 | /** 37 | * Constructs Quad Store proxy from request metadata and origin URI. 38 | * 39 | * @param quadStoreClient SPARQL 1.1 Graph Store Protocol client extended with quad support 40 | */ 41 | public DatasetQuadAccessorImpl(QuadStoreClient quadStoreClient) 42 | { 43 | if (quadStoreClient == null) throw new IllegalArgumentException("QuadStoreClient cannot be null"); 44 | this.quadStoreClient = quadStoreClient; 45 | } 46 | 47 | @Override 48 | public Dataset get() 49 | { 50 | try 51 | { 52 | return getQuadStoreClient().get(); 53 | } 54 | catch (ClientErrorException ex) 55 | { 56 | throw new BadGatewayException(ex); 57 | } 58 | } 59 | 60 | @Override 61 | public void add(Dataset dataset) 62 | { 63 | try 64 | { 65 | getQuadStoreClient().add(dataset); 66 | } 67 | catch (ClientErrorException ex) 68 | { 69 | throw new BadGatewayException(ex); 70 | } 71 | } 72 | 73 | @Override 74 | public void replace(Dataset dataset) 75 | { 76 | try 77 | { 78 | getQuadStoreClient().replace(dataset); 79 | } 80 | catch (ClientErrorException ex) 81 | { 82 | throw new BadGatewayException(ex); 83 | } 84 | } 85 | 86 | @Override 87 | public void delete() 88 | { 89 | try 90 | { 91 | getQuadStoreClient().delete(); 92 | } 93 | catch (ClientErrorException ex) 94 | { 95 | throw new BadGatewayException(ex); 96 | } 97 | } 98 | 99 | @Override 100 | public void patch(Dataset dataset) 101 | { 102 | try 103 | { 104 | getQuadStoreClient().patch(dataset); 105 | } 106 | catch (ClientErrorException ex) 107 | { 108 | throw new BadGatewayException(ex); 109 | } 110 | } 111 | 112 | public QuadStoreClient getQuadStoreClient() 113 | { 114 | return quadStoreClient; 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/remote/EndpointAccessorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.impl.remote; 17 | 18 | import com.atomgraph.core.client.SPARQLClient; 19 | import static com.atomgraph.core.client.SPARQLClient.parseBoolean; 20 | import com.atomgraph.core.exception.BadGatewayException; 21 | import com.atomgraph.core.model.EndpointAccessor; 22 | import static com.atomgraph.core.model.SPARQLEndpoint.DEFAULT_GRAPH_URI; 23 | import static com.atomgraph.core.model.SPARQLEndpoint.NAMED_GRAPH_URI; 24 | import static com.atomgraph.core.model.SPARQLEndpoint.USING_GRAPH_URI; 25 | import static com.atomgraph.core.model.SPARQLEndpoint.USING_NAMED_GRAPH_URI; 26 | import java.io.IOException; 27 | import java.net.URI; 28 | import java.util.List; 29 | import jakarta.ws.rs.ClientErrorException; 30 | import jakarta.ws.rs.core.MultivaluedHashMap; 31 | import jakarta.ws.rs.core.MultivaluedMap; 32 | import jakarta.ws.rs.core.Response; 33 | import org.apache.jena.query.Dataset; 34 | import org.apache.jena.query.Query; 35 | import org.apache.jena.query.ResultSet; 36 | import org.apache.jena.query.ResultSetRewindable; 37 | import org.apache.jena.rdf.model.Model; 38 | import org.apache.jena.update.UpdateRequest; 39 | 40 | /** 41 | * 42 | * @author Martynas Jusevičius {@literal } 43 | */ 44 | public class EndpointAccessorImpl implements EndpointAccessor 45 | { 46 | 47 | private final SPARQLClient sparqlClient; 48 | 49 | public EndpointAccessorImpl(SPARQLClient sparqlClient) 50 | { 51 | if (sparqlClient == null) throw new IllegalArgumentException("SPARQLClient cannot be null"); 52 | this.sparqlClient = sparqlClient; 53 | } 54 | 55 | @Override 56 | public Dataset loadDataset(Query query, List defaultGraphUris, List namedGraphUris) 57 | { 58 | if (defaultGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 59 | if (namedGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 60 | 61 | MultivaluedMap params = new MultivaluedHashMap(); 62 | 63 | defaultGraphUris.forEach(defaultGraphUri -> { params.add(DEFAULT_GRAPH_URI, defaultGraphUri.toString()); }); 64 | namedGraphUris.forEach(namedGraphUri -> { params.add(NAMED_GRAPH_URI, namedGraphUri.toString()); }); 65 | 66 | try (Response cr = getSPARQLClient().query(query, Dataset.class, params)) 67 | { 68 | return cr.readEntity(Dataset.class); 69 | } 70 | catch (ClientErrorException ex) 71 | { 72 | throw new BadGatewayException(ex); 73 | } 74 | } 75 | 76 | @Override 77 | public Model loadModel(Query query, List defaultGraphUris, List namedGraphUris) 78 | { 79 | if (defaultGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 80 | if (namedGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 81 | 82 | MultivaluedMap params = new MultivaluedHashMap(); 83 | 84 | defaultGraphUris.forEach(defaultGraphUri -> { params.add(DEFAULT_GRAPH_URI, defaultGraphUri.toString()); }); 85 | namedGraphUris.forEach(namedGraphUri -> { params.add(NAMED_GRAPH_URI, namedGraphUri.toString()); }); 86 | 87 | try (Response cr = getSPARQLClient().query(query, Model.class, params)) 88 | { 89 | return cr.readEntity(Model.class); 90 | } 91 | catch (ClientErrorException ex) 92 | { 93 | throw new BadGatewayException(ex); 94 | } 95 | } 96 | 97 | @Override 98 | public ResultSetRewindable select(Query query, List defaultGraphUris, List namedGraphUris) 99 | { 100 | if (defaultGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 101 | if (namedGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 102 | 103 | MultivaluedMap params = new MultivaluedHashMap(); 104 | 105 | defaultGraphUris.forEach(defaultGraphUri -> { params.add(DEFAULT_GRAPH_URI, defaultGraphUri.toString()); }); 106 | namedGraphUris.forEach(namedGraphUri -> { params.add(NAMED_GRAPH_URI, namedGraphUri.toString()); }); 107 | 108 | try (Response cr = getSPARQLClient().query(query, ResultSet.class, params)) 109 | { 110 | return cr.readEntity(ResultSetRewindable.class); 111 | } 112 | catch (ClientErrorException ex) 113 | { 114 | throw new BadGatewayException(ex); 115 | } 116 | } 117 | 118 | @Override 119 | public boolean ask(Query query, List defaultGraphUris, List namedGraphUris) 120 | { 121 | if (defaultGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 122 | if (namedGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 123 | 124 | MultivaluedMap params = new MultivaluedHashMap(); 125 | 126 | defaultGraphUris.forEach(defaultGraphUri -> { params.add(DEFAULT_GRAPH_URI, defaultGraphUri.toString()); }); 127 | namedGraphUris.forEach(namedGraphUri -> { params.add(NAMED_GRAPH_URI, namedGraphUri.toString()); }); 128 | 129 | try (Response cr = getSPARQLClient().query(query, ResultSet.class, params)) 130 | { 131 | return parseBoolean(cr); 132 | } 133 | catch (IOException | ClientErrorException ex) 134 | { 135 | throw new BadGatewayException(ex); 136 | } 137 | } 138 | 139 | @Override 140 | public void update(UpdateRequest updateRequest, List usingGraphUris, List usingNamedGraphUris) 141 | { 142 | if (usingGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 143 | if (usingNamedGraphUris == null) throw new IllegalArgumentException("List cannot be null"); 144 | 145 | MultivaluedMap params = new MultivaluedHashMap(); 146 | 147 | usingGraphUris.forEach(usingGraphUri -> { params.add(USING_GRAPH_URI, usingGraphUri.toString()); }); 148 | usingNamedGraphUris.forEach(usingNamedGraphUri -> { params.add(USING_NAMED_GRAPH_URI, usingNamedGraphUri.toString()); }); 149 | 150 | try 151 | { 152 | getSPARQLClient().update(updateRequest, params); 153 | } 154 | catch (ClientErrorException ex) 155 | { 156 | throw new BadGatewayException(ex); 157 | } 158 | } 159 | 160 | public SPARQLClient getSPARQLClient() 161 | { 162 | return sparqlClient; 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/impl/remote/ServiceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.impl.remote; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import com.atomgraph.core.client.GraphStoreClient; 20 | import com.atomgraph.core.client.QuadStoreClient; 21 | import com.atomgraph.core.client.SPARQLClient; 22 | import com.atomgraph.core.model.DatasetAccessor; 23 | import com.atomgraph.core.model.DatasetQuadAccessor; 24 | import com.atomgraph.core.model.EndpointAccessor; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | import com.atomgraph.core.model.RemoteService; 28 | import jakarta.ws.rs.client.Client; 29 | import jakarta.ws.rs.client.WebTarget; 30 | import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; 31 | 32 | /** 33 | * 34 | * @author Martynas Jusevičius {@literal } 35 | */ 36 | public class ServiceImpl implements RemoteService 37 | { 38 | 39 | private static final Logger log = LoggerFactory.getLogger(ServiceImpl.class); 40 | 41 | private final org.apache.jena.rdf.model.Resource endpoint, graphStore, quadStore; 42 | private final Client client; 43 | private final MediaTypes mediaTypes; 44 | private final String authUser, authPwd; 45 | private final Integer maxGetRequestSize; 46 | 47 | public ServiceImpl(Client client, MediaTypes mediaTypes, org.apache.jena.rdf.model.Resource endpoint, org.apache.jena.rdf.model.Resource graphStore, org.apache.jena.rdf.model.Resource quadStore, 48 | String authUser, String authPwd, Integer maxGetRequestSize) 49 | { 50 | if (client == null) throw new IllegalArgumentException("Client must be not null"); 51 | if (mediaTypes == null) throw new IllegalArgumentException("MediaTypes must be not null"); 52 | if (endpoint == null) throw new IllegalArgumentException("SPARQL endpoint Resource must be not null"); 53 | if (!endpoint.isURIResource()) throw new IllegalArgumentException("SPARQL endpoint Resource must be URI resource"); 54 | if (graphStore == null) throw new IllegalArgumentException("Graph Store Resource must be not null"); 55 | if (!graphStore.isURIResource()) throw new IllegalArgumentException("Graph Store Resource must be URI resource"); 56 | 57 | this.client = client; 58 | this.mediaTypes = mediaTypes; 59 | this.endpoint = endpoint; 60 | this.graphStore = graphStore; 61 | this.quadStore = quadStore; 62 | this.authUser = authUser; 63 | this.authPwd = authPwd; 64 | this.maxGetRequestSize = maxGetRequestSize; 65 | } 66 | 67 | public ServiceImpl(Client client, MediaTypes mediaTypes, org.apache.jena.rdf.model.Resource endpoint, org.apache.jena.rdf.model.Resource graphStore, org.apache.jena.rdf.model.Resource quadStore) 68 | { 69 | this(client, mediaTypes, endpoint, graphStore, quadStore, null, null, null); 70 | } 71 | 72 | @Override 73 | public SPARQLClient getSPARQLClient() 74 | { 75 | return getSPARQLClient(getClient().target(getSPARQLEndpoint().getURI())); 76 | } 77 | 78 | public SPARQLClient getSPARQLClient(WebTarget resource) 79 | { 80 | SPARQLClient sparqlClient; 81 | 82 | if (getMaxGetRequestSize() != null) 83 | sparqlClient = SPARQLClient.create(getMediaTypes(), resource, getMaxGetRequestSize()); 84 | else 85 | sparqlClient = SPARQLClient.create(getMediaTypes(), resource); 86 | 87 | if (getAuthUser() != null && getAuthPwd() != null) 88 | { 89 | HttpAuthenticationFeature authFeature = HttpAuthenticationFeature.basicBuilder(). 90 | credentials(getAuthUser(), getAuthPwd()). 91 | build(); 92 | 93 | sparqlClient.getEndpoint().register(authFeature); 94 | } 95 | 96 | return sparqlClient; 97 | } 98 | 99 | @Override 100 | public EndpointAccessor getEndpointAccessor() 101 | { 102 | return new EndpointAccessorImpl(getSPARQLClient()); 103 | } 104 | 105 | @Override 106 | public GraphStoreClient getGraphStoreClient() 107 | { 108 | return getGraphStoreClient(getClient().target(getGraphStore().getURI())); 109 | } 110 | 111 | public GraphStoreClient getGraphStoreClient(WebTarget resource) 112 | { 113 | GraphStoreClient graphStoreClient = GraphStoreClient.create(resource); 114 | 115 | if (getAuthUser() != null && getAuthPwd() != null) 116 | { 117 | HttpAuthenticationFeature authFeature = HttpAuthenticationFeature.basicBuilder(). 118 | credentials(getAuthUser(), getAuthPwd()). 119 | build(); 120 | 121 | graphStoreClient.getEndpoint().register(authFeature); 122 | } 123 | 124 | return graphStoreClient; 125 | } 126 | 127 | @Override 128 | public QuadStoreClient getQuadStoreClient() 129 | { 130 | return getQuadStoreClient(getClient().target(getQuadStore().getURI())); 131 | } 132 | 133 | public QuadStoreClient getQuadStoreClient(WebTarget resource) 134 | { 135 | QuadStoreClient quadStoreClient = QuadStoreClient.create(resource); 136 | 137 | if (getAuthUser() != null && getAuthPwd() != null) 138 | { 139 | HttpAuthenticationFeature authFeature = HttpAuthenticationFeature.basicBuilder(). 140 | credentials(getAuthUser(), getAuthPwd()). 141 | build(); 142 | 143 | quadStoreClient.getEndpoint().register(authFeature); 144 | } 145 | 146 | return quadStoreClient; 147 | } 148 | 149 | @Override 150 | @Deprecated 151 | public DatasetAccessor getDatasetAccessor() 152 | { 153 | return new DatasetAccessorImpl(getGraphStoreClient()); 154 | } 155 | 156 | @Override 157 | @Deprecated 158 | public DatasetQuadAccessor getDatasetQuadAccessor() 159 | { 160 | return new DatasetQuadAccessorImpl(getQuadStoreClient()); 161 | } 162 | 163 | @Override 164 | public org.apache.jena.rdf.model.Resource getSPARQLEndpoint() 165 | { 166 | return endpoint; 167 | } 168 | 169 | @Override 170 | public org.apache.jena.rdf.model.Resource getGraphStore() 171 | { 172 | return graphStore; 173 | } 174 | 175 | @Override 176 | public org.apache.jena.rdf.model.Resource getQuadStore() 177 | { 178 | return quadStore; 179 | } 180 | 181 | public Client getClient() 182 | { 183 | return client; 184 | } 185 | 186 | public MediaTypes getMediaTypes() 187 | { 188 | return mediaTypes; 189 | } 190 | 191 | @Override 192 | public String getAuthUser() // protected? 193 | { 194 | return authUser; 195 | } 196 | 197 | @Override 198 | public String getAuthPwd() // protected? 199 | { 200 | return authPwd; 201 | } 202 | 203 | public Integer getMaxGetRequestSize() 204 | { 205 | return maxGetRequestSize; 206 | } 207 | 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/remote/GraphStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.remote; 17 | 18 | import com.atomgraph.core.client.GraphStoreClient; 19 | 20 | /** 21 | * Remote Graph Store identified by URI. 22 | * 23 | * @author Martynas Jusevičius {@literal } 24 | */ 25 | public interface GraphStore extends com.atomgraph.core.model.GraphStore 26 | { 27 | 28 | String getURI(); 29 | 30 | GraphStoreClient getGraphStoreClient(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/remote/QuadStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.remote; 17 | 18 | import com.atomgraph.core.client.QuadStoreClient; 19 | 20 | /** 21 | * 22 | * @author Martynas Jusevičius {@literal } 23 | */ 24 | public interface QuadStore extends com.atomgraph.core.model.QuadStore 25 | { 26 | 27 | String getURI(); 28 | 29 | QuadStoreClient getQuadStoreClient(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/model/remote/SPARQLEndpoint.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.remote; 17 | 18 | import com.atomgraph.core.client.SPARQLClient; 19 | 20 | /** 21 | * Remote SPARQL endpoint identified by URI. 22 | * 23 | * @author Martynas Jusevičius {@literal } 24 | */ 25 | public interface SPARQLEndpoint extends com.atomgraph.core.model.SPARQLEndpoint 26 | { 27 | 28 | String getURI(); 29 | 30 | SPARQLClient getSPARQLClient(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/provider/QueryParamProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.provider; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Type; 21 | import jakarta.ws.rs.BadRequestException; 22 | import jakarta.ws.rs.ext.ParamConverter; 23 | import jakarta.ws.rs.ext.ParamConverterProvider; 24 | import jakarta.ws.rs.ext.Provider; 25 | import org.apache.jena.query.Query; 26 | import org.apache.jena.query.QueryException; 27 | import org.apache.jena.query.QueryFactory; 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | 31 | /** 32 | * JAX-RS query parameter provider for SPARQL string. 33 | * Needs to be registered in the JAX-RS application. 34 | * 35 | * @author Martynas Jusevičius {@literal } 36 | * @see org.apache.jena.query.Query 37 | * @see jakarta.ws.rs.QueryParam 38 | * @see jakarta.ws.rs.core.Context 39 | */ 40 | @Provider 41 | public class QueryParamProvider implements ParamConverterProvider 42 | { 43 | private static final Logger log = LoggerFactory.getLogger(QueryParamProvider.class); 44 | 45 | @Override 46 | public ParamConverter getConverter(final Class rawType, Type type, Annotation[] antns) 47 | { 48 | if (rawType.equals(Query.class)) 49 | { 50 | return new ParamConverter() 51 | { 52 | 53 | @Override 54 | public T fromString(final String value) 55 | { 56 | if (value == null) throw new IllegalArgumentException("Cannot parse Query from null String"); 57 | 58 | try 59 | { 60 | return rawType.cast(QueryFactory.create(value)); 61 | } 62 | catch (QueryException ex) 63 | { 64 | if (log.isWarnEnabled()) log.warn("Supplied SPARQL query string could not be parsed, check syntax: {}", value); 65 | throw new BadRequestException(ex); 66 | } 67 | } 68 | 69 | @Override 70 | public String toString(final T query) 71 | { 72 | return query.toString(); 73 | } 74 | }; 75 | } 76 | 77 | return null; 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/riot/RDFLanguages.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.riot; 18 | 19 | import org.apache.jena.riot.Lang; 20 | import org.apache.jena.riot.LangBuilder; 21 | import com.atomgraph.core.MediaType; 22 | 23 | /** 24 | * Adds new RDF languages to Jena's registry. 25 | * 26 | * @author Martynas Jusevičius {@literal } 27 | * @see org.apache.jena.riot.RDFLanguages 28 | */ 29 | public class RDFLanguages extends org.apache.jena.riot.RDFLanguages 30 | { 31 | 32 | public static final String strLangRDFPOST = "RDF/POST" ; 33 | 34 | public static final Lang RDFPOST = LangBuilder.create(strLangRDFPOST, MediaType.APPLICATION_RDF_URLENCODED). 35 | addFileExtensions("rpo"). 36 | build(); 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/riot/lang/RDFPostReaderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.atomgraph.core.riot.lang; 18 | 19 | import com.atomgraph.core.riot.RDFLanguages; 20 | import org.apache.jena.atlas.lib.InternalErrorException; 21 | import org.apache.jena.riot.Lang; 22 | import org.apache.jena.riot.ReaderRIOT; 23 | import org.apache.jena.riot.ReaderRIOTFactory; 24 | import org.apache.jena.riot.system.ParserProfile; 25 | 26 | /** 27 | * RDF/POST reader factory. 28 | * 29 | * @author Martynas Jusevičius {@literal } 30 | */ 31 | public class RDFPostReaderFactory implements ReaderRIOTFactory 32 | { 33 | 34 | @Override 35 | public ReaderRIOT create(Lang lang, ParserProfile profile) 36 | { 37 | if (!RDFLanguages.RDFPOST.equals(lang)) 38 | throw new InternalErrorException("Attempt to parse " + lang + " as RDF/POST"); 39 | 40 | return new RDFPostReader(lang, profile, profile.getErrorHandler()); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/util/Link.java: -------------------------------------------------------------------------------- 1 | package com.atomgraph.core.util; 2 | 3 | import java.net.URI; 4 | import java.net.URISyntaxException; 5 | import java.util.HashMap; 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | /** 10 | * Represents HTTP Link header. 11 | * This class is based on
ex09_1
from the "RESTful Java with JAX-RS" book. 12 | * 13 | * @author Martynas Jusevičius {@literal } 14 | * @see RESTful Java with JAX-RS 15 | */ 16 | @Deprecated 17 | public class Link 18 | { 19 | private static Pattern PATTERN = Pattern.compile("<(.+)>\\s*;\\s*(.+)"); 20 | 21 | private URI href = null; 22 | private String rel = null; 23 | private String type = null; 24 | 25 | private Link() 26 | { 27 | } 28 | 29 | public Link(URI href, String rel, String type) 30 | { 31 | if (href == null) throw new IllegalArgumentException("Link value cannot be null"); 32 | if (rel == null) throw new IllegalArgumentException("Link relationship cannot be null"); 33 | 34 | this.href = href; 35 | this.rel = rel; 36 | this.type = type; 37 | } 38 | 39 | public String getRel() 40 | { 41 | return rel; 42 | } 43 | 44 | public void setRel(String rel) 45 | { 46 | this.rel = rel; 47 | } 48 | 49 | public URI getHref() 50 | { 51 | return href; 52 | } 53 | 54 | public void setHref(URI href) 55 | { 56 | this.href = href; 57 | } 58 | 59 | public String getType() 60 | { 61 | return type; 62 | } 63 | 64 | public void setType(String type) 65 | { 66 | this.type = type; 67 | } 68 | 69 | /** 70 | * To write as Link header 71 | * 72 | * @return header value 73 | */ 74 | @Override 75 | public String toString() 76 | { 77 | StringBuilder builder = new StringBuilder("<"); 78 | builder.append(getHref()).append(">; rel=").append(getRel()); 79 | if (getType() != null) builder.append("; type=").append(getType()); 80 | return builder.toString(); 81 | } 82 | 83 | /** 84 | * For unmarshalling Link Headers. 85 | * Its not an efficient or perfect algorithm 86 | * and does make a few assumptions 87 | * 88 | * @param val header value 89 | * @return parsed link object 90 | * @throws java.net.URISyntaxException thrown if href value cannot be parsed 91 | */ 92 | public static Link valueOf(String val) throws URISyntaxException 93 | { 94 | if (val == null) throw new IllegalArgumentException("Link value cannot be null"); 95 | 96 | Matcher matcher = PATTERN.matcher(val); 97 | if (!matcher.matches()) 98 | throw new RuntimeException("Failed to parse link: " + val); 99 | 100 | Link link = new Link(); 101 | link.setHref(new URI(matcher.group(1))); 102 | String[] props = matcher.group(2).split(";"); 103 | HashMap map = new HashMap(); 104 | for (String prop : props) 105 | { 106 | String[] split = prop.split("="); 107 | map.put(split[0].trim(), split[1].trim()); 108 | } 109 | if (map.containsKey("rel")) link.setRel(map.get("rel")); 110 | if (map.containsKey("type")) link.setType(map.get("type")); 111 | 112 | return link; 113 | } 114 | 115 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/util/ModelUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | See lda-top/LICENCE (or http://elda.googlecode.com/hg/LICENCE) 3 | for the licence for this software. 4 | 5 | (c) Copyright 2011 Epimorphics Limited 6 | $Id$ 7 | 8 | File: ResultSet.java 9 | Created by: Dave Reynolds 10 | Created on: 31 Jan 2010 11 | */ 12 | 13 | package com.atomgraph.core.util; 14 | 15 | import org.apache.jena.graph.Node; 16 | import org.apache.jena.graph.Triple; 17 | import org.apache.jena.rdf.model.Model; 18 | import org.apache.jena.util.iterator.ExtendedIterator; 19 | 20 | /** 21 | * Model hash calculator. 22 | */ 23 | public class ModelUtils 24 | { 25 | 26 | public static long hashModel(Model m) 27 | { 28 | long result = 0; 29 | ExtendedIterator it = m.getGraph().find(Node.ANY, Node.ANY, Node.ANY); 30 | while (it.hasNext()) result ^= hashTriple(it.next()); 31 | return result; 32 | } 33 | 34 | public static long hashTriple(Triple t) 35 | { 36 | long result = 0; 37 | Node S = t.getSubject(), P = t.getPredicate(), O = t.getObject(); 38 | if (!S.isBlank()) result = (long) S.hashCode() << 32; 39 | if (!P.isBlank()) result ^= (long) P.hashCode() << 16; 40 | if (!O.isBlank()) result ^= (long) O.hashCode(); 41 | return result; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/util/ResultSetUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.atomgraph.core.util; 19 | 20 | import org.apache.jena.query.QuerySolution; 21 | import org.apache.jena.query.ResultSet; 22 | import org.apache.jena.rdf.model.RDFNode; 23 | import java.util.Iterator; 24 | 25 | /** 26 | * Result set hash calculator. 27 | * 28 | * @author Martynas Jusevičius {@literal } 29 | */ 30 | public class ResultSetUtils 31 | { 32 | public static long hashResultSet(ResultSet result) 33 | { 34 | long hash = 0; 35 | 36 | while (result.hasNext()) hash ^= hashQuerySolution(result.next()); 37 | 38 | return hash; 39 | } 40 | 41 | public static long hashQuerySolution(QuerySolution solution) 42 | { 43 | long hash = 0; 44 | 45 | Iterator it = solution.varNames(); 46 | while (it.hasNext()) 47 | { 48 | RDFNode node = solution.get(it.next()); 49 | if (node != null) hash ^= (long) node.hashCode(); 50 | } 51 | 52 | return hash; 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/util/jena/DataManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.util.jena; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import java.net.URI; 20 | import jakarta.ws.rs.client.Client; 21 | import jakarta.ws.rs.client.WebTarget; 22 | import jakarta.ws.rs.core.Response; 23 | import org.apache.jena.ext.com.google.common.collect.ImmutableMap; 24 | import org.apache.jena.rdf.model.Model; 25 | import org.apache.jena.rdf.model.ModelGetter; 26 | 27 | /** 28 | * 29 | * @author Martynas Jusevičius {@literal } 30 | */ 31 | public interface DataManager extends ModelGetter 32 | { 33 | 34 | ImmutableMap getModelCache(); 35 | 36 | // Client getClient(); 37 | 38 | // MediaTypes getMediaTypes(); 39 | 40 | //WebTarget getEndpoint(URI endpointURI); 41 | 42 | Response get(String uri, jakarta.ws.rs.core.MediaType[] acceptedTypes); // TO-DO: deprecate? 43 | 44 | boolean usePreemptiveAuth(); 45 | 46 | Model loadModel(String uri); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/util/jena/DataManagerImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.util.jena; 18 | 19 | import org.apache.jena.rdf.model.Model; 20 | import org.apache.jena.util.LocationMapper; 21 | import java.net.URI; 22 | import com.atomgraph.core.client.LinkedDataClient; 23 | import java.util.Map; 24 | import jakarta.ws.rs.core.Response; 25 | import jakarta.ws.rs.core.UriBuilder; 26 | import org.apache.jena.ext.com.google.common.collect.ImmutableMap; 27 | import org.apache.jena.rdf.model.ModelFactory; 28 | import org.apache.jena.rdf.model.ModelReader; 29 | import org.apache.jena.util.FileManagerImpl; 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | 33 | /** 34 | * Utility class for retrieval of RDF models from remote URLs. 35 | * 36 | * @author Martynas Jusevičius {@literal } 37 | * @see org.apache.jena.util.FileManager 38 | * @see org.apache.jena.rdf.model.ModelGetter 39 | * @see com.atomgraph.core.client.LinkedDataClient 40 | */ 41 | 42 | public class DataManagerImpl extends FileManagerImpl implements DataManager 43 | { 44 | 45 | private static final Logger log = LoggerFactory.getLogger(DataManagerImpl.class); 46 | 47 | private final boolean preemptiveAuth; 48 | private final LinkedDataClient ldc; 49 | private boolean cacheModelLoads; 50 | private final Map modelCache; 51 | 52 | /** 53 | * Creates data manager. 54 | * 55 | * @param mapper location mapper 56 | * @param modelCache model cache map 57 | * @param ldc Linked Data client 58 | * @param cacheModelLoads if true, cache models after loading, using locations as keys 59 | * @param preemptiveAuth if true, preemptive HTTP authentication will be used 60 | */ 61 | public DataManagerImpl(LocationMapper mapper, Map modelCache, 62 | LinkedDataClient ldc, 63 | boolean cacheModelLoads, boolean preemptiveAuth) 64 | { 65 | super(mapper); 66 | if (modelCache == null) throw new IllegalArgumentException("Model cache Map must be not null"); 67 | this.modelCache = modelCache; 68 | this.cacheModelLoads = cacheModelLoads; 69 | this.preemptiveAuth = preemptiveAuth; 70 | this.ldc = ldc; 71 | 72 | addLocatorFile() ; 73 | addLocatorURL() ; 74 | addLocatorClassLoader(getClass().getClassLoader()) ; 75 | } 76 | 77 | public URI getEndpoint(URI endpointURI) 78 | { 79 | if (endpointURI == null) throw new IllegalArgumentException("Endpoint URI must be not null"); 80 | 81 | return UriBuilder.fromUri(endpointURI).fragment(null).build().normalize(); // cannot use the URI class because query string with special chars such as '+' gets decoded 82 | } 83 | 84 | @Override 85 | public Response get(String uri, jakarta.ws.rs.core.MediaType[] acceptedTypes) 86 | { 87 | return getLinkedDataClient().get(getEndpoint(URI.create(uri)), acceptedTypes); 88 | } 89 | 90 | @Override 91 | public Model loadModel(String uri) 92 | { 93 | // only handle HTTP/HTTPS URIs, leave the rest to Jena 94 | if (!hasCachedModel(uri)) 95 | { 96 | String mappedURI = mapURI(uri); 97 | if (mappedURI.startsWith("http") || mappedURI.startsWith("https")) 98 | { 99 | Model model = getLinkedDataClient().getModel(getEndpoint(URI.create(uri)).toString()); 100 | 101 | if (isCachingModels()) addCacheModel(uri, model) ; 102 | 103 | return model; 104 | } 105 | } 106 | 107 | return super.loadModel(uri); 108 | } 109 | 110 | @Override 111 | public Model getModel(String uri) 112 | { 113 | return loadModel(uri); 114 | } 115 | 116 | @Override 117 | public Model getModel(String uri, ModelReader loadIfAbsent) 118 | { 119 | Model model = getModel(uri); 120 | 121 | if (model == null) return loadIfAbsent.readModel(ModelFactory.createDefaultModel(), uri); 122 | 123 | return model; 124 | } 125 | 126 | @Override 127 | public Model readModel(Model model, String uri) 128 | { 129 | String mappedURI = mapURI(uri); 130 | if (mappedURI.startsWith("http") || mappedURI.startsWith("https")) 131 | return model.add(getLinkedDataClient().getModel(getEndpoint(URI.create(uri)).toString())); 132 | 133 | return super.readModel(model, uri); 134 | } 135 | 136 | /** 137 | * Returns an immutable copy of the model cache 138 | * 139 | * @return immutable cache map 140 | */ 141 | @Override 142 | public ImmutableMap getModelCache() 143 | { 144 | return ImmutableMap.copyOf(modelCache); 145 | } 146 | 147 | /** 148 | * Reset the model cache 149 | */ 150 | @Override 151 | public void resetCache() 152 | { 153 | modelCache.clear() ; 154 | } 155 | 156 | /** 157 | * Change the state of model cache : does not clear the cache. 158 | * Deprecated - use constructor argument instead. 159 | * 160 | * @param state true to enable caching 161 | */ 162 | @Override 163 | @Deprecated 164 | public void setModelCaching(boolean state) 165 | { 166 | this.cacheModelLoads = state; 167 | } 168 | 169 | /** 170 | * Return whether caching is on of off 171 | * 172 | * @return true if caching is enabled 173 | */ 174 | @Override 175 | public boolean isCachingModels() 176 | { 177 | return cacheModelLoads; 178 | } 179 | 180 | /** 181 | * Read out of the cache - return null if not in the cache 182 | * 183 | * @param filenameOrURI the location to load model from 184 | * @return model instance or null if it's not cached or caching is off 185 | */ 186 | @Override 187 | public Model getFromCache(String filenameOrURI) 188 | { 189 | if (!isCachingModels()) return null; 190 | 191 | return modelCache.get(filenameOrURI); 192 | } 193 | 194 | /** 195 | * Check if model is cached for a given URI 196 | * 197 | * @param filenameOrURI model location 198 | * @return true if cached, if it's not cached or caching is off 199 | */ 200 | @Override 201 | public boolean hasCachedModel(String filenameOrURI) 202 | { 203 | if (!isCachingModels()) return false; 204 | 205 | return modelCache.containsKey(filenameOrURI) ; 206 | } 207 | 208 | /** 209 | * Add model to cache using given URI as key 210 | * 211 | * @param uri model URI (cache key) 212 | * @param m the model 213 | */ 214 | @Override 215 | public void addCacheModel(String uri, Model m) 216 | { 217 | if (isCachingModels()) modelCache.put(uri, m); 218 | } 219 | 220 | /** 221 | * Remove cache from model using given URI key 222 | * 223 | * @param uri cache key 224 | */ 225 | @Override 226 | public void removeCacheModel(String uri) 227 | { 228 | if (isCachingModels()) modelCache.remove(uri) ; 229 | } 230 | 231 | @Override 232 | public boolean usePreemptiveAuth() 233 | { 234 | return preemptiveAuth; 235 | } 236 | 237 | /** 238 | * Returns Linked Data client. 239 | * 240 | * @return client instance 241 | */ 242 | public LinkedDataClient getLinkedDataClient() 243 | { 244 | return ldc; 245 | } 246 | 247 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/util/jena/StartupListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.util.jena; 17 | 18 | import jakarta.servlet.ServletContextEvent; 19 | import jakarta.servlet.ServletContextListener; 20 | import org.apache.jena.sys.JenaSystem; 21 | 22 | /** 23 | * 24 | * @author Martynas Jusevičius {@literal } 25 | */ 26 | public class StartupListener implements ServletContextListener 27 | { 28 | 29 | @Override 30 | public void contextInitialized(ServletContextEvent sce) 31 | { 32 | JenaSystem.init(); 33 | } 34 | 35 | @Override 36 | public void contextDestroyed(ServletContextEvent sce) 37 | { 38 | JenaSystem.shutdown(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/vocabulary/A.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.vocabulary; 18 | 19 | import org.apache.jena.ontology.DatatypeProperty; 20 | import org.apache.jena.ontology.ObjectProperty; 21 | import org.apache.jena.ontology.OntModel; 22 | import org.apache.jena.ontology.OntModelSpec; 23 | import org.apache.jena.rdf.model.ModelFactory; 24 | import org.apache.jena.rdf.model.Resource; 25 | 26 | /** 27 | * 28 | * @author Martynas Jusevičius {@literal } 29 | */ 30 | public final class A 31 | { 32 | /**

The RDF model that holds the vocabulary terms

*/ 33 | private static OntModel m_model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, null); 34 | 35 | /**

The namespace of the vocabulary as a string

*/ 36 | public static final String NS = "https://w3id.org/atomgraph/core#"; 37 | 38 | /**

The namespace of the vocabulary as a string

39 | * @return namespace URI 40 | * @see #NS */ 41 | public static String getURI() 42 | { 43 | return NS; 44 | } 45 | 46 | /**

The namespace of the vocabulary as a resource

*/ 47 | public static final Resource NAMESPACE = m_model.createResource( NS ); 48 | 49 | /** Dataset file property */ 50 | public static final DatatypeProperty dataset = m_model.createDatatypeProperty( NS + "dataset" ); 51 | 52 | /** Graph Store URL property */ 53 | public static final ObjectProperty graphStore = m_model.createObjectProperty( NS + "graphStore" ); 54 | 55 | /** Quad store URL property */ 56 | public static final ObjectProperty quadStore = m_model.createObjectProperty( NS + "quadStore" ); 57 | 58 | /** Cache-Control property **/ 59 | public static final DatatypeProperty cacheControl = m_model.createDatatypeProperty( NS + "cacheControl" ); 60 | 61 | /** Result limit property */ 62 | public static final DatatypeProperty resultLimit = m_model.createDatatypeProperty( NS + "resultLimit" ); 63 | 64 | /** Cache models property */ 65 | public static final DatatypeProperty cacheModelLoads = m_model.createDatatypeProperty( NS + "cacheModelLoads" ); 66 | 67 | /** Preemptive HTTP Basic auth property */ 68 | public static final DatatypeProperty preemptiveAuth = m_model.createDatatypeProperty( NS + "preemptiveAuth" ); 69 | 70 | /** Max GET request size property */ 71 | public static final DatatypeProperty maxGetRequestSize = m_model.createDatatypeProperty( NS + "maxGetRequestSize" ); 72 | 73 | /** HTTP Basic auth user property */ 74 | public static final DatatypeProperty authUser = m_model.createDatatypeProperty( NS + "authUser" ); 75 | 76 | /** HTTP Basic auth password property */ 77 | public static final DatatypeProperty authPwd = m_model.createDatatypeProperty( NS + "authPwd" ); 78 | 79 | } -------------------------------------------------------------------------------- /src/main/java/com/atomgraph/core/vocabulary/SD.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Martynas Jusevičius 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.atomgraph.core.vocabulary; 18 | 19 | import org.apache.jena.ontology.Individual; 20 | import org.apache.jena.ontology.ObjectProperty; 21 | import org.apache.jena.ontology.OntClass; 22 | import org.apache.jena.ontology.OntModel; 23 | import org.apache.jena.ontology.OntModelSpec; 24 | import org.apache.jena.rdf.model.ModelFactory; 25 | import org.apache.jena.rdf.model.Resource; 26 | 27 | /** 28 | * 29 | * @author Martynas 30 | */ 31 | public class SD 32 | { 33 | /**

The RDF model that holds the vocabulary terms

*/ 34 | private static OntModel m_model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, null); 35 | 36 | /**

The namespace of the vocabulary as a string

*/ 37 | public static final String NS = "http://www.w3.org/ns/sparql-service-description#"; 38 | 39 | /**

The namespace of the vocabulary as a string

40 | * @return namespace URI 41 | * @see #NS */ 42 | public static String getURI() 43 | { 44 | return NS; 45 | } 46 | 47 | /**

The namespace of the vocabulary as a resource

*/ 48 | public static final Resource NAMESPACE = m_model.createResource( NS ); 49 | 50 | public static final OntClass Dataset = m_model.createClass( NS + "Dataset" ); 51 | 52 | public static final OntClass Service = m_model.createClass( NS + "Service" ); 53 | 54 | public static final OntClass Graph = m_model.createClass( NS + "Graph" ); 55 | 56 | public static final OntClass NamedGraph = m_model.createClass( NS + "NamedGraph" ); 57 | 58 | public static final OntClass Language = m_model.createClass( NS + "Language" ); 59 | 60 | public static final ObjectProperty endpoint = m_model.createObjectProperty( NS + "endpoint" ); 61 | 62 | public static final ObjectProperty graph = m_model.createObjectProperty( NS + "graph" ); 63 | 64 | public static final ObjectProperty name = m_model.createObjectProperty( NS + "name" ); 65 | 66 | public static final ObjectProperty defaultGraph = m_model.createObjectProperty( NS + "defaultGraph" ); 67 | 68 | public static final ObjectProperty namedGraph = m_model.createObjectProperty( NS + "namedGraph" ); 69 | 70 | public static final ObjectProperty supportedLanguage = m_model.createObjectProperty( NS + "supportedLanguage" ); 71 | 72 | public static final Individual SPARQL10Query = m_model.createIndividual(NS + "SPARQL10Query", Language); 73 | 74 | public static final Individual SPARQL11Query = m_model.createIndividual(NS + "SPARQL11Query", Language); 75 | 76 | public static final Individual SPARQL11Update = m_model.createIndividual(NS + "SPARQL11Update", Language); 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/resources/com/atomgraph/core/ns.ttl: -------------------------------------------------------------------------------- 1 | @base . 2 | 3 | @prefix : <#> . 4 | @prefix rdf: . 5 | @prefix rdfs: . 6 | @prefix xsd: . 7 | @prefix owl: . 8 | @prefix http: . 9 | @prefix sd: . 10 | @prefix sioc: . 11 | @prefix foaf: . 12 | 13 | : a owl:Ontology ; 14 | owl:imports sd:, http: ; 15 | rdfs:label "AtomGraph Core ontology" ; 16 | owl:versionInfo "2.1.0" . 17 | 18 | :graphStore a owl:ObjectProperty, owl:InverseFunctionalProperty ; 19 | rdfs:domain sd:Service ; 20 | rdfs:label "Graph Store" ; 21 | rdfs:seeAlso sd:service ; 22 | rdfs:isDefinedBy <#> . 23 | 24 | :preemptiveAuth a owl:DatatypeProperty ; 25 | rdfs:range xsd:boolean ; 26 | rdfs:label "Preemptive authentication" ; 27 | rdfs:seeAlso ; 28 | rdfs:isDefinedBy <#> . 29 | 30 | :cacheControl a owl:DatatypeProperty ; 31 | rdfs:subPropertyOf http:fieldValue ; 32 | rdfs:range xsd:string ; 33 | rdfs:label "Cache control" ; 34 | rdfs:seeAlso ; 35 | rdfs:isDefinedBy <#> . 36 | 37 | :resultLimit a owl:DatatypeProperty ; 38 | rdfs:range xsd:long ; 39 | rdfs:label "LIMIT modifier" ; 40 | rdfs:description "Value of this property is set on all executed SELECT queries" ; 41 | rdfs:seeAlso ; 42 | rdfs:isDefinedBy <#> . 43 | 44 | :absolutePath a owl:ObjectProperty ; 45 | rdfs:label "Absolute path URI" ; 46 | rdfs:domain http:Request ; 47 | rdfs:comment "Absolute path of the request" ; 48 | rdfs:seeAlso http:absoluteURI ; 49 | rdfs:isDefinedBy <#> . 50 | 51 | :requestUri a owl:ObjectProperty ; 52 | rdfs:label "Request URI" ; 53 | rdfs:domain http:Request ; 54 | rdfs:comment "Absolute path of the request" ; 55 | rdfs:seeAlso http:requestURI ; 56 | rdfs:isDefinedBy <#> . -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=DEBUG, stdout 2 | com.hp.hpl.jena.util.FileManager=ALL 3 | com.hp.hpl.jena.util.LocationManager=ALL 4 | com.hp.hpl.jena.reasoner=WARN 5 | 6 | # Direct log messages to console 7 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 8 | log4j.appender.stdout.Target=System.out 9 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 11 | 12 | # Rolling file appender 13 | log4j.appender.myLogFile=org.apache.log4j.RollingFileAppender 14 | log4j.appender.myLogFile.File=browser.log 15 | log4j.appender.myLogFile.MaxFileSize=100KB 16 | log4j.appender.myLogFile.MaxBackupIndex=2 17 | log4j.appender.myLogFile.layout=org.apache.log4j.PatternLayout 18 | log4j.appender.myLogFile.layout.ConversionPattern=%d{MMM d, yyyy hh:mm:ss a}: %p [%t] %m%n 19 | log4j.appender.myLogFile.threshold=WARN -------------------------------------------------------------------------------- /src/main/webapp/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | AtomGraph Core 8 | Generic Linked Data framework 9 | 10 | com.atomgraph.core.Application 11 | 21 | 31 | 32 | https://w3id.org/atomgraph/core#preemptiveAuth 33 | true 34 | 35 | 36 | https://w3id.org/atomgraph/core#cacheControl 37 | no-cache 38 | 39 | 40 | https://w3id.org/atomgraph/core#resultLimit 41 | 100 42 | 43 | 44 | https://w3id.org/atomgraph/core#maxGetRequestSize 45 | 8192 46 | 47 | 48 | 49 | com.atomgraph.core.Application 50 | /* 51 | 52 | 53 | com.atomgraph.core.util.jena.StartupListener 54 | 55 | -------------------------------------------------------------------------------- /src/test/java/com/atomgraph/core/client/GraphStoreClientTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Martynas.Jusevicius. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.client; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import static com.atomgraph.core.model.impl.GraphStoreImplTest.NAMED_GRAPH_URI; 20 | import static com.atomgraph.core.model.impl.GraphStoreImplTest.dataset; 21 | import jakarta.ws.rs.NotFoundException; 22 | import jakarta.ws.rs.client.WebTarget; 23 | import jakarta.ws.rs.core.Application; 24 | import java.util.UUID; 25 | import org.apache.jena.query.Dataset; 26 | import org.apache.jena.query.DatasetFactory; 27 | import org.apache.jena.rdf.model.ModelFactory; 28 | import org.apache.jena.rdf.model.ResourceFactory; 29 | import org.apache.jena.sparql.vocabulary.FOAF; 30 | import org.glassfish.jersey.client.ClientConfig; 31 | import org.glassfish.jersey.test.JerseyTest; 32 | import org.junit.Before; 33 | import org.junit.BeforeClass; 34 | import org.junit.Test; 35 | 36 | /** 37 | * 38 | * @author Martynas.Jusevicius 39 | */ 40 | public class GraphStoreClientTest extends JerseyTest 41 | { 42 | 43 | public com.atomgraph.core.Application system; 44 | public WebTarget endpoint; 45 | public GraphStoreClient gsc; 46 | 47 | @BeforeClass 48 | public static void initClass() 49 | { 50 | dataset = DatasetFactory.createTxnMem(); 51 | dataset.setDefaultModel(ModelFactory.createDefaultModel().add(ResourceFactory.createResource("http://default/graph/resource"), FOAF.name, "Smth")); 52 | dataset.addNamedModel(NAMED_GRAPH_URI, ModelFactory.createDefaultModel().add(ResourceFactory.createResource("http://default/graph/resource"), FOAF.name, "Whateverest")); 53 | } 54 | 55 | @Before 56 | public void init() 57 | { 58 | endpoint = system.getClient().target(getBaseUri().resolve("service")); 59 | gsc = GraphStoreClient.create(new MediaTypes(), endpoint); 60 | } 61 | 62 | protected Dataset getDataset() 63 | { 64 | return dataset; 65 | } 66 | 67 | @Override 68 | protected Application configure() 69 | { 70 | system = new com.atomgraph.core.Application(getDataset(), 71 | null, null, null, null, null, 72 | new MediaTypes(), com.atomgraph.core.Application.getClient(new ClientConfig()), 73 | null, false, false); 74 | system.init(); 75 | 76 | return system; 77 | } 78 | 79 | @Test(expected = NotFoundException.class) 80 | public void testGetNotFoundNamedModel() 81 | { 82 | gsc.getModel("http://host/" + UUID.randomUUID().toString()); 83 | } 84 | 85 | @Test(expected = NotFoundException.class) 86 | public void testDeleteNotFoundNamedModel() 87 | { 88 | gsc.deleteModel("http://host/" + UUID.randomUUID().toString()); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/com/atomgraph/core/io/ModelProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Martynas.Jusevicius. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.io; 17 | 18 | import com.atomgraph.core.MediaType; 19 | import com.atomgraph.core.MediaTypes; 20 | import com.atomgraph.core.client.GraphStoreClient; 21 | import static com.atomgraph.core.client.GraphStoreClient.DEFAULT_PARAM_NAME; 22 | import jakarta.ws.rs.client.WebTarget; 23 | import jakarta.ws.rs.core.Application; 24 | import jakarta.ws.rs.core.MultivaluedHashMap; 25 | import jakarta.ws.rs.core.MultivaluedMap; 26 | import jakarta.ws.rs.core.Response; 27 | import java.io.ByteArrayInputStream; 28 | import java.io.InputStream; 29 | import java.net.URI; 30 | import java.nio.charset.StandardCharsets; 31 | import org.apache.jena.query.DatasetFactory; 32 | import org.apache.jena.rdf.model.Model; 33 | import org.apache.jena.rdf.model.ModelFactory; 34 | import org.apache.jena.rdf.model.ResourceFactory; 35 | import org.apache.jena.riot.Lang; 36 | import org.apache.jena.riot.RiotException; 37 | import org.apache.jena.sparql.vocabulary.FOAF; 38 | import org.glassfish.jersey.client.ClientConfig; 39 | import org.glassfish.jersey.test.JerseyTest; 40 | import static org.junit.Assert.fail; 41 | import org.junit.Before; 42 | import org.junit.Test; 43 | 44 | /** 45 | * 46 | * @author Martynas.Jusevicius 47 | */ 48 | public class ModelProviderTest extends JerseyTest 49 | { 50 | 51 | public com.atomgraph.core.Application system; 52 | public WebTarget endpoint; 53 | public GraphStoreClient gsc; 54 | 55 | @Before 56 | public void init() 57 | { 58 | endpoint = system.getClient().target(getBaseUri().resolve("service")); 59 | gsc = GraphStoreClient.create(new MediaTypes(), endpoint); 60 | } 61 | 62 | @Override 63 | protected Application configure() 64 | { 65 | system = new com.atomgraph.core.Application(DatasetFactory.createTxnMem(), 66 | null, null, null, null, null, 67 | new MediaTypes(), com.atomgraph.core.Application.getClient(new ClientConfig()), 68 | null, false, false); 69 | system.init(); 70 | 71 | return system; 72 | } 73 | 74 | 75 | @Test(expected = RiotException.class) 76 | public void testRelativeURIsInNTriples() 77 | { 78 | String invalidNTriples = """ 79 | "Smth" . 80 | """; 81 | 82 | InputStream inputStream = new ByteArrayInputStream(invalidNTriples.getBytes(StandardCharsets.UTF_8)); 83 | 84 | Model model = ModelFactory.createDefaultModel(); 85 | 86 | ModelProvider modelProvider = new ModelProvider(); 87 | modelProvider.read(model, inputStream, Lang.NTRIPLES, null); 88 | } 89 | 90 | @Test 91 | public void testRelativeURIsResolvedAgainstBaseInNTriples() 92 | { 93 | String baseUri = "http://example.com/"; 94 | String relativeUri = "relative"; 95 | 96 | String invalidNTriples = String.format(""" 97 | <%s> "Smth" . 98 | """, relativeUri); 99 | 100 | InputStream inputStream = new ByteArrayInputStream(invalidNTriples.getBytes(StandardCharsets.UTF_8)); 101 | ModelProvider modelProvider = new ModelProvider(); 102 | // needs to use Turtle in order to allow relative URIs 103 | Model actual = modelProvider.read(ModelFactory.createDefaultModel(), inputStream, Lang.TURTLE, baseUri); 104 | 105 | Model expected = ModelFactory.createDefaultModel(). 106 | add(ResourceFactory.createResource(URI.create(baseUri).resolve(relativeUri).toString()), FOAF.name, "Smth"); 107 | 108 | assertIsomorphic(expected, actual); 109 | } 110 | 111 | @Test 112 | public void testTurtleRelativeURIsResolvedInWrittenModel() 113 | { 114 | String relativeUri = "relative"; 115 | Model modelWithRelativeURIs = ModelFactory.createDefaultModel(). 116 | add(ResourceFactory.createResource(relativeUri), FOAF.name, "Smth"); 117 | 118 | MultivaluedMap params = new MultivaluedHashMap(); 119 | params.putSingle(DEFAULT_PARAM_NAME, Boolean.TRUE.toString()); 120 | 121 | // needs to use Turtle in order to allow relative URIs 122 | try (Response cr = gsc.post(modelWithRelativeURIs, MediaType.TEXT_TURTLE_TYPE, new jakarta.ws.rs.core.MediaType[]{}, params)) 123 | { 124 | URI absoluteUri = getBaseUri().resolve(relativeUri); 125 | Model expected = ModelFactory.createDefaultModel(). 126 | add(ResourceFactory.createResource(absoluteUri.toString()), FOAF.name, "Smth"); 127 | 128 | System.out.println(gsc.getModel()); 129 | 130 | // check that the model that was written had resolved relative URIs against the base URI 131 | assertIsomorphic(expected, gsc.getModel()); 132 | } 133 | } 134 | 135 | public static void assertIsomorphic(Model wanted, Model got) 136 | { 137 | if (!wanted.isIsomorphicWith(got)) 138 | fail("Models not isomorphic (not structurally equal))"); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/test/java/com/atomgraph/core/model/impl/LocaleEntityTagTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Martynas.Jusevicius. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.impl; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import com.atomgraph.core.client.LinkedDataClient; 20 | import com.atomgraph.core.model.Service; 21 | import jakarta.inject.Inject; 22 | import jakarta.ws.rs.GET; 23 | import jakarta.ws.rs.NotFoundException; 24 | import jakarta.ws.rs.Path; 25 | import jakarta.ws.rs.core.Application; 26 | import jakarta.ws.rs.core.Context; 27 | import jakarta.ws.rs.core.HttpHeaders; 28 | import jakarta.ws.rs.core.MediaType; 29 | import jakarta.ws.rs.core.Request; 30 | import jakarta.ws.rs.core.Response.ResponseBuilder; 31 | import jakarta.ws.rs.core.UriInfo; 32 | import java.net.URI; 33 | import java.util.Arrays; 34 | import java.util.List; 35 | import java.util.Locale; 36 | import java.util.function.Predicate; 37 | import org.apache.jena.query.Dataset; 38 | import org.apache.jena.query.DatasetFactory; 39 | import org.apache.jena.rdf.model.Model; 40 | import org.apache.jena.rdf.model.ModelFactory; 41 | import org.apache.jena.rdf.model.ResourceFactory; 42 | import org.apache.jena.sparql.vocabulary.FOAF; 43 | import org.glassfish.jersey.client.ClientConfig; 44 | import org.glassfish.jersey.test.JerseyTest; 45 | import static org.junit.Assert.assertEquals; 46 | import static org.junit.Assert.assertNotEquals; 47 | import org.junit.Before; 48 | import org.junit.BeforeClass; 49 | import org.junit.Test; 50 | 51 | /** 52 | * 53 | * @author Martynas Jusevičius {@literal } 54 | */ 55 | public class LocaleEntityTagTest extends JerseyTest 56 | { 57 | 58 | public static final String RELATIVE_PATH = "test", RELATIVE_PATH_LANG = "test-lang"; 59 | public static final String RESOURCE_URI = "http://localhost:9998/" + RELATIVE_PATH; // assume that base URI is http://localhost:9998/ - has to match getBaseUri() 60 | public static final String RESOURCE_URI_LANG = "http://localhost:9998/" + RELATIVE_PATH_LANG; // assume that base URI is http://localhost:9998/ - has to match getBaseUri() 61 | public static Dataset dataset; 62 | 63 | private com.atomgraph.core.Application system; 64 | private LinkedDataClient ldc; 65 | private URI uri, uriLang; 66 | 67 | @BeforeClass 68 | public static void initClass() 69 | { 70 | dataset = DatasetFactory.createTxnMem(); 71 | Model defaultModel = ModelFactory.createDefaultModel(). 72 | add(ResourceFactory.createResource(RESOURCE_URI), FOAF.name, "Smth"). 73 | add(ResourceFactory.createResource(RESOURCE_URI_LANG), FOAF.name, "Whateverest"); 74 | dataset.setDefaultModel(defaultModel); 75 | } 76 | 77 | @Before 78 | public void init() 79 | { 80 | uri = getBaseUri().resolve(RELATIVE_PATH); 81 | uriLang = getBaseUri().resolve(RELATIVE_PATH_LANG); 82 | ldc = LinkedDataClient.create(system.getClient(), new MediaTypes()); 83 | } 84 | 85 | @Path(RELATIVE_PATH) 86 | public static class TestResource extends QueriedResourceBase 87 | { 88 | 89 | @Inject 90 | public TestResource(@Context UriInfo uriInfo, @Context Request request, MediaTypes mediaTypes, Service service) 91 | { 92 | super(uriInfo, request, mediaTypes, service); 93 | } 94 | 95 | } 96 | 97 | @Path(RELATIVE_PATH_LANG) 98 | public static class LangSpecificTestResource extends QueriedResourceBase 99 | { 100 | 101 | @Inject 102 | public LangSpecificTestResource(@Context UriInfo uriInfo, @Context Request request, MediaTypes mediaTypes, Service service) 103 | { 104 | super(uriInfo, request, mediaTypes, service); 105 | } 106 | 107 | @GET 108 | @Override 109 | public jakarta.ws.rs.core.Response get() 110 | { 111 | final Model model = describe(); 112 | 113 | if (model.isEmpty()) 114 | { 115 | throw new NotFoundException("Query result Dataset is empty"); 116 | } 117 | 118 | return getResponse(model); 119 | } 120 | 121 | @Override 122 | public List getLanguages() 123 | { 124 | return Arrays.asList(Locale.ENGLISH); 125 | } 126 | 127 | @Override 128 | // 129 | public ResponseBuilder getResponseBuilder(Model model) 130 | { 131 | return new com.atomgraph.core.model.impl.Response(getRequest(), 132 | model, 133 | getLastModified(model), 134 | getEntityTag(model), 135 | getWritableMediaTypes(Model.class), 136 | getLanguages(), 137 | getEncodings(), 138 | new RDFXMLMediaTypePredicate()). 139 | getResponseBuilder(); 140 | } 141 | 142 | } 143 | 144 | protected Dataset getDataset() 145 | { 146 | return dataset; 147 | } 148 | 149 | @Override 150 | protected Application configure() 151 | { 152 | system = new com.atomgraph.core.Application(getDataset(), 153 | null, null, null, null, null, 154 | new MediaTypes(), com.atomgraph.core.Application.getClient(new ClientConfig()), 155 | null, false, false); 156 | system.init(); 157 | system.register(TestResource.class); 158 | system.register(LangSpecificTestResource.class); 159 | 160 | return system; 161 | } 162 | @Test 163 | public void testLocales() 164 | { 165 | Locale locale = Locale.ENGLISH; 166 | 167 | jakarta.ws.rs.core.Response resp = ldc.getClient(). 168 | target(uri). 169 | request(com.atomgraph.core.MediaType.APPLICATION_RDF_XML_TYPE). 170 | get(); 171 | assertEquals(200, resp.getStatus()); 172 | assertEquals(null, resp.getLanguage()); 173 | 174 | jakarta.ws.rs.core.Response langSpecificResp = ldc.getClient(). 175 | target(uriLang). 176 | request(com.atomgraph.core.MediaType.APPLICATION_RDF_XML_TYPE). // RDF/XML media type marked as language significant on this endpoint! 177 | header(HttpHeaders.ACCEPT_LANGUAGE, locale.getLanguage()). 178 | get(); 179 | 180 | assertEquals(200, langSpecificResp.getStatus()); 181 | assertEquals(locale, langSpecificResp.getLanguage()); 182 | 183 | assertNotEquals(langSpecificResp.getEntityTag(), resp.getEntityTag()); 184 | } 185 | 186 | // make Accept-Language/Content-Language significant for RDF/XML (just as a test) 187 | public static class RDFXMLMediaTypePredicate implements Predicate 188 | { 189 | 190 | @Override 191 | public boolean test(MediaType mediaType) 192 | { 193 | if (mediaType == null) 194 | { 195 | return false; 196 | } 197 | 198 | return mediaType.isCompatible(com.atomgraph.core.MediaType.APPLICATION_RDF_XML_TYPE); 199 | } 200 | 201 | } 202 | protected URI getURI() 203 | { 204 | return uri; 205 | } 206 | 207 | protected LinkedDataClient getLinkedDataClient() 208 | { 209 | return ldc; 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /src/test/java/com/atomgraph/core/model/impl/QueriedResourceBaseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Martynas Jusevičius . 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.atomgraph.core.model.impl; 17 | 18 | import com.atomgraph.core.MediaTypes; 19 | import com.atomgraph.core.client.LinkedDataClient; 20 | import com.atomgraph.core.model.Service; 21 | import java.net.URI; 22 | import jakarta.inject.Inject; 23 | import jakarta.ws.rs.Path; 24 | import jakarta.ws.rs.core.Application; 25 | import jakarta.ws.rs.core.Context; 26 | import jakarta.ws.rs.core.EntityTag; 27 | import jakarta.ws.rs.core.MediaType; 28 | import jakarta.ws.rs.core.Request; 29 | import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; 30 | import static jakarta.ws.rs.core.Response.Status.NOT_ACCEPTABLE; 31 | import static jakarta.ws.rs.core.Response.Status.NOT_FOUND; 32 | import static jakarta.ws.rs.core.Response.Status.UNSUPPORTED_MEDIA_TYPE; 33 | import jakarta.ws.rs.core.UriInfo; 34 | import java.util.Arrays; 35 | import org.apache.jena.query.Dataset; 36 | import org.apache.jena.query.DatasetFactory; 37 | import org.apache.jena.query.ResultSet; 38 | import org.apache.jena.rdf.model.Model; 39 | import org.apache.jena.rdf.model.ModelFactory; 40 | import org.apache.jena.rdf.model.ResourceFactory; 41 | import org.apache.jena.sparql.vocabulary.FOAF; 42 | import org.glassfish.jersey.client.ClientConfig; 43 | import org.glassfish.jersey.test.JerseyTest; 44 | import static org.junit.Assert.assertEquals; 45 | import static org.junit.Assert.assertNotEquals; 46 | import static org.junit.Assert.fail; 47 | import org.junit.Before; 48 | import org.junit.BeforeClass; 49 | import org.junit.Test; 50 | 51 | /** 52 | * 53 | * @author Martynas Jusevičius {@literal } 54 | */ 55 | public class QueriedResourceBaseTest extends JerseyTest 56 | { 57 | 58 | public static final String RELATIVE_PATH = "test"; 59 | public static final String RESOURCE_URI = "http://localhost:9998/" + RELATIVE_PATH; // assume that base URI is http://localhost:9998/ - has to match getBaseUri() 60 | public static Dataset dataset; 61 | 62 | public com.atomgraph.core.Application system; 63 | public LinkedDataClient ldc; 64 | public URI uri; 65 | 66 | @BeforeClass 67 | public static void initClass() 68 | { 69 | dataset = DatasetFactory.createTxnMem(); 70 | dataset.setDefaultModel(ModelFactory.createDefaultModel().add(ResourceFactory.createResource(RESOURCE_URI), FOAF.name, "Smth")); 71 | } 72 | 73 | @Before 74 | public void init() 75 | { 76 | uri = getBaseUri().resolve(RELATIVE_PATH); 77 | ldc = LinkedDataClient.create(system.getClient(), new MediaTypes()); 78 | } 79 | 80 | @Path(RELATIVE_PATH) 81 | public static class TestResource extends QueriedResourceBase 82 | { 83 | 84 | @Inject 85 | public TestResource(@Context UriInfo uriInfo, @Context Request request, MediaTypes mediaTypes, Service service) 86 | { 87 | super(uriInfo, request, mediaTypes, service); 88 | } 89 | 90 | } 91 | 92 | protected Dataset getDataset() 93 | { 94 | return dataset; 95 | } 96 | 97 | @Override 98 | protected Application configure() 99 | { 100 | system = new com.atomgraph.core.Application(getDataset(), 101 | null, null, null, null, null, 102 | new MediaTypes(), com.atomgraph.core.Application.getClient(new ClientConfig()), 103 | null, false, false); 104 | system.init(); 105 | system.register(TestResource.class); 106 | 107 | return system; 108 | } 109 | 110 | @Test 111 | public void testGet() 112 | { 113 | assertIsomorphic(getDataset().getDefaultModel(), ldc.getModel(uri.toString())); 114 | } 115 | 116 | @Test 117 | public void testNotAcceptableGetType() 118 | { 119 | assertEquals(NOT_ACCEPTABLE.getStatusCode(), ldc.get(uri, ldc.getReadableMediaTypes(ResultSet.class)).getStatus()); 120 | } 121 | 122 | @Test 123 | public void testNotFound() 124 | { 125 | URI nonExisting = getBaseUri().resolve("non-existing"); 126 | assertEquals(NOT_FOUND.getStatusCode(), ldc.get(nonExisting, ldc.getReadableMediaTypes(Model.class)).getStatus()); 127 | } 128 | 129 | @Test 130 | public void testNotUnsupportedPostType() 131 | { 132 | assertEquals(UNSUPPORTED_MEDIA_TYPE.getStatusCode(), ldc.post(uri, ldc.getReadableMediaTypes(Model.class), "BAD RDF", MediaType.TEXT_XML_TYPE).getStatus()); 133 | } 134 | 135 | @Test 136 | public void testInvalidTurtlePost() 137 | { 138 | assertEquals(BAD_REQUEST.getStatusCode(), ldc.post(uri, ldc.getReadableMediaTypes(Model.class), "BAD TURTLE", com.atomgraph.core.MediaType.TEXT_TURTLE_TYPE).getStatus()); 139 | } 140 | 141 | @Test 142 | public void testInvalidTurtlePut() 143 | { 144 | assertEquals(BAD_REQUEST.getStatusCode(), ldc.put(uri, ldc.getReadableMediaTypes(Model.class), "BAD TURTLE", com.atomgraph.core.MediaType.TEXT_TURTLE_TYPE).getStatus()); 145 | } 146 | 147 | public static void assertIsomorphic(Model wanted, Model got) 148 | { 149 | if (!wanted.isIsomorphicWith(got)) 150 | fail("Models not isomorphic (not structurally equal))"); 151 | } 152 | 153 | @Test 154 | public void testDifferentMediaTypesDifferentETags() 155 | { 156 | jakarta.ws.rs.core.Response nTriplesResp = ldc.get(uri, Arrays.asList(com.atomgraph.core.MediaType.APPLICATION_NTRIPLES_TYPE).toArray(com.atomgraph.core.MediaType[]::new)); 157 | EntityTag nTriplesETag = nTriplesResp.getEntityTag(); 158 | assertEquals(nTriplesResp.getLanguage(), null); 159 | 160 | jakarta.ws.rs.core.Response rdfXmlResp = ldc.get(uri, Arrays.asList(com.atomgraph.core.MediaType.APPLICATION_RDF_XML_TYPE).toArray(com.atomgraph.core.MediaType[]::new)); 161 | EntityTag rdfXmlETag = rdfXmlResp.getEntityTag(); 162 | assertEquals(rdfXmlResp.getLanguage(), null); 163 | 164 | assertNotEquals(nTriplesETag, rdfXmlETag); 165 | } 166 | 167 | } 168 | --------------------------------------------------------------------------------