Merge pull request #867 from afs/n3-writer
JENA-1997: Remove old Turtle/N3 writer
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) {
diff --git a/jena-shacl/src/main/java/org/apache/jena/shacl/Imports.java b/jena-shacl/src/main/java/org/apache/jena/shacl/Imports.java
new file mode 100644
index 0000000..222221a
--- /dev/null
+++ b/jena-shacl/src/main/java/org/apache/jena/shacl/Imports.java
@@ -0,0 +1,152 @@
+/*
+ * 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.shacl;
+
+import static org.apache.jena.atlas.iterator.Iter.iter;
+import static org.apache.jena.sparql.graph.NodeConst.nodeOwlImports;
+import static org.apache.jena.sparql.graph.NodeConst.nodeOwlOntology;
+import static org.apache.jena.sparql.graph.NodeConst.nodeRDFType;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.jena.atlas.lib.Pair;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.riot.RDFDataMgr;
+import org.apache.jena.riot.other.G;
+import org.apache.jena.riot.system.IRIResolver;
+import org.apache.jena.sparql.graph.GraphFactory;
+
+/**
+ * Import processing.
+ * <p>
+ * Imports are triggered by a base (a single triple "? rdf:type owl:Ontology")
+ * and imports (triples "base owl:Imports URI").
+ * <p>
+ * If there are other "? owl:imports ?" triples, they are ignored.
+ */
+public class Imports {
+ private Imports() {}
+
+ /**
+ * Load a graph and process owl:imports to create a new, single graph.
+ */
+ public static Graph loadWithImports(String url) {
+ url = IRIResolver.resolveString(url);
+ Graph graph = RDFDataMgr.loadGraph(url);
+ return withImportsWorker(url, graph);
+ }
+
+ /**
+ * Process and return the owl:imports closure of a graph. The graph is included
+ * in the results. Note that without knowing the URI, the start graph may be read
+ * again if it is named as an import.
+ */
+ public static Graph withImports(Graph graph) {
+ return withImportsWorker(null, graph);
+ }
+
+ /**
+ * Process and return the owl:imports closure of a graph.
+ * The graph is included in the results.
+ */
+ public static Graph withImports(String url, Graph graph) {
+ url = IRIResolver.resolveString(url);
+ return withImportsWorker(url, graph);
+ }
+
+ private static Graph withImportsWorker(String url, Graph graph) {
+ // Partial check for any imports. Are there any imports triples?
+ boolean hasImports = G.contains(graph, null, nodeOwlImports, null);
+ if ( ! hasImports )
+ return graph;
+ // Probably some work to do.
+ // This is "import self", and start the "visited".
+ Graph acc = GraphFactory.createDefaultGraph();
+ GraphUtil.addInto(acc, graph);
+ Set<String> visited = new HashSet<>();
+ if ( url != null )
+ visited.add(url);
+ processImports(visited, graph, acc);
+ return acc;
+ }
+
+ /** Carefully traverse the imports, loading graphs. */
+ private static void processImports(Set<String> visited, Graph graph, Graph acc) {
+ List<Node> imports = imports(graph);
+ for ( Node imported : imports ) {
+ if ( ! imported.isURI() )
+ // Ignore non-URIs.
+ continue;
+ String uri = imported.getURI();
+ if ( ! visited.contains(uri) ) {
+ visited.add(uri);
+ // Read into a temporary graph to isolate errors.
+ try {
+ Graph g2 = RDFDataMgr.loadGraph(uri);
+ GraphUtil.addInto(acc, g2);
+ processImports(visited, g2, acc);
+ } catch (RuntimeException ex) {}
+ }
+ }
+ }
+
+ /** Return the imports for a graph */
+ public static List<Node> imports(Graph graph) {
+ Pair<Node,List<Node>> pair = baseAndImports(graph);
+ return pair.getRight();
+ }
+
+ /**
+ * Locate the base (a single triple ? rdf:type owl:Ontology)
+ * and imports (triples "base owl:Imports URI").
+ * Returns a Pair of (null,EmptyList) for no base.
+ */
+ public static Pair<Node,List<Node>> baseAndImports(Graph graph) {
+ Node base = G.getZeroOrOnePO(graph, nodeRDFType, nodeOwlOntology);
+ if ( base == null )
+ return Pair.create(null, Collections.emptyList());
+ List<Node> imports = allImports(base, graph);
+ return Pair.create(base, imports);
+ }
+
+ /**
+ * Locate the base (a single triple ? rdf:type owl:Ontology).
+ * If none or more than one matching triple, then return null.
+ */
+ public static Node base(Graph graph) {
+ // Filter for URI?
+ return G.getZeroOrOnePO(graph, nodeRDFType, nodeOwlOntology);
+ }
+
+ /**
+ * Locate any imports (triples "base owl:Imports URI").
+ * Base may be a wildcard indicating "any owl:imports".
+ */
+ public static List<Node> allImports(Node base, Graph graph) {
+ List<Node> imports = iter(G.listSP(graph, base, nodeOwlImports)).filter(Node::isURI).collect(Collectors.toList());
+ return imports;
+ }
+}
+
diff --git a/jena-shacl/src/main/java/org/apache/jena/shacl/Shapes.java b/jena-shacl/src/main/java/org/apache/jena/shacl/Shapes.java
index 12401a0..8e10e70 100644
--- a/jena-shacl/src/main/java/org/apache/jena/shacl/Shapes.java
+++ b/jena-shacl/src/main/java/org/apache/jena/shacl/Shapes.java
@@ -18,19 +18,14 @@
package org.apache.jena.shacl;
-import static org.apache.jena.sparql.graph.NodeConst.nodeOwlImports;
-import static org.apache.jena.sparql.graph.NodeConst.nodeOwlOntology;
-import static org.apache.jena.sparql.graph.NodeConst.nodeRDFType;
-
import java.util.*;
import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.atlas.lib.Pair;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.Node;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.riot.RDFDataMgr;
-import org.apache.jena.riot.other.G;
-import org.apache.jena.riot.other.RDFDataException;
import org.apache.jena.shacl.engine.Targets;
import org.apache.jena.shacl.parser.Shape;
import org.apache.jena.shacl.parser.ShapesParser;
@@ -70,6 +65,16 @@
return parse(g);
}
+ /** Load the file, parse the graph and return the shapes. */
+ public static Shapes parse(String fileOrURL, boolean withImports) {
+ Graph g = withImports
+ ? Imports.loadWithImports(fileOrURL)
+ : RDFDataMgr.loadGraph(fileOrURL);
+ return parse(g);
+ }
+
+
+
/** Parse the graph and return the shapes connected to the targets. */
public static Shapes parse(Graph graph) {
return parseAll(graph);
@@ -122,7 +127,7 @@
return new Shapes(shapesGraph, shapesMap, targets, rootShapes, declShapes);
}
- public Shapes(Graph shapesGraph, Map<Node, Shape> shapesMap, Targets targets,
+ private Shapes(Graph shapesGraph, Map<Node, Shape> shapesMap, Targets targets,
Collection<Shape> rootShapes, Collection<Shape> declShapes) {
this.shapesGraph = shapesGraph;
this.targets = targets;
@@ -130,15 +135,10 @@
this.rootShapes = rootShapes;
this.declShapes = declShapes;
- Node _shapesBase = null;
- List<Node> _imports = null;
// Extract base and imports.
- try {
- _shapesBase = G.getOnePO(shapesGraph, nodeRDFType, nodeOwlOntology);
- _imports = G.listSP(shapesGraph, _shapesBase, nodeOwlImports);
- } catch (RDFDataException ex) {}
- this.shapesBase = _shapesBase;
- this.imports = _imports;
+ Pair<Node,List<Node>> pair = Imports.baseAndImports(shapesGraph);
+ this.shapesBase = pair.getLeft();
+ this.imports = pair.getRight();
}
public boolean isEmpty() {
diff --git a/jena-shacl/src/main/java/org/apache/jena/shacl/parser/ShapesParser.java b/jena-shacl/src/main/java/org/apache/jena/shacl/parser/ShapesParser.java
index b4daec9..bb2e331 100644
--- a/jena-shacl/src/main/java/org/apache/jena/shacl/parser/ShapesParser.java
+++ b/jena-shacl/src/main/java/org/apache/jena/shacl/parser/ShapesParser.java
@@ -70,13 +70,13 @@
* Applications should call functions in {@link Shapes} rather than call the parser directly.
*/
public static Collection<Shape> parseShapes(Graph shapesGraph, Targets targets, Map<Node, Shape> shapesMap) {
- // Cycle detection.
+ // Cycle detection.
Set<Node> cycles = new HashSet<>();
return parseShapes(shapesGraph, targets, shapesMap, cycles);
}
-
+
/*package*/ static Collection<Shape> parseShapes(Graph shapesGraph, Targets targets, Map<Node, Shape> shapesMap, Set<Node> cycles) {
-
+
Targets rootShapes = targets;
if ( DEBUG )
@@ -173,21 +173,20 @@
// ---- Main parser worker.
/**
- * Parse one shape updating the record of shapes already parsed.
+ * Parse one shape, updating the record of shapes already parsed.
*
* @param shapesMap
* @param shapesGraph
* @param shNode
* @return Shape
*/
-
+
public static Shape parseShape(Map<Node, Shape> shapesMap, Graph shapesGraph, Node shNode) {
Set<Node> traversed = new HashSet<>();
Shape shape = parseShapeStep(traversed, shapesMap, shapesGraph, shNode);
return shape;
}
-
// /** Parse a specific shape from the Shapes graph */
// private static Shape parseShape(Graph shapesGraph, Node shNode) {
// // Avoid recursion.
@@ -230,18 +229,18 @@
| sh:path |
-------------------
*/
-
+
/** Do nothing placeholder shape. */
- static Shape unshape(Graph shapesGraph, Node shapeNode) { return
+ static Shape unshape(Graph shapesGraph, Node shapeNode) { return
new NodeShape(shapesGraph, shapeNode, false, Severity.Violation,
Collections.emptySet(), Collections.emptySet(),
Collections.singleton(new JLogConstraint("Cycle")),
Collections.emptySet());
}
-
+
/** parse a shape during a parsing process */
/*package*/ static Shape parseShapeStep(Set<Node> traversed, Map<Node, Shape> parsed, Graph shapesGraph, Node shapeNode) {
- try {
+ try {
// Called by Constraints
if ( parsed.containsKey(shapeNode) )
return parsed.get(shapeNode);
diff --git a/jena-shacl/src/test/files/imports/graph1.ttl b/jena-shacl/src/test/files/imports/graph1.ttl
new file mode 100644
index 0000000..1331124
--- /dev/null
+++ b/jena-shacl/src/test/files/imports/graph1.ttl
@@ -0,0 +1,12 @@
+PREFIX : <http://example/>
+
+PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+PREFIX sh: <http://www.w3.org/ns/shacl#>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+PREFIX owl: <http://www.w3.org/2002/07/owl#>
+
+:graph1 rdf:type owl:Ontology ;
+ owl:imports <graph2.ttl> , <graph3.ttl> .
+
+:graph1 :p [] .
diff --git a/jena-shacl/src/test/files/imports/graph2.ttl b/jena-shacl/src/test/files/imports/graph2.ttl
new file mode 100644
index 0000000..2e71c06
--- /dev/null
+++ b/jena-shacl/src/test/files/imports/graph2.ttl
@@ -0,0 +1,13 @@
+PREFIX : <http://example/>
+
+PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+PREFIX sh: <http://www.w3.org/ns/shacl#>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+PREFIX owl: <http://www.w3.org/2002/07/owl#>
+
+:graph2 rdf:type owl:Ontology .
+
+:graph2 owl:imports <graph4.ttl> .
+
+:graph2 :p [] .
diff --git a/jena-shacl/src/test/files/imports/graph3.ttl b/jena-shacl/src/test/files/imports/graph3.ttl
new file mode 100644
index 0000000..7ab1c13
--- /dev/null
+++ b/jena-shacl/src/test/files/imports/graph3.ttl
@@ -0,0 +1,16 @@
+PREFIX : <http://example/>
+
+PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+PREFIX sh: <http://www.w3.org/ns/shacl#>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+PREFIX owl: <http://www.w3.org/2002/07/owl#>
+
+:graph3 rdf:type owl:Ontology .
+
+# Complicated - if starting at graph1, this is a cycle.
+:graph3 owl:imports <graph1.ttl> .
+
+:graph3 owl:imports <graph4.ttl> , <graph5.ttl> .
+
+:graph3 :p [] .
diff --git a/jena-shacl/src/test/files/imports/graph4.ttl b/jena-shacl/src/test/files/imports/graph4.ttl
new file mode 100644
index 0000000..8e68743
--- /dev/null
+++ b/jena-shacl/src/test/files/imports/graph4.ttl
@@ -0,0 +1,9 @@
+PREFIX : <http://example/>
+
+PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+PREFIX sh: <http://www.w3.org/ns/shacl#>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+PREFIX owl: <http://www.w3.org/2002/07/owl#>
+
+:graph4 :p [] .
diff --git a/jena-shacl/src/test/files/imports/graph5.ttl b/jena-shacl/src/test/files/imports/graph5.ttl
new file mode 100644
index 0000000..2f2c7c4
--- /dev/null
+++ b/jena-shacl/src/test/files/imports/graph5.ttl
@@ -0,0 +1,9 @@
+PREFIX : <http://example/>
+
+PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+PREFIX sh: <http://www.w3.org/ns/shacl#>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+PREFIX owl: <http://www.w3.org/2002/07/owl#>
+
+:graph5 :p [] .
diff --git a/jena-shacl/src/test/java/org/apache/jena/shacl/TC_SHACL.java b/jena-shacl/src/test/java/org/apache/jena/shacl/TC_SHACL.java
index 9fa247b..3ced5f8 100644
--- a/jena-shacl/src/test/java/org/apache/jena/shacl/TC_SHACL.java
+++ b/jena-shacl/src/test/java/org/apache/jena/shacl/TC_SHACL.java
@@ -19,6 +19,7 @@
package org.apache.jena.shacl;
import org.apache.jena.shacl.compact.TS_Compact;
+import org.apache.jena.shacl.tests.TestImports;
import org.apache.jena.shacl.tests.TestValidationReport;
import org.apache.jena.shacl.tests.jena_shacl.TS_JenaShacl;
import org.apache.jena.shacl.tests.std.TS_StdSHACL;
@@ -31,6 +32,7 @@
, TS_StdSHACL.class
, TS_JenaShacl.class
, TS_Compact.class
+ , TestImports.class
} )
public class TC_SHACL { }
diff --git a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/TestImports.java b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/TestImports.java
new file mode 100644
index 0000000..0d39d16
--- /dev/null
+++ b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/TestImports.java
@@ -0,0 +1,115 @@
+/*
+ * 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.shacl.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.apache.jena.atlas.lib.Pair;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.riot.RDFDataMgr;
+import org.apache.jena.riot.other.G;
+import org.apache.jena.riot.system.IRIResolver;
+import org.apache.jena.shacl.Imports;
+import org.junit.Test;
+
+public class TestImports {
+ // Work in absolute URIs.
+ private static String FILES = IRIResolver.resolveString("src/test/files/imports");
+ private static Node g1 = NodeFactory.createURI("http://example/graph1");
+ private static Node g2 = NodeFactory.createURI("http://example/graph2");
+ private static Node g3 = NodeFactory.createURI("http://example/graph3");
+ private static Node g4 = NodeFactory.createURI("http://example/graph4");
+ private static Node g5 = NodeFactory.createURI("http://example/graph5");
+
+ private static Node u1 = NodeFactory.createURI(FILES+"/graph1.ttl");
+ private static Node u2 = NodeFactory.createURI(FILES+"/graph2.ttl");
+ private static Node u3 = NodeFactory.createURI(FILES+"/graph3.ttl");
+ private static Node u4 = NodeFactory.createURI(FILES+"/graph4.ttl");
+ private static Node u5 = NodeFactory.createURI(FILES+"/graph5.ttl");
+
+ private static Node predicate = NodeFactory.createURI("http://example/p");
+
+ @Test public void testImports1() {
+ Graph graph = RDFDataMgr.loadGraph(FILES+"/graph1.ttl");
+ Node base = Imports.base(graph);
+ assertEquals(g1, base);
+ }
+
+ @Test public void testImports2() {
+ Graph graph = RDFDataMgr.loadGraph(FILES+"/graph1.ttl");
+ List<Node> imports = Imports.imports(graph);
+ assertEquals(2, imports.size());
+ assertTrue(imports.contains(u2));
+ assertTrue(imports.contains(u3));
+ }
+
+ @Test public void testImports3() {
+ Graph graph = RDFDataMgr.loadGraph(FILES+"/graph1.ttl");
+
+ Pair<Node, List<Node>> pair = Imports.baseAndImports(graph);
+ Node base = pair.getLeft();
+ List<Node> imports = pair.getRight();
+
+ assertEquals(g1, base);
+ assertEquals(2, imports.size());
+ assertTrue(imports.contains(u2));
+ assertTrue(imports.contains(u3));
+ }
+
+ @Test public void testImportsLoading1() {
+ Graph graph = Imports.loadWithImports(FILES+"/graph1.ttl");
+ // Used blank nodes to detect loaded once or multiple times.
+ //RDFDataMgr.write(System.out, graph, Lang.TTL);
+ assertTrue(G.containsOne(graph, g1, predicate, null));
+ assertTrue(G.containsOne(graph, g2, predicate, null));
+ assertTrue(G.containsOne(graph, g3, predicate, null));
+ assertTrue(G.containsOne(graph, g4, predicate, null));
+ assertTrue(G.containsOne(graph, g5, predicate, null));
+ }
+
+ @Test public void testImportsLoading2() {
+ Graph graph1 = RDFDataMgr.loadGraph(FILES+"/graph1.ttl");
+ Graph graph = Imports.withImports(FILES+"/graph1.ttl",graph1);
+ assertTrue(G.containsOne(graph, g1, predicate, null));
+ assertTrue(G.containsOne(graph, g2, predicate, null));
+ assertTrue(G.containsOne(graph, g3, predicate, null));
+ assertTrue(G.containsOne(graph, g4, predicate, null));
+ assertTrue(G.containsOne(graph, g5, predicate, null));
+ }
+
+ @Test public void testImportsLoading3() {
+ Graph graph1 = RDFDataMgr.loadGraph(FILES+"/graph1.ttl");
+ Graph graph = Imports.withImports(graph1);
+ // Will be read again due to not knowing it URI.
+ // Skip test.
+ // assertTrue(G.containsOne(graph, g1, p, null));
+ assertTrue(G.containsOne(graph, g2, predicate, null));
+ assertTrue(G.containsOne(graph, g3, predicate, null));
+ assertTrue(G.containsOne(graph, g4, predicate, null));
+ assertTrue(G.containsOne(graph, g5, predicate, null));
+ }
+
+
+}
+