Merge pull request #866 from afs/shacl-imports

JENA-1998: Imports closure machinery
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/async/AsyncPool.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/async/AsyncPool.java
index 0315900..aaf2bb6 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/async/AsyncPool.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/async/AsyncPool.java
@@ -65,7 +65,13 @@
             Callable<Object> c = ()->{
                 try { task.run(); }
                 catch (Throwable th) {
+                    // Generally speaking tasks should provide more specific log messages when they fail but this
+                    // handles the case of tasks not doing that
                     Fuseki.serverLog.error(format("Exception in task %s execution", taskId), th);
+                    
+                    // Need to throw the error upwards so that the AsyncTask, which is itself a Callable, can use
+                    // this to set the success flag correctly
+                    throw th;
                 }
                 return null;
             };
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/async/AsyncTask.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/async/AsyncTask.java
index 56cc408..71b4810 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/async/AsyncTask.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/async/AsyncTask.java
@@ -46,7 +46,9 @@
     private final String taskId;
 
     private long requestId;
-
+    
+    private Boolean success = null;
+    
     /*package*/ AsyncTask(Callable<Object> callable,
                           AsyncPool pool,
                           String taskId,
@@ -95,10 +97,15 @@
     public Object call() {
         try {
             start();
-            return callable.call();
+            Object result = callable.call();
+            this.success = true;
+            return result;
         }
-        catch (Exception ex) {
-            log.error("Async task threw an expection", ex);
+        catch (Throwable ex) {
+            // NB - Since the only place that constructs an AsyncTask is AsyncPool.submit() and that is already
+            // set up to handle uncaught exceptions and throw them onwards all we need to do here is set the
+            // success flag to false
+            this.success = false;
             return null;
         }
         finally {
@@ -114,5 +121,9 @@
     public String getFinishPoint() {
         return finishPoint;
     }
+    
+    public Boolean wasSuccessful() {
+        return this.success;
+    }
 }
 
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionSleep.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionSleep.java
index eae26d2..ab47f03 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionSleep.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionSleep.java
@@ -102,6 +102,9 @@
                 log.info(format("[Task %d] << Sleep finish", actionId));
             } catch (Exception ex) {
                 log.info(format("[Task %d] **** Exception", actionId), ex);
+                // Must also throw the error upwards so that the async task tracking infrastucture can set the
+                // success flag correctly
+                throw ex;
             }
         }
     }
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionTasks.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionTasks.java
index df60bf9..b674294 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionTasks.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionTasks.java
@@ -80,7 +80,6 @@
 
             for ( AsyncPool pool : pools ) {
                 for ( AsyncTask aTask : pool.tasks() ) {
-                    //builder.value(aTask.getTaskId());
                     descOneTask(builder, aTask);
                 }
             }
@@ -116,6 +115,8 @@
             builder.key(JsonConstCtl.started).value(aTask.getStartPoint());
         if ( aTask.getFinishPoint() != null )
             builder.key(JsonConstCtl.finished).value(aTask.getFinishPoint());
+        if ( aTask.wasSuccessful() != null )
+            builder.key(JsonConstCtl.success).value(aTask.wasSuccessful());
         builder.finishObject("SingleTask");
     }
 }
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/JsonConstCtl.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/JsonConstCtl.java
index 6f439d6..db67b9b 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/JsonConstCtl.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/JsonConstCtl.java
@@ -25,5 +25,6 @@
     public static final String task             = "task";
     public static final String finished         = "finished";
     public static final String started          = "started";
+    public static final String success          = "success";
 
 }
diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
index 12b1ecd..051757c 100644
--- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
+++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
@@ -1018,6 +1018,7 @@
                 addServlet(context, "/$/stats/*", new ActionStats());
             if ( withMetrics )
                 addServlet(context, "/$/metrics", new ActionMetrics());
+            // TODO Should we support registering other functionality e.g. /$/backup/* and /$/compact/*
 
             servlets.forEach(p-> addServlet(context, p.getLeft(), p.getRight()));
             filters.forEach (p-> addFilter(context, p.getLeft(), p.getRight()));
diff --git a/jena-fuseki2/jena-fuseki-webapp/pom.xml b/jena-fuseki2/jena-fuseki-webapp/pom.xml
index 8744ccf..52693b5 100644
--- a/jena-fuseki2/jena-fuseki-webapp/pom.xml
+++ b/jena-fuseki2/jena-fuseki-webapp/pom.xml
@@ -56,7 +56,7 @@
       <artifactId>jena-text</artifactId>
       <version>3.17.0-SNAPSHOT</version>
     </dependency>
-
+    
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-webapp</artifactId>
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ActionBackup.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ActionBackup.java
index aa153af..bb669d4b 100644
--- a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ActionBackup.java
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ActionBackup.java
@@ -61,8 +61,11 @@
                 log.info(format("[%d] >>>> Start backup %s -> %s", actionId, datasetName, backupFilename));
                 Backup.backup(transactional, dataset, backupFilename);
                 log.info(format("[%d] <<<< Finish backup %s -> %s", actionId, datasetName, backupFilename));
-            } catch (Exception ex) {
+            } catch (Throwable ex) {
                 log.info(format("[%d] **** Exception in backup", actionId), ex);
+                // Must also throw the error upwards so that the async task tracking infrastucture can set the
+                // success flag correctly
+                throw ex;
             }
         }
     }
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ActionCompact.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ActionCompact.java
new file mode 100644
index 0000000..4d8a597
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ActionCompact.java
@@ -0,0 +1,72 @@
+/**
+ * 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.mgt;
+
+import static java.lang.String.format;
+
+import org.apache.jena.fuseki.ctl.ActionAsyncTask;
+import org.apache.jena.fuseki.ctl.TaskBase;
+import org.apache.jena.fuseki.servlets.HttpAction;
+import org.apache.jena.fuseki.servlets.ServletOps;
+import org.apache.jena.tdb2.DatabaseMgr;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ActionCompact extends ActionAsyncTask
+{
+    public ActionCompact() { super("Compact"); }
+
+    @Override
+    public void validate(HttpAction action) {}
+
+    @Override
+    protected Runnable createRunnable(HttpAction action) {
+        String name = getItemName(action);
+        if ( name == null ) {
+            action.log.error("Null for dataset name in item request");
+            ServletOps.errorOccurred("Null for dataset name in item request");
+            return null;
+        }
+
+        action.log.info(format("[%d] Compact dataset %s", action.id, name));
+        return new CompactTask(action);
+    }
+
+    static class CompactTask extends TaskBase {
+        static private Logger log = LoggerFactory.getLogger("Compact");
+
+        public CompactTask(HttpAction action) {
+            super(action);
+        }
+
+        @Override
+        public void run() {
+            try {
+                log.info(format("[%d] >>>> Start compact %s", actionId, datasetName));
+                DatabaseMgr.compact(dataset);
+                log.info(format("[%d] <<<< Finish compact %s", actionId, datasetName));
+            } catch (Throwable ex) {
+                log.info(format("[%d] **** Exception in compact", actionId), ex);
+                // Must also throw the error upwards so that the async task tracking infrastucture can set the
+                // success flag correctly
+                throw ex;
+            }
+        }
+    }
+}
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/Backup.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/Backup.java
index 3ac2457..8d49f3b 100644
--- a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/Backup.java
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/Backup.java
@@ -27,7 +27,6 @@
 import org.apache.jena.atlas.io.IO;
 import org.apache.jena.atlas.lib.DateTimeUtils;
 import org.apache.jena.atlas.logging.FmtLog;
-import org.apache.jena.atlas.logging.Log;
 import org.apache.jena.fuseki.Fuseki;
 import org.apache.jena.fuseki.FusekiException;
 import org.apache.jena.fuseki.webapp.FusekiWebapp;
@@ -71,10 +70,7 @@
         transactional.begin(ReadWrite.READ);
         try {
             Backup.backup(dsg, backupfile);
-        } catch (Exception ex) {
-            Log.warn(Fuseki.serverLog, "Exception in backup", ex);
-        }
-        finally {
+        } finally {
             transactional.end();
         }
     }
@@ -84,6 +80,10 @@
      * @see #backup(Transactional, DatasetGraph, String)
      */
     private static void backup(DatasetGraph dsg, String backupfile) {
+        if (dsg == null) {
+            throw new FusekiException("No dataset provided to backup");
+        }
+        
         if ( !backupfile.endsWith(".nq") )
             backupfile = backupfile + ".nq";
 
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ServerMgtConst.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ServerMgtConst.java
index dd92290..056b161 100644
--- a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ServerMgtConst.java
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/mgt/ServerMgtConst.java
@@ -24,6 +24,8 @@
  */
 public class ServerMgtConst {
     public static final String  opDatasets      = "datasets";
+    public static final String  opBackup        = "backup";
+    public static final String  opCompact       = "compact";
     public static final String  opListBackups   = "backups-list";
     public static final String  opServer        = "server";
 
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/WEB-INF/web.xml b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/WEB-INF/web.xml
index 7af1640..ab64a9a 100644
--- a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/WEB-INF/web.xml
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/WEB-INF/web.xml
@@ -207,6 +207,11 @@
     <servlet-name>BackupListServlet</servlet-name>
     <servlet-class>org.apache.jena.fuseki.mgt.ActionBackupList</servlet-class>
   </servlet>
+  
+  <servlet>
+    <servlet-name>ActionCompact</servlet-name>
+    <servlet-class>org.apache.jena.fuseki.mgt.ActionCompact</servlet-class>
+  </servlet>
 
   <!-- An action that only creates a background task that sleeps. -->
   <servlet>
@@ -233,6 +238,11 @@
     <servlet-name>BackupListServlet</servlet-name>
     <url-pattern>/$/backups-list</url-pattern>
   </servlet-mapping>
+  
+  <servlet-mapping>
+    <servlet-name>ActionCompact</servlet-name>
+    <url-pattern>/$/compact/*</url-pattern>
+  </servlet-mapping>
 
   <!-- Admin controls-->
 
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/test/java/org/apache/jena/fuseki/TestAdmin.java b/jena-fuseki2/jena-fuseki-webapp/src/test/java/org/apache/jena/fuseki/TestAdmin.java
index 6b07ea0..d7d8866 100644
--- a/jena-fuseki2/jena-fuseki-webapp/src/test/java/org/apache/jena/fuseki/TestAdmin.java
+++ b/jena-fuseki2/jena-fuseki-webapp/src/test/java/org/apache/jena/fuseki/TestAdmin.java
@@ -18,11 +18,8 @@
 
 package org.apache.jena.fuseki;
 
-import static org.apache.jena.fuseki.mgt.ServerMgtConst.opDatasets;
-import static org.apache.jena.fuseki.mgt.ServerMgtConst.opListBackups;
-import static org.apache.jena.fuseki.mgt.ServerMgtConst.opServer;
-import static org.apache.jena.fuseki.server.ServerConst.opPing;
-import static org.apache.jena.fuseki.server.ServerConst.opStats;
+import static org.apache.jena.fuseki.mgt.ServerMgtConst.*;
+import static org.apache.jena.fuseki.server.ServerConst.*;
 import static org.apache.jena.riot.web.HttpOp.execHttpDelete;
 import static org.apache.jena.riot.web.HttpOp.execHttpGet;
 import static org.apache.jena.riot.web.HttpOp.execHttpPost;
@@ -35,6 +32,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.lang3.SystemUtils;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.entity.FileEntity;
@@ -46,6 +44,7 @@
 import org.apache.jena.atlas.lib.Lib;
 import org.apache.jena.atlas.web.HttpException;
 import org.apache.jena.atlas.web.TypedInputStream;
+import org.apache.jena.fuseki.ctl.JsonConstCtl;
 import org.apache.jena.fuseki.mgt.ServerMgtConst;
 import org.apache.jena.fuseki.server.ServerConst;
 import org.apache.jena.fuseki.test.FusekiTest;
@@ -53,15 +52,18 @@
 import org.apache.jena.riot.web.HttpOp;
 import org.apache.jena.riot.web.HttpResponseHandler;
 import org.apache.jena.web.HttpSC;
+import org.junit.Assert;
+import org.junit.AssumptionViolatedException;
 import org.junit.Test;
 
 /** Tests of the admin functionality */
 public class TestAdmin extends AbstractFusekiTest {
 
     // Name of the dataset in the assembler file.
-    static String dsTest    = "test-ds1";
-    static String dsTestInf = "test-ds4";
-    static String fileBase  = "testing/";
+    static String dsTest      = "test-ds1";
+    static String dsTestInf   = "test-ds4";
+    static String dsTestTdb2  = "test-tdb2";
+    static String fileBase    = "testing/";
 
     // --- Ping
 
@@ -187,6 +189,21 @@
         addTestDataset(fileBase+"config-ds-plain-2.ttl");
         checkExists("test-ds2");
     }
+    
+    @Test public void add_delete_dataset_6() {
+        assumeNotWindows();
+        
+        checkNotThere(dsTestTdb2);
+
+        addTestDatasetTdb2();
+
+        // Check exists.
+        checkExists(dsTestTdb2);
+
+        // Remove it.
+        deleteDataset(dsTestTdb2);
+        checkNotThere(dsTestTdb2);
+    }
 
     @Test public void add_error_1() {
         FusekiTest.execWithHttpException(HttpSC.BAD_REQUEST_400,
@@ -247,6 +264,116 @@
     }
 
     // ---- Backup
+    
+    @Test public void create_backup_1() {
+        String id = null;
+        try {
+            JsonResponseHandler x = new JsonResponseHandler();
+            execHttpPost(ServerCtl.urlRoot() + "$/" + opBackup + "/" + ServerCtl.datasetPath(), null, WebContent.contentTypeJSON, x);
+            JsonValue v = x.getJSON();
+            id = v.getAsObject().getString("taskId");
+        } finally {
+            waitForTasksToFinish(1000, 5000);
+        }
+        Assert.assertNotNull(id);
+        checkInTasks(id);
+        
+        // Check a backup was created
+        try ( TypedInputStream in = execHttpGet(ServerCtl.urlRoot()+"$/"+opListBackups) ) {
+            assertEqualsIgnoreCase(WebContent.contentTypeJSON, in.getContentType());
+            JsonValue v = JSON.parseAny(in);
+            assertNotNull(v.getAsObject().get("backups"));
+            JsonArray a = v.getAsObject().get("backups").getAsArray();
+            Assert.assertEquals(1, a.size());
+        }
+        
+        JsonValue task = getTask(id);
+        Assert.assertNotNull(id);
+        // Expect task success
+        Assert.assertTrue("Expected task to be marked as successful", task.getAsObject().getBoolean(JsonConstCtl.success));
+    }
+    
+    @Test
+    public void create_backup_2() {
+        String id = null;
+        try {
+            JsonResponseHandler x = new JsonResponseHandler();
+            execHttpPost(ServerCtl.urlRoot() + "$/" + opBackup + "/noSuchDataset", null, WebContent.contentTypeJSON, x);
+            JsonValue v = x.getJSON();
+            id = v.getAsObject().getString(JsonConstCtl.taskId);
+        } finally {
+            waitForTasksToFinish(1000, 5000);
+        }
+        Assert.assertNotNull(id);
+        checkInTasks(id);
+        
+        JsonValue task = getTask(id);
+        Assert.assertNotNull(task);
+        // Expect task failure
+        Assert.assertFalse("Expected task to be marked as failed", task.getAsObject().getBoolean(JsonConstCtl.success));
+    }
+
+    @Test public void list_backups_1() {
+        try ( TypedInputStream in = execHttpGet(ServerCtl.urlRoot()+"$/"+opListBackups) ) {
+            assertEqualsIgnoreCase(WebContent.contentTypeJSON, in.getContentType());
+            JsonValue v = JSON.parseAny(in);
+            assertNotNull(v.getAsObject().get("backups"));
+        }
+    }
+    
+    // ---- Compact
+    
+    @Test public void compact_01() {
+        assumeNotWindows();
+        try {
+            checkNotThere(dsTestTdb2);
+            addTestDatasetTdb2();
+            checkExists(dsTestTdb2);
+            
+            String id = null;
+            try {
+                JsonResponseHandler x = new JsonResponseHandler();
+                execHttpPost(ServerCtl.urlRoot() + "$/" + opCompact + "/" + dsTestTdb2, null, WebContent.contentTypeJSON, x);
+                JsonValue v = x.getJSON();
+                id = v.getAsObject().getString(JsonConstCtl.taskId);
+            } finally {
+                waitForTasksToFinish(1000, 5000);
+            }
+            Assert.assertNotNull(id);
+            checkInTasks(id);
+            
+            JsonValue task = getTask(id);
+            Assert.assertNotNull(id);
+            // Expect task success
+            Assert.assertTrue("Expected task to be marked as successful", task.getAsObject().getBoolean(JsonConstCtl.success));
+        } finally {
+            deleteDataset(dsTestTdb2);
+        }
+    }
+    
+    @Test public void compact_02() {
+        String id = null;
+        try {
+            JsonResponseHandler x = new JsonResponseHandler();
+            execHttpPost(ServerCtl.urlRoot() + "$/" + opCompact + "/noSuchDataset", null, WebContent.contentTypeJSON, x);
+            JsonValue v = x.getJSON();
+            id = v.getAsObject().getString(JsonConstCtl.taskId);
+        } finally {
+            waitForTasksToFinish(1000, 5000);
+        }
+        Assert.assertNotNull(id);
+        checkInTasks(id);
+        
+        JsonValue task = getTask(id);
+        Assert.assertNotNull(id);
+        // Expect task failure
+        Assert.assertFalse("Expected task to be marked as failed", task.getAsObject().getBoolean(JsonConstCtl.success));
+    }
+
+    private void assumeNotWindows() {
+        if (SystemUtils.IS_OS_WINDOWS)
+            throw new AssumptionViolatedException("Test may be unstable on Windows due to inability to delete memory-mapped files");
+    }
 
     // ---- Server
 
@@ -393,14 +520,6 @@
         }
     }
 
-    @Test public void list_backups_1() {
-        try ( TypedInputStream in = execHttpGet(ServerCtl.urlRoot()+"$/"+opListBackups) ) {
-            assertEqualsIgnoreCase(WebContent.contentTypeJSON, in.getContentType());
-            JsonValue v = JSON.parseAny(in);
-            assertNotNull(v.getAsObject().get("backups"));
-        }
-    }
-
     private void assertEqualsIgnoreCase(String contenttypejson, String contentType) {}
 
     private static JsonValue getTask(String taskId) {
@@ -425,6 +544,10 @@
     private static void addTestDatasetInf() {
         addTestDataset(fileBase+"config-ds-inf.ttl");
     }
+    
+    private static void addTestDatasetTdb2() {
+        addTestDataset(fileBase+"config-tdb2.ttl");
+    }
 
     private static void addTestDataset(String filename) {
         File f = new File(filename);
@@ -659,6 +782,7 @@
         POST    /$/datasets/*{name}*?state=offline
         POST    /$/datasets/*{name}*?state=active
         POST    /$/backup/*{name}*
+        POST    /$/compact/*{name}*
         GET     /$/server
         POST    /$/server/shutdown
         GET     /$/stats/
diff --git a/jena-fuseki2/jena-fuseki-webapp/testing/config-tdb2.ttl b/jena-fuseki2/jena-fuseki-webapp/testing/config-tdb2.ttl
new file mode 100644
index 0000000..0c35f4c
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/testing/config-tdb2.ttl
@@ -0,0 +1,18 @@
+## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0
+
+PREFIX :        <#>
+PREFIX fuseki:  <http://jena.apache.org/fuseki#>
+PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>
+PREFIX ja:      <http://jena.hpl.hp.com/2005/11/Assembler#>
+PREFIX tdb2:    <http://jena.apache.org/2016/tdb#>
+
+<#service1> #rdf:type fuseki:Service ;
+    # URI of the dataset -- http://host:port/ds
+    fuseki:name                        "test-tdb2" ; 
+    fuseki:serviceQuery                "sparql" ;
+    fuseki:dataset                     <#dataset> .
+
+<#dataset> rdf:type      tdb2:DatasetTDB2 ;
+    tdb2:location "target/tdb2" .
diff --git a/jena-geosparql/pom.xml b/jena-geosparql/pom.xml
index f0975b0..2ce3d9c 100644
--- a/jena-geosparql/pom.xml
+++ b/jena-geosparql/pom.xml
@@ -41,7 +41,7 @@
     <dependency>
       <groupId>org.apache.sis.non-free</groupId>
       <artifactId>sis-embedded-data</artifactId>
-      <version>0.8</version>
+      <version>1.0</version>
       <scope>test</scope>
     </dependency>
 
@@ -60,7 +60,7 @@
     <dependency>
       <groupId>org.apache.sis.core</groupId>
       <artifactId>sis-referencing</artifactId>
-      <version>0.8</version>
+      <version>1.0</version>
     </dependency>
 
     <dependency>
diff --git a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/datatype/GMLDatatypeTest.java b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/datatype/GMLDatatypeTest.java
index 2678e91..5cfa147 100644
--- a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/datatype/GMLDatatypeTest.java
+++ b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/datatype/GMLDatatypeTest.java
@@ -17,7 +17,12 @@
  */
 package org.apache.jena.geosparql.implementation.datatype;
 
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
 import java.io.IOException;
+
 import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
 import org.apache.jena.geosparql.implementation.DimensionInfo;
 import org.apache.jena.geosparql.implementation.GeometryWrapper;
@@ -25,22 +30,9 @@
 import org.apache.jena.geosparql.implementation.jts.CustomCoordinateSequence;
 import org.apache.jena.geosparql.implementation.jts.CustomGeometryFactory;
 import org.apache.jena.geosparql.implementation.vocabulary.SRS_URI;
-import static org.hamcrest.CoreMatchers.not;
 import org.jdom2.JDOMException;
-import org.junit.After;
-import org.junit.AfterClass;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.locationtech.jts.geom.Coordinate;
-import org.locationtech.jts.geom.Geometry;
-import org.locationtech.jts.geom.GeometryFactory;
-import org.locationtech.jts.geom.LineString;
-import org.locationtech.jts.geom.LinearRing;
-import org.locationtech.jts.geom.Point;
-import org.locationtech.jts.geom.Polygon;
+import org.junit.*;
+import org.locationtech.jts.geom.*;
 
 /**
  *
diff --git a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/datatype/WKTDatatypeTest.java b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/datatype/WKTDatatypeTest.java
index 73f6856..fdbc349 100644
--- a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/datatype/WKTDatatypeTest.java
+++ b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/datatype/WKTDatatypeTest.java
@@ -28,7 +28,7 @@
 import org.junit.After;
 import org.junit.AfterClass;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
diff --git a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/registry/SRSRegistryTest.java b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/registry/SRSRegistryTest.java
index 7f230ab..0269aa7 100644
--- a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/registry/SRSRegistryTest.java
+++ b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/registry/SRSRegistryTest.java
@@ -87,10 +87,10 @@
                     + "  Scope[\"Horizontal component of 3D system. Used by the GPS satellite navigation system and for NATO military geodetic surveying.\"],\n"
                     + "  Area[\"World.\"],\n"
                     + "  BBox[-90.00, -180.00, 90.00, 180.00],\n"
-                    + "  Id[\"CRS\", 84, Citation[\"OGC:WMS\"], URI[\"urn:ogc:def:crs:OGC:1.3:CRS84\"]]]";
+                    + "  Id[\"CRS\", 84, Citation[\"WMS\"], URI[\"urn:ogc:def:crs:OGC:1.3:CRS84\"]]]";
 
             CoordinateReferenceSystem expResult = CRS.fromWKT(default_CRS_WKT);
-            CoordinateReferenceSystem result = SRSRegistry.getCRS(srsURI);
+            CoordinateReferenceSystem result = SRSRegistry.getCRS(srsURI);          
             assertEquals(expResult.toWKT(), result.toWKT());
         } catch (FactoryException ex) {