From 396c174c49d2d2db10d69d13bea4ba7f0728bfda Mon Sep 17 00:00:00 2001 From: Karolina Kadzielawa Date: Mon, 10 Jun 2024 01:13:44 +0000 Subject: [PATCH 1/2] GH-2538: prefixes-service incorporated into Jena --- jena-fuseki2/examples/config-prefixes.ttl | 22 + jena-fuseki2/jena-fuseki-core/pom.xml | 6 + .../jena/fuseki/server/FusekiVocab.java | 3 + .../apache/jena/fuseki/server/Operation.java | 5 + .../jena/fuseki/servlets/ActionPrefixesR.java | 175 ++++++ .../fuseki/servlets/ActionPrefixesRW.java | 126 ++++ .../jena/fuseki/servlets/PrefixesService.java | 52 ++ .../jena/fuseki/servlets/ServletOps.java | 2 - .../servlets/prefixes/ActionPrefixesBase.java | 47 ++ .../servlets/prefixes/ActionProcPrefixes.java | 228 ++++++++ .../fuseki/servlets/prefixes/JsonObject.java | 21 + .../fuseki/servlets/prefixes/PrefixUtils.java | 48 ++ .../servlets/prefixes/PrefixesAccess.java | 42 ++ .../fuseki/servlets/prefixes/PrefixesMap.java | 74 +++ .../servlets/prefixes/PrefixesPlain.java | 76 +++ .../fuseki/servlets/prefixes/PrefixesRDF.java | 227 ++++++++ .../fuseki/servlets/prefixes/RegexTests.java | 44 ++ .../fuseki/servlets/prefixes/UtilsTests.java | 90 +++ jena-fuseki2/jena-fuseki-main/pom.xml | 12 + .../jena/fuseki/main/TS_FusekiMain.java | 16 +- .../main/files/config-prefixes-test.ttl | 24 + .../jena/fuseki/main/files/data-test.trig | 1 + .../fuseki/main/prefixes/JsonObjectTests.java | 88 +++ .../prefixes/TestAbstractPrefixParam.java | 527 +++++++++++++++++ .../main/prefixes/TestPrefixesService.java | 537 ++++++++++++++++++ .../prefixes/TestPrefixesServicePlain.java | 28 + .../TestPrefixesServicePrefixesMap.java | 35 ++ .../main/prefixes/TestPrefixesServiceRDF.java | 27 + 28 files changed, 2575 insertions(+), 8 deletions(-) create mode 100644 jena-fuseki2/examples/config-prefixes.ttl mode change 100644 => 100755 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesR.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesRW.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/PrefixesService.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionPrefixesBase.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionProcPrefixes.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/JsonObject.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixUtils.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesAccess.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesMap.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesPlain.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesRDF.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/servlets/prefixes/RegexTests.java create mode 100644 jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/servlets/prefixes/UtilsTests.java create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/data-test.trig create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/JsonObjectTests.java create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestAbstractPrefixParam.java create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesService.java create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePlain.java create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePrefixesMap.java create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServiceRDF.java diff --git a/jena-fuseki2/examples/config-prefixes.ttl b/jena-fuseki2/examples/config-prefixes.ttl new file mode 100644 index 00000000000..217eed7696c --- /dev/null +++ b/jena-fuseki2/examples/config-prefixes.ttl @@ -0,0 +1,22 @@ +## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 + +PREFIX : <#> +PREFIX fuseki: +PREFIX rdf: +PREFIX ja: +PREFIX tdb2: + + +:service rdf:type fuseki:Service ; + fuseki:name "dataset" ; + fuseki:endpoint [ fuseki:operation fuseki:query ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:update ; ] ; + + fuseki:endpoint [ fuseki:operation fuseki:prefixes-r ; fuseki:name "prefixes" ] ; + fuseki:endpoint [ fuseki:operation fuseki:prefixes-ws ; fuseki:name "updatePrefixes" ] ; + fuseki:dataset :dataset ; + . + +:dataset rdf:type ja:MemoryDataset ; + ja:data "example-data.trig"; + . diff --git a/jena-fuseki2/jena-fuseki-core/pom.xml b/jena-fuseki2/jena-fuseki-core/pom.xml index 9f844f15e3b..bb7d5fe8c6a 100644 --- a/jena-fuseki2/jena-fuseki-core/pom.xml +++ b/jena-fuseki2/jena-fuseki-core/pom.xml @@ -103,6 +103,12 @@ test + + org.junit.jupiter + junit-jupiter + test + + io.micrometer diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java old mode 100644 new mode 100755 index a0feefaf328..47d67fb509e --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java @@ -89,6 +89,9 @@ public class FusekiVocab public static final Resource opShacl = resource("shacl"); public static final Resource opPatch = resource("patch"); + public static final Resource opPREFIXES_R = resource("prefixes-r"); + public static final Resource opPREFIXES_RW = resource("prefixes-ws"); + // Internal private static final String stateNameActive = DataServiceStatus.ACTIVE.name; private static final String stateNameOffline = DataServiceStatus.OFFLINE.name; diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java index 5b1ef7536fb..2664f111db3 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java @@ -87,6 +87,11 @@ static private Operation create(Node id, String shortName, String description) { public static final Operation Patch = alloc(FusekiVocab.opPatch.asNode(), "patch", "RDF Patch"); public static final Operation NoOp = alloc(FusekiVocab.opNoOp.asNode(), "no-op", "No Op"); + + public static final Operation PREFIXES_R = alloc(FusekiVocab.opPREFIXES_R.asNode(), "prefixes-r", "Read prefixes"); + public static final Operation PREFIXES_RW = alloc(FusekiVocab.opPREFIXES_RW.asNode(), "prefixes-ws", "Read-write prefixes"); + + static { // Not everyone will remember "_" vs "-" so ... altName(FusekiVocab.opNoOp_alt, FusekiVocab.opNoOp); diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesR.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesR.java new file mode 100644 index 00000000000..04dce5a40fb --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesR.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets; + +import com.google.gson.JsonArray; +import org.apache.jena.atlas.logging.FmtLog; +import org.apache.jena.riot.WebContent; +import org.apache.jena.riot.web.HttpNames; + +import org.apache.jena.fuseki.servlets.prefixes.ActionPrefixesBase; +import org.apache.jena.fuseki.servlets.prefixes.PrefixUtils; +import org.apache.jena.fuseki.servlets.prefixes.JsonObject; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ActionPrefixesR extends ActionPrefixesBase { + + private static final String NO_PREFIX_NS = ""; + + public ActionPrefixesR() {} + + @Override + protected void doOptions(HttpAction action) { + ActionLib.setCommonHeadersForOptions(action); + action.setResponseHeader(HttpNames.hAllow, "GET,OPTIONS"); + ServletOps.success(action); + } + + public void validateGet(HttpAction action) { + validate(action); + // check if the combination of parameters is legal + String prefix = action.getRequestParameter(PrefixUtils.PREFIX); + String uri = action.getRequestParameter(PrefixUtils.URI); + if(prefix != null && uri != null) { + ServletOps.errorBadRequest("Provide only one of the prefix or uri parameters!"); + return; + } + } + + enum ResponseTypes { + GET_ALL, + FETCH_URI, + FETCH_PREFIX, + BAD_REQUEST + } + + protected ResponseTypes chooseResponseType (String prefix, String uri) { + if (prefix == null && uri == null) + return ResponseTypes.GET_ALL; + else if (prefix != null && uri == null) { + if (prefix.isEmpty()) { + ServletOps.errorBadRequest("Empty prefix!"); + return ResponseTypes.BAD_REQUEST; + } + else if (!PrefixUtils.prefixIsValid(prefix)) { + ServletOps.errorBadRequest("Prefix contains illegal characters!"); + return ResponseTypes.BAD_REQUEST; + } + else + return ResponseTypes.FETCH_URI; + } + else if (prefix == null && uri != null) { + if (uri.isEmpty()) { + ServletOps.errorBadRequest("Empty URI!"); + return ResponseTypes.BAD_REQUEST; + } + else if (!PrefixUtils.uriIsValid(uri)) { + ServletOps.errorBadRequest("URI contains illegal characters!"); + return ResponseTypes.BAD_REQUEST; + } + else + return ResponseTypes.FETCH_PREFIX; + } + return ResponseTypes.BAD_REQUEST; + } + + @Override + protected void doGet(HttpAction action) { + ActionLib.setCommonHeaders(action); + validateGet(action); + + action.beginRead(); + try { + // Not null (valid request) + String prefix = action.getRequestParameter(PrefixUtils.PREFIX); + String uri = action.getRequestParameter(PrefixUtils.URI); + + switch(chooseResponseType(prefix, uri)) { + case GET_ALL -> { + Map allPairs = prefixes(action).getAll(); + JsonArray allJsonPairs = new JsonArray(); + allPairs.entrySet().stream() + .forEach(entry -> { + com.google.gson.JsonObject jsonObject = new com.google.gson.JsonObject(); + jsonObject.addProperty(PrefixUtils.PREFIX, entry.getKey()); + jsonObject.addProperty(PrefixUtils.URI, entry.getValue()); + allJsonPairs.add(jsonObject); + FmtLog.info(action.log, "[%d] - %s", action.id, new JsonObject(entry.getKey(), entry.getValue())); + }); + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(String.valueOf(allJsonPairs)); + + ServletOps.success(action); + action.endRead(); + return; + } + case FETCH_URI -> { + Optional x = prefixes(action).fetchURI(prefix); + String namespace = x.orElse(NO_PREFIX_NS); + + JsonObject jsonObject = new JsonObject(prefix, namespace); + + // Build the response. + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(namespace); + // Indicate success + FmtLog.info(action.log, "[%d] %s -> %s", action.id, prefix, jsonObject.toString()); + action.commit(); + ServletOps.success(action); + return; + } + case FETCH_PREFIX -> { + List prefixList =prefixes(action).fetchPrefix(uri); + JsonArray prefixJsonArray = new JsonArray(); + for (String p : prefixList) { + com.google.gson.JsonObject jsonObject2 = new com.google.gson.JsonObject(); + jsonObject2.addProperty(PrefixUtils.PREFIX, p); + jsonObject2.addProperty(PrefixUtils.URI, uri); + prefixJsonArray.add(jsonObject2); + FmtLog.info(action.log, "[%d] - %s", action.id, new JsonObject(p, uri)); + } + // Build the response. + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(String.valueOf(prefixJsonArray)); + // Indicate success + action.commit(); + ServletOps.success(action); + action.endRead(); + return; + } + default -> { + ServletOps.errorBadRequest("Bad request"); + return; + } + } + } catch (RuntimeException | IOException ex) { + try { action.abort(); } + catch (Throwable th ) { + FmtLog.warn(action.log, th, "[%d] GET prefix = %s", action.id); + } + ServletOps.errorOccurred(ex); + } finally { + action.endRead(); + } + } +} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesRW.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesRW.java new file mode 100644 index 00000000000..3628e4221d1 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesRW.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets; + +import org.apache.jena.atlas.logging.FmtLog; +import org.apache.jena.riot.WebContent; +import org.apache.jena.riot.web.HttpNames; + +import org.apache.jena.fuseki.servlets.prefixes.PrefixUtils; + +import java.io.IOException; + +public class ActionPrefixesRW extends ActionPrefixesR { + + public ActionPrefixesRW() {} + + @Override + protected void doOptions(HttpAction action) { + ActionLib.setCommonHeadersForOptions(action); + action.setResponseHeader(HttpNames.hAllow, "GET,OPTIONS,POST,DELETE"); + ServletOps.success(action); + } + + public void validateDelete(HttpAction action) { + validate(action); + String prefixToRemove = action.getRequestParameter(PrefixUtils.PREFIX); + if (prefixToRemove == null || prefixToRemove.isEmpty() || !PrefixUtils.prefixIsValid(prefixToRemove)) { + ServletOps.errorBadRequest("Remove operation unsuccessful!"); + return; + } + } + + @Override + protected void doDelete(HttpAction action) { + validateDelete(action); + action.beginWrite(); + + try { + String prefixToRemove = action.getRequestParameter(PrefixUtils.PREFIX); + prefixes(action).removePrefix(prefixToRemove); + FmtLog.info(action.log, "[%d] Remove %s:", action.id, prefixToRemove); + + action.commit(); + + // Indicate success + ServletOps.success(action); + + // Build the response. + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(""); + + } catch (RuntimeException | IOException ex) { + try { action.abort(); } + catch (Throwable th ) { + FmtLog.warn(action.log, th, "[%d] POST prefix = %s", action.id); + } + ServletOps.errorOccurred(ex); + } finally { + action.end(); + } + } + + + public void validatePost(HttpAction action) { + validate(action); + String prefix = action.getRequestParameter(PrefixUtils.PREFIX); + String uri = action.getRequestParameter(PrefixUtils.URI); + + if (prefix.isEmpty() || uri.isEmpty()) { + ServletOps.errorBadRequest("Empty operation - unsuccessful!"); + return; + } + else if (!PrefixUtils.prefixIsValid(prefix) || !PrefixUtils.uriIsValid(uri)) { + ServletOps.errorBadRequest("Empty operation - unsuccessful!"); + return; + } + } + + @Override + protected void doPost(HttpAction action) { + validatePost(action); + action.beginWrite(); + + try { + String prefix = action.getRequestParameter(PrefixUtils.PREFIX); + String uri = action.getRequestParameter(PrefixUtils.URI); + + prefixes(action).updatePrefix(prefix, uri); + FmtLog.info(action.log, "[%d] Set %s: <%s>", action.id, prefix, uri); + + action.commit(); + + // Indicate success + ServletOps.success(action); + + // Build the response. + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(""); + + } catch (RuntimeException | IOException ex) { + try { action.abort(); } + catch (Throwable th ) { + FmtLog.warn(action.log, th, "[%d] POST prefix = %s", action.id); + } + ServletOps.errorOccurred(ex); + } finally { + action.end(); + } + } +} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/PrefixesService.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/PrefixesService.java new file mode 100644 index 00000000000..16d61f2f2a3 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/PrefixesService.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets; + +import org.apache.jena.fuseki.server.Operation; +import org.apache.jena.fuseki.server.OperationRegistry; + +/** The PrefixesService class registers the PrefixesR and PrefixesRW operations + * and actions for the Prefixes Service. The service allows for prefix management + * on a given dataset provided in the config.ttl file. When making requests + * to the API the url can have 3 parameters: prefix, uri, and prefixToRemove, + * the combination of which defines the operation performed. The read operations + * are fetching the prefix by URI, fetching the URI by prefix, and fetching all. + * They are evoked via HTTP GET. The read-write operations are removing and updating + * prefix-URI pairs. Those are POST requests. */ + +public class PrefixesService { + public static final Operation operationPrefixesRW; + public static final Operation operationPrefixesR; + + private static final ActionService procPrefixR; + private static final ActionService procPrefixRW; + + static { + operationPrefixesR = Operation.PREFIXES_R; + operationPrefixesRW = Operation.PREFIXES_RW; + + procPrefixR = new ActionPrefixesR(); + procPrefixRW = new ActionPrefixesRW(); + + OperationRegistry.get().register(operationPrefixesR, procPrefixR); + OperationRegistry.get().register(operationPrefixesRW, procPrefixRW); + } + + public static void init() {} +} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java index 92612ffe388..f8f05b5bf15 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java @@ -268,8 +268,6 @@ public static void errorOccurred(Throwable ex) { } public static void errorOccurred(String message, Throwable ex) { - if ( message == null ) - System.err.println(); if ( ex instanceof ActionErrorException actionErr ) throw actionErr; throw new ActionErrorException(HttpSC.INTERNAL_SERVER_ERROR_500, message, ex); diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionPrefixesBase.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionPrefixesBase.java new file mode 100644 index 00000000000..67051bb46e0 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionPrefixesBase.java @@ -0,0 +1,47 @@ +/* + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + +import org.apache.jena.fuseki.servlets.BaseActionREST; +import org.apache.jena.fuseki.servlets.HttpAction; +import org.apache.jena.fuseki.servlets.ServletOps; +import org.apache.jena.sparql.core.DatasetGraph; + +import java.util.Iterator; + +public class ActionPrefixesBase extends BaseActionREST { + + /** Create a {@link PrefixesAccess} for this {@link HttpAction}. */ + protected static PrefixesAccess prefixes(HttpAction action) { + DatasetGraph dsg = action.getDataset(); + PrefixesMap pMap = new PrefixesMap(dsg.prefixes(), dsg); + return pMap; + } + + @Override + public void validate(HttpAction action) { + Iterator paramNames = action.getRequestParameterNames().asIterator(); + while(paramNames.hasNext()) { + String check = paramNames.next(); + if(!check.equals(PrefixUtils.PREFIX) && !check.equals(PrefixUtils.URI) && !check.equals(PrefixUtils.REMOVEPREFIX)) { + ServletOps.errorBadRequest("Unrecognized parameter"); + return; + } + } + } +} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionProcPrefixes.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionProcPrefixes.java new file mode 100644 index 00000000000..a82e698c18d --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionProcPrefixes.java @@ -0,0 +1,228 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + +import com.google.gson.JsonArray; +import org.apache.jena.atlas.logging.FmtLog; +import org.apache.jena.fuseki.servlets.*; +import org.apache.jena.query.TxnType; +import org.apache.jena.riot.WebContent; +import org.apache.jena.sparql.core.Transactional; + +import java.io.IOException; +import java.util.*; + + +//validate and unpack the HTTP Get request, +//call the storage's fetch URI by the prefix function from the HTTP request + +public class ActionProcPrefixes extends BaseActionREST { + + private final PrefixesAccess storage; + + // The response to a prefix lookup when there is no such prefix. + // This value is not a proper namespace because it is not an absolute URI. + private static final String NO_PREFIX_NS = ""; + + public ActionProcPrefixes(PrefixesAccess storage) { + this.storage = storage; + } + + public void validateGet (HttpAction action) { + + // sanitize parameters + Iterator paramNames = action.getRequestParameterNames().asIterator(); + while(paramNames.hasNext()) { + String check = paramNames.next(); + if(!check.equals("prefix") && !check.equals("uri") && !check.equals("removeprefix")) { + ServletOps.errorBadRequest("Unrecognized parameter"); + return; + } + } + // check if the combination of parameters is legal + String prefix = action.getRequestParameter("prefix"); + String uri = action.getRequestParameter("uri"); + if(prefix != null && uri != null) { + ServletOps.errorBadRequest("Provide only one of the prefix or uri parameters!"); + return; + } + } + + public void validatePost (HttpAction action) { + String prefix = action.getRequestParameter("prefix"); + String uri = action.getRequestParameter("uri"); + String prefixToRemove = action.getRequestParameter("removeprefix"); + + if (prefix.isEmpty() && uri.isEmpty() && prefixToRemove.isEmpty()) { + ServletOps.errorBadRequest("Empty operation - unsuccessful!"); + return; + } + if (prefixToRemove.isEmpty()) { + if (prefix.isEmpty() || uri.isEmpty() || !PrefixUtils.prefixIsValid(prefix) || !PrefixUtils.uriIsValid(uri)) { + ServletOps.errorBadRequest("Update operation unsuccessful!"); + return; + } + } + if (prefix.isEmpty() && uri.isEmpty()) { + if (!PrefixUtils.prefixIsValid(prefixToRemove)) { + ServletOps.errorBadRequest("Remove operation unsuccessful!"); + return; + } + } + } + + @Override + public void doGet (HttpAction action) { + + validateGet(action); + + Transactional transactional = storage.transactional(); + transactional.begin(TxnType.READ); + + try { + // Not null (valid request) + String prefix = action.getRequestParameter("prefix"); + String uri = action.getRequestParameter("uri"); + + if (prefix == null && uri == null) { + //getAll + Map allPairs = storage.getAll(); + JsonArray allJsonPairs = new JsonArray(); + allPairs.entrySet().stream() + .forEach(entry -> { + com.google.gson.JsonObject jsonObject = new com.google.gson.JsonObject(); + jsonObject.addProperty("prefix", entry.getKey()); + jsonObject.addProperty("uri", entry.getValue()); + allJsonPairs.add(jsonObject); + FmtLog.info(action.log, "[%d] - %s", action.id, new JsonObject(entry.getKey(), entry.getValue())); + }); + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(String.valueOf(allJsonPairs)); + + transactional.commit(); + ServletOps.success(action); + transactional.end(); + return; + } + if (prefix != null && uri == null) { + + if (prefix.isEmpty()) { + ServletOps.errorBadRequest("Empty prefix!"); + return; + } + else if (!PrefixUtils.prefixIsValid(prefix)) { + ServletOps.errorBadRequest("Prefix contains illegal characters!"); + return; + } + else { + //fetchURI + Optional x = storage.fetchURI(prefix); + String namespace = x.orElse(NO_PREFIX_NS); + + JsonObject jsonObject = new JsonObject(prefix, namespace); + + // Build the response. + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(namespace); + // Indicate success + FmtLog.info(action.log, "[%d] %s -> %s", action.id, prefix, jsonObject.toString()); + transactional.commit(); + ServletOps.success(action); + return; + } + } + if (prefix == null && uri != null) { + if (uri.isEmpty()) { + ServletOps.errorBadRequest("Empty URI!"); + return; + } + else if (!PrefixUtils.uriIsValid(uri)) { + ServletOps.errorBadRequest("URI contains illegal characters!"); + return; + } + else { + //fetchPrefix + List prefixList =storage.fetchPrefix(uri); + JsonArray prefixJsonArray = new JsonArray(); + for (String p : prefixList) { + com.google.gson.JsonObject jsonObject2 = new com.google.gson.JsonObject(); + jsonObject2.addProperty("prefix", p); + jsonObject2.addProperty("uri", uri); + prefixJsonArray.add(jsonObject2); + FmtLog.info(action.log, "[%d] - %s", action.id, new JsonObject(p, uri)); + } + // Build the response. + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(String.valueOf(prefixJsonArray)); + // Indicate success + transactional.commit(); + ServletOps.success(action); + transactional.end(); + return; + } + } + + } catch (RuntimeException | IOException ex) { + try { transactional.abort(); } + catch (Throwable th ) { + FmtLog.warn(action.log, th, "[%d] GET prefix = %s", action.id); + } + ServletOps.errorOccurred(ex); + } finally { + transactional.end(); + } + } + + @Override + public void doPost (HttpAction action) { + validatePost(action); + Transactional transactional = storage.transactional(); + + transactional.begin(TxnType.WRITE); + try { + String prefix = action.getRequestParameter("prefix"); + String uri = action.getRequestParameter("uri"); + + if(prefix.isEmpty()) { + String prefixToRemove = action.getRequestParameter("removeprefix"); + storage.removePrefix(prefixToRemove); + FmtLog.info(action.log, "[%d] Remove %s:", action.id, prefix); + } + else { + storage.updatePrefix(prefix, uri); + FmtLog.info(action.log, "[%d] Set %s: <%s>", action.id, prefix, uri); + } + transactional.commit(); + + // Build the response. + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(""); + // Indicate success + ServletOps.success(action); + } catch (RuntimeException | IOException ex) { + try { transactional.abort(); } + catch (Throwable th ) { + FmtLog.warn(action.log, th, "[%d] POST prefix = %s", action.id); + } + ServletOps.errorOccurred(ex); + } finally { + transactional.end(); + } + } +} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/JsonObject.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/JsonObject.java new file mode 100644 index 00000000000..6b530e89638 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/JsonObject.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + +public record JsonObject(String prefix, String namespace) {} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixUtils.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixUtils.java new file mode 100644 index 00000000000..efea16f4dcf --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixUtils.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + +import org.apache.jena.irix.IRIx; + +import java.util.regex.Pattern; + +public class PrefixUtils { + public static final String PREFIX = "prefix" ; + public static final String URI = "uri" ; + public static final String REMOVEPREFIX = "removeprefix" ; + + private PrefixUtils() {} + private static final Pattern regex = Pattern.compile("\\p{Alpha}([\\w.-]*\\w)?"); + + public static boolean prefixIsValid(String prefix) { + return regex.matcher(prefix).matches(); + } + + public static boolean uriIsValid(String uri) { + boolean valid; + try { + IRIx iri = IRIx.create(uri); + valid = iri.isReference(); + } + catch (Exception ex) { + valid = false; + } + return valid; + } +} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesAccess.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesAccess.java new file mode 100644 index 00000000000..42c31d15630 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesAccess.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + + +import org.apache.jena.sparql.core.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +//interface for interacting with the storages +public interface PrefixesAccess { + + Optional fetchURI(String prefix); + + Transactional transactional(); + + void updatePrefix(String prefix, String uri); + void removePrefix(String prefixToRemove); + + Map getAll(); + + /** Fetches the prefixes assigned to the provided URI. There can be multiple in the List.**/ + List fetchPrefix(String uri); +} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesMap.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesMap.java new file mode 100644 index 00000000000..12f10467d03 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesMap.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.jena.riot.system.PrefixMap; +import org.apache.jena.sparql.core.Transactional; + +public class PrefixesMap implements PrefixesAccess { + private final PrefixMap prefixMap; + private final Transactional transactional; + + public PrefixesMap(PrefixMap prefixMap, Transactional transactional) { + this.transactional = transactional; + this.prefixMap = prefixMap; + } + + @Override + public Transactional transactional() { + return transactional; + } + + @Override + public Optional fetchURI(String prefix) { + return Optional.ofNullable(prefixMap.get(prefix)); + } + + @Override + public void updatePrefix(String prefix, String uri) { + prefixMap.delete(prefix); + prefixMap.add(prefix, uri); + } + + @Override + public void removePrefix(String prefixToRemove) { + prefixMap.delete(prefixToRemove); + } + + @Override + public Map getAll() { + return prefixMap.getMapping(); + } + + @Override + public List fetchPrefix(String uri) { + List prefixList = new ArrayList<>(); + for (String prefix : prefixMap.getMapping().keySet()) { + if (prefixMap.getMapping().get(prefix).equals(uri)) { + prefixList.add(prefix); + } + } + return prefixList; + } +} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesPlain.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesPlain.java new file mode 100644 index 00000000000..fe260ffe66a --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesPlain.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.jena.sparql.core.Transactional; +import org.apache.jena.sparql.core.TransactionalLock; + + +public class PrefixesPlain implements PrefixesAccess { + private final TransactionalLock transactional; + private Map pairs = new ConcurrentHashMap<>(); + public Map getPairs() { + return pairs; + } + + public PrefixesPlain() { + this.transactional = TransactionalLock.createMRSW(); + } + + @Override + public Transactional transactional() { return transactional; } + + @Override + public Optional fetchURI(String prefix) { + Objects.requireNonNull(prefix); + return Optional.ofNullable(this.pairs.get(prefix)); + } + + @Override + public void updatePrefix(String prefix, String uri) { + this.pairs.put(prefix, uri); + } + + @Override + public void removePrefix(String prefixToRemove) { + this.pairs.remove(prefixToRemove); + } + + @Override + public Map getAll() { + return this.pairs; + } + + @Override + public List fetchPrefix(String uri) { + Objects.requireNonNull(uri); + List prefixList = new ArrayList<>(); + for (String prefix : pairs.keySet()) { + if (pairs.get(prefix).equals(uri)) + prefixList.add(prefix); + } + return prefixList; + } + + +} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesRDF.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesRDF.java new file mode 100644 index 00000000000..d48b791ccb5 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesRDF.java @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.jena.datatypes.xsd.XSDDatatype; +import org.apache.jena.query.ParameterizedSparqlString; +import org.apache.jena.sparql.core.DatasetGraph; +import org.apache.jena.sparql.core.Transactional; +import org.apache.jena.sparql.exec.QueryExec; +import org.apache.jena.sparql.exec.RowSet; +import org.apache.jena.sparql.exec.UpdateExec; +import org.apache.jena.tdb2.DatabaseMgr; + +/** + * The prefix-URI mappings are represented in blank nodes of type Prefix, with prefixName and prefixURI attributes. + * The prefixName and prefixURI of the same node are a distinct prefix-URI mapping. + * + * PREFIX prefixes: + * PREFIX rdf: + * PREFIX xsd: + * + * [] rdf:type prefixes:Prefix ; + * prefixes:prefixName "test" ; + * prefixes:prefixURI "http://example/testPrefix#"^^xsd:anyURI + * . + * + * [ rdf:type prefixes:Prefix ; + * prefixes:prefixName "ns" ; + * prefixes:prefixURI "http://example/namespace#"^^xsd:anyURI + * ] + */ + +public class PrefixesRDF implements PrefixesAccess { + + DatasetGraph dataset = DatabaseMgr.createDatasetGraph(); + + @Override + public Transactional transactional() { return dataset; } + + @Override + public Optional fetchURI(String prefix) { + + ParameterizedSparqlString pss = new ParameterizedSparqlString( + """ + PREFIX prefixes: + SELECT ?prefixURI WHERE { + ?X prefixes:prefixName ?prefixName . + ?X prefixes:prefixURI ?prefixURI + } + """ + ); + pss.setLiteral("prefixName", prefix); + String query = pss.toString(); + + + try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { + + RowSet rowSet = qExec.select(); + List x = new ArrayList(); + + rowSet.forEachRemaining(row -> { + String prefixNameLiteral = row.get("prefixURI").getLiteralLexicalForm(); + if (prefixNameLiteral != null) { + x.add(prefixNameLiteral); + } + }); + if (x.isEmpty()) + return Optional.empty(); + //originally x.getFirst() + return Optional.ofNullable(x.get(0)); + } + } + + @Override + public void updatePrefix(String prefix, String uri) { + + ParameterizedSparqlString pss = new ParameterizedSparqlString( + """ + PREFIX prefixes: + PREFIX xsd: + ASK WHERE { ?X prefixes:prefixName ?prefixName ; + prefixes:prefixURI ?prefixURI . + } + """); + pss.setLiteral("prefixName", prefix); + String query = pss.toString(); + + try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { + + AtomicBoolean result = new AtomicBoolean(false); + dataset.executeRead(()->{ + result.set(qExec.ask()); + }); + + String update; + ParameterizedSparqlString pssUpdate; + if (result.get()) { + pssUpdate = new ParameterizedSparqlString( + """ + PREFIX prefixes: + PREFIX xsd: + DELETE { ?X prefixes:prefixURI ?oldURI } + INSERT { ?X prefixes:prefixURI ?newURI } + WHERE { + ?X prefixes:prefixName ?prefixName ; + prefixes:prefixURI ?oldURI + } + """); + pssUpdate.setLiteral("prefixName", prefix); + pssUpdate.setLiteral("newURI", uri, XSDDatatype.XSDanyURI); + update = pssUpdate.toString(); + } + else { + pssUpdate = new ParameterizedSparqlString( + """ + PREFIX prefixes: + PREFIX xsd: + PREFIX rdf: + INSERT DATA { + [] rdf:type prefixes:Prefix ; + prefixes:prefixName ?prefixName ; + prefixes:prefixURI ?newURI + } + """); + pssUpdate.setLiteral("prefixName", prefix); + pssUpdate.setLiteral("newURI", uri, XSDDatatype.XSDanyURI); + update = pssUpdate.toString(); + } + UpdateExec.dataset(dataset).update(update).execute(); + } + catch (RuntimeException e) { + throw new RuntimeException(e); + } + } + + @Override + public void removePrefix(String prefixToRemove) { + ParameterizedSparqlString pss = new ParameterizedSparqlString( + """ + PREFIX prefixes: + DELETE WHERE { ?X prefixes:prefixName ?prefixName } + """ + ); + pss.setLiteral("prefixName", prefixToRemove); + String update = pss.toString(); + UpdateExec.dataset(dataset).update(update).execute(); + } + + @Override + public Map getAll() { + String query = + """ + PREFIX prefixes: + SELECT ?prefixName ?prefixURI WHERE { + ?X prefixes:prefixName ?prefixName . + ?X prefixes:prefixURI ?prefixURI + } + """; + + try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { + + RowSet rowSet = qExec.select(); + Map allPairs = new ConcurrentHashMap<>(); + rowSet.forEachRemaining(row -> { + String prefixNameLiteral = row.get("prefixName").getLiteralLexicalForm(); + String prefixURILiteral = row.get("prefixURI").getLiteralLexicalForm(); + if (prefixNameLiteral != null && prefixURILiteral != null) { + allPairs.put(prefixNameLiteral, prefixURILiteral); + } + }); + return allPairs; + } + } + + @Override + public List fetchPrefix(String uri) { + ParameterizedSparqlString pss = new ParameterizedSparqlString( + """ + PREFIX prefixes: + PREFIX xsd: + SELECT ?prefixName WHERE { + ?X prefixes:prefixURI ?uriName . + ?X prefixes:prefixName ?prefixName + } + """); + pss.setLiteral("uriName", uri, XSDDatatype.XSDanyURI); + String query = pss.toString(); + + try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { + + RowSet rowSet = qExec.select(); + List prefixes = new ArrayList(); + + rowSet.forEachRemaining(row -> { + String prefixNameLiteral = row.get("prefixName").getLiteralLexicalForm(); + if (prefixNameLiteral != null) { + prefixes.add(prefixNameLiteral); + } + }); + + return prefixes; + } + } +} diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/servlets/prefixes/RegexTests.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/servlets/prefixes/RegexTests.java new file mode 100644 index 00000000000..3340e95c80a --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/servlets/prefixes/RegexTests.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class RegexTests { + String serviceName = "prefixes"; + public final Pattern regex = Pattern.compile("^/" + serviceName + "(?:/.*)?$"); + + @ParameterizedTest + @ValueSource(strings = {"abc", "pre_fix/abc", "abcde", "prefix"}) + public void patternMatchFalse(String name) { + assertFalse(regex.matcher(name).matches()); + } + + @ParameterizedTest + @ValueSource(strings = {"/prefixes", "/prefixes/abc", "/prefixes/"}) + public void patternMatchTrue(String name) { + assertTrue(regex.matcher(name).matches()); + } +} diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/servlets/prefixes/UtilsTests.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/servlets/prefixes/UtilsTests.java new file mode 100644 index 00000000000..f2810811afd --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/servlets/prefixes/UtilsTests.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.servlets.prefixes; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class UtilsTests { + @Test + public void prefixIsValidTrue0() { + assertTrue(PrefixUtils.prefixIsValid("prefix1")); + } + + @Test + public void prefixIsValidTrue1() { + assertTrue(PrefixUtils.prefixIsValid("pr.efix1")); + } + + @Test + public void prefixIsValidTrue2() { + assertTrue(PrefixUtils.prefixIsValid("pr-efix1")); + } + + @Test + public void prefixIsValidTrue3() { + assertTrue(PrefixUtils.prefixIsValid("p")); + } + + @Test + public void prefixIsValidTrue4() { + assertTrue(PrefixUtils.prefixIsValid("ca7--t")); + } + @Test + public void prefixIsValidTrue5() { + assertTrue(PrefixUtils.prefixIsValid("a__b")); + } + @Test + public void prefixIsValidFalse0() { + assertFalse(PrefixUtils.prefixIsValid("-prefix1")); + } + + @Test + public void prefixIsValidFalse1() { + assertFalse(PrefixUtils.prefixIsValid("prefix1-")); + } + + @Test + public void prefixIsValidFalse2() { + assertFalse(PrefixUtils.prefixIsValid("")); + } + + @Test + public void prefixIsValidFalse4() { + assertFalse(PrefixUtils.prefixIsValid("c-b--")); + } + + @Test + public void prefixIsValidFalse5() { + assertFalse(PrefixUtils.prefixIsValid("pre/fix")); + } + + @Test + public void uriIsValidTrue0() { + assertTrue(PrefixUtils.uriIsValid("http://www.w3.org/")); + } + + @Test + public void uriIsValidFalse0() { + assertFalse(PrefixUtils.uriIsValid("...")); + } + +} diff --git a/jena-fuseki2/jena-fuseki-main/pom.xml b/jena-fuseki2/jena-fuseki-main/pom.xml index b1852cffea3..fc8fb7d2566 100644 --- a/jena-fuseki2/jena-fuseki-main/pom.xml +++ b/jena-fuseki2/jena-fuseki-main/pom.xml @@ -89,6 +89,18 @@ test + + org.junit.jupiter + junit-jupiter + test + + + + org.junit.platform + junit-platform-suite + test + + org.apache.logging.log4j log4j-slf4j2-impl diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java index 6c60f82cfa6..f9a44c60305 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java @@ -18,13 +18,13 @@ package org.apache.jena.fuseki.main; +import org.apache.jena.fuseki.main.prefixes.*; import org.apache.jena.fuseki.main.sys.TestFusekiModules; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; -@RunWith(Suite.class) -@SuiteClasses({ +@Suite +@SelectClasses({ TestPlainServer.class @@ -54,7 +54,11 @@ , TestPatchFuseki.class , TestFusekiCustomScriptFunc.class - // Test ping. + , TestPrefixesService.class + , TestPrefixesServicePlain.class + , TestPrefixesServiceRDF.class + , TestPrefixesServicePrefixesMap.class + , TestMetrics.class , TestFusekiShaclValidation.class }) diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl new file mode 100644 index 00000000000..f46a1d7d702 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl @@ -0,0 +1,24 @@ +## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 + +PREFIX fuseki: +PREFIX rdf: +PREFIX : <#> +PREFIX ja: +PREFIX tdb2: + + +:service rdf:type fuseki:Service ; + fuseki:name "dataset" ; + fuseki:endpoint [ fuseki:operation fuseki:query ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:update ; ] ; + + fuseki:endpoint [ fuseki:operation fuseki:prefixes-r ; fuseki:name "prefixes" ] ; + fuseki:endpoint [ fuseki:operation fuseki:prefixes-ws ; fuseki:name "updatePrefixes" ] ; + fuseki:dataset :dataset ; + . + +# Transactional in-memory dataset. +:dataset rdf:type ja:MemoryDataset ; + ja:data "src/test/java/org/apache/jena/fuseki/main/files/data-test.trig"; + . + \ No newline at end of file diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/data-test.trig b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/data-test.trig new file mode 100644 index 00000000000..fc613821fe1 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/data-test.trig @@ -0,0 +1 @@ +## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/JsonObjectTests.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/JsonObjectTests.java new file mode 100644 index 00000000000..3189b14d4a1 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/JsonObjectTests.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main.prefixes; + +import com.google.gson.Gson; +import org.apache.jena.atlas.web.TypedInputStream; +import org.apache.jena.fuseki.main.FusekiServer; +import org.apache.jena.fuseki.servlets.prefixes.ActionProcPrefixes; +import org.apache.jena.fuseki.servlets.prefixes.JsonObject; +import org.apache.jena.fuseki.servlets.prefixes.PrefixesPlain; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.apache.jena.http.HttpOp.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class JsonObjectTests { + + private static FusekiServer server = null; + private static String serviceURL = null; + + @BeforeAll + public static void beforeSuite() { + PrefixesPlain s = new PrefixesPlain(); + server = FusekiServer.create() + .port(0) + .addProcessor("/prefixes", new ActionProcPrefixes(s)) + .build(); + server.start(); + serviceURL = String.format("http://localhost:%d/prefixes", server.getHttpPort()); + } + + @AfterAll + public static void afterSuite() { + if ( server != null ) + server.stop(); + } + + + @Test + public void fetchURIllegal0() { + // check content type + TypedInputStream x = exec(serviceURL, "?prefix=prefix2"); + assertEquals("application/json", x.getContentType(), "Expected application/json"); + } + + + @Test + public void stringJsonObject0() { + JsonObject jsonObject = new JsonObject("prefix1", "http://www.localhost.org/uri1"); + Gson gson = new Gson(); + String x = gson.toJson(jsonObject); + assertEquals("{\"prefix\":\"prefix1\",\"namespace\":\"http://www.localhost.org/uri1\"}", x, "Got " + x); + } + + @Test + public void fieldsJsonObject0() { + JsonObject jsonObject = new JsonObject("prefix1", "http://www.localhost.org/uri1"); + assertEquals("prefix1", jsonObject.prefix()); + assertEquals("http://www.localhost.org/uri1", jsonObject.namespace()); + } + + private static TypedInputStream exec(String url, String queryString) { + String urlExec = queryString.startsWith("?") + ? url + queryString + : url + "?" + queryString; + return httpGet(urlExec); + } + +} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestAbstractPrefixParam.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestAbstractPrefixParam.java new file mode 100644 index 00000000000..6c4955c6bdc --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestAbstractPrefixParam.java @@ -0,0 +1,527 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main.prefixes; + +import com.google.gson.*; +import org.apache.jena.atlas.web.HttpException; +import org.apache.jena.fuseki.main.FusekiServer; +import org.apache.jena.fuseki.servlets.prefixes.ActionProcPrefixes; +import org.apache.jena.fuseki.servlets.prefixes.PrefixesAccess; +import org.apache.jena.sparql.exec.http.Params; +import org.apache.jena.web.HttpSC; +import org.junit.jupiter.api.*; + +import java.util.HashSet; +import java.util.Set; + +import static org.apache.jena.http.HttpOp.httpGetString; +import static org.apache.jena.http.HttpOp.httpPostForm; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public abstract class TestAbstractPrefixParam { + + private final PrefixesAccess prefixes; + + public TestAbstractPrefixParam(PrefixesAccess storage) { + this.prefixes = storage; + } + + private FusekiServer server = null; + private String serviceURL = null; + private static final String serviceToFormatURL = "http://localhost:%d/prefixes"; + + @BeforeEach + public void before() { + server = FusekiServer.create() + .port(0) + .addProcessor("/prefixes", new ActionProcPrefixes(prefixes)) + .build(); + server.start(); + serviceURL = String.format(serviceToFormatURL, server.getHttpPort()); + } + + @AfterEach + public void afterSuite() { + if ( server != null ) + server.stop(); + } + +// FETCH URI tests +// --------------------------------------------------------------------------------------------- + + @Test + public void fetchURILegal() { + // request legal, prefix does not exist implies return "" + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix=abc"); + assertEquals("", x, "Expected empty string"); + } + + @Test + public void fetchURIBadArgument() { + // Bad argument, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?junk"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void fetchURIEmptyPrefix0() { + // Empty prefix, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix="); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void fetchURIEmptyPrefix1() { + // Empty prefix, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void fetchURIIllegalChars0() { + // illegal prefix, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix=pr."); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + +// UPDATE URI tests +// --------------------------------------------------------------------------------------------- + + @Test + public void updateURINewLegal0() { + // valid new prefix, valid new uri, implies return uri3 + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix3", "http://www.localhost.org/uri3", null); + String x = exec(url, "?prefix=prefix3"); + assertEquals("http://www.localhost.org/uri3", x, "Expected http://www.localhost.org/uri3 got " + x); + } + + @Test + public void updateURINewLegal1() { + // valid new prefix, existing uri, implies return uri3 + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix4", "http://www.localhost.org/uri3", null); + String x = exec(url, "?prefix=prefix4"); + assertEquals("http://www.localhost.org/uri3", x, "Expected http://www.localhost.org/uri3 got " + x); + } + + @Test + public void updateURINewLegal2() { + // existing prefix, valid new uri, implies return uri7 + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix1", "http://www.localhost.org/uri7", null); + String x = exec(url, "?prefix=prefix1"); + assertEquals("http://www.localhost.org/uri7", x, "Expected http://www.localhost.org/uri7 got " + x); + } + + @Test + public void updateURINewLegal3() { + // existing prefix, existing uri, implies return uri2 + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix2", "http://www.localhost.org/uri2", null); + String x = exec(url, "?prefix=prefix2"); + assertEquals("http://www.localhost.org/uri2", x, "Expected http://www.localhost.org/uri2 got " + x); + } + + @Test + public void updateValidNewPrefixInvalidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + //valid new prefix, invalid uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix4", "-.-", null); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateValidNewPrefixEmptyURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + //valid new prefix, empty uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix4", "", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateValidNewPrefixNullURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // valid new prefix, null uri (bad argument), 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix4", null, ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateExistingPrefixInvalidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // existing prefix, invalid uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix1", "http:abc", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateExistingPrefixEmptyURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // existing prefix, empty uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix1", "", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateExistingPrefixNullURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // existing prefix null uri (bad argument), 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix1", null, ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixNewValidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, valid new uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix..-", "http://www.localhost.org/uri7", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixExistingURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, existing uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "-refix..1", "http://www.localhost.org/uri1", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixInvalidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, invalid uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "-", "http://", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixEmptyURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, empty uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "p/p", "", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixNullURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, null uri (bad argument), 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "prefix..-", null, ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixValidNewURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, valid new uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "", "http://www.localhost.org/uri5", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixExistingURI() { + String url = String.format(serviceURL, server.getHttpPort()); + // empty prefix, existing uri, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + execPost(url, "", "http://www.localhost.org/uri1", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixEInvalidURI() { + String url = String.format(serviceURL, server.getHttpPort()); + // empty prefix, invalid uri, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + execPost(url, "", "http:abcur..i1", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixEmptyURI() { + String url = String.format(serviceURL, server.getHttpPort()); + // empty prefix, empty uri, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + execPost(url, "", "", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixNullURI() { + String url = String.format(serviceURL, server.getHttpPort()); + // empty prefix, null uri (bad argument), 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + execPost(url, "", null, ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixValidNewURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), valid new uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, null, "http://www.localhost.org/uri6", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixExistingURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), existing uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, null, "http://www.localhost.org/uri1", null); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixInValidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), invalid uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, null, "...", null); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixEmptyURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), empty uri, 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, null, "", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixNullURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), null uri (bad argument), 400 bad request exception expected + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, null, null, null); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + +// REMOVE URI tests +// --------------------------------------------------------------------------------------------- + @Test + public void removeURI0() { + // request legal, prefix exists, implies return null + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, null, null, "prefix1"); + String x = exec(url, "?prefix=prefix1"); + assertEquals("", x, "Expected null got " + x); + } + + @Test + public void removeURI1() { + // request legal, prefix doesn't exist implies return null + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, null, null, "prefix16"); + String x = exec(url, "?prefix=prefix16"); + assertEquals("", x, "Expected null got " + x); + } + + @Test + public void removeURI2() { + // request illegal, prefix invalid, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, null, null, "prefix16-"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void removeURI3() { + // request legal, prefix exists implies return null + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, null, null, "prefix2"); + String x = exec(url, "?prefix=prefix2"); + assertEquals("", x, "Expected null got " + x); + } + +// GET All tests +// --------------------------------------------------------------------------------------------- + + @Test + public void getAllLegal() { + // request legal, returns multiple prefix-uri pairs + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "test", "http://www.localhost.org/uritest", null); + execPost(url, "test2", "http://www.localhost.org/uritest2", null); + execPost(url, "test3", "http://www.localhost.org/uritest3", null); + String x = exec(url, ""); + + // convert to set + Set set = new HashSet<>(); + set.add("{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}"); + set.add("{\"prefix\":\"test2\",\"uri\":\"http://www.localhost.org/uritest2\"}"); + set.add("{\"prefix\":\"test3\",\"uri\":\"http://www.localhost.org/uritest3\"}"); + + Set resultSet = new HashSet<>(); + JsonArray jsonArray = JsonParser.parseString(x).getAsJsonArray(); + for (JsonElement element : jsonArray) { + resultSet.add(element.getAsJsonObject().toString()); + } + assertEquals(set, resultSet, "Expected prefix"); + } + + @Test + public void getAllEmpty() { + // request legal, dataset empty implies return [] + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, ""); + assertEquals("[]", x, "Expected prefix"); + } + +// FETCH PREFIX tests +// --------------------------------------------------------------------------------------------- + + @Test + public void fetchPrefixLegal() { + // request legal, uri exists in the database with a single prefix assigned + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "test", "http://www.localhost.org/uritest", null); + String x = exec(url, "?uri=http://www.localhost.org/uritest"); + assertEquals("[{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}]", x, "Expected prefix"); + } + + @Test + public void fetchPrefixLegalMultiple() { + // request legal, uri exists in the database with multiple prefixes assigned + String url = String.format(serviceURL, server.getHttpPort()); + execPost(url, "test", "http://www.localhost.org/uritest", null); + execPost(url, "testDuplicate", "http://www.localhost.org/uritest", null); + String x = exec(url, "?uri=http://www.localhost.org/uritest"); + + // convert to set + Set set = new HashSet<>(); + set.add("{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}"); + set.add("{\"prefix\":\"testDuplicate\",\"uri\":\"http://www.localhost.org/uritest\"}"); + + Set resultSet = new HashSet<>(); + JsonArray jsonArray = JsonParser.parseString(x).getAsJsonArray(); + for (JsonElement element : jsonArray) { + resultSet.add(element.getAsJsonObject().toString()); + } + assertEquals(set, resultSet, "Expected prefix"); + } + + @Test + public void fetchPrefixLegalNull() { + // request legal, uri does not exist implies return [] + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?uri=http://www.localhost.org/uritest"); + assertEquals("[]", x, "Expected prefix"); + } + + @Test + public void fetchPrefixIllegal() { + // request illegal, uri is not valid + HttpException ex = assertThrows(HttpException.class, ()-> { + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?uri=----localhost.org/uritest"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void fetchPrefixEmpty() { + // request illegal, uri is empty + HttpException ex = assertThrows(HttpException.class, ()-> { + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?uri="); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void tooManyParams() { + // request illegal, provided too many arguments + HttpException ex = assertThrows(HttpException.class, ()-> { + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix=abc&uri=http://www.localhost.org/uritest"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + +// --------------------------------------------------------------------------------------------- + + private static String exec(String url, String queryString) { + String urlExec = queryString.startsWith("?") + ? url + queryString + : url + "?" + queryString; + return httpGetString(urlExec); + } + + private static void execPost(String url, String prefix, String uri, String prefixToRemove) { + Params params = Params.create() + .add("prefix", prefix) + .add("uri", uri) + .add("removeprefix", prefixToRemove); + httpPostForm(url, params); + } +} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesService.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesService.java new file mode 100644 index 00000000000..1e3976b0ad7 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesService.java @@ -0,0 +1,537 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main.prefixes; + +import static org.apache.jena.http.HttpOp.httpDelete; +import static org.apache.jena.http.HttpOp.httpGetString; +import static org.apache.jena.http.HttpOp.httpPostForm; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.HashSet; +import java.util.Set; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +import org.apache.jena.atlas.web.HttpException; +import org.apache.jena.fuseki.main.FusekiServer; +import org.apache.jena.fuseki.servlets.PrefixesService; +import org.apache.jena.sparql.exec.http.Params; +import org.apache.jena.web.HttpSC; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class TestPrefixesService { + + private FusekiServer server = null; + private String serviceURL = null; + String serviceUpdateURL = null; + + @BeforeEach + public void before() { + PrefixesService.init(); + String DATASET = "dataset"; + server = FusekiServer.create() + .port(0) + .parseConfigFile("src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl") + .start(); + + int port = server.getHttpPort(); + serviceURL = "http://localhost:"+port+"/"+DATASET+"/prefixes"; + serviceUpdateURL = "http://localhost:"+port+"/"+DATASET+"/updatePrefixes"; + } + + @AfterEach + public void afterSuite() { + if ( server != null ) + server.stop(); + } + +// FETCH URI tests +// --------------------------------------------------------------------------------------------- + + @Test + public void fetchURILegal() { + // request legal, prefix does not exist implies return "" + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix=abc"); + assertEquals("", x, "Expected empty string"); + } + + @Test + public void fetchURIBadArgument() { + // Bad argument, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?junk"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void fetchURIEmptyPrefix0() { + // Empty prefix, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix="); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void fetchURIEmptyPrefix1() { + // Empty prefix, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void fetchURIIllegalChars0() { + // illegal prefix, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix=pr."); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + +// UPDATE URI tests +// --------------------------------------------------------------------------------------------- + + @Test + public void updateURINewLegal0() { + // valid new prefix, valid new uri, implies return uri3 + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix3", "http://www.localhost.org/uri3"); + String x = exec(url, "?prefix=prefix3"); + assertEquals("http://www.localhost.org/uri3", x, "Expected http://www.localhost.org/uri3 got " + x); + } + + @Test + public void updateURINewLegal1() { + // valid new prefix, existing uri, implies return uri3 + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix4", "http://www.localhost.org/uri3"); + String x = exec(url, "?prefix=prefix4"); + assertEquals("http://www.localhost.org/uri3", x, "Expected http://www.localhost.org/uri3 got " + x); + } + + @Test + public void updateURINewLegal2() { + // existing prefix, valid new uri, implies return uri7 + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix1", "http://www.localhost.org/uri7"); + String x = exec(url, "?prefix=prefix1"); + assertEquals("http://www.localhost.org/uri7", x, "Expected http://www.localhost.org/uri7 got " + x); + } + + @Test + public void updateURINewLegal3() { + // existing prefix, existing uri, implies return uri2 + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix2", "http://www.localhost.org/uri2"); + String x = exec(url, "?prefix=prefix2"); + assertEquals("http://www.localhost.org/uri2", x, "Expected http://www.localhost.org/uri2 got " + x); + } + + @Test + public void updateValidNewPrefixInvalidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + //valid new prefix, invalid uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix4", "-.-"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateValidNewPrefixEmptyURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + //valid new prefix, empty uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix4", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateValidNewPrefixNullURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // valid new prefix, null uri (bad argument), 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix4", null); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateExistingPrefixInvalidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // existing prefix, invalid uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix1", "http:abc"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateExistingPrefixEmptyURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // existing prefix, empty uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix1", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateExistingPrefixNullURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // existing prefix null uri (bad argument), 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix1", null); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixNewValidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, valid new uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix..-", "http://www.localhost.org/uri7"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixExistingURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, existing uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "-refix..1", "http://www.localhost.org/uri1"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixInvalidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, invalid uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "-", "http://"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixEmptyURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, empty uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "p/p", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateInvalidPrefixNullURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, null uri (bad argument), 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "prefix..-", null); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixValidNewURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // invalid prefix, valid new uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, "", "http://www.localhost.org/uri5"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixExistingURI() { + String url = String.format(serviceUpdateURL, server.getHttpPort()); + // empty prefix, existing uri, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + execPost(url, "", "http://www.localhost.org/uri1"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixEInvalidURI() { + String url = String.format(serviceUpdateURL, server.getHttpPort()); + // empty prefix, invalid uri, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + execPost(url, "", "http:abcur..i1"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixEmptyURI() { + String url = String.format(serviceUpdateURL, server.getHttpPort()); + // empty prefix, empty uri, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + execPost(url, "", ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateEmptyPrefixNullURI() { + String url = String.format(serviceUpdateURL, server.getHttpPort()); + // empty prefix, null uri (bad argument), 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + execPost(url, "", null); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixValidNewURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), valid new uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, null, "http://www.localhost.org/uri6"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixExistingURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), existing uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, null, "http://www.localhost.org/uri1"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixInValidURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), invalid uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, null, "..."); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixEmptyURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), empty uri, 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, null, ""); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void updateNullPrefixNullURI() { + HttpException ex = assertThrows(HttpException.class, ()->{ + // null prefix (bad argument), null uri (bad argument), 400 bad request exception expected + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(url, null, null); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + +// GET ALL tests +// --------------------------------------------------------------------------------------------- + + @Test + public void getAllLegal() { + // request legal, returns multiple prefix-uri pairs + String url = String.format(serviceURL, server.getHttpPort()); + String postURL = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(postURL, "test", "http://www.localhost.org/uritest"); + execPost(postURL, "test2", "http://www.localhost.org/uritest2"); + execPost(postURL, "test3", "http://www.localhost.org/uritest3"); + String x = exec(url, ""); + + // convert to set + Set set = new HashSet<>(); + set.add("{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}"); + set.add("{\"prefix\":\"test2\",\"uri\":\"http://www.localhost.org/uritest2\"}"); + set.add("{\"prefix\":\"test3\",\"uri\":\"http://www.localhost.org/uritest3\"}"); + + Set resultSet = new HashSet<>(); + JsonArray jsonArray = JsonParser.parseString(x).getAsJsonArray(); + for (JsonElement element : jsonArray) { + resultSet.add(element.getAsJsonObject().toString()); + } + assertEquals(set, resultSet, "Expected prefix"); + } + + @Test + public void getAllEmpty() { + // request legal, dataset empty implies return [] + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, ""); + assertEquals("[]", x, "Expected prefix"); + } + +// FETCH PREFIX tests +// --------------------------------------------------------------------------------------------- + + @Test + public void fetchPrefixLegal() { + // request legal, uri exists in the database with a single prefix assigned + String url = String.format(serviceURL, server.getHttpPort()); + String postURL = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(postURL, "test", "http://www.localhost.org/uritest"); + String x = exec(url, "?uri=http://www.localhost.org/uritest"); + assertEquals("[{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}]", x, "Expected prefix"); + } + + @Test + public void fetchPrefixLegalMultiple() { + // request legal, uri exists in the database with multiple prefixes assigned + String url = String.format(serviceURL, server.getHttpPort()); + String postURL = String.format(serviceUpdateURL, server.getHttpPort()); + execPost(postURL, "test", "http://www.localhost.org/uritest"); + execPost(postURL, "testDuplicate", "http://www.localhost.org/uritest"); + String x = exec(url, "?uri=http://www.localhost.org/uritest"); + + // convert to set + Set set = new HashSet<>(); + set.add("{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}"); + set.add("{\"prefix\":\"testDuplicate\",\"uri\":\"http://www.localhost.org/uritest\"}"); + + Set resultSet = new HashSet<>(); + JsonArray jsonArray = JsonParser.parseString(x).getAsJsonArray(); + for (JsonElement element : jsonArray) { + resultSet.add(element.getAsJsonObject().toString()); + } + assertEquals(set, resultSet, "Expected prefix"); + } + + @Test + public void fetchPrefixLegalNull() { + // request legal, uri does not exist implies return [] + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?uri=http://www.localhost.org/uritest"); + assertEquals("[]", x, "Expected prefix"); + } + + @Test + public void fetchPrefixIllegal() { + // request illegal, uri is not valid + HttpException ex = assertThrows(HttpException.class, ()-> { + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?uri=----localhost.org/uritest"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void fetchPrefixEmpty() { + // request illegal, uri is empty + HttpException ex = assertThrows(HttpException.class, ()-> { + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?uri="); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void tooManyParams() { + // request illegal, provided too many arguments + HttpException ex = assertThrows(HttpException.class, ()-> { + String url = String.format(serviceURL, server.getHttpPort()); + String x = exec(url, "?prefix=abc?uri=cde"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + // REMOVE HTTP DELETE tests +// --------------------------------------------------------------------------------------------- + @Test + public void deleteURI0() { + // request legal, prefix exists, implies return null + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execDelete(url, "?prefix=prefix1"); + String x = exec(url, "?prefix=prefix1"); + assertEquals("", x, "Expected null got " + x); + } + + @Test + public void deleteURI1() { + // request legal, prefix doesn't exist implies return null + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execDelete(url, "?prefix=prefix16"); + String x = exec(url, "?prefix=prefix16"); + assertEquals("", x, "Expected null got " + x); + } + + @Test + public void deleteURI2() { + // request illegal, prefix invalid, 400 bad request exception expected + HttpException ex = assertThrows(HttpException.class, ()->{ + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execDelete(url, "?prefix=prefix16-"); + }); + assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); + } + + @Test + public void deleteURI3() { + // request legal, prefix exists implies return null + String url = String.format(serviceUpdateURL, server.getHttpPort()); + execDelete(url, "?prefix=prefix2"); + String x = exec(url, "?prefix=prefix2"); + assertEquals("", x, "Expected null got " + x); + } +// --------------------------------------------------------------------------------------------- + + private static String exec(String url, String queryString) { + String urlExec = queryString.startsWith("?") + ? url + queryString + : url + "?" + queryString; + return httpGetString(urlExec); + } + + private static void execPost(String url, String prefix, String uri) { + Params params = Params.create() + .add("prefix", prefix) + .add("uri", uri); + httpPostForm(url, params); + } + + private static void execDelete(String url, String queryString) { + String urlExec = queryString.startsWith("?") + ? url + queryString + : url+"?"+queryString; + httpDelete(urlExec); + } +} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePlain.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePlain.java new file mode 100644 index 00000000000..68dd6963f21 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePlain.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main.prefixes; + +import org.apache.jena.fuseki.servlets.prefixes.PrefixesPlain; + +public class +TestPrefixesServicePlain extends TestAbstractPrefixParam { + public TestPrefixesServicePlain() { + super(new PrefixesPlain()); + } +} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePrefixesMap.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePrefixesMap.java new file mode 100644 index 00000000000..2bc0446c824 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePrefixesMap.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main.prefixes; + +import org.apache.jena.fuseki.servlets.prefixes.PrefixesAccess; +import org.apache.jena.fuseki.servlets.prefixes.PrefixesMap; +import org.apache.jena.sparql.core.DatasetGraph; +import org.apache.jena.sparql.core.DatasetGraphFactory; + +public class TestPrefixesServicePrefixesMap extends TestAbstractPrefixParam { + public TestPrefixesServicePrefixesMap() { + super(make()); + } + + private static PrefixesAccess make() { + DatasetGraph dsg = DatasetGraphFactory.createTxnMem(); + return new PrefixesMap(dsg.prefixes(), dsg); + } +} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServiceRDF.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServiceRDF.java new file mode 100644 index 00000000000..a2e7749d3bc --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServiceRDF.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main.prefixes; + +import org.apache.jena.fuseki.servlets.prefixes.PrefixesRDF; + +public class TestPrefixesServiceRDF extends TestAbstractPrefixParam { + public TestPrefixesServiceRDF() { + super(new PrefixesRDF()); + } +} From 0a4b9a7d948b83126c2cc54516bb3910ad62cad3 Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Sun, 7 Jul 2024 16:59:39 +0100 Subject: [PATCH 2/2] GH-2538: Add content negotiation for get-by-prefix. Refactor code and tests --- .../sparql/pfunction/PropertyFunction.java | 18 +- .../jena/fuseki/server/DataService.java | 2 + .../jena/fuseki/server/FusekiVocab.java | 4 +- .../apache/jena/fuseki/server/Operation.java | 4 +- .../jena/fuseki/server/OperationRegistry.java | 5 + .../jena/fuseki/servlets/ActionPrefixesR.java | 205 ++++--- .../fuseki/servlets/ActionPrefixesRW.java | 87 ++- .../jena/fuseki/servlets/HttpAction.java | 22 +- .../jena/fuseki/servlets/PrefixesService.java | 52 -- .../servlets/prefixes/ActionPrefixesBase.java | 66 ++- .../servlets/prefixes/ActionProcPrefixes.java | 211 +------ .../fuseki/servlets/prefixes/PrefixUtils.java | 19 +- .../fuseki/servlets/prefixes/PrefixesMap.java | 6 + .../servlets/prefixes/PrefixesPlain.java | 5 +- .../fuseki/servlets/prefixes/PrefixesRDF.java | 126 ++-- .../src/test/files/config-prefixes-empty.ttl | 22 + .../src/test/files/config-prefixes.ttl | 22 + .../jena-fuseki-main/src/test/files/data.trig | 6 + .../jena/fuseki/main/TS_FusekiMain.java | 6 +- .../main/files/config-prefixes-test.ttl | 24 - .../jena/fuseki/main/files/data-test.trig | 1 - ...ixParam.java => AbstractTestPrefixes.java} | 331 +++++------ .../prefixes/AbstractTestPrefixesImpl.java | 68 +++ .../fuseki/main/prefixes/JsonObjectTests.java | 88 --- .../main/prefixes/PrefixesServiceTests.java} | 16 +- .../prefixes/TestPrefixesActionResponse.java | 127 +++++ .../main/prefixes/TestPrefixesActions.java | 64 +++ .../main/prefixes/TestPrefixesService.java | 537 ------------------ .../prefixes/TestPrefixesServicePlain.java | 4 +- .../TestPrefixesServicePrefixesMap.java | 3 +- .../main/prefixes/TestPrefixesServiceRDF.java | 3 +- .../src/test/resources/log4j2-test.properties | 26 +- 32 files changed, 857 insertions(+), 1323 deletions(-) delete mode 100644 jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/PrefixesService.java create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/files/config-prefixes-empty.ttl create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/files/config-prefixes.ttl create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/files/data.trig delete mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl delete mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/data-test.trig rename jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/{TestAbstractPrefixParam.java => AbstractTestPrefixes.java} (58%) create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/AbstractTestPrefixesImpl.java delete mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/JsonObjectTests.java rename jena-fuseki2/{jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/JsonObject.java => jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/PrefixesServiceTests.java} (67%) create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesActionResponse.java create mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesActions.java delete mode 100644 jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesService.java diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/pfunction/PropertyFunction.java b/jena-arq/src/main/java/org/apache/jena/sparql/pfunction/PropertyFunction.java index 90907442311..4b5edf7e77b 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/pfunction/PropertyFunction.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/pfunction/PropertyFunction.java @@ -23,35 +23,35 @@ import org.apache.jena.sparql.engine.QueryIterator ; /* Abstraction: QueryStage = PlanElement has a single "build" - * but it's never worng - this two step process here allows for checking + * but it's never wrong - this two step process here allows for checking */ /* Can have: * One arg or list for both subject and object - * (?x) is not the same as ?x + * (?x) is not the same as ?x */ public interface PropertyFunction { /** Called during query plan construction immediately after the * construction of the property function instance. - * @param argSubject The parsed argument(s) in the subject position + * @param argSubject The parsed argument(s) in the subject position * @param predicate The extension URI (as a Node). - * @param argObject The parsed argument(s) in the object position + * @param argObject The parsed argument(s) in the object position * @param execCxt Execution context - */ + */ public void build(PropFuncArg argSubject, Node predicate, PropFuncArg argObject, ExecutionContext execCxt) ; - /** Create an iterator of bindings for the given inputs + /** Create an iterator of bindings for the given inputs * @param input QueryIterator from the previous stage - * @param argSubject The parsed argument(s) in the subject position + * @param argSubject The parsed argument(s) in the subject position * @param predicate The extension URI (as a Node). - * @param argObject The parsed argument(s) in the object position + * @param argObject The parsed argument(s) in the object position * @param execCxt The execution context * @return QueryIterator */ - public QueryIterator exec(QueryIterator input, + public QueryIterator exec(QueryIterator input, PropFuncArg argSubject, Node predicate, PropFuncArg argObject, ExecutionContext execCxt) ; } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java index 7d823180b6e..bf671c4b120 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java @@ -233,12 +233,14 @@ public long getRequestsBad() { /** Cumulative counter of transactions */ public AtomicLong totalTxn = new AtomicLong(0); + /** Note the start of a transaction */ public void startTxn(TxnType mode) { check(DataServiceStatus.ACTIVE); activeTxn.getAndIncrement(); totalTxn.getAndIncrement(); } + /** Note the finish of a transaction */ public void finishTxn() { activeTxn.decrementAndGet(); } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java index 47d67fb509e..8efe5947906 100755 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java @@ -89,8 +89,8 @@ public class FusekiVocab public static final Resource opShacl = resource("shacl"); public static final Resource opPatch = resource("patch"); - public static final Resource opPREFIXES_R = resource("prefixes-r"); - public static final Resource opPREFIXES_RW = resource("prefixes-ws"); + public static final Resource opPREFIXES_R = resource("prefixes-r"); + public static final Resource opPREFIXES_RW = resource("prefixes-rw"); // Internal private static final String stateNameActive = DataServiceStatus.ACTIVE.name; diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java index 2664f111db3..6c833c113fc 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java @@ -88,8 +88,8 @@ static private Operation create(Node id, String shortName, String description) { public static final Operation NoOp = alloc(FusekiVocab.opNoOp.asNode(), "no-op", "No Op"); - public static final Operation PREFIXES_R = alloc(FusekiVocab.opPREFIXES_R.asNode(), "prefixes-r", "Read prefixes"); - public static final Operation PREFIXES_RW = alloc(FusekiVocab.opPREFIXES_RW.asNode(), "prefixes-ws", "Read-write prefixes"); + public static final Operation PREFIXES_R = alloc(FusekiVocab.opPREFIXES_R.asNode(), "prefixes-r", "Read prefixes"); + public static final Operation PREFIXES_RW = alloc(FusekiVocab.opPREFIXES_RW.asNode(), "prefixes-rw", "Read-write prefixes"); static { diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/OperationRegistry.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/OperationRegistry.java index 7038c82f78f..30efc0f356d 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/OperationRegistry.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/OperationRegistry.java @@ -49,6 +49,8 @@ public class OperationRegistry { private static final ActionService rdfPatch = new PatchApply(); private static final ActionService noOperation = new NoOpActionService(); private static final ActionService shaclValidation = new SHACL_Validation(); + private static final ActionService prefixes_R = new ActionPrefixesR(); + private static final ActionService prefixes_RW = new ActionPrefixesRW(); /** The server-wide standard configuration. */ private static final OperationRegistry stdConfig = stdConfig(); @@ -71,6 +73,9 @@ private static OperationRegistry stdConfig() { stdOpReg.register(Operation.Shacl, null, shaclValidation); stdOpReg.register(Operation.Upload, null, uploadServlet); + stdOpReg.register(Operation.PREFIXES_R, null, prefixes_R); + stdOpReg.register(Operation.PREFIXES_RW, null, prefixes_RW); + stdOpReg.register(Operation.NoOp, null, noOperation); return stdOpReg; } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesR.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesR.java index 04dce5a40fb..6a0a0c13120 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesR.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesR.java @@ -18,26 +18,36 @@ package org.apache.jena.fuseki.servlets; -import com.google.gson.JsonArray; -import org.apache.jena.atlas.logging.FmtLog; -import org.apache.jena.riot.WebContent; -import org.apache.jena.riot.web.HttpNames; - -import org.apache.jena.fuseki.servlets.prefixes.ActionPrefixesBase; -import org.apache.jena.fuseki.servlets.prefixes.PrefixUtils; -import org.apache.jena.fuseki.servlets.prefixes.JsonObject; - import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Optional; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import org.apache.jena.atlas.logging.FmtLog; +import org.apache.jena.atlas.web.AcceptList; +import org.apache.jena.atlas.web.MediaType; +import org.apache.jena.fuseki.servlets.prefixes.ActionPrefixesBase; +import org.apache.jena.fuseki.servlets.prefixes.PrefixUtils; +import org.apache.jena.fuseki.servlets.prefixes.PrefixesAccess; +import org.apache.jena.fuseki.system.ConNeg; +import org.apache.jena.riot.WebContent; +import org.apache.jena.riot.web.HttpNames; +import org.apache.jena.web.HttpSC; + public class ActionPrefixesR extends ActionPrefixesBase { private static final String NO_PREFIX_NS = ""; public ActionPrefixesR() {} + @Override + protected PrefixesAccess prefixes(HttpAction action) { + return ActionPrefixesBase.prefixesFromAction(action); + } + @Override protected void doOptions(HttpAction action) { ActionLib.setCommonHeadersForOptions(action); @@ -45,17 +55,6 @@ protected void doOptions(HttpAction action) { ServletOps.success(action); } - public void validateGet(HttpAction action) { - validate(action); - // check if the combination of parameters is legal - String prefix = action.getRequestParameter(PrefixUtils.PREFIX); - String uri = action.getRequestParameter(PrefixUtils.URI); - if(prefix != null && uri != null) { - ServletOps.errorBadRequest("Provide only one of the prefix or uri parameters!"); - return; - } - } - enum ResponseTypes { GET_ALL, FETCH_URI, @@ -93,83 +92,129 @@ else if (!PrefixUtils.uriIsValid(uri)) { return ResponseTypes.BAD_REQUEST; } + @Override + protected void validatePrefixesGET(HttpAction action) { + // Only need to check for presence of expected parameters. + // Values have been checked. + String prefix = action.getRequestParameter(PrefixUtils.PREFIX); + String uri = action.getRequestParameter(PrefixUtils.URI); + if ( prefix != null && uri != null ) { + ServletOps.errorBadRequest("Provide only no paremetrs, or one of the prefix or uri!"); + return; + } + } + @Override protected void doGet(HttpAction action) { ActionLib.setCommonHeaders(action); - validateGet(action); - action.beginRead(); try { - // Not null (valid request) String prefix = action.getRequestParameter(PrefixUtils.PREFIX); String uri = action.getRequestParameter(PrefixUtils.URI); + PrefixesAccess prefixes = prefixes(action); switch(chooseResponseType(prefix, uri)) { - case GET_ALL -> { - Map allPairs = prefixes(action).getAll(); - JsonArray allJsonPairs = new JsonArray(); - allPairs.entrySet().stream() - .forEach(entry -> { - com.google.gson.JsonObject jsonObject = new com.google.gson.JsonObject(); - jsonObject.addProperty(PrefixUtils.PREFIX, entry.getKey()); - jsonObject.addProperty(PrefixUtils.URI, entry.getValue()); - allJsonPairs.add(jsonObject); - FmtLog.info(action.log, "[%d] - %s", action.id, new JsonObject(entry.getKey(), entry.getValue())); - }); - action.setResponseContentType(WebContent.contentTypeJSON); - action.getResponseOutputStream().print(String.valueOf(allJsonPairs)); - - ServletOps.success(action); - action.endRead(); - return; - } - case FETCH_URI -> { - Optional x = prefixes(action).fetchURI(prefix); - String namespace = x.orElse(NO_PREFIX_NS); - - JsonObject jsonObject = new JsonObject(prefix, namespace); - - // Build the response. - action.setResponseContentType(WebContent.contentTypeJSON); - action.getResponseOutputStream().print(namespace); - // Indicate success - FmtLog.info(action.log, "[%d] %s -> %s", action.id, prefix, jsonObject.toString()); - action.commit(); - ServletOps.success(action); - return; - } - case FETCH_PREFIX -> { - List prefixList =prefixes(action).fetchPrefix(uri); - JsonArray prefixJsonArray = new JsonArray(); - for (String p : prefixList) { - com.google.gson.JsonObject jsonObject2 = new com.google.gson.JsonObject(); - jsonObject2.addProperty(PrefixUtils.PREFIX, p); - jsonObject2.addProperty(PrefixUtils.URI, uri); - prefixJsonArray.add(jsonObject2); - FmtLog.info(action.log, "[%d] - %s", action.id, new JsonObject(p, uri)); - } - // Build the response. - action.setResponseContentType(WebContent.contentTypeJSON); - action.getResponseOutputStream().print(String.valueOf(prefixJsonArray)); - // Indicate success - action.commit(); - ServletOps.success(action); - action.endRead(); - return; - } + case GET_ALL -> execGetAll(action, prefixes); + case FETCH_URI -> execFetchURIByPrefix(action, prefixes, prefix); + case FETCH_PREFIX -> execFetchPrefixForURI(action, prefixes, uri); default -> { ServletOps.errorBadRequest("Bad request"); return; } } - } catch (RuntimeException | IOException ex) { - try { action.abort(); } - catch (Throwable th ) { - FmtLog.warn(action.log, th, "[%d] GET prefix = %s", action.id); - } + } catch (ActionErrorException ex) { + // pass through + } catch (RuntimeException ex) { + action.abortSilent(); ServletOps.errorOccurred(ex); } finally { action.endRead(); } } + + private void execGetAll(HttpAction action, PrefixesAccess prefixes) { + Map allPairs = prefixes.getAll(); + JsonArray allJsonPairs = new JsonArray(); + allPairs.entrySet().stream().forEach(entry -> { + JsonObject jsonObject = jsonObject(entry.getKey(), entry.getValue()); + allJsonPairs.add(jsonObject); + FmtLog.debug(action.log, "[%d] Entry: %s: <%s>", action.id, entry.getKey(), entry.getValue()); + }); + FmtLog.info(action.log, "[%d] - Get all prefix mappings", action.id); + ServletOps.success(action); + try { + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(String.valueOf(allJsonPairs)); + ServletOps.success(action); + } catch (IOException ex) { + FmtLog.warn(action.log, "[%d] Get all prefixes: Failed to send response: %s", action.id, ex.getMessage()); + ServletOps.errorOccurred(ex); + } + } + + private static JsonObject jsonObject(String prefix, String uri) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty(PrefixUtils.PREFIX, prefix); + jsonObject.addProperty(PrefixUtils.URI, uri); + return jsonObject; + } + + private static AcceptList acceptGET = AcceptList.create(WebContent.contentTypeTextPlain, WebContent.contentTypeJSON); + private static MediaType dftMediaType = MediaType.create(WebContent.contentTypeJSON); + + private void execFetchURIByPrefix(HttpAction action, PrefixesAccess prefixes, String prefix) { + Optional x = prefixes.fetchURI(prefix); + String namespace = x.orElse(NO_PREFIX_NS); + + try { + MediaType mt = ConNeg.chooseContentType(action.getRequest(), acceptGET, dftMediaType); + String ctString = mt.getContentTypeStr(); + switch (ctString) { + case WebContent.contentTypeTextPlain -> responseText(action, prefix, namespace); + case WebContent.contentTypeJSON -> responseJSON(action, prefix, namespace); + default -> + ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415); + } + FmtLog.info(action.log, "[%d] %s -> %s", action.id, prefix, namespace); + ServletOps.success(action); + } catch (IOException ex) { + FmtLog.warn(action.log, "[%d] Fetch URI by prefix: Failed to send response: %s", action.id, ex.getMessage()); + ServletOps.errorOccurred(ex); + } + FmtLog.info(action.log, "[%d] %s -> %s", action.id, prefix, namespace); + action.commit(); + ServletOps.success(action); + } + + private static void responseJSON(HttpAction action, String prefix, String uri) throws IOException { + action.setResponseContentType(WebContent.contentTypeJSON); + JsonObject jObj = jsonObject(prefix, uri); + action.getResponseOutputStream().print(String.valueOf(jObj)); + } + + private static void responseText(HttpAction action, String prefix, String uri) throws IOException { + action.setResponseContentType(WebContent.contentTypeTextPlain); + action.getResponseOutputStream().print(uri); + } + + private void execFetchPrefixForURI(HttpAction action, PrefixesAccess prefixes, String uri) { + List prefixList = prefixes.fetchPrefix(uri); + JsonArray prefixJsonArray = new JsonArray(); + for (String p : prefixList) { + JsonObject jsonObject2 = jsonObject(p, uri); + prefixJsonArray.add(jsonObject2); + } + FmtLog.info(action.log, "[%d] PrefixForURI: %s: %s", action.id, String.valueOf(prefixJsonArray)); + + try { + action.setResponseContentType(WebContent.contentTypeJSON); + action.getResponseOutputStream().print(String.valueOf(prefixJsonArray)); + } catch (IOException ex) { + FmtLog.warn(action.log, "[%d] Fetch prefixes for URI: Failed to send response: %s", action.id, ex.getMessage()); + ServletOps.errorOccurred(ex); + } + action.commit(); + ServletOps.success(action); + action.endRead(); + } } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesRW.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesRW.java index 3628e4221d1..6b62f353493 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesRW.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionPrefixesRW.java @@ -18,13 +18,11 @@ package org.apache.jena.fuseki.servlets; +import org.apache.commons.lang3.StringUtils; import org.apache.jena.atlas.logging.FmtLog; -import org.apache.jena.riot.WebContent; -import org.apache.jena.riot.web.HttpNames; - import org.apache.jena.fuseki.servlets.prefixes.PrefixUtils; - -import java.io.IOException; +import org.apache.jena.fuseki.servlets.prefixes.PrefixesAccess; +import org.apache.jena.riot.web.HttpNames; public class ActionPrefixesRW extends ActionPrefixesR { @@ -37,55 +35,47 @@ protected void doOptions(HttpAction action) { ServletOps.success(action); } - public void validateDelete(HttpAction action) { - validate(action); + @Override + protected void validatePrefixesDELETE(HttpAction action) { String prefixToRemove = action.getRequestParameter(PrefixUtils.PREFIX); - if (prefixToRemove == null || prefixToRemove.isEmpty() || !PrefixUtils.prefixIsValid(prefixToRemove)) { + if (prefixToRemove == null || prefixToRemove.isEmpty() || !PrefixUtils.prefixIsValid(prefixToRemove)) ServletOps.errorBadRequest("Remove operation unsuccessful!"); - return; - } } @Override protected void doDelete(HttpAction action) { - validateDelete(action); + ActionLib.setCommonHeaders(action); action.beginWrite(); - try { String prefixToRemove = action.getRequestParameter(PrefixUtils.PREFIX); - prefixes(action).removePrefix(prefixToRemove); - FmtLog.info(action.log, "[%d] Remove %s:", action.id, prefixToRemove); + PrefixesAccess prefixes = prefixes(action); + prefixes.removePrefix(prefixToRemove); + FmtLog.info(action.log, "[%d] Remove %s:", action.id, prefixToRemove); action.commit(); - - // Indicate success ServletOps.success(action); - - // Build the response. - action.setResponseContentType(WebContent.contentTypeJSON); - action.getResponseOutputStream().print(""); - - } catch (RuntimeException | IOException ex) { - try { action.abort(); } - catch (Throwable th ) { - FmtLog.warn(action.log, th, "[%d] POST prefix = %s", action.id); - } + } catch (RuntimeException ex) { + action.abortSilent(); ServletOps.errorOccurred(ex); } finally { action.end(); } } - - public void validatePost(HttpAction action) { - validate(action); + @Override + protected void validatePrefixesPOST(HttpAction action) { String prefix = action.getRequestParameter(PrefixUtils.PREFIX); String uri = action.getRequestParameter(PrefixUtils.URI); - if (prefix.isEmpty() || uri.isEmpty()) { - ServletOps.errorBadRequest("Empty operation - unsuccessful!"); + if (prefix.isEmpty() ) { + ServletOps.errorBadRequest("Missing prefix parameter"); + return; + } + if ( StringUtils.isEmpty(uri) ) { + ServletOps.errorBadRequest("Missing URI parameter"); return; } + else if (!PrefixUtils.prefixIsValid(prefix) || !PrefixUtils.uriIsValid(uri)) { ServletOps.errorBadRequest("Empty operation - unsuccessful!"); return; @@ -94,31 +84,22 @@ else if (!PrefixUtils.prefixIsValid(prefix) || !PrefixUtils.uriIsValid(uri)) { @Override protected void doPost(HttpAction action) { - validatePost(action); + ActionLib.setCommonHeaders(action); action.beginWrite(); - try { - String prefix = action.getRequestParameter(PrefixUtils.PREFIX); - String uri = action.getRequestParameter(PrefixUtils.URI); - - prefixes(action).updatePrefix(prefix, uri); - FmtLog.info(action.log, "[%d] Set %s: <%s>", action.id, prefix, uri); - - action.commit(); - - // Indicate success - ServletOps.success(action); - - // Build the response. - action.setResponseContentType(WebContent.contentTypeJSON); - action.getResponseOutputStream().print(""); - - } catch (RuntimeException | IOException ex) { - try { action.abort(); } - catch (Throwable th ) { - FmtLog.warn(action.log, th, "[%d] POST prefix = %s", action.id); + try { + String prefix = action.getRequestParameter(PrefixUtils.PREFIX); + String uri = action.getRequestParameter(PrefixUtils.URI); + PrefixesAccess prefixes = prefixes(action); + + prefixes.updatePrefix(prefix, uri); + FmtLog.info(action.log, "[%d] Set %s: <%s>", action.id, prefix, uri); + action.commit(); + ServletOps.success(action); + } catch (RuntimeException ex) { + action.abortSilent(); + ServletOps.errorOccurred(ex); } - ServletOps.errorOccurred(ex); } finally { action.end(); } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java index 5a5d1b7a344..a5ee54fc894 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java @@ -309,8 +309,6 @@ public final void finishRequest() { * Prefer one of {@link #beginRead()} or {@link #beginWrite()} if the action is * known to be a a read or write at the start or call {@link #begin()} * if the transaction may promote. - * - * */ public void begin(TxnType txnType) { enterActionTxn(); @@ -331,7 +329,7 @@ public void begin(TxnType txnType) { finishActionTxn(); if ( dataService != null ) dataService.finishTxn(); - if ( transactional.isInTransaction() ) { + if ( transactional != null && transactional.isInTransaction() ) { switch(transactional.transactionMode() ) { case READ -> {} case WRITE -> { @@ -475,23 +473,27 @@ private void finishActionTxn() { // ---- public void commit() { - dataService.finishTxn(); - transactional.commit(); + if ( transactional != null ) + transactional.commit(); end(); } /** Abort: ignore exceptions (for clearup code) */ public void abortSilent() { - try { transactional.abort(); } - catch (Exception ex) {} - finally { + try { + if ( transactional != null ) + transactional.abort(); + } catch (Exception ex) { + } finally { try { end(); } catch (Exception ex) {} } } public void abort() { - try { transactional.abort(); } - catch (Exception ex) { + try { + if ( transactional != null ) + transactional.abort(); + } catch (Exception ex) { // Some datasets claim to be transactional but // don't provide a real abort. We tried to avoid // them earlier but even if they sneak through, diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/PrefixesService.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/PrefixesService.java deleted file mode 100644 index 16d61f2f2a3..00000000000 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/PrefixesService.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jena.fuseki.servlets; - -import org.apache.jena.fuseki.server.Operation; -import org.apache.jena.fuseki.server.OperationRegistry; - -/** The PrefixesService class registers the PrefixesR and PrefixesRW operations - * and actions for the Prefixes Service. The service allows for prefix management - * on a given dataset provided in the config.ttl file. When making requests - * to the API the url can have 3 parameters: prefix, uri, and prefixToRemove, - * the combination of which defines the operation performed. The read operations - * are fetching the prefix by URI, fetching the URI by prefix, and fetching all. - * They are evoked via HTTP GET. The read-write operations are removing and updating - * prefix-URI pairs. Those are POST requests. */ - -public class PrefixesService { - public static final Operation operationPrefixesRW; - public static final Operation operationPrefixesR; - - private static final ActionService procPrefixR; - private static final ActionService procPrefixRW; - - static { - operationPrefixesR = Operation.PREFIXES_R; - operationPrefixesRW = Operation.PREFIXES_RW; - - procPrefixR = new ActionPrefixesR(); - procPrefixRW = new ActionPrefixesRW(); - - OperationRegistry.get().register(operationPrefixesR, procPrefixR); - OperationRegistry.get().register(operationPrefixesRW, procPrefixRW); - } - - public static void init() {} -} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionPrefixesBase.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionPrefixesBase.java index 67051bb46e0..b6a8d64e0e9 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionPrefixesBase.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionPrefixesBase.java @@ -17,31 +17,85 @@ package org.apache.jena.fuseki.servlets.prefixes; +import org.apache.jena.atlas.logging.FmtLog; +import org.apache.jena.fuseki.servlets.ActionREST; import org.apache.jena.fuseki.servlets.BaseActionREST; import org.apache.jena.fuseki.servlets.HttpAction; import org.apache.jena.fuseki.servlets.ServletOps; +import org.apache.jena.riot.web.HttpNames; import org.apache.jena.sparql.core.DatasetGraph; import java.util.Iterator; -public class ActionPrefixesBase extends BaseActionREST { +/** + * Base of {@link ActionREST} that provides + * to an {@link HttpAction}. + */ +public abstract class ActionPrefixesBase extends BaseActionREST { - /** Create a {@link PrefixesAccess} for this {@link HttpAction}. */ - protected static PrefixesAccess prefixes(HttpAction action) { + /** Helper function that returns a {@link PrefixesAccess} for the dataset of this {@link HttpAction}. */ + protected static PrefixesAccess prefixesFromAction(HttpAction action) { DatasetGraph dsg = action.getDataset(); PrefixesMap pMap = new PrefixesMap(dsg.prefixes(), dsg); return pMap; } + /** Return an {@link PrefixesAccess} for the dataset of this {@link HttpAction}. */ + protected abstract PrefixesAccess prefixes(HttpAction action); + @Override - public void validate(HttpAction action) { + public final void validate(HttpAction action) { + // General validation Iterator paramNames = action.getRequestParameterNames().asIterator(); while(paramNames.hasNext()) { String check = paramNames.next(); - if(!check.equals(PrefixUtils.PREFIX) && !check.equals(PrefixUtils.URI) && !check.equals(PrefixUtils.REMOVEPREFIX)) { - ServletOps.errorBadRequest("Unrecognized parameter"); + if ( ! PrefixUtils.isPrefixesParam(check) ) { + FmtLog.warn(action.log, "[%d] Parameter not recognized: %s", action.id, check); + ServletOps.errorBadRequest("Parameter not recognized: "+check); + return; + } + } + + String prefix = action.getRequestParameter(PrefixUtils.PREFIX); + String uri = action.getRequestParameter(PrefixUtils.URI); + + if ( prefix != null ) { + if ( prefix.isEmpty() ) { + FmtLog.warn(action.log, "[%d] Empty prefix - not supported", action.id); + ServletOps.errorBadRequest("Bad prefix parameter value"); + return; + } + if ( ! PrefixUtils.prefixIsValid(prefix) ) { + FmtLog.warn(action.log, "[%d] Bad value for prefix: '%s'", action.id, prefix); + ServletOps.errorBadRequest("Bad prefix parameter value"); return; } } + + if ( uri != null && ! PrefixUtils.uriIsValid(uri) ) { + FmtLog.warn(action.log, "[%d] Bad value for uri: '%s'", action.id, uri); + ServletOps.errorBadRequest("Bad uri parameter value"); + return; + } + + // Per HTTP operation validation. + switch ( action.getRequestMethod() ) { + case HttpNames.METHOD_GET -> validatePrefixesGET(action); + case HttpNames.METHOD_POST -> validatePrefixesPOST(action); + case HttpNames.METHOD_DELETE -> validatePrefixesDELETE(action); + } + } + + // Default actions + protected void validatePrefixesGET(HttpAction action) { + ServletOps.errorMethodNotAllowed(action.getRequestMethod()); + } + + protected void validatePrefixesPOST(HttpAction action) { + ServletOps.errorMethodNotAllowed(action.getRequestMethod()); + } + + protected void validatePrefixesDELETE(HttpAction action) { + ServletOps.errorMethodNotAllowed(action.getRequestMethod()); } } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionProcPrefixes.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionProcPrefixes.java index a82e698c18d..3ce49c89ad2 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionProcPrefixes.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/ActionProcPrefixes.java @@ -18,211 +18,26 @@ package org.apache.jena.fuseki.servlets.prefixes; -import com.google.gson.JsonArray; -import org.apache.jena.atlas.logging.FmtLog; -import org.apache.jena.fuseki.servlets.*; -import org.apache.jena.query.TxnType; -import org.apache.jena.riot.WebContent; -import org.apache.jena.sparql.core.Transactional; - -import java.io.IOException; -import java.util.*; - - -//validate and unpack the HTTP Get request, -//call the storage's fetch URI by the prefix function from the HTTP request - -public class ActionProcPrefixes extends BaseActionREST { +import org.apache.jena.fuseki.servlets.ActionPrefixesRW; +import org.apache.jena.fuseki.servlets.HttpAction; + +/** + * An {@linkActionREST} that provides a all the HTTP services over a fixed {@link PrefixesAccess}. + *

+ * This is in support of testing. + * Instead of taking the prefixes from the action, this classes uses a provided {@link PrefixesAccess}. + */ +public class ActionProcPrefixes extends ActionPrefixesRW { private final PrefixesAccess storage; - // The response to a prefix lookup when there is no such prefix. - // This value is not a proper namespace because it is not an absolute URI. - private static final String NO_PREFIX_NS = ""; - public ActionProcPrefixes(PrefixesAccess storage) { this.storage = storage; } - public void validateGet (HttpAction action) { - - // sanitize parameters - Iterator paramNames = action.getRequestParameterNames().asIterator(); - while(paramNames.hasNext()) { - String check = paramNames.next(); - if(!check.equals("prefix") && !check.equals("uri") && !check.equals("removeprefix")) { - ServletOps.errorBadRequest("Unrecognized parameter"); - return; - } - } - // check if the combination of parameters is legal - String prefix = action.getRequestParameter("prefix"); - String uri = action.getRequestParameter("uri"); - if(prefix != null && uri != null) { - ServletOps.errorBadRequest("Provide only one of the prefix or uri parameters!"); - return; - } - } - - public void validatePost (HttpAction action) { - String prefix = action.getRequestParameter("prefix"); - String uri = action.getRequestParameter("uri"); - String prefixToRemove = action.getRequestParameter("removeprefix"); - - if (prefix.isEmpty() && uri.isEmpty() && prefixToRemove.isEmpty()) { - ServletOps.errorBadRequest("Empty operation - unsuccessful!"); - return; - } - if (prefixToRemove.isEmpty()) { - if (prefix.isEmpty() || uri.isEmpty() || !PrefixUtils.prefixIsValid(prefix) || !PrefixUtils.uriIsValid(uri)) { - ServletOps.errorBadRequest("Update operation unsuccessful!"); - return; - } - } - if (prefix.isEmpty() && uri.isEmpty()) { - if (!PrefixUtils.prefixIsValid(prefixToRemove)) { - ServletOps.errorBadRequest("Remove operation unsuccessful!"); - return; - } - } - } - + // Instead of taking the prefixes from the action, this classes uses a provided PrefixesAccess. @Override - public void doGet (HttpAction action) { - - validateGet(action); - - Transactional transactional = storage.transactional(); - transactional.begin(TxnType.READ); - - try { - // Not null (valid request) - String prefix = action.getRequestParameter("prefix"); - String uri = action.getRequestParameter("uri"); - - if (prefix == null && uri == null) { - //getAll - Map allPairs = storage.getAll(); - JsonArray allJsonPairs = new JsonArray(); - allPairs.entrySet().stream() - .forEach(entry -> { - com.google.gson.JsonObject jsonObject = new com.google.gson.JsonObject(); - jsonObject.addProperty("prefix", entry.getKey()); - jsonObject.addProperty("uri", entry.getValue()); - allJsonPairs.add(jsonObject); - FmtLog.info(action.log, "[%d] - %s", action.id, new JsonObject(entry.getKey(), entry.getValue())); - }); - action.setResponseContentType(WebContent.contentTypeJSON); - action.getResponseOutputStream().print(String.valueOf(allJsonPairs)); - - transactional.commit(); - ServletOps.success(action); - transactional.end(); - return; - } - if (prefix != null && uri == null) { - - if (prefix.isEmpty()) { - ServletOps.errorBadRequest("Empty prefix!"); - return; - } - else if (!PrefixUtils.prefixIsValid(prefix)) { - ServletOps.errorBadRequest("Prefix contains illegal characters!"); - return; - } - else { - //fetchURI - Optional x = storage.fetchURI(prefix); - String namespace = x.orElse(NO_PREFIX_NS); - - JsonObject jsonObject = new JsonObject(prefix, namespace); - - // Build the response. - action.setResponseContentType(WebContent.contentTypeJSON); - action.getResponseOutputStream().print(namespace); - // Indicate success - FmtLog.info(action.log, "[%d] %s -> %s", action.id, prefix, jsonObject.toString()); - transactional.commit(); - ServletOps.success(action); - return; - } - } - if (prefix == null && uri != null) { - if (uri.isEmpty()) { - ServletOps.errorBadRequest("Empty URI!"); - return; - } - else if (!PrefixUtils.uriIsValid(uri)) { - ServletOps.errorBadRequest("URI contains illegal characters!"); - return; - } - else { - //fetchPrefix - List prefixList =storage.fetchPrefix(uri); - JsonArray prefixJsonArray = new JsonArray(); - for (String p : prefixList) { - com.google.gson.JsonObject jsonObject2 = new com.google.gson.JsonObject(); - jsonObject2.addProperty("prefix", p); - jsonObject2.addProperty("uri", uri); - prefixJsonArray.add(jsonObject2); - FmtLog.info(action.log, "[%d] - %s", action.id, new JsonObject(p, uri)); - } - // Build the response. - action.setResponseContentType(WebContent.contentTypeJSON); - action.getResponseOutputStream().print(String.valueOf(prefixJsonArray)); - // Indicate success - transactional.commit(); - ServletOps.success(action); - transactional.end(); - return; - } - } - - } catch (RuntimeException | IOException ex) { - try { transactional.abort(); } - catch (Throwable th ) { - FmtLog.warn(action.log, th, "[%d] GET prefix = %s", action.id); - } - ServletOps.errorOccurred(ex); - } finally { - transactional.end(); - } - } - - @Override - public void doPost (HttpAction action) { - validatePost(action); - Transactional transactional = storage.transactional(); - - transactional.begin(TxnType.WRITE); - try { - String prefix = action.getRequestParameter("prefix"); - String uri = action.getRequestParameter("uri"); - - if(prefix.isEmpty()) { - String prefixToRemove = action.getRequestParameter("removeprefix"); - storage.removePrefix(prefixToRemove); - FmtLog.info(action.log, "[%d] Remove %s:", action.id, prefix); - } - else { - storage.updatePrefix(prefix, uri); - FmtLog.info(action.log, "[%d] Set %s: <%s>", action.id, prefix, uri); - } - transactional.commit(); - - // Build the response. - action.setResponseContentType(WebContent.contentTypeJSON); - action.getResponseOutputStream().print(""); - // Indicate success - ServletOps.success(action); - } catch (RuntimeException | IOException ex) { - try { transactional.abort(); } - catch (Throwable th ) { - FmtLog.warn(action.log, th, "[%d] POST prefix = %s", action.id); - } - ServletOps.errorOccurred(ex); - } finally { - transactional.end(); - } + protected PrefixesAccess prefixes(HttpAction action) { + return storage; } } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixUtils.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixUtils.java index efea16f4dcf..8512ad6c522 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixUtils.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixUtils.java @@ -18,31 +18,36 @@ package org.apache.jena.fuseki.servlets.prefixes; -import org.apache.jena.irix.IRIx; - +import java.util.Set; import java.util.regex.Pattern; +import org.apache.jena.irix.IRIx; + public class PrefixUtils { public static final String PREFIX = "prefix" ; public static final String URI = "uri" ; - public static final String REMOVEPREFIX = "removeprefix" ; + public static final Set PARAMS = Set.of(PREFIX, URI); private PrefixUtils() {} private static final Pattern regex = Pattern.compile("\\p{Alpha}([\\w.-]*\\w)?"); + public static boolean isPrefixesParam(String param) { + return PARAMS.contains(param); + } + public static boolean prefixIsValid(String prefix) { + if ( prefix.isEmpty() ) + return true; return regex.matcher(prefix).matches(); } public static boolean uriIsValid(String uri) { - boolean valid; try { IRIx iri = IRIx.create(uri); - valid = iri.isReference(); + return iri.isReference(); } catch (Exception ex) { - valid = false; + return false; } - return valid; } } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesMap.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesMap.java index 12f10467d03..56d26ebe3ba 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesMap.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesMap.java @@ -26,6 +26,12 @@ import org.apache.jena.riot.system.PrefixMap; import org.apache.jena.sparql.core.Transactional; +/** + * {@link PrefixesAccess} implementation using a {@link PrefixMap}. + * This is the implementation used by {@link ActionPrefixesBase} + * which forms the way the prefixes operation is added to a Fuseki + * service. + */ public class PrefixesMap implements PrefixesAccess { private final PrefixMap prefixMap; private final Transactional transactional; diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesPlain.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesPlain.java index fe260ffe66a..43d79b4127e 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesPlain.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesPlain.java @@ -25,7 +25,10 @@ import org.apache.jena.sparql.core.Transactional; import org.apache.jena.sparql.core.TransactionalLock; - +/** + * {@link PrefixesAccess} implementation using an in-memory + * {@code ConcurrentHashMap}. + */ public class PrefixesPlain implements PrefixesAccess { private final TransactionalLock transactional; private Map pairs = new ConcurrentHashMap<>(); diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesRDF.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesRDF.java index d48b791ccb5..920ba8207e8 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesRDF.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/PrefixesRDF.java @@ -35,9 +35,13 @@ import org.apache.jena.tdb2.DatabaseMgr; /** - * The prefix-URI mappings are represented in blank nodes of type Prefix, with prefixName and prefixURI attributes. - * The prefixName and prefixURI of the same node are a distinct prefix-URI mapping. + * {@link PrefixesAccess} implementation using a dedicated {@link DatasetGraph} the + * record the prefixes in an RDF format. + *

+ * The prefix-URI mappings are represented in blank nodes of type Prefix, with + * prefixName and prefixURI attributes. * + *

  * PREFIX prefixes: 
  * PREFIX rdf:      
  * PREFIX xsd:      
@@ -51,6 +55,7 @@
  *   prefixes:prefixName   "ns" ;
  *   prefixes:prefixURI    "http://example/namespace#"^^xsd:anyURI
  * ]
+ * 
*/ public class PrefixesRDF implements PrefixesAccess { @@ -62,7 +67,6 @@ public class PrefixesRDF implements PrefixesAccess { @Override public Optional fetchURI(String prefix) { - ParameterizedSparqlString pss = new ParameterizedSparqlString( """ PREFIX prefixes: @@ -74,24 +78,21 @@ public Optional fetchURI(String prefix) { ); pss.setLiteral("prefixName", prefix); String query = pss.toString(); - - - try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { - - RowSet rowSet = qExec.select(); - List x = new ArrayList(); - - rowSet.forEachRemaining(row -> { - String prefixNameLiteral = row.get("prefixURI").getLiteralLexicalForm(); - if (prefixNameLiteral != null) { - x.add(prefixNameLiteral); - } - }); - if (x.isEmpty()) - return Optional.empty(); - //originally x.getFirst() - return Optional.ofNullable(x.get(0)); - } + return dataset.calculateRead(() -> { + try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { + List x = new ArrayList(); + RowSet rowSet = qExec.select(); + rowSet.forEachRemaining(row -> { + String prefixNameLiteral = row.get("prefixURI").getLiteralLexicalForm(); + if ( prefixNameLiteral != null ) { + x.add(prefixNameLiteral); + } + }); + if (x.isEmpty()) + return Optional.empty(); + return Optional.ofNullable(x.get(0)); + } + }); } @Override @@ -108,12 +109,11 @@ public void updatePrefix(String prefix, String uri) { pss.setLiteral("prefixName", prefix); String query = pss.toString(); - try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { - + dataset.executeWrite(()->{ AtomicBoolean result = new AtomicBoolean(false); - dataset.executeRead(()->{ + try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { result.set(qExec.ask()); - }); + } String update; ParameterizedSparqlString pssUpdate; @@ -136,24 +136,21 @@ public void updatePrefix(String prefix, String uri) { else { pssUpdate = new ParameterizedSparqlString( """ - PREFIX prefixes: - PREFIX xsd: - PREFIX rdf: - INSERT DATA { - [] rdf:type prefixes:Prefix ; - prefixes:prefixName ?prefixName ; - prefixes:prefixURI ?newURI - } - """); + PREFIX prefixes: + PREFIX xsd: + PREFIX rdf: + INSERT DATA { + [] rdf:type prefixes:Prefix ; + prefixes:prefixName ?prefixName ; + prefixes:prefixURI ?newURI + } + """); pssUpdate.setLiteral("prefixName", prefix); pssUpdate.setLiteral("newURI", uri, XSDDatatype.XSDanyURI); update = pssUpdate.toString(); } UpdateExec.dataset(dataset).update(update).execute(); - } - catch (RuntimeException e) { - throw new RuntimeException(e); - } + }); } @Override @@ -166,7 +163,9 @@ public void removePrefix(String prefixToRemove) { ); pss.setLiteral("prefixName", prefixToRemove); String update = pss.toString(); - UpdateExec.dataset(dataset).update(update).execute(); + dataset.executeWrite(()->{ + UpdateExec.dataset(dataset).update(update).execute(); + }); } @Override @@ -179,20 +178,19 @@ public Map getAll() { ?X prefixes:prefixURI ?prefixURI } """; - - try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { - - RowSet rowSet = qExec.select(); + return dataset.calculateRead(()->{ Map allPairs = new ConcurrentHashMap<>(); - rowSet.forEachRemaining(row -> { - String prefixNameLiteral = row.get("prefixName").getLiteralLexicalForm(); - String prefixURILiteral = row.get("prefixURI").getLiteralLexicalForm(); - if (prefixNameLiteral != null && prefixURILiteral != null) { - allPairs.put(prefixNameLiteral, prefixURILiteral); - } - }); - return allPairs; - } + try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { + RowSet rowSet = qExec.select(); + rowSet.forEachRemaining(row -> { + String prefixNameLiteral = row.get("prefixName").getLiteralLexicalForm(); + String prefixURILiteral = row.get("prefixURI").getLiteralLexicalForm(); + if (prefixNameLiteral != null && prefixURILiteral != null) + allPairs.put(prefixNameLiteral, prefixURILiteral); + }); + return allPairs; + } + }); } @Override @@ -208,20 +206,20 @@ public List fetchPrefix(String uri) { """); pss.setLiteral("uriName", uri, XSDDatatype.XSDanyURI); String query = pss.toString(); + return dataset.calculateRead(()->{ + try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { - try (QueryExec qExec = QueryExec.dataset(dataset).query(query).build()) { + RowSet rowSet = qExec.select(); + List prefixes = new ArrayList(); - RowSet rowSet = qExec.select(); - List prefixes = new ArrayList(); - - rowSet.forEachRemaining(row -> { - String prefixNameLiteral = row.get("prefixName").getLiteralLexicalForm(); - if (prefixNameLiteral != null) { - prefixes.add(prefixNameLiteral); - } - }); + rowSet.forEachRemaining(row -> { + String prefixNameLiteral = row.get("prefixName").getLiteralLexicalForm(); + if (prefixNameLiteral != null) { + prefixes.add(prefixNameLiteral); + } + }); - return prefixes; - } + return prefixes; + }}); } } diff --git a/jena-fuseki2/jena-fuseki-main/src/test/files/config-prefixes-empty.ttl b/jena-fuseki2/jena-fuseki-main/src/test/files/config-prefixes-empty.ttl new file mode 100644 index 00000000000..80144337173 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/files/config-prefixes-empty.ttl @@ -0,0 +1,22 @@ +## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 + +PREFIX : <#> +PREFIX fuseki: +PREFIX rdf: +PREFIX ja: +PREFIX tdb2: + +:service rdf:type fuseki:Service ; + fuseki:name "dataset" ; + fuseki:endpoint [ fuseki:operation fuseki:query ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:update ; ] ; + + fuseki:endpoint [ fuseki:operation fuseki:prefixes-r ; fuseki:name "prefixes" ] ; + fuseki:endpoint [ fuseki:operation fuseki:prefixes-rw ; fuseki:name "prefixes-rw" ] ; + fuseki:dataset :dataset ; + . + +## No initial data or prefixes. +# Transactional in-memory dataset. +:dataset rdf:type ja:MemoryDataset ; + . diff --git a/jena-fuseki2/jena-fuseki-main/src/test/files/config-prefixes.ttl b/jena-fuseki2/jena-fuseki-main/src/test/files/config-prefixes.ttl new file mode 100644 index 00000000000..ce931244ca0 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/files/config-prefixes.ttl @@ -0,0 +1,22 @@ +## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 + +PREFIX : <#> +PREFIX fuseki: +PREFIX rdf: +PREFIX ja: +PREFIX tdb2: + +:service rdf:type fuseki:Service ; + fuseki:name "dataset" ; + fuseki:endpoint [ fuseki:operation fuseki:query ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:update ; ] ; + + fuseki:endpoint [ fuseki:operation fuseki:prefixes-r ; fuseki:name "prefixes" ] ; + fuseki:endpoint [ fuseki:operation fuseki:prefixes-rw ; fuseki:name "prefixes-rw" ] ; + fuseki:dataset :dataset ; + . + +# Transactional in-memory dataset. +:dataset rdf:type ja:MemoryDataset ; + ja:data ; + . diff --git a/jena-fuseki2/jena-fuseki-main/src/test/files/data.trig b/jena-fuseki2/jena-fuseki-main/src/test/files/data.trig new file mode 100644 index 00000000000..d925071c485 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/files/data.trig @@ -0,0 +1,6 @@ +## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 + +PREFIX prefix1: +PREFIX prefix2: + +prefix1:s prefix2:p "abc" . diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java index f9a44c60305..78b902b6705 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java @@ -47,17 +47,13 @@ , TestAuthUpdate_JDK.class , TestHttpOperations.class , TestHttpOptions.class - , TestQuery.class , TestSPARQLProtocol.class , TestPatchFuseki.class , TestFusekiCustomScriptFunc.class - , TestPrefixesService.class - , TestPrefixesServicePlain.class - , TestPrefixesServiceRDF.class - , TestPrefixesServicePrefixesMap.class + , PrefixesServiceTests.class , TestMetrics.class , TestFusekiShaclValidation.class diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl deleted file mode 100644 index f46a1d7d702..00000000000 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl +++ /dev/null @@ -1,24 +0,0 @@ -## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 - -PREFIX fuseki: -PREFIX rdf: -PREFIX : <#> -PREFIX ja: -PREFIX tdb2: - - -:service rdf:type fuseki:Service ; - fuseki:name "dataset" ; - fuseki:endpoint [ fuseki:operation fuseki:query ; ] ; - fuseki:endpoint [ fuseki:operation fuseki:update ; ] ; - - fuseki:endpoint [ fuseki:operation fuseki:prefixes-r ; fuseki:name "prefixes" ] ; - fuseki:endpoint [ fuseki:operation fuseki:prefixes-ws ; fuseki:name "updatePrefixes" ] ; - fuseki:dataset :dataset ; - . - -# Transactional in-memory dataset. -:dataset rdf:type ja:MemoryDataset ; - ja:data "src/test/java/org/apache/jena/fuseki/main/files/data-test.trig"; - . - \ No newline at end of file diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/data-test.trig b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/data-test.trig deleted file mode 100644 index fc613821fe1..00000000000 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/files/data-test.trig +++ /dev/null @@ -1 +0,0 @@ -## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestAbstractPrefixParam.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/AbstractTestPrefixes.java similarity index 58% rename from jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestAbstractPrefixParam.java rename to jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/AbstractTestPrefixes.java index 6c4955c6bdc..faf40b08e7a 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestAbstractPrefixParam.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/AbstractTestPrefixes.java @@ -18,68 +18,49 @@ package org.apache.jena.fuseki.main.prefixes; -import com.google.gson.*; -import org.apache.jena.atlas.web.HttpException; -import org.apache.jena.fuseki.main.FusekiServer; -import org.apache.jena.fuseki.servlets.prefixes.ActionProcPrefixes; -import org.apache.jena.fuseki.servlets.prefixes.PrefixesAccess; -import org.apache.jena.sparql.exec.http.Params; -import org.apache.jena.web.HttpSC; -import org.junit.jupiter.api.*; - -import java.util.HashSet; -import java.util.Set; - import static org.apache.jena.http.HttpOp.httpGetString; import static org.apache.jena.http.HttpOp.httpPostForm; +import static org.apache.jena.riot.WebContent.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public abstract class TestAbstractPrefixParam { - - private final PrefixesAccess prefixes; +import java.util.HashSet; +import java.util.Set; - public TestAbstractPrefixParam(PrefixesAccess storage) { - this.prefixes = storage; - } +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; - private FusekiServer server = null; - private String serviceURL = null; - private static final String serviceToFormatURL = "http://localhost:%d/prefixes"; +import org.apache.jena.atlas.web.HttpException; +import org.apache.jena.http.HttpOp; +import org.apache.jena.sparql.exec.http.Params; +import org.apache.jena.web.HttpSC; +import org.junit.jupiter.api.Test; - @BeforeEach - public void before() { - server = FusekiServer.create() - .port(0) - .addProcessor("/prefixes", new ActionProcPrefixes(prefixes)) - .build(); - server.start(); - serviceURL = String.format(serviceToFormatURL, server.getHttpPort()); - } +/** The tests to run. */ +public abstract class AbstractTestPrefixes { - @AfterEach - public void afterSuite() { - if ( server != null ) - server.stop(); - } + protected abstract String testReadURL(); + protected abstract String testWriteURL(); // FETCH URI tests // --------------------------------------------------------------------------------------------- + // UPDATE URI tests + // --------------------------------------------------------------------------------------------- + @Test public void fetchURILegal() { // request legal, prefix does not exist implies return "" - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix=abc"); - assertEquals("", x, "Expected empty string"); + testGetByPrefix(testReadURL(), "?prefix=abc", + "{}", ""); } @Test public void fetchURIBadArgument() { // Bad argument, 400 bad request exception expected HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?junk"); + String x = execGet(testReadURL(), "?junk"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -88,8 +69,7 @@ public void fetchURIBadArgument() { public void fetchURIEmptyPrefix0() { // Empty prefix, 400 bad request exception expected HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix="); + String x = execGet(testReadURL(), "?prefix="); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -98,8 +78,7 @@ public void fetchURIEmptyPrefix0() { public void fetchURIEmptyPrefix1() { // Empty prefix, 400 bad request exception expected HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix"); + String x = execGet(testReadURL(), "?prefix", contentTypeJSON); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -108,57 +87,62 @@ public void fetchURIEmptyPrefix1() { public void fetchURIIllegalChars0() { // illegal prefix, 400 bad request exception expected HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix=pr."); + String x = execGet(testReadURL(), "?prefix=pr.", contentTypeJSON); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } -// UPDATE URI tests -// --------------------------------------------------------------------------------------------- + // UPDATE URI tests + // --------------------------------------------------------------------------------------------- @Test public void updateURINewLegal0() { // valid new prefix, valid new uri, implies return uri3 - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix3", "http://www.localhost.org/uri3", null); - String x = exec(url, "?prefix=prefix3"); - assertEquals("http://www.localhost.org/uri3", x, "Expected http://www.localhost.org/uri3 got " + x); + execPost(testWriteURL(), "prefix3", "http://www.localhost.org/uri3"); + + testGetByPrefix(testReadURL(), "?prefix=prefix3", + "{\"prefix\":\"prefix3\",\"uri\":\"http://www.localhost.org/uri3\"}", + "http://www.localhost.org/uri3"); } @Test public void updateURINewLegal1() { // valid new prefix, existing uri, implies return uri3 - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix4", "http://www.localhost.org/uri3", null); - String x = exec(url, "?prefix=prefix4"); - assertEquals("http://www.localhost.org/uri3", x, "Expected http://www.localhost.org/uri3 got " + x); + execPost(testWriteURL(), "prefix4", "http://www.localhost.org/uri3"); + + testGetByPrefix(testReadURL(), "?prefix=prefix4", + "{\"prefix\":\"prefix4\",\"uri\":\"http://www.localhost.org/uri3\"}", + "http://www.localhost.org/uri3"); } @Test public void updateURINewLegal2() { // existing prefix, valid new uri, implies return uri7 - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix1", "http://www.localhost.org/uri7", null); - String x = exec(url, "?prefix=prefix1"); - assertEquals("http://www.localhost.org/uri7", x, "Expected http://www.localhost.org/uri7 got " + x); + + execPost(testWriteURL(), "prefix1", "http://www.localhost.org/uri6"); + execPost(testWriteURL(), "prefix1", "http://www.localhost.org/uri7"); + + testGetByPrefix(testReadURL(), "?prefix=prefix1", + "{\"prefix\":\"prefix1\",\"uri\":\"http://www.localhost.org/uri7\"}", + "http://www.localhost.org/uri7"); } @Test public void updateURINewLegal3() { // existing prefix, existing uri, implies return uri2 - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix2", "http://www.localhost.org/uri2", null); - String x = exec(url, "?prefix=prefix2"); - assertEquals("http://www.localhost.org/uri2", x, "Expected http://www.localhost.org/uri2 got " + x); + execPost(testWriteURL(), "prefix2", "http://www.localhost.org/uri2"); + execPost(testWriteURL(), "prefix2", "http://www.localhost.org/uri2"); + + testGetByPrefix(testReadURL(), "?prefix=prefix2", + "{\"prefix\":\"prefix2\",\"uri\":\"http://www.localhost.org/uri2\"}", + "http://www.localhost.org/uri2"); } @Test public void updateValidNewPrefixInvalidURI() { HttpException ex = assertThrows(HttpException.class, ()->{ //valid new prefix, invalid uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix4", "-.-", null); + execPost(testWriteURL(), "prefix4", "-.-"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -167,18 +151,16 @@ public void updateValidNewPrefixInvalidURI() { public void updateValidNewPrefixEmptyURI() { HttpException ex = assertThrows(HttpException.class, ()->{ //valid new prefix, empty uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix4", "", ""); + execPost(testWriteURL(), "prefix4", ""); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @Test - public void updateValidNewPrefixNullURI() { + public void updateValidNewPrefixNoURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // valid new prefix, null uri (bad argument), 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix4", null, ""); + execPost(testWriteURL(), "?prefix=prefix4", null); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -187,8 +169,7 @@ public void updateValidNewPrefixNullURI() { public void updateExistingPrefixInvalidURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // existing prefix, invalid uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix1", "http:abc", ""); + execPost(testWriteURL(), "prefix1", "http:abc"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -197,8 +178,8 @@ public void updateExistingPrefixInvalidURI() { public void updateExistingPrefixEmptyURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // existing prefix, empty uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix1", "", ""); + + execPost(testWriteURL(), "prefix1", ""); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -207,8 +188,8 @@ public void updateExistingPrefixEmptyURI() { public void updateExistingPrefixNullURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // existing prefix null uri (bad argument), 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix1", null, ""); + + execPost(testWriteURL(), "prefix1", null); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -217,8 +198,8 @@ public void updateExistingPrefixNullURI() { public void updateInvalidPrefixNewValidURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // invalid prefix, valid new uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix..-", "http://www.localhost.org/uri7", ""); + + execPost(testWriteURL(), "prefix..-", "http://www.localhost.org/uri7"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -227,8 +208,8 @@ public void updateInvalidPrefixNewValidURI() { public void updateInvalidPrefixExistingURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // invalid prefix, existing uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "-refix..1", "http://www.localhost.org/uri1", ""); + + execPost(testWriteURL(), "-refix..1", "http://www.localhost.org/uri1"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -237,8 +218,8 @@ public void updateInvalidPrefixExistingURI() { public void updateInvalidPrefixInvalidURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // invalid prefix, invalid uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "-", "http://", ""); + + execPost(testWriteURL(), "-", "http://"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -247,8 +228,8 @@ public void updateInvalidPrefixInvalidURI() { public void updateInvalidPrefixEmptyURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // invalid prefix, empty uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "p/p", "", ""); + + execPost(testWriteURL(), "p/p", ""); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -257,8 +238,8 @@ public void updateInvalidPrefixEmptyURI() { public void updateInvalidPrefixNullURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // invalid prefix, null uri (bad argument), 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "prefix..-", null, ""); + + execPost(testWriteURL(), "prefix..-", null); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -267,48 +248,48 @@ public void updateInvalidPrefixNullURI() { public void updateEmptyPrefixValidNewURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // invalid prefix, valid new uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "", "http://www.localhost.org/uri5", ""); + + execPost(testWriteURL(), "", "http://www.localhost.org/uri5"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @Test public void updateEmptyPrefixExistingURI() { - String url = String.format(serviceURL, server.getHttpPort()); + // empty prefix, existing uri, 400 bad request exception expected HttpException ex = assertThrows(HttpException.class, ()->{ - execPost(url, "", "http://www.localhost.org/uri1", ""); + execPost(testWriteURL(), "", "http://www.localhost.org/uri1"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @Test public void updateEmptyPrefixEInvalidURI() { - String url = String.format(serviceURL, server.getHttpPort()); + // empty prefix, invalid uri, 400 bad request exception expected HttpException ex = assertThrows(HttpException.class, ()->{ - execPost(url, "", "http:abcur..i1", ""); + execPost(testWriteURL(), "", "http:abcur..i1"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @Test public void updateEmptyPrefixEmptyURI() { - String url = String.format(serviceURL, server.getHttpPort()); + // empty prefix, empty uri, 400 bad request exception expected HttpException ex = assertThrows(HttpException.class, ()->{ - execPost(url, "", "", ""); + execPost(testWriteURL(), "", ""); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @Test public void updateEmptyPrefixNullURI() { - String url = String.format(serviceURL, server.getHttpPort()); + // empty prefix, null uri (bad argument), 400 bad request exception expected HttpException ex = assertThrows(HttpException.class, ()->{ - execPost(url, "", null, ""); + execPost(testWriteURL(), "", null); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -317,8 +298,8 @@ public void updateEmptyPrefixNullURI() { public void updateNullPrefixValidNewURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // null prefix (bad argument), valid new uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, null, "http://www.localhost.org/uri6", ""); + + execPost(testWriteURL(), null, "http://www.localhost.org/uri6"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -327,8 +308,8 @@ public void updateNullPrefixValidNewURI() { public void updateNullPrefixExistingURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // null prefix (bad argument), existing uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, null, "http://www.localhost.org/uri1", null); + + execPost(testWriteURL(), null, "http://www.localhost.org/uri1"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -337,8 +318,8 @@ public void updateNullPrefixExistingURI() { public void updateNullPrefixInValidURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // null prefix (bad argument), invalid uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, null, "...", null); + + execPost(testWriteURL(), null, "..."); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -347,8 +328,8 @@ public void updateNullPrefixInValidURI() { public void updateNullPrefixEmptyURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // null prefix (bad argument), empty uri, 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, null, "", ""); + + execPost(testWriteURL(), null, ""); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -357,63 +338,57 @@ public void updateNullPrefixEmptyURI() { public void updateNullPrefixNullURI() { HttpException ex = assertThrows(HttpException.class, ()->{ // null prefix (bad argument), null uri (bad argument), 400 bad request exception expected - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, null, null, null); + + execPost(testWriteURL(), null, null); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } - -// REMOVE URI tests -// --------------------------------------------------------------------------------------------- + // DELETE URI tests + // --------------------------------------------------------------------------------------------- @Test - public void removeURI0() { + public void deleteURI0() { // request legal, prefix exists, implies return null - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, null, null, "prefix1"); - String x = exec(url, "?prefix=prefix1"); - assertEquals("", x, "Expected null got " + x); + + execDelete(testWriteURL(), "prefix1"); + String x = execGet(testReadURL(), "?prefix=prefix1", contentTypeTextPlain); + assertEquals("", x, "Expected empty string got " + x); } @Test - public void removeURI1() { + public void deleteURI1() { // request legal, prefix doesn't exist implies return null - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, null, null, "prefix16"); - String x = exec(url, "?prefix=prefix16"); - assertEquals("", x, "Expected null got " + x); + execDelete(testWriteURL(), "prefix16"); + testGetByPrefix(testReadURL(), "?prefix=prefix16", "{}", ""); } @Test - public void removeURI2() { + public void deleteURI2() { // request illegal, prefix invalid, 400 bad request exception expected HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, null, null, "prefix16-"); + execDelete(testWriteURL(), "prefix16-"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @Test - public void removeURI3() { + public void deleteURI3() { // request legal, prefix exists implies return null - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, null, null, "prefix2"); - String x = exec(url, "?prefix=prefix2"); - assertEquals("", x, "Expected null got " + x); + execDelete(testWriteURL(), "prefix2"); + testGetByPrefix(testReadURL(), "?prefix=prefix2", "{}", ""); } -// GET All tests -// --------------------------------------------------------------------------------------------- + // GET All tests + // --------------------------------------------------------------------------------------------- @Test public void getAllLegal() { // request legal, returns multiple prefix-uri pairs - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "test", "http://www.localhost.org/uritest", null); - execPost(url, "test2", "http://www.localhost.org/uritest2", null); - execPost(url, "test3", "http://www.localhost.org/uritest3", null); - String x = exec(url, ""); + + execPost(testWriteURL(), "test", "http://www.localhost.org/uritest"); + execPost(testWriteURL(), "test2", "http://www.localhost.org/uritest2"); + execPost(testWriteURL(), "test3", "http://www.localhost.org/uritest3"); + String x = execGet(testReadURL(), ""); // convert to set Set set = new HashSet<>(); @@ -432,30 +407,28 @@ public void getAllLegal() { @Test public void getAllEmpty() { // request legal, dataset empty implies return [] - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, ""); + String x = execGet(testReadURL(), ""); assertEquals("[]", x, "Expected prefix"); } -// FETCH PREFIX tests -// --------------------------------------------------------------------------------------------- + // FETCH PREFIX tests + // --------------------------------------------------------------------------------------------- @Test public void fetchPrefixLegal() { // request legal, uri exists in the database with a single prefix assigned - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "test", "http://www.localhost.org/uritest", null); - String x = exec(url, "?uri=http://www.localhost.org/uritest"); + execPost(testWriteURL(), "test", "http://www.localhost.org/uritest"); + String x = execGet(testReadURL(), "?uri=http://www.localhost.org/uritest"); assertEquals("[{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}]", x, "Expected prefix"); } @Test public void fetchPrefixLegalMultiple() { // request legal, uri exists in the database with multiple prefixes assigned - String url = String.format(serviceURL, server.getHttpPort()); - execPost(url, "test", "http://www.localhost.org/uritest", null); - execPost(url, "testDuplicate", "http://www.localhost.org/uritest", null); - String x = exec(url, "?uri=http://www.localhost.org/uritest"); + + execPost(testWriteURL(), "test", "http://www.localhost.org/uritest"); + execPost(testWriteURL(), "testDuplicate", "http://www.localhost.org/uritest"); + String x = execGet(testReadURL(), "?uri=http://www.localhost.org/uritest"); // convert to set Set set = new HashSet<>(); @@ -473,8 +446,8 @@ public void fetchPrefixLegalMultiple() { @Test public void fetchPrefixLegalNull() { // request legal, uri does not exist implies return [] - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?uri=http://www.localhost.org/uritest"); + + String x = execGet(testReadURL(), "?uri=http://www.localhost.org/uritest"); assertEquals("[]", x, "Expected prefix"); } @@ -482,8 +455,8 @@ public void fetchPrefixLegalNull() { public void fetchPrefixIllegal() { // request illegal, uri is not valid HttpException ex = assertThrows(HttpException.class, ()-> { - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?uri=----localhost.org/uritest"); + + String x = execGet(testReadURL(), "?uri=----localhost.org/uritest"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -492,8 +465,8 @@ public void fetchPrefixIllegal() { public void fetchPrefixEmpty() { // request illegal, uri is empty HttpException ex = assertThrows(HttpException.class, ()-> { - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?uri="); + + String x = execGet(testReadURL(), "?uri="); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } @@ -502,26 +475,58 @@ public void fetchPrefixEmpty() { public void tooManyParams() { // request illegal, provided too many arguments HttpException ex = assertThrows(HttpException.class, ()-> { - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix=abc&uri=http://www.localhost.org/uritest"); + + String x = execGet(testReadURL(), "?prefix=abc&uri=http://www.localhost.org/uritest"); }); assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); } -// --------------------------------------------------------------------------------------------- + // --------------------------------------------------------------------------------------------- - private static String exec(String url, String queryString) { + private static String execGet(String url, String queryString) { + return execGet(url, queryString, contentTypeJSON); + } + private static String execGet(String url, String queryString, String acceptHeader) { String urlExec = queryString.startsWith("?") ? url + queryString : url + "?" + queryString; - return httpGetString(urlExec); + return acceptHeader != null + ? httpGetString(urlExec, acceptHeader) + : httpGetString(urlExec); + } + private static void execPost(String url, String prefix, String uri) { + Params params = Params.create().add("prefix", prefix); + if ( uri != null ) + params.add("uri", uri); + httpPostForm(url, params); + } + private static void execDelete(String url, String prefix) { + String urlExec = url+"?prefix="+prefix; + HttpOp.httpDelete(urlExec); + } + private static void assertEqualsJson(String expectedStr, String actualStr, String msg) { + JsonElement expected = JsonParser.parseString(expectedStr); + JsonElement actual = JsonParser.parseString(expectedStr); + assertEquals(actual, expected, msg); } - private static void execPost(String url, String prefix, String uri, String prefixToRemove) { - Params params = Params.create() - .add("prefix", prefix) - .add("uri", uri) - .add("removeprefix", prefixToRemove); - httpPostForm(url, params); + // FETCH URI tests + // --------------------------------------------------------------------------------------------- + + // UPDATE URI tests + // --------------------------------------------------------------------------------------------- + + // test the results of a GET by prefix with both plain text and json. + private void testGetByPrefix(String testReadURL, String prefixString, String expectedJSON, String expectedText) { + testGetByPrefixJSON(testReadURL, prefixString, expectedJSON); + testGetByPrefixText(testReadURL, prefixString, expectedText); + } + private void testGetByPrefixJSON(String testReadURL, String prefixString, String expectedJSON) { + String x1 = execGet(testReadURL(), prefixString, contentTypeJSON); + assertEqualsJson(expectedJSON, x1, "Expected '" + expectedJSON + "' got '" + x1 + "'"); + } + private void testGetByPrefixText(String testReadURL, String prefixString, String expectedText) { + String x2 = execGet(testReadURL(), prefixString, contentTypeTextPlain); + assertEquals(expectedText, x2, "Expected '" + expectedText + "' got " + x2 + "'"); } } diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/AbstractTestPrefixesImpl.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/AbstractTestPrefixesImpl.java new file mode 100644 index 00000000000..a66f66840fc --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/AbstractTestPrefixesImpl.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main.prefixes; + +import org.apache.jena.fuseki.main.FusekiServer; +import org.apache.jena.fuseki.servlets.prefixes.ActionProcPrefixes; +import org.apache.jena.fuseki.servlets.prefixes.PrefixesAccess; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +/** + * Tests setup to test {@link PrefixesAccess} as standalone implementations. + */ +public abstract class AbstractTestPrefixesImpl extends AbstractTestPrefixes { + + private final PrefixesAccess prefixes; + + public AbstractTestPrefixesImpl(PrefixesAccess storage) { + this.prefixes = storage; + } + + private FusekiServer server = null; + private String serviceURL = null; + private static final String serviceToFormatURL = "http://localhost:%d/prefixes"; + + @BeforeEach + public void before() { + server = FusekiServer.create() + .port(0) + .addProcessor("/prefixes", new ActionProcPrefixes(prefixes)) + .build(); + server.start(); + serviceURL = String.format(serviceToFormatURL, server.getHttpPort()); + } + + @AfterEach + public void afterSuite() { + if ( server != null ) + server.stop(); + } + + @Override + protected String testReadURL() { + return serviceURL; + } + + @Override + protected String testWriteURL() { + return serviceURL; + } + +} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/JsonObjectTests.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/JsonObjectTests.java deleted file mode 100644 index 3189b14d4a1..00000000000 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/JsonObjectTests.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jena.fuseki.main.prefixes; - -import com.google.gson.Gson; -import org.apache.jena.atlas.web.TypedInputStream; -import org.apache.jena.fuseki.main.FusekiServer; -import org.apache.jena.fuseki.servlets.prefixes.ActionProcPrefixes; -import org.apache.jena.fuseki.servlets.prefixes.JsonObject; -import org.apache.jena.fuseki.servlets.prefixes.PrefixesPlain; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.apache.jena.http.HttpOp.*; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class JsonObjectTests { - - private static FusekiServer server = null; - private static String serviceURL = null; - - @BeforeAll - public static void beforeSuite() { - PrefixesPlain s = new PrefixesPlain(); - server = FusekiServer.create() - .port(0) - .addProcessor("/prefixes", new ActionProcPrefixes(s)) - .build(); - server.start(); - serviceURL = String.format("http://localhost:%d/prefixes", server.getHttpPort()); - } - - @AfterAll - public static void afterSuite() { - if ( server != null ) - server.stop(); - } - - - @Test - public void fetchURIllegal0() { - // check content type - TypedInputStream x = exec(serviceURL, "?prefix=prefix2"); - assertEquals("application/json", x.getContentType(), "Expected application/json"); - } - - - @Test - public void stringJsonObject0() { - JsonObject jsonObject = new JsonObject("prefix1", "http://www.localhost.org/uri1"); - Gson gson = new Gson(); - String x = gson.toJson(jsonObject); - assertEquals("{\"prefix\":\"prefix1\",\"namespace\":\"http://www.localhost.org/uri1\"}", x, "Got " + x); - } - - @Test - public void fieldsJsonObject0() { - JsonObject jsonObject = new JsonObject("prefix1", "http://www.localhost.org/uri1"); - assertEquals("prefix1", jsonObject.prefix()); - assertEquals("http://www.localhost.org/uri1", jsonObject.namespace()); - } - - private static TypedInputStream exec(String url, String queryString) { - String urlExec = queryString.startsWith("?") - ? url + queryString - : url + "?" + queryString; - return httpGet(urlExec); - } - -} diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/JsonObject.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/PrefixesServiceTests.java similarity index 67% rename from jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/JsonObject.java rename to jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/PrefixesServiceTests.java index 6b530e89638..20c45c9479f 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/prefixes/JsonObject.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/PrefixesServiceTests.java @@ -16,6 +16,18 @@ * limitations under the License. */ -package org.apache.jena.fuseki.servlets.prefixes; +package org.apache.jena.fuseki.main.prefixes; -public record JsonObject(String prefix, String namespace) {} +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; + +@Suite +@SelectClasses({ + TestPrefixesActions.class + , TestPrefixesServicePlain.class + , TestPrefixesServiceRDF.class + , TestPrefixesServicePrefixesMap.class + , TestPrefixesActionResponse.class + +}) +public class PrefixesServiceTests {} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesActionResponse.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesActionResponse.java new file mode 100644 index 00000000000..27ee9b16a8d --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesActionResponse.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main.prefixes; + +import static org.apache.jena.http.HttpOp.httpGet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.apache.jena.atlas.io.IO; +import org.apache.jena.atlas.web.TypedInputStream; +import org.apache.jena.fuseki.main.FusekiServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Test the prefixes service when used as Fuseki operations + * on a Fuseki service with a database. + */ +public class TestPrefixesActionResponse { + + private static FusekiServer server = null; + private static String serviceR = null; + + @BeforeAll + public static void beforeAll() { + String DATASET = "dataset"; + server = FusekiServer.create() + .port(0) + // With data. read-only. + .parseConfigFile("src/test/files/config-prefixes.ttl") + .start(); + int port = server.getHttpPort(); + serviceR = "http://localhost:"+port+"/"+DATASET+"/prefixes"; + } + + @AfterAll + public static void afterAll() { + if ( server != null ) + server.stop(); + } + + private String testReadURL() { + return serviceR; + } + + // Test JSON responses + + private record PrefixesEntry(String prefix, String namespace) {} + + @Test + public void getAllJson() { + TypedInputStream x = httpGet(testReadURL()); + assertEquals("application/json", x.getContentType(), "Expected application/json"); + String response = IO.readWholeFileAsUTF8(x); + // JSON array + JsonElement elt = JsonParser.parseString(response); + assertTrue(elt.isJsonArray()); + JsonArray array = elt.getAsJsonArray(); + assertEquals(2, array.size()); + + JsonObject x1 = array.get(0).getAsJsonObject(); + JsonObject x2 = array.get(1).getAsJsonObject(); + + String fPrefix0 = x1.get("prefix").getAsString(); + if ( fPrefix0.equals("prefix2") ) { + JsonObject tmp = x1; + x1 = x2; + x2 = tmp; + } + + testJSON(x1, "prefix1", "http://example/ns#"); + testJSON(x2, "prefix2", "http://example/namespace/"); + } + + private void testJSON(JsonObject jsonObj, String prefixValue, String uriValue) { + String fPrefix = jsonObj.get("prefix").getAsString(); + assertEquals(prefixValue, fPrefix); + String fURI = jsonObj.get("uri").getAsString(); + assertEquals(uriValue, fURI); + } + + @Test + public void getPrefixJson() { + TypedInputStream x = httpGet(testReadURL()+"?prefix=prefix1"); + //assertEquals("application/json", x.getContentType(), "Expected application/json"); + String response = IO.readWholeFileAsUTF8(x); + assertEquals("http://example/ns#", response); + } + + @Test + public void getPrefixNone() { + // check content type + TypedInputStream x = execStream(testReadURL(), "?prefix=noSuchPrefix"); + //assertEquals("application/json", x.getContentType(), "Expected application/json"); + String response = IO.readWholeFileAsUTF8(x); + assertTrue(response.isEmpty()); + } + + private static TypedInputStream execStream(String url, String queryString) { + String urlExec = queryString.startsWith("?") + ? url + queryString + : url + "?" + queryString; + return httpGet(urlExec); + } +} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesActions.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesActions.java new file mode 100644 index 00000000000..373a9b29e08 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesActions.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main.prefixes; + +import org.apache.jena.fuseki.main.FusekiServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +/** + * Test the prefixes service when used as Fuseki operations + * on a Fuseki service with a database. + */ +public class TestPrefixesActions extends AbstractTestPrefixes { + + private FusekiServer server = null; + private String serviceR = null; + private String serviceRW = null; + + @BeforeEach + public void beforeEach() { + String DATASET = "dataset"; + server = FusekiServer.create() + .port(0) + // Empty dataset every test start. + .parseConfigFile("src/test/files/config-prefixes-empty.ttl") + .start(); + + int port = server.getHttpPort(); + serviceR = "http://localhost:"+port+"/"+DATASET+"/prefixes"; + serviceRW = "http://localhost:"+port+"/"+DATASET+"/prefixes-rw"; + } + + @AfterEach + public void afterEach() { + if ( server != null ) + server.stop(); + } + + @Override + protected String testReadURL() { + return serviceR; + } + + @Override + protected String testWriteURL() { + return serviceRW; + } +} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesService.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesService.java deleted file mode 100644 index 1e3976b0ad7..00000000000 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesService.java +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jena.fuseki.main.prefixes; - -import static org.apache.jena.http.HttpOp.httpDelete; -import static org.apache.jena.http.HttpOp.httpGetString; -import static org.apache.jena.http.HttpOp.httpPostForm; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.util.HashSet; -import java.util.Set; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; - -import org.apache.jena.atlas.web.HttpException; -import org.apache.jena.fuseki.main.FusekiServer; -import org.apache.jena.fuseki.servlets.PrefixesService; -import org.apache.jena.sparql.exec.http.Params; -import org.apache.jena.web.HttpSC; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class TestPrefixesService { - - private FusekiServer server = null; - private String serviceURL = null; - String serviceUpdateURL = null; - - @BeforeEach - public void before() { - PrefixesService.init(); - String DATASET = "dataset"; - server = FusekiServer.create() - .port(0) - .parseConfigFile("src/test/java/org/apache/jena/fuseki/main/files/config-prefixes-test.ttl") - .start(); - - int port = server.getHttpPort(); - serviceURL = "http://localhost:"+port+"/"+DATASET+"/prefixes"; - serviceUpdateURL = "http://localhost:"+port+"/"+DATASET+"/updatePrefixes"; - } - - @AfterEach - public void afterSuite() { - if ( server != null ) - server.stop(); - } - -// FETCH URI tests -// --------------------------------------------------------------------------------------------- - - @Test - public void fetchURILegal() { - // request legal, prefix does not exist implies return "" - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix=abc"); - assertEquals("", x, "Expected empty string"); - } - - @Test - public void fetchURIBadArgument() { - // Bad argument, 400 bad request exception expected - HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?junk"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void fetchURIEmptyPrefix0() { - // Empty prefix, 400 bad request exception expected - HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix="); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void fetchURIEmptyPrefix1() { - // Empty prefix, 400 bad request exception expected - HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void fetchURIIllegalChars0() { - // illegal prefix, 400 bad request exception expected - HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix=pr."); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - -// UPDATE URI tests -// --------------------------------------------------------------------------------------------- - - @Test - public void updateURINewLegal0() { - // valid new prefix, valid new uri, implies return uri3 - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix3", "http://www.localhost.org/uri3"); - String x = exec(url, "?prefix=prefix3"); - assertEquals("http://www.localhost.org/uri3", x, "Expected http://www.localhost.org/uri3 got " + x); - } - - @Test - public void updateURINewLegal1() { - // valid new prefix, existing uri, implies return uri3 - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix4", "http://www.localhost.org/uri3"); - String x = exec(url, "?prefix=prefix4"); - assertEquals("http://www.localhost.org/uri3", x, "Expected http://www.localhost.org/uri3 got " + x); - } - - @Test - public void updateURINewLegal2() { - // existing prefix, valid new uri, implies return uri7 - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix1", "http://www.localhost.org/uri7"); - String x = exec(url, "?prefix=prefix1"); - assertEquals("http://www.localhost.org/uri7", x, "Expected http://www.localhost.org/uri7 got " + x); - } - - @Test - public void updateURINewLegal3() { - // existing prefix, existing uri, implies return uri2 - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix2", "http://www.localhost.org/uri2"); - String x = exec(url, "?prefix=prefix2"); - assertEquals("http://www.localhost.org/uri2", x, "Expected http://www.localhost.org/uri2 got " + x); - } - - @Test - public void updateValidNewPrefixInvalidURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - //valid new prefix, invalid uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix4", "-.-"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateValidNewPrefixEmptyURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - //valid new prefix, empty uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix4", ""); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateValidNewPrefixNullURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // valid new prefix, null uri (bad argument), 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix4", null); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateExistingPrefixInvalidURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // existing prefix, invalid uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix1", "http:abc"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateExistingPrefixEmptyURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // existing prefix, empty uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix1", ""); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateExistingPrefixNullURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // existing prefix null uri (bad argument), 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix1", null); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateInvalidPrefixNewValidURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // invalid prefix, valid new uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix..-", "http://www.localhost.org/uri7"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateInvalidPrefixExistingURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // invalid prefix, existing uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "-refix..1", "http://www.localhost.org/uri1"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateInvalidPrefixInvalidURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // invalid prefix, invalid uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "-", "http://"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateInvalidPrefixEmptyURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // invalid prefix, empty uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "p/p", ""); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateInvalidPrefixNullURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // invalid prefix, null uri (bad argument), 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "prefix..-", null); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateEmptyPrefixValidNewURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // invalid prefix, valid new uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, "", "http://www.localhost.org/uri5"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateEmptyPrefixExistingURI() { - String url = String.format(serviceUpdateURL, server.getHttpPort()); - // empty prefix, existing uri, 400 bad request exception expected - HttpException ex = assertThrows(HttpException.class, ()->{ - execPost(url, "", "http://www.localhost.org/uri1"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateEmptyPrefixEInvalidURI() { - String url = String.format(serviceUpdateURL, server.getHttpPort()); - // empty prefix, invalid uri, 400 bad request exception expected - HttpException ex = assertThrows(HttpException.class, ()->{ - execPost(url, "", "http:abcur..i1"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateEmptyPrefixEmptyURI() { - String url = String.format(serviceUpdateURL, server.getHttpPort()); - // empty prefix, empty uri, 400 bad request exception expected - HttpException ex = assertThrows(HttpException.class, ()->{ - execPost(url, "", ""); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateEmptyPrefixNullURI() { - String url = String.format(serviceUpdateURL, server.getHttpPort()); - // empty prefix, null uri (bad argument), 400 bad request exception expected - HttpException ex = assertThrows(HttpException.class, ()->{ - execPost(url, "", null); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateNullPrefixValidNewURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // null prefix (bad argument), valid new uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, null, "http://www.localhost.org/uri6"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateNullPrefixExistingURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // null prefix (bad argument), existing uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, null, "http://www.localhost.org/uri1"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateNullPrefixInValidURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // null prefix (bad argument), invalid uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, null, "..."); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateNullPrefixEmptyURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // null prefix (bad argument), empty uri, 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, null, ""); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void updateNullPrefixNullURI() { - HttpException ex = assertThrows(HttpException.class, ()->{ - // null prefix (bad argument), null uri (bad argument), 400 bad request exception expected - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(url, null, null); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - -// GET ALL tests -// --------------------------------------------------------------------------------------------- - - @Test - public void getAllLegal() { - // request legal, returns multiple prefix-uri pairs - String url = String.format(serviceURL, server.getHttpPort()); - String postURL = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(postURL, "test", "http://www.localhost.org/uritest"); - execPost(postURL, "test2", "http://www.localhost.org/uritest2"); - execPost(postURL, "test3", "http://www.localhost.org/uritest3"); - String x = exec(url, ""); - - // convert to set - Set set = new HashSet<>(); - set.add("{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}"); - set.add("{\"prefix\":\"test2\",\"uri\":\"http://www.localhost.org/uritest2\"}"); - set.add("{\"prefix\":\"test3\",\"uri\":\"http://www.localhost.org/uritest3\"}"); - - Set resultSet = new HashSet<>(); - JsonArray jsonArray = JsonParser.parseString(x).getAsJsonArray(); - for (JsonElement element : jsonArray) { - resultSet.add(element.getAsJsonObject().toString()); - } - assertEquals(set, resultSet, "Expected prefix"); - } - - @Test - public void getAllEmpty() { - // request legal, dataset empty implies return [] - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, ""); - assertEquals("[]", x, "Expected prefix"); - } - -// FETCH PREFIX tests -// --------------------------------------------------------------------------------------------- - - @Test - public void fetchPrefixLegal() { - // request legal, uri exists in the database with a single prefix assigned - String url = String.format(serviceURL, server.getHttpPort()); - String postURL = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(postURL, "test", "http://www.localhost.org/uritest"); - String x = exec(url, "?uri=http://www.localhost.org/uritest"); - assertEquals("[{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}]", x, "Expected prefix"); - } - - @Test - public void fetchPrefixLegalMultiple() { - // request legal, uri exists in the database with multiple prefixes assigned - String url = String.format(serviceURL, server.getHttpPort()); - String postURL = String.format(serviceUpdateURL, server.getHttpPort()); - execPost(postURL, "test", "http://www.localhost.org/uritest"); - execPost(postURL, "testDuplicate", "http://www.localhost.org/uritest"); - String x = exec(url, "?uri=http://www.localhost.org/uritest"); - - // convert to set - Set set = new HashSet<>(); - set.add("{\"prefix\":\"test\",\"uri\":\"http://www.localhost.org/uritest\"}"); - set.add("{\"prefix\":\"testDuplicate\",\"uri\":\"http://www.localhost.org/uritest\"}"); - - Set resultSet = new HashSet<>(); - JsonArray jsonArray = JsonParser.parseString(x).getAsJsonArray(); - for (JsonElement element : jsonArray) { - resultSet.add(element.getAsJsonObject().toString()); - } - assertEquals(set, resultSet, "Expected prefix"); - } - - @Test - public void fetchPrefixLegalNull() { - // request legal, uri does not exist implies return [] - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?uri=http://www.localhost.org/uritest"); - assertEquals("[]", x, "Expected prefix"); - } - - @Test - public void fetchPrefixIllegal() { - // request illegal, uri is not valid - HttpException ex = assertThrows(HttpException.class, ()-> { - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?uri=----localhost.org/uritest"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void fetchPrefixEmpty() { - // request illegal, uri is empty - HttpException ex = assertThrows(HttpException.class, ()-> { - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?uri="); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void tooManyParams() { - // request illegal, provided too many arguments - HttpException ex = assertThrows(HttpException.class, ()-> { - String url = String.format(serviceURL, server.getHttpPort()); - String x = exec(url, "?prefix=abc?uri=cde"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - // REMOVE HTTP DELETE tests -// --------------------------------------------------------------------------------------------- - @Test - public void deleteURI0() { - // request legal, prefix exists, implies return null - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execDelete(url, "?prefix=prefix1"); - String x = exec(url, "?prefix=prefix1"); - assertEquals("", x, "Expected null got " + x); - } - - @Test - public void deleteURI1() { - // request legal, prefix doesn't exist implies return null - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execDelete(url, "?prefix=prefix16"); - String x = exec(url, "?prefix=prefix16"); - assertEquals("", x, "Expected null got " + x); - } - - @Test - public void deleteURI2() { - // request illegal, prefix invalid, 400 bad request exception expected - HttpException ex = assertThrows(HttpException.class, ()->{ - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execDelete(url, "?prefix=prefix16-"); - }); - assertEquals(HttpSC.BAD_REQUEST_400, ex.getStatusCode()); - } - - @Test - public void deleteURI3() { - // request legal, prefix exists implies return null - String url = String.format(serviceUpdateURL, server.getHttpPort()); - execDelete(url, "?prefix=prefix2"); - String x = exec(url, "?prefix=prefix2"); - assertEquals("", x, "Expected null got " + x); - } -// --------------------------------------------------------------------------------------------- - - private static String exec(String url, String queryString) { - String urlExec = queryString.startsWith("?") - ? url + queryString - : url + "?" + queryString; - return httpGetString(urlExec); - } - - private static void execPost(String url, String prefix, String uri) { - Params params = Params.create() - .add("prefix", prefix) - .add("uri", uri); - httpPostForm(url, params); - } - - private static void execDelete(String url, String queryString) { - String urlExec = queryString.startsWith("?") - ? url + queryString - : url+"?"+queryString; - httpDelete(urlExec); - } -} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePlain.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePlain.java index 68dd6963f21..4cc36ec5c4e 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePlain.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePlain.java @@ -20,8 +20,8 @@ import org.apache.jena.fuseki.servlets.prefixes.PrefixesPlain; -public class -TestPrefixesServicePlain extends TestAbstractPrefixParam { +/** Test the {@link PrefixesPlain} implementation. */ +public class TestPrefixesServicePlain extends AbstractTestPrefixesImpl { public TestPrefixesServicePlain() { super(new PrefixesPlain()); } diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePrefixesMap.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePrefixesMap.java index 2bc0446c824..f42fad16305 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePrefixesMap.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServicePrefixesMap.java @@ -23,7 +23,8 @@ import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.DatasetGraphFactory; -public class TestPrefixesServicePrefixesMap extends TestAbstractPrefixParam { +/** Test the {@link PrefixesMap} implementation. */ +public class TestPrefixesServicePrefixesMap extends AbstractTestPrefixesImpl { public TestPrefixesServicePrefixesMap() { super(make()); } diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServiceRDF.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServiceRDF.java index a2e7749d3bc..41c28d24262 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServiceRDF.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/prefixes/TestPrefixesServiceRDF.java @@ -20,7 +20,8 @@ import org.apache.jena.fuseki.servlets.prefixes.PrefixesRDF; -public class TestPrefixesServiceRDF extends TestAbstractPrefixParam { +/** Test the {@link PrefixesRDF} implementation. */ +public class TestPrefixesServiceRDF extends AbstractTestPrefixesImpl { public TestPrefixesServiceRDF() { super(new PrefixesRDF()); } diff --git a/jena-fuseki2/jena-fuseki-main/src/test/resources/log4j2-test.properties b/jena-fuseki2/jena-fuseki-main/src/test/resources/log4j2-test.properties index 6502551e14d..ac4c56bbcd6 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/resources/log4j2-test.properties +++ b/jena-fuseki2/jena-fuseki-main/src/test/resources/log4j2-test.properties @@ -22,23 +22,13 @@ logger.jena.level = INFO logger.arq-exec.name = org.apache.jena.arq.exec logger.arq-exec.level = INFO -## Dev -logger.http.name = org.apache.jena.http -logger.http.level = INFO - -logger.riot.name = org.apache.jena.riot -logger.riot.level = INFO - logger.fuseki.name = org.apache.jena.fuseki logger.fuseki.level = WARN -## Dev -logger.fuseki-main.name = org.apache.jena.fuseki.main -logger.fuseki-main.level = INFO - -#logger.fuseki-fuseki.name = org.apache.jena.fuseki.Fuseki -#logger.fuseki-fuseki.level = INFO -# +## Some tests generate request WARNings. +logger.fuseki-fuseki.name = org.apache.jena.fuseki.Fuseki +logger.fuseki-fuseki.level = ERROR + #logger.fuseki-server.name = org.apache.jena.fuseki.Server #logger.fuseki-server.level = INFO # @@ -47,10 +37,16 @@ logger.fuseki-main.level = INFO # #logger.fuseki-compact.name = org.apache.jena.fuseki.Compact #logger.fuseki-compact.level = WARN - + logger.fuseki-autoload.name = org.apache.jena.fuseki.main.sys.FusekiAutoModules logger.fuseki-autoload.level = ERROR +logger.http.name = org.apache.jena.http +logger.http.level = INFO + +logger.riot.name = org.apache.jena.riot +logger.riot.level = INFO + logger.jetty.name = org.eclipse.jetty logger.jetty.level = WARN