You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2026/04/06 09:56:50 UTC
(jena) 02/03: GH-3831: Handle UpdateException as 'bad request'
This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
commit 8035c616801abf58b8c4283d56422e3be765fdda
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Fri Apr 3 11:20:29 2026 +0100
GH-3831: Handle UpdateException as 'bad request'
---
.../jena/sparql/lang/arq/ParserARQUpdate.java | 10 +--
.../jena/fuseki/servlets/SPARQLProtocol.java | 6 +-
.../apache/jena/fuseki/servlets/SPARQL_Update.java | 18 ++---
.../org/apache/jena/fuseki/main/TS_FusekiMain.java | 3 +-
.../org/apache/jena/fuseki/main/TestUpdate.java | 79 ++++++++++++++++++++++
5 files changed, 92 insertions(+), 24 deletions(-)
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/lang/arq/ParserARQUpdate.java b/jena-arq/src/main/java/org/apache/jena/sparql/lang/arq/ParserARQUpdate.java
index 649f70fad4..c735e44a4c 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/lang/arq/ParserARQUpdate.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/lang/arq/ParserARQUpdate.java
@@ -26,11 +26,11 @@ import java.io.Reader;
import org.apache.jena.atlas.logging.Log;
import org.apache.jena.query.QueryException;
import org.apache.jena.query.QueryParseException;
-import org.apache.jena.shared.JenaException;
import org.apache.jena.sparql.core.Prologue;
import org.apache.jena.sparql.lang.UpdateParser;
import org.apache.jena.sparql.lang.arq.javacc.ARQParser;
import org.apache.jena.sparql.modify.UpdateSink;
+import org.apache.jena.update.UpdateException;
public class ParserARQUpdate extends UpdateParser {
public ParserARQUpdate() {}
@@ -50,18 +50,14 @@ public class ParserARQUpdate extends UpdateParser {
int col = parser.token.endColumn;
int line = parser.token.endLine;
throw new QueryParseException(tErr.getMessage(), line, col);
- }
-
- catch (QueryException ex) {
+ } catch (QueryException | UpdateException ex) {
throw ex;
- } catch (JenaException ex) {
- throw new QueryException(ex.getMessage(), ex);
} catch (Error err) {
// The token stream can throw errors.
throw new QueryParseException(err.getMessage(), err, -1, -1);
} catch (Throwable th) {
Log.error(this, "Unexpected throwable: ", th);
- throw new QueryException(th.getMessage(), th);
+ throw new UpdateException(th.getMessage(), th);
}
}
}
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQLProtocol.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQLProtocol.java
index d95c87c2d2..3c971523d8 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQLProtocol.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQLProtocol.java
@@ -30,11 +30,9 @@ import java.util.List;
import java.util.function.Predicate;
import jakarta.servlet.http.HttpServletRequest;
-
import org.apache.jena.atlas.iterator.Iter;
import org.apache.jena.atlas.lib.Lib;
import org.apache.jena.query.Query;
-import org.apache.jena.query.QueryException;
import org.apache.jena.query.QueryParseException;
import org.apache.jena.sparql.core.DatasetDescription;
@@ -44,9 +42,9 @@ import org.apache.jena.sparql.core.DatasetDescription;
public class SPARQLProtocol {
/**
- * Form a message from a {@link QueryException}.
+ * Form a message from an {@link Exception}.
*/
- public static String messageForException(QueryException ex) {
+ public static String messageForException(Exception ex) {
if ( ex.getMessage() != null )
return ex.getMessage();
if ( ex.getCause() != null )
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
index be1dc1b8b2..ddf594a36c 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
@@ -42,7 +42,6 @@ import java.util.Enumeration;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
-
import org.apache.jena.atlas.io.IO;
import org.apache.jena.atlas.lib.Bytes;
import org.apache.jena.atlas.lib.StrUtils;
@@ -52,13 +51,12 @@ import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.irix.IRIx;
import org.apache.jena.irix.IRIxResolver;
-import org.apache.jena.query.QueryBuildException;
+import org.apache.jena.query.QueryException;
import org.apache.jena.query.QueryParseException;
import org.apache.jena.query.Syntax;
import org.apache.jena.riot.WebContent;
import org.apache.jena.riot.web.HttpNames;
import org.apache.jena.shared.OperationDeniedException;
-import org.apache.jena.sparql.engine.http.QueryExceptionHTTP;
import org.apache.jena.sparql.modify.UsingList;
import org.apache.jena.update.UpdateAction;
import org.apache.jena.update.UpdateException;
@@ -230,24 +228,20 @@ public class SPARQL_Update extends ActionService
else
UpdateAction.execute(req, action.getActiveDSG());
action.commit();
- } catch (UpdateException ex) {
- ActionLib.consumeBody(action);
- abortSilent(action);
- incCounter(action.getEndpoint().getCounters(), UpdateExecErrors);
- ServletOps.errorOccurred(ex.getMessage());
} catch (QueryParseException ex) {
ActionLib.consumeBody(action);
abortSilent(action);
+ incCounter(action.getEndpoint().getCounters(), UpdateExecErrors);
String msg = messageForParseException(ex);
action.log.warn(format("[%d] Parse error: %s", action.id, msg));
- ServletOps.errorBadRequest(messageForException(ex));
- } catch (QueryBuildException|QueryExceptionHTTP ex) {
+ ServletOps.errorBadRequest(msg);
+ } catch (UpdateException | QueryException ex) {
ActionLib.consumeBody(action);
abortSilent(action);
- // Counter inc'ed further out.
+ incCounter(action.getEndpoint().getCounters(), UpdateExecErrors);
String msg = messageForException(ex);
action.log.warn(format("[%d] Bad request: %s", action.id, msg));
- ServletOps.errorBadRequest(messageForException(ex));
+ ServletOps.errorBadRequest(msg);
} catch (OperationDeniedException ex) {
ActionLib.consumeBody(action);
abortSilent(action);
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 443b8b9f81..09da890cda 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
@@ -56,6 +56,7 @@ import org.apache.jena.fuseki.main.sys.TestFusekiModules;
, TestHttpOptions.class
, TestQuery.class
, TestSPARQLProtocol.class
+ , TestUpdate.class
, TestPatchFuseki.class
, TestFusekiCustomScriptFunc.class
@@ -63,7 +64,7 @@ import org.apache.jena.fuseki.main.sys.TestFusekiModules;
, TS_PrefixesService.class
, TestMetrics.class
, TestFusekiShaclValidation.class
-
+
// Temporary independent test due for tarcking failures.
, TestFusekiShaclValidation2.class
diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestUpdate.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestUpdate.java
new file mode 100644
index 0000000000..88f67f6219
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestUpdate.java
@@ -0,0 +1,79 @@
+/*
+ * 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
+ *
+ * https://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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.apache.jena.fuseki.main;
+
+import org.junit.jupiter.api.Test;
+
+import org.apache.jena.rdflink.RDFLink;
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.apache.jena.sparql.core.DatasetGraphFactory;
+import org.apache.jena.sparql.exec.UpdateExec;
+
+public class TestUpdate {
+/*
+curl -v -XPOST 'http://localhost:3030/'"${DS}"'/?using-named-graph-uri=http%3A%2F%2Fexample%2Fpeople' \
+ -H 'Content-type: application/sparql-update' \
+ --data-binary 'WITH <http://example/addresses> DELETE { ?person ?p "Bill" } WHERE {}'
+ */
+
+ private static String PREFIXES = """
+ PREFIX : <http://example/>
+ """;
+ private static String DS = "/updateTest";
+
+ private FusekiServer server() {
+ DatasetGraph dsgTesting = DatasetGraphFactory.createTxnMem();
+ FusekiServer server = FusekiServer.create()
+ .port(0)
+ //.verbose(true)
+ .add(DS, dsgTesting)
+ .enablePing(true)
+ .enableMetrics(true)
+ .start();
+ return server;
+
+ }
+
+ @Test public void update2() {
+ FusekiServer server = server();
+ String serviceURL = server.datasetURL(DS);
+ try ( RDFLink link = RDFLink.connect(serviceURL) ) {
+ link.update(PREFIXES+"INSERT DATA { :s :p :o }");
+ }
+ }
+
+
+ @Test public void update1() {
+ FusekiServer server = server();
+ String serviceURL = server.datasetURL(DS);
+ UpdateExec.service(serviceURL).update(PREFIXES+"INSERT DATA { :s :p :o }").execute();
+ }
+
+ @Test public void updateError1() {
+ FusekiServer server = server();
+ String serviceURL = server.datasetURL(DS);
+ String URL = serviceURL+"/?using-named-graph-uri=http://example/ng1";
+ FusekiTestLib.expect400(()->
+ UpdateExec.service(URL).update(PREFIXES+" WITH <http://example/ng2> INSERT { :s :p :o } WHERE {}").execute()
+ );
+ }
+}